diff options
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 39 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 17 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 51 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 81 |
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) && |