aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse')
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp39
-rw-r--r--lib/Parse/ParseDecl.cpp17
-rw-r--r--lib/Parse/ParseDeclCXX.cpp51
-rw-r--r--lib/Parse/Parser.cpp81
4 files changed, 156 insertions, 32 deletions
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 1e1a0e2b07..dee00275e7 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -25,8 +25,9 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers& VS, ExprResult& Init) {
assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
- assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) &&
- "Current token not a '{', ':' or 'try'!");
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) ||
+ Tok.is(tok::equal)) &&
+ "Current token not a '{', ':', '=', or 'try'!");
MultiTemplateParamsArg TemplateParams(Actions,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
@@ -48,6 +49,40 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
D.complete(FnD);
+ if (Tok.is(tok::equal)) {
+ ConsumeToken();
+
+ bool Delete = false;
+ SourceLocation KWLoc;
+ if (Tok.is(tok::kw_delete)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDeleted(FnD, KWLoc);
+ Delete = true;
+ } else if (Tok.is(tok::kw_default)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDefaulted(FnD, KWLoc);
+ } else {
+ llvm_unreachable("function definition after = not 'delete' or 'default'");
+ }
+
+ if (Tok.is(tok::comma)) {
+ Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
+ << Delete;
+ SkipUntil(tok::semi);
+ } else {
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ Delete ? "delete" : "default", tok::semi);
+ }
+
+ return FnD;
+ }
+
// In delayed template parsing mode, if we are within a class template
// or if we are about to parse function member template then consume
// the tokens and store them for parsing at the end of the translation unit.
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index c54a0ed707..d7b90f129c 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -968,14 +968,17 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
diag::err_invalid_equalequal_after_declarator)) {
ConsumeToken();
if (Tok.is(tok::kw_delete)) {
- SourceLocation DelLoc = ConsumeToken();
-
- if (!getLang().CPlusPlus0x)
- Diag(DelLoc, diag::warn_deleted_function_accepted_as_extension);
-
- Actions.SetDeclDeleted(ThisDecl, DelLoc);
+ if (D.isFunctionDeclarator())
+ Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_deleted_non_function);
} else if (Tok.is(tok::kw_default)) {
- Diag(ConsumeToken(), diag::err_default_special_members);
+ if (D.isFunctionDeclarator())
+ Diag(Tok, diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_default_special_members);
} else {
if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
EnterScope(0);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index ecf66a79db..91b55d5b58 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1614,10 +1614,21 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SkipUntil(tok::comma, true, true);
}
+ bool IsDefinition = false;
// function-definition:
- if (Tok.is(tok::l_brace)
- || (DeclaratorInfo.isFunctionDeclarator() &&
- (Tok.is(tok::colon) || Tok.is(tok::kw_try)))) {
+ if (Tok.is(tok::l_brace)) {
+ IsDefinition = true;
+ } else if (DeclaratorInfo.isFunctionDeclarator()) {
+ if (Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
+ IsDefinition = true;
+ } else if (Tok.is(tok::equal)) {
+ const Token &KW = NextToken();
+ if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
+ IsDefinition = true;
+ }
+ }
+
+ if (IsDefinition) {
if (!DeclaratorInfo.isFunctionDeclarator()) {
Diag(Tok, diag::err_func_def_no_params);
ConsumeBrace();
@@ -1644,9 +1655,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init);
- // Consume the optional ';'
- if (Tok.is(tok::semi))
+
+ // Consume the ';' - it's optional unless we have a delete or default
+ if (Tok.is(tok::semi)) {
ConsumeToken();
+ }
return;
}
@@ -1658,8 +1671,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
llvm::SmallVector<Decl *, 8> DeclsInGroup;
ExprResult BitfieldSize;
- bool Deleted = false;
- SourceLocation DefaultLoc;
while (1) {
// member-declarator:
@@ -1687,14 +1698,17 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::equal)) {
ConsumeToken();
if (Tok.is(tok::kw_delete)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
- ConsumeToken();
- Deleted = true;
+ if (DeclaratorInfo.isFunctionDeclarator())
+ Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_deleted_non_function);
} else if (Tok.is(tok::kw_default)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
- DefaultLoc = ConsumeToken();
+ if (DeclaratorInfo.isFunctionDeclarator())
+ Diag(Tok, diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_default_special_members);
} else {
Init = ParseInitializer();
if (Init.isInvalid())
@@ -1722,9 +1736,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
Decl *ThisDecl = 0;
if (DS.isFriendSpecified()) {
- if (DefaultLoc.isValid())
- Diag(DefaultLoc, diag::err_default_special_members);
-
// TODO: handle initializers, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
/*IsDefinition*/ false,
@@ -1734,9 +1745,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DeclaratorInfo,
move(TemplateParams),
BitfieldSize.release(),
- VS, Init.release(),
- /*IsDefinition*/Deleted,
- Deleted, DefaultLoc);
+ VS, Init.release(), false);
}
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);
@@ -1762,8 +1771,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
VS.clear();
BitfieldSize = 0;
Init = 0;
- Deleted = false;
- DefaultLoc = SourceLocation();
// Attributes are only allowed on the second declarator.
MaybeParseGNUAttributes(DeclaratorInfo);
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 263a4916b6..4e4819e9fc 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -677,7 +677,14 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
/// \brief Determine whether the current token, if it occurs after a
/// declarator, continues a declaration or declaration list.
-bool Parser::isDeclarationAfterDeclarator() const {
+bool Parser::isDeclarationAfterDeclarator() {
+ // Check for '= delete' or '= default'
+ if (getLang().CPlusPlus && Tok.is(tok::equal)) {
+ const Token &KW = NextToken();
+ if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
+ return false;
+ }
+
return Tok.is(tok::equal) || // int X()= -> not a function def
Tok.is(tok::comma) || // int X(), -> not a function def
Tok.is(tok::semi) || // int X(); -> not a function def
@@ -698,6 +705,11 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
if (!getLang().CPlusPlus &&
Declarator.getFunctionTypeInfo().isKNRPrototype())
return isDeclarationSpecifier();
+
+ if (getLang().CPlusPlus && Tok.is(tok::equal)) {
+ const Token &KW = NextToken();
+ return KW.is(tok::kw_default) || KW.is(tok::kw_delete);
+ }
return Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
Tok.is(tok::kw_try); // X() try { ... }
@@ -820,6 +832,73 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (FTI.isKNRPrototype())
ParseKNRParamDeclarations(D);
+ if (Tok.is(tok::equal)) {
+ assert(getLang().CPlusPlus && "Only C++ function definitions have '='");
+ ConsumeToken();
+
+ Decl *Decl = 0;
+ // Here we complete the declaration as if it were normal
+ switch (TemplateInfo.Kind) {
+ case ParsedTemplateInfo::NonTemplate:
+ Decl = Actions.ActOnDeclarator(getCurScope(), D, true);
+ break;
+
+ case ParsedTemplateInfo::Template:
+ case ParsedTemplateInfo::ExplicitSpecialization:
+ Decl = Actions.ActOnTemplateDeclarator(getCurScope(),
+ MultiTemplateParamsArg(Actions,
+ TemplateInfo.TemplateParams->data(),
+ TemplateInfo.TemplateParams->size()),
+ D);
+ break;
+
+ case ParsedTemplateInfo::ExplicitInstantiation: {
+ DeclResult Result
+ = Actions.ActOnExplicitInstantiation(getCurScope(),
+ TemplateInfo.ExternLoc,
+ TemplateInfo.TemplateLoc,
+ D);
+ if (Result.isInvalid()) {
+ SkipUntil(tok::semi);
+ return 0;
+ }
+
+ Decl = Result.get();
+ break;
+ }
+ }
+
+ bool Delete = false;
+ SourceLocation KWLoc;
+ if (Tok.is(tok::kw_delete)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDeleted(Decl, KWLoc);
+ Delete = true;
+ } else if (Tok.is(tok::kw_default)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDefaulted(Decl, KWLoc);
+ } else {
+ llvm_unreachable("function definition after = not 'delete' or 'default'");
+ }
+
+ if (Tok.is(tok::comma)) {
+ Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
+ << Delete;
+ SkipUntil(tok::semi);
+ } else {
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ Delete ? "delete" : "default", tok::semi);
+ }
+
+ return Decl;
+ }
+
// We should have either an opening brace or, in a C++ constructor,
// we may have a colon.
if (Tok.isNot(tok::l_brace) &&