diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp | 35 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp | 120 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp | 1544 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp | 685 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp | 365 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp | 610 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp | 179 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp | 526 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp | 118 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParsePragma.h | 10 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp | 252 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp | 184 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp | 331 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/Parser.cpp | 454 |
14 files changed, 3569 insertions, 1844 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp index fdd7d0f..d1c2624 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp @@ -38,23 +38,24 @@ using namespace clang; void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, ASTContext &Ctx, bool PrintStats, TranslationUnitKind TUKind, - CodeCompleteConsumer *CompletionConsumer) { + CodeCompleteConsumer *CompletionConsumer, + bool SkipFunctionBodies) { - llvm::OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer, + OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer)); // Recover resources if we crash before exiting this method. - llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleaupSema(S.get()); + llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get()); - ParseAST(*S.get(), PrintStats); + ParseAST(*S.get(), PrintStats, SkipFunctionBodies); } -void clang::ParseAST(Sema &S, bool PrintStats) { +void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { // Collect global stats on Decls/Stmts (until we have a module streamer). if (PrintStats) { - Decl::CollectingStats(true); - Stmt::CollectingStats(true); + Decl::EnableStatistics(); + Stmt::EnableStatistics(); } // Also turn on collection of stats inside of the Sema object. @@ -63,14 +64,15 @@ void clang::ParseAST(Sema &S, bool PrintStats) { ASTConsumer *Consumer = &S.getASTConsumer(); - llvm::OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S)); + OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S, + SkipFunctionBodies)); Parser &P = *ParseOP.get(); PrettyStackTraceParserEntry CrashInfo(P); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<Parser> - CleaupParser(ParseOP.get()); + CleanupParser(ParseOP.get()); S.getPreprocessor().EnterMainSourceFile(); P.Initialize(); @@ -79,18 +81,23 @@ void clang::ParseAST(Sema &S, bool PrintStats) { if (ExternalASTSource *External = S.getASTContext().getExternalSource()) External->StartTranslationUnit(Consumer); + bool Abort = false; Parser::DeclGroupPtrTy ADecl; while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. // If we got a null return and something *was* parsed, ignore it. This // is due to a top-level semicolon, an action override, or a parse error // skipping something. - if (ADecl) - Consumer->HandleTopLevelDecl(ADecl.get()); + if (ADecl) { + if (!Consumer->HandleTopLevelDecl(ADecl.get())) { + Abort = true; + break; + } + } }; - // Check for any pending objective-c implementation decl. - while ((ADecl = P.FinishPendingObjCActions())) - Consumer->HandleTopLevelDecl(ADecl.get()); + + if (Abort) + return; // Process any TopLevelDecls generated by #pragma weak. for (SmallVector<Decl*,2>::iterator diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp index b387e9e..c000f69 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -24,8 +24,10 @@ using namespace clang; Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs, ParsingDeclarator &D, - const ParsedTemplateInfo &TemplateInfo, - const VirtSpecifiers& VS, ExprResult& Init) { + const ParsedTemplateInfo &TemplateInfo, + const VirtSpecifiers& VS, + FunctionDefinitionKind DefinitionKind, + 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) || Tok.is(tok::equal)) && @@ -36,20 +38,20 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); Decl *FnD; - D.setFunctionDefinition(true); + D.setFunctionDefinitionKind(DefinitionKind); if (D.getDeclSpec().isFriendSpecified()) FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, move(TemplateParams)); else { FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, move(TemplateParams), 0, - VS, /*HasInit=*/false); + VS, /*HasDeferredInit=*/false); if (FnD) { Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false, true); bool TypeSpecContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; - if (Init.get()) + if (Init.isUsable()) Actions.AddInitializerToDecl(FnD, Init.get(), false, TypeSpecContainsAuto); else @@ -64,18 +66,25 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, if (Tok.is(tok::equal)) { ConsumeToken(); + if (!FnD) { + SkipUntil(tok::semi); + return 0; + } + bool Delete = false; SourceLocation KWLoc; if (Tok.is(tok::kw_delete)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::warn_deleted_function_accepted_as_extension); + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_deleted_function : + diag::ext_deleted_function); 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); + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_defaulted_function : + diag::ext_defaulted_function); KWLoc = ConsumeToken(); Actions.SetDeclDefaulted(FnD, KWLoc); @@ -98,15 +107,13 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, // 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. - if (getLang().DelayedTemplateParsing && + if (getLangOpts().DelayedTemplateParsing && ((Actions.CurContext->isDependentContext() || TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) && - !Actions.IsInsideALocalClassWithinATemplateFunction()) && - !D.getDeclSpec().isFriendSpecified()) { + !Actions.IsInsideALocalClassWithinATemplateFunction())) { if (FnD) { - LateParsedTemplatedFunction *LPT = - new LateParsedTemplatedFunction(this, FnD); + LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD); FunctionDecl *FD = 0; if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD)) @@ -138,16 +145,14 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, // function body. if (ConsumeAndStoreFunctionPrologue(Toks)) { // We didn't find the left-brace we expected after the - // constructor initializer. - if (Tok.is(tok::semi)) { - // We found a semicolon; complain, consume the semicolon, and - // don't try to parse this method later. - Diag(Tok.getLocation(), diag::err_expected_lbrace); - ConsumeAnyToken(); - delete getCurrentClass().LateParsedDeclarations.back(); - getCurrentClass().LateParsedDeclarations.pop_back(); - return FnD; - } + // constructor initializer; we already printed an error, and it's likely + // impossible to recover, so don't try to parse this method later. + // If we stopped at a semicolon, consume it to avoid an extra warning. + if (Tok.is(tok::semi)) + ConsumeToken(); + delete getCurrentClass().LateParsedDeclarations.back(); + getCurrentClass().LateParsedDeclarations.pop_back(); + return FnD; } else { // Consume everything up to (and including) the matching right brace. ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); @@ -188,7 +193,7 @@ void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) { tok::TokenKind kind = Tok.getKind(); if (kind == tok::equal) { Toks.push_back(Tok); - ConsumeAnyToken(); + ConsumeToken(); } if (kind == tok::l_brace) { @@ -290,7 +295,8 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { Scope::FunctionPrototypeScope|Scope::DeclScope); for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { // Introduce the parameter into scope. - Actions.ActOnDelayedCXXMethodParameter(getCurScope(), LM.DefaultArgs[I].Param); + Actions.ActOnDelayedCXXMethodParameter(getCurScope(), + LM.DefaultArgs[I].Param); if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { // Save the current token position. @@ -310,9 +316,15 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // The argument isn't actually potentially evaluated unless it is // used. EnterExpressionEvaluationContext Eval(Actions, - Sema::PotentiallyEvaluatedIfUsed); - - ExprResult DefArgResult(ParseAssignmentExpression()); + Sema::PotentiallyEvaluatedIfUsed, + LM.DefaultArgs[I].Param); + + ExprResult DefArgResult; + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + DefArgResult = ParseBraceInitializer(); + } else + DefArgResult = ParseAssignmentExpression(); if (DefArgResult.isInvalid()) Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); else { @@ -469,7 +481,8 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { ConsumeAnyToken(); SourceLocation EqualLoc; - ExprResult Init = ParseCXXMemberInitializer(/*IsFunction=*/false, EqualLoc); + ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false, + EqualLoc); Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release()); @@ -596,6 +609,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { Toks.push_back(Tok); ConsumeToken(); } + bool ReadInitializer = false; if (Tok.is(tok::colon)) { // Initializers can contain braces too. Toks.push_back(Tok); @@ -603,37 +617,52 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { while (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { if (Tok.is(tok::eof) || Tok.is(tok::semi)) - return true; + return Diag(Tok.getLocation(), diag::err_expected_lbrace); // Grab the identifier. if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false)) - return true; + return Diag(Tok.getLocation(), diag::err_expected_lparen); tok::TokenKind kind = Tok.getKind(); Toks.push_back(Tok); - if (kind == tok::l_paren) + bool IsLParen = (kind == tok::l_paren); + SourceLocation LOpen = Tok.getLocation(); + + if (IsLParen) { ConsumeParen(); - else { + } else { assert(kind == tok::l_brace && "Must be left paren or brace here."); ConsumeBrace(); // In C++03, this has to be the start of the function body, which - // means the initializer is malformed. - if (!getLang().CPlusPlus0x) + // means the initializer is malformed; we'll diagnose it later. + if (!getLangOpts().CPlusPlus0x) return false; } // Grab the initializer - if (!ConsumeAndStoreUntil(kind == tok::l_paren ? tok::r_paren : - tok::r_brace, - Toks, /*StopAtSemi=*/true)) + if (!ConsumeAndStoreUntil(IsLParen ? tok::r_paren : tok::r_brace, + Toks, /*StopAtSemi=*/true)) { + Diag(Tok, IsLParen ? diag::err_expected_rparen : + diag::err_expected_rbrace); + Diag(LOpen, diag::note_matching) << (IsLParen ? "(" : "{"); return true; + } + + // Grab pack ellipsis, if present + if (Tok.is(tok::ellipsis)) { + Toks.push_back(Tok); + ConsumeToken(); + } // Grab the separating comma, if any. if (Tok.is(tok::comma)) { Toks.push_back(Tok); ConsumeToken(); + } else if (Tok.isNot(tok::l_brace)) { + ReadInitializer = true; + break; } } } @@ -641,11 +670,14 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { // Grab any remaining garbage to be diagnosed later. We stop when we reach a // brace: an opening one is the function body, while a closing one probably // means we've reached the end of the class. - if (!ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks, - /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false)) - return true; - if(Tok.isNot(tok::l_brace)) - return true; + ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks, + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false); + if (Tok.isNot(tok::l_brace)) { + if (ReadInitializer) + return Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma); + return Diag(Tok.getLocation(), diag::err_expected_lbrace); + } Toks.push_back(Tok); ConsumeBrace(); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index 2aa178f..cf3dca2 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -19,6 +19,7 @@ #include "clang/Sema/PrettyDeclStackTrace.h" #include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; @@ -35,9 +36,11 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, Declarator::TheContext Context, AccessSpecifier AS, Decl **OwnedType) { + DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context); + // Parse the common declaration-specifiers piece. DeclSpec DS(AttrFactory); - ParseSpecifierQualifierList(DS, AS); + ParseSpecifierQualifierList(DS, AS, DSC); if (OwnedType) *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0; @@ -94,6 +97,8 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) { /// which is followed by a comma or close parenthesis, then the arguments /// start with that identifier; otherwise they are an expression list." /// +/// GCC does not require the ',' between attribs in an attribute-list. +/// /// At the moment, I am not doing 2 token lookahead. I am also unaware of /// any attributes that don't work (based on my limited testing). Most /// attributes are very simple in practice. Until we find a bug, I don't see @@ -129,14 +134,15 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, if (Tok.is(tok::l_paren)) { // handle "parameterized" attributes - if (LateAttrs && !ClassStack.empty() && - isAttributeLateParsed(*AttrName)) { - // Delayed parsing is only available for attributes that occur - // in certain locations within a class scope. + if (LateAttrs && isAttributeLateParsed(*AttrName)) { LateParsedAttribute *LA = new LateParsedAttribute(this, *AttrName, AttrNameLoc); LateAttrs->push_back(LA); - getCurrentClass().LateParsedDeclarations.push_back(LA); + + // Attributes in a class are parsed at the end of the class, along + // with other late-parsed declarations. + if (!ClassStack.empty()) + getCurrentClass().LateParsedDeclarations.push_back(LA); // consume everything up to and including the matching right parens ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false); @@ -187,107 +193,89 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, ConsumeParen(); // ignore the left paren loc for now - if (Tok.is(tok::identifier)) { - IdentifierInfo *ParmName = Tok.getIdentifierInfo(); - SourceLocation ParmLoc = ConsumeToken(); + IdentifierInfo *ParmName = 0; + SourceLocation ParmLoc; + bool BuiltinType = false; - if (Tok.is(tok::r_paren)) { - // __attribute__(( mode(byte) )) - SourceLocation RParen = ConsumeParen(); - Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, - ParmName, ParmLoc, 0, 0); - } else if (Tok.is(tok::comma)) { + switch (Tok.getKind()) { + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_bool: + case tok::kw_short: + case tok::kw_int: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_float: + case tok::kw_double: + case tok::kw_void: + case tok::kw_typeof: + // __attribute__(( vec_type_hint(char) )) + // FIXME: Don't just discard the builtin type token. + ConsumeToken(); + BuiltinType = true; + break; + + case tok::identifier: + ParmName = Tok.getIdentifierInfo(); + ParmLoc = ConsumeToken(); + break; + + default: + break; + } + + ExprVector ArgExprs(Actions); + + if (!BuiltinType && + (ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) { + // Eat the comma. + if (ParmLoc.isValid()) ConsumeToken(); - // __attribute__(( format(printf, 1, 2) )) - ExprVector ArgExprs(Actions); - bool ArgExprsOk = true; - - // now parse the non-empty comma separated list of expressions - while (1) { - ExprResult ArgExpr(ParseAssignmentExpression()); - if (ArgExpr.isInvalid()) { - ArgExprsOk = false; - SkipUntil(tok::r_paren); - break; - } else { - ArgExprs.push_back(ArgExpr.release()); - } - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // Eat the comma, move to the next argument - } - if (ArgExprsOk && Tok.is(tok::r_paren)) { - SourceLocation RParen = ConsumeParen(); - Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, - ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); + + // Parse the non-empty comma-separated list of expressions. + while (1) { + ExprResult ArgExpr(ParseAssignmentExpression()); + if (ArgExpr.isInvalid()) { + SkipUntil(tok::r_paren); + return; } + ArgExprs.push_back(ArgExpr.release()); + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // Eat the comma, move to the next argument } - } else { // not an identifier - switch (Tok.getKind()) { - case tok::r_paren: { - // parse a possibly empty comma separated list of expressions - // __attribute__(( nonnull() )) - SourceLocation RParen = ConsumeParen(); - Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, - 0, SourceLocation(), 0, 0); - break; - } - case tok::kw_char: - case tok::kw_wchar_t: - case tok::kw_char16_t: - case tok::kw_char32_t: - case tok::kw_bool: - case tok::kw_short: - case tok::kw_int: - case tok::kw_long: - case tok::kw___int64: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::kw_float: - case tok::kw_double: - case tok::kw_void: - case tok::kw_typeof: { - // If it's a builtin type name, eat it and expect a rparen - // __attribute__(( vec_type_hint(char) )) - SourceLocation EndLoc = ConsumeToken(); - if (Tok.is(tok::r_paren)) - EndLoc = ConsumeParen(); - AttributeList *attr - = Attrs.addNew(AttrName, SourceRange(AttrNameLoc, EndLoc), 0, - AttrNameLoc, 0, SourceLocation(), 0, 0); - if (attr->getKind() == AttributeList::AT_IBOutletCollection) - Diag(Tok, diag::err_iboutletcollection_builtintype); - break; - } - default: - // __attribute__(( aligned(16) )) - ExprVector ArgExprs(Actions); - bool ArgExprsOk = true; - - // now parse the list of expressions - while (1) { - ExprResult ArgExpr(ParseAssignmentExpression()); - if (ArgExpr.isInvalid()) { - ArgExprsOk = false; - SkipUntil(tok::r_paren); + } + else if (Tok.is(tok::less) && AttrName->isStr("iboutletcollection")) { + if (!ExpectAndConsume(tok::less, diag::err_expected_less_after, "<", + tok::greater)) { + while (Tok.is(tok::identifier)) { + ConsumeToken(); + if (Tok.is(tok::greater)) break; - } else { - ArgExprs.push_back(ArgExpr.release()); + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; } - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // Eat the comma, move to the next argument - } - // Match the ')'. - if (ArgExprsOk && Tok.is(tok::r_paren)) { - SourceLocation RParen = ConsumeParen(); - Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, - AttrNameLoc, 0, SourceLocation(), - ArgExprs.take(), ArgExprs.size()); } - break; + if (Tok.isNot(tok::greater)) + Diag(Tok, diag::err_iboutletcollection_with_protocol); + SkipUntil(tok::r_paren, false, true); // skip until ')' } } + + SourceLocation RParen = Tok.getLocation(); + if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { + AttributeList *attr = + Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, + ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); + if (BuiltinType && attr->getKind() == AttributeList::AT_iboutletcollection) + Diag(Tok, diag::err_iboutletcollection_builtintype); + } } @@ -450,7 +438,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { // are stored in the numeric constant. We utilize a quirk of the // lexer, which is that it handles something like 1.2.3 as a single // numeric constant, rather than two separate tokens. - llvm::SmallString<512> Buffer; + SmallString<512> Buffer; Buffer.resize(Tok.getLength()+1); const char *ThisTokBegin = &Buffer[0]; @@ -539,7 +527,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { /// \brief Parse the contents of the "availability" attribute. /// /// availability-attribute: -/// 'availability' '(' platform ',' version-arg-list ')' +/// 'availability' '(' platform ',' version-arg-list, opt-message')' /// /// platform: /// identifier @@ -551,8 +539,10 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { /// version-arg: /// 'introduced' '=' version /// 'deprecated' '=' version -/// 'removed' = version +/// 'obsoleted' = version /// 'unavailable' +/// opt-message: +/// 'message' '=' <string> void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, SourceLocation AvailabilityLoc, ParsedAttributes &attrs, @@ -562,6 +552,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, enum { Introduced, Deprecated, Obsoleted, Unknown }; AvailabilityChange Changes[Unknown]; + ExprResult MessageExpr; // Opening '('. BalancedDelimiterTracker T(*this, tok::l_paren); @@ -590,6 +581,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, Ident_deprecated = PP.getIdentifierInfo("deprecated"); Ident_obsoleted = PP.getIdentifierInfo("obsoleted"); Ident_unavailable = PP.getIdentifierInfo("unavailable"); + Ident_message = PP.getIdentifierInfo("message"); } // Parse the set of introductions/deprecations/removals. @@ -616,7 +608,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, ConsumeToken(); continue; } - + if (Tok.isNot(tok::equal)) { Diag(Tok, diag::err_expected_equal_after) << Keyword; @@ -624,6 +616,15 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, return; } ConsumeToken(); + if (Keyword == Ident_message) { + if (!isTokenStringLiteral()) { + Diag(Tok, diag::err_expected_string_literal); + SkipUntil(tok::r_paren); + return; + } + MessageExpr = ParseStringLiteralExpression(); + break; + } SourceRange VersionRange; VersionTuple Version = ParseVersionTuple(VersionRange); @@ -694,12 +695,13 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, // Record this attribute attrs.addNew(&Availability, SourceRange(AvailabilityLoc, T.getCloseLocation()), - 0, SourceLocation(), + 0, AvailabilityLoc, Platform, PlatformLoc, Changes[Introduced], Changes[Deprecated], Changes[Obsoleted], - UnavailableLoc, false, false); + UnavailableLoc, MessageExpr.take(), + false, false); } @@ -713,7 +715,7 @@ void Parser::LateParsedClass::ParseLexedAttributes() { } void Parser::LateParsedAttribute::ParseLexedAttributes() { - Self->ParseLexedAttribute(*this); + Self->ParseLexedAttribute(*this, true, false); } /// Wrapper class which calls ParseLexedAttribute, after setting up the @@ -733,17 +735,39 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) { ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); + // Enter the scope of nested classes + if (!AlreadyHasClassScope) + Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), + Class.TagOrTemplate); + for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i) { Class.LateParsedDeclarations[i]->ParseLexedAttributes(); } + + if (!AlreadyHasClassScope) + Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), + Class.TagOrTemplate); +} + + +/// \brief Parse all attributes in LAs, and attach them to Decl D. +void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, + bool EnterScope, bool OnDefinition) { + for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) { + LAs[i]->addDecl(D); + ParseLexedAttribute(*LAs[i], EnterScope, OnDefinition); + } + LAs.clear(); } + /// \brief Finish parsing an attribute for which parsing was delayed. /// This will be called at the end of parsing a class declaration /// for each LateParsedAttribute. We consume the saved tokens and /// create an attribute with the arguments filled in. We add this /// to the Attribute list for the decl. -void Parser::ParseLexedAttribute(LateParsedAttribute &LA) { +void Parser::ParseLexedAttribute(LateParsedAttribute &LA, + bool EnterScope, bool OnDefinition) { // Save the current token position. SourceLocation OrigLoc = Tok.getLocation(); @@ -754,35 +778,49 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA) { // Consume the previously pushed token. ConsumeAnyToken(); + if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) { + Diag(Tok, diag::warn_attribute_on_function_definition) + << LA.AttrName.getName(); + } + ParsedAttributes Attrs(AttrFactory); SourceLocation endLoc; - // If the Decl is templatized, add template parameters to scope. - bool HasTemplateScope = LA.D && LA.D->isTemplateDecl(); - ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) - Actions.ActOnReenterTemplateScope(Actions.CurScope, LA.D); + if (LA.Decls.size() == 1) { + Decl *D = LA.Decls[0]; - // If the Decl is on a function, add function parameters to the scope. - bool HasFunctionScope = LA.D && LA.D->isFunctionOrFunctionTemplate(); - ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope); - if (HasFunctionScope) - Actions.ActOnReenterFunctionContext(Actions.CurScope, LA.D); + // If the Decl is templatized, add template parameters to scope. + bool HasTemplateScope = EnterScope && D->isTemplateDecl(); + ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(Actions.CurScope, D); - ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); + // If the Decl is on a function, add function parameters to the scope. + bool HasFunctionScope = EnterScope && D->isFunctionOrFunctionTemplate(); + ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope); + if (HasFunctionScope) + Actions.ActOnReenterFunctionContext(Actions.CurScope, D); - if (HasFunctionScope) { - Actions.ActOnExitFunctionContext(); - FnScope.Exit(); // Pop scope, and remove Decls from IdResolver - } - if (HasTemplateScope) { - TempScope.Exit(); + ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); + + if (HasFunctionScope) { + Actions.ActOnExitFunctionContext(); + FnScope.Exit(); // Pop scope, and remove Decls from IdResolver + } + if (HasTemplateScope) { + TempScope.Exit(); + } + } else if (LA.Decls.size() > 0) { + // If there are multiple decls, then the decl cannot be within the + // function scope. + ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); + } else { + Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName(); } - // Late parsed attributes must be attached to Decls by hand. If the - // LA.D is not set, then this was not done properly. - assert(LA.D && "No decl attached to late parsed attribute"); - Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.D, Attrs); + for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i) { + Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.Decls[i], Attrs); + } if (Tok.getLocation() != OrigLoc) { // Due to a parsing error, we either went over the cached tokens or @@ -792,7 +830,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA) { if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), OrigLoc)) while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof)) - ConsumeAnyToken(); + ConsumeAnyToken(); } } @@ -846,7 +884,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, bool ArgExprsOk = true; // now parse the list of expressions - while (1) { + while (Tok.isNot(tok::r_paren)) { ExprResult ArgExpr(ParseAssignmentExpression()); if (ArgExpr.isInvalid()) { ArgExprsOk = false; @@ -868,6 +906,40 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, *EndLoc = T.getCloseLocation(); } +/// DiagnoseProhibitedCXX11Attribute - We have found the opening square brackets +/// of a C++11 attribute-specifier in a location where an attribute is not +/// permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. Diagnose this +/// situation. +/// +/// \return \c true if we skipped an attribute-like chunk of tokens, \c false if +/// this doesn't appear to actually be an attribute-specifier, and the caller +/// should try to parse it. +bool Parser::DiagnoseProhibitedCXX11Attribute() { + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)); + + switch (isCXX11AttributeSpecifier(/*Disambiguate*/true)) { + case CAK_NotAttributeSpecifier: + // No diagnostic: we're in Obj-C++11 and this is not actually an attribute. + return false; + + case CAK_InvalidAttributeSpecifier: + Diag(Tok.getLocation(), diag::err_l_square_l_square_not_attribute); + return false; + + case CAK_AttributeSpecifier: + // Parse and discard the attributes. + SourceLocation BeginLoc = ConsumeBracket(); + ConsumeBracket(); + SkipUntil(tok::r_square, /*StopAtSemi*/ false); + assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied"); + SourceLocation EndLoc = ConsumeBracket(); + Diag(BeginLoc, diag::err_attributes_not_allowed) + << SourceRange(BeginLoc, EndLoc); + return true; + } + llvm_unreachable("All cases handled above."); +} + void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) << attrs.Range; @@ -886,7 +958,7 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { /// [C++] namespace-definition /// [C++] using-directive /// [C++] using-declaration -/// [C++0x/C1X] static_assert-declaration +/// [C++0x/C11] static_assert-declaration /// others... [FIXME] /// Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, @@ -908,7 +980,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, break; case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. - if (getLang().CPlusPlus && NextToken().is(tok::kw_namespace)) { + if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) { ProhibitAttributes(attrs); SourceLocation InlineLoc = ConsumeToken(); SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc); @@ -965,10 +1037,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, getDeclSpecContextFromDeclaratorContext(Context)); - StmtResult R = Actions.ActOnVlaStmt(DS); - if (R.isUsable()) - Stmts.push_back(R.release()); - + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { @@ -982,6 +1051,133 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI); } +/// Returns true if this might be the start of a declarator, or a common typo +/// for a declarator. +bool Parser::MightBeDeclarator(unsigned Context) { + switch (Tok.getKind()) { + case tok::annot_cxxscope: + case tok::annot_template_id: + case tok::caret: + case tok::code_completion: + case tok::coloncolon: + case tok::ellipsis: + case tok::kw___attribute: + case tok::kw_operator: + case tok::l_paren: + case tok::star: + return true; + + case tok::amp: + case tok::ampamp: + return getLangOpts().CPlusPlus; + + case tok::l_square: // Might be an attribute on an unnamed bit-field. + return Context == Declarator::MemberContext && getLangOpts().CPlusPlus0x && + NextToken().is(tok::l_square); + + case tok::colon: // Might be a typo for '::' or an unnamed bit-field. + return Context == Declarator::MemberContext || getLangOpts().CPlusPlus; + + case tok::identifier: + switch (NextToken().getKind()) { + case tok::code_completion: + case tok::coloncolon: + case tok::comma: + case tok::equal: + case tok::equalequal: // Might be a typo for '='. + case tok::kw_alignas: + case tok::kw_asm: + case tok::kw___attribute: + case tok::l_brace: + case tok::l_paren: + case tok::l_square: + case tok::less: + case tok::r_brace: + case tok::r_paren: + case tok::r_square: + case tok::semi: + return true; + + case tok::colon: + // At namespace scope, 'identifier:' is probably a typo for 'identifier::' + // and in block scope it's probably a label. Inside a class definition, + // this is a bit-field. + return Context == Declarator::MemberContext || + (getLangOpts().CPlusPlus && Context == Declarator::FileContext); + + case tok::identifier: // Possible virt-specifier. + return getLangOpts().CPlusPlus0x && isCXX0XVirtSpecifier(NextToken()); + + default: + return false; + } + + default: + return false; + } +} + +/// Skip until we reach something which seems like a sensible place to pick +/// up parsing after a malformed declaration. This will sometimes stop sooner +/// than SkipUntil(tok::r_brace) would, but will never stop later. +void Parser::SkipMalformedDecl() { + while (true) { + switch (Tok.getKind()) { + case tok::l_brace: + // Skip until matching }, then stop. We've probably skipped over + // a malformed class or function definition or similar. + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi*/false); + if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) { + // This declaration isn't over yet. Keep skipping. + continue; + } + if (Tok.is(tok::semi)) + ConsumeToken(); + return; + + case tok::l_square: + ConsumeBracket(); + SkipUntil(tok::r_square, /*StopAtSemi*/false); + continue; + + case tok::l_paren: + ConsumeParen(); + SkipUntil(tok::r_paren, /*StopAtSemi*/false); + continue; + + case tok::r_brace: + return; + + case tok::semi: + ConsumeToken(); + return; + + case tok::kw_inline: + // 'inline namespace' at the start of a line is almost certainly + // a good place to pick back up parsing. + if (Tok.isAtStartOfLine() && NextToken().is(tok::kw_namespace)) + return; + break; + + case tok::kw_namespace: + // 'namespace' at the start of a line is almost certainly a good + // place to pick back up parsing. + if (Tok.isAtStartOfLine()) + return; + break; + + case tok::eof: + return; + + default: + break; + } + + ConsumeAnyToken(); + } +} + /// ParseDeclGroup - Having concluded that this is either a function /// definition or a group of object declarations, actually parse the /// result. @@ -996,13 +1192,16 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // Bail out if the first declarator didn't seem well-formed. if (!D.hasName() && !D.mayOmitIdentifier()) { - // Skip until ; or }. - SkipUntil(tok::r_brace, true, true); - if (Tok.is(tok::semi)) - ConsumeToken(); + SkipMalformedDecl(); return DeclGroupPtrTy(); } + // Save late-parsed attributes for now; they need to be parsed in the + // appropriate function scope after the function Decl has been constructed. + LateParsedAttrList LateParsedAttrs; + if (D.isFunctionDeclarator()) + MaybeParseGNUAttributes(D, &LateParsedAttrs); + // Check to see if we have a function *definition* which must have a body. if (AllowFunctionDefinitions && D.isFunctionDeclarator() && // Look at the next token to make sure that this isn't a function @@ -1018,7 +1217,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DS.ClearStorageClassSpecs(); } - Decl *TheDecl = ParseFunctionDefinition(D); + Decl *TheDecl = + ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -1035,7 +1235,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } } - if (ParseAttributesAfterDeclarator(D)) + if (ParseAsmAttributesAfterDeclarator(D)) return DeclGroupPtrTy(); // C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we @@ -1050,23 +1250,38 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); Actions.ActOnCXXForRangeDecl(ThisDecl); Actions.FinalizeDeclaration(ThisDecl); + D.complete(ThisDecl); return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1); } SmallVector<Decl *, 8> DeclsInGroup; Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D); + if (LateParsedAttrs.size() > 0) + ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false); D.complete(FirstDecl); if (FirstDecl) DeclsInGroup.push_back(FirstDecl); + bool ExpectSemi = Context != Declarator::ForContext; + // If we don't have a comma, it is either the end of the list (a ';') or an // error, bail out. while (Tok.is(tok::comma)) { - // Consume the comma. - ConsumeToken(); + SourceLocation CommaLoc = ConsumeToken(); + + if (Tok.isAtStartOfLine() && ExpectSemi && !MightBeDeclarator(Context)) { + // This comma was followed by a line-break and something which can't be + // the start of a declarator. The comma was probably a typo for a + // semicolon. + Diag(CommaLoc, diag::err_expected_semi_declaration) + << FixItHint::CreateReplacement(CommaLoc, ";"); + ExpectSemi = false; + break; + } // Parse the next declarator. D.clear(); + D.setCommaLoc(CommaLoc); // Accept attributes in an init-declarator. In the first declarator in a // declaration, these would be part of the declspec. In subsequent @@ -1078,17 +1293,18 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, MaybeParseGNUAttributes(D); ParseDeclarator(D); - - Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); - D.complete(ThisDecl); - if (ThisDecl) - DeclsInGroup.push_back(ThisDecl); + if (!D.isInvalidType()) { + Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); + D.complete(ThisDecl); + if (ThisDecl) + DeclsInGroup.push_back(ThisDecl); + } } if (DeclEnd) *DeclEnd = Tok.getLocation(); - if (Context != Declarator::ForContext && + if (ExpectSemi && ExpectAndConsume(tok::semi, Context == Declarator::FileContext ? diag::err_invalid_token_after_toplevel_declarator @@ -1110,7 +1326,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, /// Parse an optional simple-asm-expr and attributes, and attach them to a /// declarator. Returns true on an error. -bool Parser::ParseAttributesAfterDeclarator(Declarator &D) { +bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; @@ -1152,7 +1368,7 @@ bool Parser::ParseAttributesAfterDeclarator(Declarator &D) { /// Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, const ParsedTemplateInfo &TemplateInfo) { - if (ParseAttributesAfterDeclarator(D)) + if (ParseAsmAttributesAfterDeclarator(D)) return 0; return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo); @@ -1196,8 +1412,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; // Parse declarator '=' initializer. - if (isTokenEqualOrMistypedEqualEqual( - diag::err_invalid_equalequal_after_declarator)) { + // If a '==' or '+=' is found, suggest a fixit to '='. + if (isTokenEqualOrEqualTypo()) { ConsumeToken(); if (Tok.is(tok::kw_delete)) { if (D.isFunctionDeclarator()) @@ -1207,12 +1423,12 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, Diag(ConsumeToken(), diag::err_deleted_non_function); } else if (Tok.is(tok::kw_default)) { if (D.isFunctionDeclarator()) - Diag(Tok, diag::err_default_delete_in_multiple_declaration) - << 1 /* delete */; + Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) + << 0 /* default */; else Diag(ConsumeToken(), diag::err_default_special_members); } else { - if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { EnterScope(0); Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); } @@ -1225,7 +1441,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, ExprResult Init(ParseInitializer()); - if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); ExitScope(); } @@ -1245,7 +1461,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, ExprVector Exprs(Actions); CommaLocsTy CommaLocs; - if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { EnterScope(0); Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); } @@ -1253,7 +1469,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, if (ParseExpressionList(Exprs, CommaLocs)) { SkipUntil(tok::r_paren); - if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); ExitScope(); } @@ -1264,18 +1480,21 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() && "Unexpected number of commas!"); - if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); ExitScope(); } - Actions.AddCXXDirectInitializerToDecl(ThisDecl, T.getOpenLocation(), - move_arg(Exprs), - T.getCloseLocation(), - TypeContainsAuto); + ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), + T.getCloseLocation(), + move_arg(Exprs)); + Actions.AddInitializerToDecl(ThisDecl, Initializer.take(), + /*DirectInit=*/true, TypeContainsAuto); } - } else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { + } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { // Parse C++0x braced-init-list. + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + if (D.getCXXScopeSpec().isSet()) { EnterScope(0); Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); @@ -1309,17 +1528,24 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, /// type-qualifier specifier-qualifier-list[opt] /// [GNU] attributes specifier-qualifier-list[opt] /// -void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) { +void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, + DeclSpecContext DSC) { /// specifier-qualifier-list is a subset of declaration-specifiers. Just /// parse declaration-specifiers and complain about extra stuff. /// TODO: diagnose attribute-specifiers and alignment-specifiers. - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC); // Validate declspec for type-name. unsigned Specs = DS.getParsedSpecifiers(); - if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && - !DS.hasAttributes()) + if (DSC == DSC_type_specifier && !DS.hasTypeSpecifier()) { + Diag(Tok, diag::err_expected_type); + DS.SetTypeSpecError(); + } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && + !DS.hasAttributes()) { Diag(Tok, diag::err_typename_requires_specqual); + if (!DS.hasTypeSpecifier()) + DS.SetTypeSpecError(); + } // Issue diagnostic and remove storage class if present. if (Specs & DeclSpec::PQ_StorageClassSpecifier) { @@ -1340,6 +1566,12 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) { Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec); DS.ClearFunctionSpecs(); } + + // Issue diagnostic and remove constexpr specfier if present. + if (DS.isConstexprSpecified()) { + Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr); + DS.ClearConstexprSpec(); + } } /// isValidAfterIdentifierInDeclaratorAfterDeclSpec - Return true if the @@ -1378,7 +1610,7 @@ static bool isValidAfterIdentifierInDeclarator(const Token &T) { /// bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, const ParsedTemplateInfo &TemplateInfo, - AccessSpecifier AS) { + AccessSpecifier AS, DeclSpecContext DSC) { assert(Tok.is(tok::identifier) && "should have identifier"); SourceLocation Loc = Tok.getLocation(); @@ -1397,8 +1629,13 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, assert(!DS.hasTypeSpecifier() && "Type specifier checked above"); // Since we know that this either implicit int (which is rare) or an - // error, we'd do lookahead to try to do better recovery. - if (isValidAfterIdentifierInDeclarator(NextToken())) { + // error, do lookahead to try to do better recovery. This never applies within + // a type specifier. + // FIXME: Don't bail out here in languages with no implicit int (like + // C++ with no -fms-extensions). This is much more likely to be an undeclared + // type or typo than a use of implicit int. + if (DSC != DSC_type_specifier && + isValidAfterIdentifierInDeclarator(NextToken())) { // If this token is valid for implicit int, e.g. "static x = 4", then // we just avoid eating the identifier, so it will be parsed as the // identifier in the declarator. @@ -1429,14 +1666,15 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, if (TagName) { Diag(Loc, diag::err_use_of_tag_name_without_tag) - << Tok.getIdentifierInfo() << TagName << getLang().CPlusPlus + << Tok.getIdentifierInfo() << TagName << getLangOpts().CPlusPlus << FixItHint::CreateInsertion(Tok.getLocation(),FixitTagName); // Parse this as a tag as if the missing tag were present. if (TagKind == tok::kw_enum) - ParseEnumSpecifier(Loc, DS, TemplateInfo, AS); + ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSC_normal); else - ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS); + ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS, + /*EnteringContext*/ false, DSC_normal); return true; } } @@ -1470,9 +1708,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, } // Mark this as an error. - const char *PrevSpec; - unsigned DiagID; - DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec, DiagID); + DS.SetTypeSpecError(); DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); @@ -1493,6 +1729,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { return DSC_class; if (Context == Declarator::FileContext) return DSC_top_level; + if (Context == Declarator::TrailingReturnContext) + return DSC_trailing; return DSC_normal; } @@ -1501,29 +1739,36 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { /// FIXME: Simply returns an alignof() expression if the argument is a /// type. Ideally, the type should be propagated directly into Sema. /// -/// [C1X/C++0x] type-id -/// [C1X] constant-expression -/// [C++0x] assignment-expression -ExprResult Parser::ParseAlignArgument(SourceLocation Start) { +/// [C11] type-id +/// [C11] constant-expression +/// [C++0x] type-id ...[opt] +/// [C++0x] assignment-expression ...[opt] +ExprResult Parser::ParseAlignArgument(SourceLocation Start, + SourceLocation &EllipsisLoc) { + ExprResult ER; if (isTypeIdInParens()) { - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); SourceLocation TypeLoc = Tok.getLocation(); ParsedType Ty = ParseTypeName().get(); SourceRange TypeRange(Start, Tok.getLocation()); - return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, - Ty.getAsOpaquePtr(), TypeRange); + ER = Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, + Ty.getAsOpaquePtr(), TypeRange); } else - return ParseConstantExpression(); + ER = ParseConstantExpression(); + + if (getLangOpts().CPlusPlus0x && Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + + return ER; } /// ParseAlignmentSpecifier - Parse an alignment-specifier, and add the /// attribute to Attrs. /// /// alignment-specifier: -/// [C1X] '_Alignas' '(' type-id ')' -/// [C1X] '_Alignas' '(' constant-expression ')' -/// [C++0x] 'alignas' '(' type-id ')' -/// [C++0x] 'alignas' '(' assignment-expression ')' +/// [C11] '_Alignas' '(' type-id ')' +/// [C11] '_Alignas' '(' constant-expression ')' +/// [C++0x] 'alignas' '(' type-id ...[opt] ')' +/// [C++0x] 'alignas' '(' assignment-expression ...[opt] ')' void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *endLoc) { assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) && @@ -1536,7 +1781,8 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, if (T.expectAndConsume(diag::err_expected_lparen)) return; - ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation()); + SourceLocation EllipsisLoc; + ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc); if (ArgExpr.isInvalid()) { SkipUntil(tok::r_paren); return; @@ -1546,6 +1792,12 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, if (endLoc) *endLoc = T.getCloseLocation(); + // FIXME: Handle pack-expansions here. + if (EllipsisLoc.isValid()) { + Diag(EllipsisLoc, diag::err_alignas_pack_exp_unsupported); + return; + } + ExprVector ArgExprs(Actions); ArgExprs.push_back(ArgExpr.release()); Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc, @@ -1557,7 +1809,7 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, /// storage-class-specifier declaration-specifiers[opt] /// type-specifier declaration-specifiers[opt] /// [C99] function-specifier declaration-specifiers[opt] -/// [C1X] alignment-specifier declaration-specifiers[opt] +/// [C11] alignment-specifier declaration-specifiers[opt] /// [GNU] attributes declaration-specifiers[opt] /// [Clang] '__module_private__' declaration-specifiers[opt] /// @@ -1581,12 +1833,14 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, - DeclSpecContext DSContext) { + DeclSpecContext DSContext, + LateParsedAttrList *LateAttrs) { if (DS.getSourceRange().isInvalid()) { DS.SetRangeStart(Tok.getLocation()); DS.SetRangeEnd(Tok.getLocation()); } + bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); while (1) { bool isInvalid = false; const char *PrevSpec = 0; @@ -1631,7 +1885,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, : Sema::PCC_Template; else if (DSContext == DSC_class) CCC = Sema::PCC_Class; - else if (ObjCImpDecl) + else if (CurParsedObjCImpl) CCC = Sema::PCC_ObjCImplementation; Actions.CodeCompleteOrdinaryName(getCurScope(), CCC); @@ -1755,6 +2009,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Next.getLocation(), getCurScope(), &SS, false, false, ParsedType(), + /*IsCtorOrDtorName=*/false, /*NonTrivialSourceInfo=*/true); // If the referenced identifier is not a type, then this declspec is @@ -1763,7 +2018,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // typename. if (TypeRep == 0) { ConsumeToken(); // Eat the scope spec so the identifier is current. - if (ParseImplicitInt(DS, &SS, TemplateInfo, AS)) continue; + if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext)) continue; goto DoneWithDeclSpec; } @@ -1798,7 +2053,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an // Objective-C interface. - if (Tok.is(tok::less) && getLang().ObjC1) + if (Tok.is(tok::less) && getLangOpts().ObjC1) ParseObjCProtocolQualifiers(DS); continue; @@ -1823,10 +2078,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, goto DoneWithDeclSpec; // typedef-name + case tok::kw_decltype: case tok::identifier: { // In C++, check to see if this is a scope specifier like foo::bar::, if // so handle it as such. This is important for ctor parsing. - if (getLang().CPlusPlus) { + if (getLangOpts().CPlusPlus) { if (TryAnnotateCXXScopeToken(true)) { if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); @@ -1846,7 +2102,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) break; - // It has to be available as a typedef too! ParsedType TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope()); @@ -1854,13 +2109,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. if (!TypeRep) { - if (ParseImplicitInt(DS, 0, TemplateInfo, AS)) continue; + if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext)) continue; goto DoneWithDeclSpec; } // If we're in a context where the identifier could be a class name, // check whether this is a constructor declaration. - if (getLang().CPlusPlus && DSContext == DSC_class && + if (getLangOpts().CPlusPlus && DSContext == DSC_class && Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) && isConstructorDeclarator()) goto DoneWithDeclSpec; @@ -1876,7 +2131,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an // Objective-C interface. - if (Tok.is(tok::less) && getLang().ObjC1) + if (Tok.is(tok::less) && getLangOpts().ObjC1) ParseObjCProtocolQualifiers(DS); // Need to support trailing type qualifiers (e.g. "id<p> const"). @@ -1896,7 +2151,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If we're in a context where the template-id could be a // constructor name or specialization, check whether this is a // constructor declaration. - if (getLang().CPlusPlus && DSContext == DSC_class && + if (getLangOpts().CPlusPlus && DSContext == DSC_class && Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) && isConstructorDeclarator()) goto DoneWithDeclSpec; @@ -1909,7 +2164,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // GNU attributes support. case tok::kw___attribute: - ParseGNUAttributes(DS.getAttributes()); + ParseGNUAttributes(DS.getAttributes(), 0, LateAttrs); continue; // Microsoft declspec support. @@ -1965,7 +2220,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, PrevSpec, DiagID); break; case tok::kw_auto: - if (getLang().CPlusPlus0x) { + if (getLangOpts().CPlusPlus0x) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, PrevSpec, DiagID); @@ -2004,8 +2259,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // alignment-specifier case tok::kw__Alignas: - if (!getLang().C1X) - Diag(Tok, diag::ext_c1x_alignas); + if (!getLangOpts().C11) + Diag(Tok, diag::ext_c11_alignas); ParseAlignmentSpecifier(DS.getAttributes()); continue; @@ -2075,10 +2330,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; - case tok::kw_half: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, - DiagID); - break; + case tok::kw___int128: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, + DiagID); + break; + case tok::kw_half: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, + DiagID); + break; case tok::kw_float: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); @@ -2143,28 +2402,29 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); ConsumeToken(); - ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS); + ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS, + EnteringContext, DSContext); continue; } // enum-specifier: case tok::kw_enum: ConsumeToken(); - ParseEnumSpecifier(Loc, DS, TemplateInfo, AS); + ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext); continue; // cv-qualifier: case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID, - getLang()); + getLangOpts()); break; case tok::kw_volatile: isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, - getLang()); + getLangOpts()); break; case tok::kw_restrict: isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, - getLang()); + getLangOpts()); break; // C++ typename-specifier: @@ -2182,7 +2442,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseTypeofSpecifier(DS); continue; - case tok::kw_decltype: + case tok::annot_decltype: ParseDecltypeSpecifier(DS); continue; @@ -2196,7 +2456,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // OpenCL qualifiers: case tok::kw_private: - if (!getLang().OpenCL) + if (!getLangOpts().OpenCL) goto DoneWithDeclSpec; case tok::kw___private: case tok::kw___global: @@ -2212,7 +2472,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // GCC ObjC supports types like "<SomeProtocol>" as a synonym for // "id<SomeProtocol>". This is hopelessly old fashioned and dangerous, // but we support it. - if (DS.hasTypeSpecifier() || !getLang().ObjC1) + if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1) goto DoneWithDeclSpec; if (!ParseObjCProtocolQualifiers(DS)) @@ -2242,299 +2502,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } } -/// ParseOptionalTypeSpecifier - Try to parse a single type-specifier. We -/// primarily follow the C++ grammar with additions for C99 and GNU, -/// which together subsume the C grammar. Note that the C++ -/// type-specifier also includes the C type-qualifier (for const, -/// volatile, and C99 restrict). Returns true if a type-specifier was -/// found (and parsed), false otherwise. -/// -/// type-specifier: [C++ 7.1.5] -/// simple-type-specifier -/// class-specifier -/// enum-specifier -/// elaborated-type-specifier [TODO] -/// cv-qualifier -/// -/// cv-qualifier: [C++ 7.1.5.1] -/// 'const' -/// 'volatile' -/// [C99] 'restrict' -/// -/// simple-type-specifier: [ C++ 7.1.5.2] -/// '::'[opt] nested-name-specifier[opt] type-name [TODO] -/// '::'[opt] nested-name-specifier 'template' template-id [TODO] -/// 'char' -/// 'wchar_t' -/// 'bool' -/// 'short' -/// 'int' -/// 'long' -/// 'signed' -/// 'unsigned' -/// 'float' -/// 'double' -/// 'void' -/// [C99] '_Bool' -/// [C99] '_Complex' -/// [C99] '_Imaginary' // Removed in TC2? -/// [GNU] '_Decimal32' -/// [GNU] '_Decimal64' -/// [GNU] '_Decimal128' -/// [GNU] typeof-specifier -/// [OBJC] class-name objc-protocol-refs[opt] [TODO] -/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO] -/// [C++0x] 'decltype' ( expression ) -/// [AltiVec] '__vector' -bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, - const char *&PrevSpec, - unsigned &DiagID, - const ParsedTemplateInfo &TemplateInfo, - bool SuppressDeclarations) { - SourceLocation Loc = Tok.getLocation(); - - switch (Tok.getKind()) { - case tok::identifier: // foo::bar - // If we already have a type specifier, this identifier is not a type. - if (DS.getTypeSpecType() != DeclSpec::TST_unspecified || - DS.getTypeSpecWidth() != DeclSpec::TSW_unspecified || - DS.getTypeSpecSign() != DeclSpec::TSS_unspecified) - return false; - // Check for need to substitute AltiVec keyword tokens. - if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) - break; - // Fall through. - case tok::kw_typename: // typename foo::bar - // Annotate typenames and C++ scope specifiers. If we get one, just - // recurse to handle whatever we get. - if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false, - /*NeedType=*/true)) - return true; - if (Tok.is(tok::identifier)) - return false; - return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, - TemplateInfo, SuppressDeclarations); - case tok::coloncolon: // ::foo::bar - if (NextToken().is(tok::kw_new) || // ::new - NextToken().is(tok::kw_delete)) // ::delete - return false; - - // Annotate typenames and C++ scope specifiers. If we get one, just - // recurse to handle whatever we get. - if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false, - /*NeedType=*/true)) - return true; - return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, - TemplateInfo, SuppressDeclarations); - - // simple-type-specifier: - case tok::annot_typename: { - if (ParsedType T = getTypeAnnotation(Tok)) { - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, - Tok.getAnnotationEndLoc(), PrevSpec, - DiagID, T); - } else - DS.SetTypeSpecError(); - DS.SetRangeEnd(Tok.getAnnotationEndLoc()); - ConsumeToken(); // The typename - - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. If we don't have Objective-C or a '<', this is - // just a normal reference to a typedef name. - if (Tok.is(tok::less) && getLang().ObjC1) - ParseObjCProtocolQualifiers(DS); - - return true; - } - - case tok::kw_short: - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID); - break; - case tok::kw_long: - if (DS.getTypeSpecWidth() != DeclSpec::TSW_long) - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, - DiagID); - else - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, - DiagID); - break; - case tok::kw___int64: - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, - DiagID); - break; - case tok::kw_signed: - isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); - break; - case tok::kw_unsigned: - isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, - DiagID); - break; - case tok::kw__Complex: - isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec, - DiagID); - break; - case tok::kw__Imaginary: - isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec, - DiagID); - break; - case tok::kw_void: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID); - break; - case tok::kw_char: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID); - break; - case tok::kw_int: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); - break; - case tok::kw_half: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID); - break; - case tok::kw_float: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); - break; - case tok::kw_double: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID); - break; - case tok::kw_wchar_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID); - break; - case tok::kw_char16_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID); - break; - case tok::kw_char32_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID); - break; - case tok::kw_bool: - case tok::kw__Bool: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); - break; - case tok::kw__Decimal32: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec, - DiagID); - break; - case tok::kw__Decimal64: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec, - DiagID); - break; - case tok::kw__Decimal128: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec, - DiagID); - break; - case tok::kw___vector: - isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); - break; - case tok::kw___pixel: - isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); - break; - - // class-specifier: - case tok::kw_class: - case tok::kw_struct: - case tok::kw_union: { - tok::TokenKind Kind = Tok.getKind(); - ConsumeToken(); - ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS_none, - SuppressDeclarations); - return true; - } - - // enum-specifier: - case tok::kw_enum: - ConsumeToken(); - ParseEnumSpecifier(Loc, DS, TemplateInfo, AS_none); - return true; - - // cv-qualifier: - case tok::kw_const: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, - DiagID, getLang()); - break; - case tok::kw_volatile: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, - DiagID, getLang()); - break; - case tok::kw_restrict: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, - DiagID, getLang()); - break; - - // GNU typeof support. - case tok::kw_typeof: - ParseTypeofSpecifier(DS); - return true; - - // C++0x decltype support. - case tok::kw_decltype: - ParseDecltypeSpecifier(DS); - return true; - - // C++0x type traits support. - case tok::kw___underlying_type: - ParseUnderlyingTypeSpecifier(DS); - return true; - - case tok::kw__Atomic: - ParseAtomicSpecifier(DS); - return true; - - // OpenCL qualifiers: - case tok::kw_private: - if (!getLang().OpenCL) - return false; - case tok::kw___private: - case tok::kw___global: - case tok::kw___local: - case tok::kw___constant: - case tok::kw___read_only: - case tok::kw___write_only: - case tok::kw___read_write: - ParseOpenCLQualifiers(DS); - break; - - // C++0x auto support. - case tok::kw_auto: - // This is only called in situations where a storage-class specifier is - // illegal, so we can assume an auto type specifier was intended even in - // C++98. In C++98 mode, DeclSpec::Finish will produce an appropriate - // extension diagnostic. - if (!getLang().CPlusPlus) - return false; - - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID); - break; - - case tok::kw___ptr64: - case tok::kw___ptr32: - case tok::kw___w64: - case tok::kw___cdecl: - case tok::kw___stdcall: - case tok::kw___fastcall: - case tok::kw___thiscall: - case tok::kw___unaligned: - ParseMicrosoftTypeAttributes(DS.getAttributes()); - return true; - - case tok::kw___pascal: - ParseBorlandTypeAttributes(DS.getAttributes()); - return true; - - default: - // Not a type-specifier; do nothing. - return false; - } - - // If the specifier combination wasn't legal, issue a diagnostic. - if (isInvalid) { - assert(PrevSpec && "Method did not return previous specifier!"); - // Pick between error or extwarn. - Diag(Tok, DiagID) << PrevSpec; - } - DS.SetRangeEnd(Tok.getLocation()); - ConsumeToken(); // whatever we parsed above. - return true; -} - /// ParseStructDeclaration - Parse a struct declaration without the terminating /// semicolon. /// @@ -2574,9 +2541,11 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // Read struct-declarators until we find the semicolon. bool FirstDeclarator = true; + SourceLocation CommaLoc; while (1) { ParsingDeclRAIIObject PD(*this); FieldDeclarator DeclaratorInfo(DS); + DeclaratorInfo.D.setCommaLoc(CommaLoc); // Attributes are only allowed here on successive declarators. if (!FirstDeclarator) @@ -2612,7 +2581,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { return; // Consume the comma. - ConsumeToken(); + CommaLoc = ConsumeToken(); FirstDeclarator = false; } @@ -2642,9 +2611,10 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in // C++. - if (Tok.is(tok::r_brace) && !getLang().CPlusPlus) - Diag(Tok, diag::ext_empty_struct_union) - << (TagType == TST_union); + if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) { + Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union); + Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union); + } SmallVector<Decl *, 32> FieldDecls; @@ -2742,22 +2712,25 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}' /// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt] /// '}' attributes[opt] +/// [MS] 'enum' __declspec[opt] identifier[opt] '{' enumerator-list ',' [opt] +/// '}' /// 'enum' identifier /// [GNU] 'enum' attributes[opt] identifier /// -/// [C++0x] enum-head '{' enumerator-list[opt] '}' -/// [C++0x] enum-head '{' enumerator-list ',' '}' +/// [C++11] enum-head '{' enumerator-list[opt] '}' +/// [C++11] enum-head '{' enumerator-list ',' '}' /// -/// enum-head: [C++0x] -/// enum-key attributes[opt] identifier[opt] enum-base[opt] -/// enum-key attributes[opt] nested-name-specifier identifier enum-base[opt] +/// enum-head: [C++11] +/// enum-key attribute-specifier-seq[opt] identifier[opt] enum-base[opt] +/// enum-key attribute-specifier-seq[opt] nested-name-specifier +/// identifier enum-base[opt] /// -/// enum-key: [C++0x] +/// enum-key: [C++11] /// 'enum' /// 'enum' 'class' /// 'enum' 'struct' /// -/// enum-base: [C++0x] +/// enum-base: [C++11] /// ':' type-specifier-seq /// /// [C++] elaborated-type-specifier: @@ -2765,7 +2738,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, /// void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, - AccessSpecifier AS) { + AccessSpecifier AS, DeclSpecContext DSC) { // Parse the tag portion of this. if (Tok.is(tok::code_completion)) { // Code completion for an enum name. @@ -2773,30 +2746,46 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return cutOffParsing(); } - bool IsScopedEnum = false; + SourceLocation ScopedEnumKWLoc; bool IsScopedUsingClassTag = false; - if (getLang().CPlusPlus0x && + if (getLangOpts().CPlusPlus0x && (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) { - IsScopedEnum = true; + Diag(Tok, diag::warn_cxx98_compat_scoped_enum); IsScopedUsingClassTag = Tok.is(tok::kw_class); - ConsumeToken(); + ScopedEnumKWLoc = ConsumeToken(); } - + + // C++11 [temp.explicit]p12: The usual access controls do not apply to names + // used to specify explicit instantiations. We extend this to also cover + // explicit specializations. + Sema::SuppressAccessChecksRAII SuppressAccess(Actions, + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + // If attributes exist after tag, parse them. ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); - bool AllowFixedUnderlyingType - = getLang().CPlusPlus0x || getLang().MicrosoftExt || getLang().ObjC2; + // If declspecs exist after tag, parse them. + while (Tok.is(tok::kw___declspec)) + ParseMicrosoftDeclSpec(attrs); + + // Enum definitions should not be parsed in a trailing-return-type. + bool AllowDeclaration = DSC != DSC_trailing; + + bool AllowFixedUnderlyingType = AllowDeclaration && + (getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt || + getLangOpts().ObjC2); CXXScopeSpec &SS = DS.getTypeSpecScope(); - if (getLang().CPlusPlus) { + if (getLangOpts().CPlusPlus) { // "enum foo : bar;" is not a potential typo for "enum foo::bar;" // if a fixed underlying type is allowed. ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType); - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false)) return; if (SS.isSet() && Tok.isNot(tok::identifier)) { @@ -2812,7 +2801,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // Must have either 'enum name' or 'enum {...}'. if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) && - (AllowFixedUnderlyingType && Tok.isNot(tok::colon))) { + !(AllowFixedUnderlyingType && Tok.is(tok::colon))) { Diag(Tok, diag::err_expected_ident_lbrace); // Skip the rest of this declarator, up until the comma or semicolon. @@ -2828,14 +2817,17 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, NameLoc = ConsumeToken(); } - if (!Name && IsScopedEnum) { + if (!Name && ScopedEnumKWLoc.isValid()) { // C++0x 7.2p2: The optional identifier shall not be omitted in the // declaration of a scoped enumeration. Diag(Tok, diag::err_scoped_enum_missing_identifier); - IsScopedEnum = false; + ScopedEnumKWLoc = SourceLocation(); IsScopedUsingClassTag = false; } + // Stop suppressing access control now we've parsed the enum name. + SuppressAccess.done(); + TypeResult BaseType; // Parse the fixed underlying type. @@ -2870,10 +2862,16 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // Consume the ':'. ConsumeToken(); - - if ((getLang().CPlusPlus && - isCXXDeclarationSpecifier() != TPResult::True()) || - (!getLang().CPlusPlus && !isDeclarationSpecifier(true))) { + + // If we see a type specifier followed by an open-brace, we have an + // ambiguity between an underlying type and a C++11 braced + // function-style cast. Resolve this by always treating it as an + // underlying type. + // FIXME: The standard is not entirely clear on how to disambiguate in + // this case. + if ((getLangOpts().CPlusPlus && + isCXXDeclarationSpecifier(TPResult::True()) != TPResult::True()) || + (!getLangOpts().CPlusPlus && !isDeclarationSpecifier(true))) { // We'll parse this as a bitfield later. PossibleBitfield = true; TPA.Revert(); @@ -2891,56 +2889,74 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, SourceRange Range; BaseType = ParseTypeName(&Range); - if (!getLang().CPlusPlus0x && !getLang().ObjC2) + if (!getLangOpts().CPlusPlus0x && !getLangOpts().ObjC2) Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type) << Range; + if (getLangOpts().CPlusPlus0x) + Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type); } } - // There are three options here. If we have 'enum foo;', then this is a - // forward declaration. If we have 'enum foo {...' then this is a - // definition. Otherwise we have something like 'enum foo xyz', a reference. + // There are four options here. If we have 'friend enum foo;' then this is a + // friend declaration, and cannot have an accompanying definition. If we have + // 'enum foo;', then this is a forward declaration. If we have + // 'enum foo {...' then this is a definition. Otherwise we have something + // like 'enum foo xyz', a reference. // // This is needed to handle stuff like this right (C99 6.7.2.3p11): // enum foo {..}; void bar() { enum foo; } <- new foo in bar. // enum foo {..}; void bar() { enum foo x; } <- use of old foo. // Sema::TagUseKind TUK; - if (Tok.is(tok::l_brace)) + if (DS.isFriendSpecified()) + TUK = Sema::TUK_Friend; + else if (!AllowDeclaration) + TUK = Sema::TUK_Reference; + else if (Tok.is(tok::l_brace)) TUK = Sema::TUK_Definition; - else if (Tok.is(tok::semi)) + else if (Tok.is(tok::semi) && DSC != DSC_type_specifier) TUK = Sema::TUK_Declaration; else TUK = Sema::TUK_Reference; - - // enums cannot be templates, although they can be referenced from a - // template. + + MultiTemplateParamsArg TParams; if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && TUK != Sema::TUK_Reference) { - Diag(Tok, diag::err_enum_template); - - // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); - return; + if (!getLangOpts().CPlusPlus0x || !SS.isSet()) { + // Skip the rest of this declarator, up until the comma or semicolon. + Diag(Tok, diag::err_enum_template); + SkipUntil(tok::comma, true); + return; + } + + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + // Enumerations can't be explicitly instantiated. + DS.SetTypeSpecError(); + Diag(StartLoc, diag::err_explicit_instantiation_enum); + return; + } + + assert(TemplateInfo.TemplateParams && "no template parameters"); + TParams = MultiTemplateParamsArg(TemplateInfo.TemplateParams->data(), + TemplateInfo.TemplateParams->size()); } - + if (!Name && TUK != Sema::TUK_Definition) { Diag(Tok, diag::err_enumerator_unnamed_no_def); - + // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, true); return; } - + bool Owned = false; bool IsDependent = false; const char *PrevSpec = 0; unsigned DiagID; Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, attrs.getList(), - AS, DS.getModulePrivateSpecLoc(), - MultiTemplateParamsArg(Actions), - Owned, IsDependent, IsScopedEnum, + AS, DS.getModulePrivateSpecLoc(), TParams, + Owned, IsDependent, ScopedEnumKWLoc, IsScopedUsingClassTag, BaseType); if (IsDependent) { @@ -2971,7 +2987,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (!TagDecl) { // The action failed to produce an enumeration tag. If this is a // definition, consume the entire definition. - if (Tok.is(tok::l_brace)) { + if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { ConsumeBrace(); SkipUntil(tok::r_brace); } @@ -2979,9 +2995,17 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, DS.SetTypeSpecError(); return; } - - if (Tok.is(tok::l_brace)) - ParseEnumBody(StartLoc, TagDecl); + + if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { + if (TUK == Sema::TUK_Friend) { + Diag(Tok, diag::err_friend_decl_defines_type) + << SourceRange(DS.getFriendSpecLoc()); + ConsumeBrace(); + SkipUntil(tok::r_brace); + } else { + ParseEnumBody(StartLoc, TagDecl); + } + } if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, @@ -3008,7 +3032,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { T.consumeOpen(); // C does not allow an empty enumerator-list, C++ does [dcl.enum]. - if (Tok.is(tok::r_brace) && !getLang().CPlusPlus) + if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) Diag(Tok, diag::error_empty_enum); SmallVector<Decl *, 32> EnumConstantDecls; @@ -3026,6 +3050,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { SourceLocation EqualLoc; ExprResult AssignedVal; + ParsingDeclRAIIObject PD(*this); + if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); AssignedVal = ParseConstantExpression(); @@ -3039,6 +3065,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { IdentLoc, Ident, attrs.getList(), EqualLoc, AssignedVal.release()); + PD.complete(EnumConstDecl); + EnumConstantDecls.push_back(EnumConstDecl); LastEnumConstDecl = EnumConstDecl; @@ -3054,11 +3082,15 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { break; SourceLocation CommaLoc = ConsumeToken(); - if (Tok.isNot(tok::identifier) && - !(getLang().C99 || getLang().CPlusPlus0x)) - Diag(CommaLoc, diag::ext_enumerator_list_comma) - << getLang().CPlusPlus - << FixItHint::CreateRemoval(CommaLoc); + if (Tok.isNot(tok::identifier)) { + if (!getLangOpts().C99 && !getLangOpts().CPlusPlus0x) + Diag(CommaLoc, diag::ext_enumerator_list_comma) + << getLangOpts().CPlusPlus + << FixItHint::CreateRemoval(CommaLoc); + else if (getLangOpts().CPlusPlus0x) + Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma) + << FixItHint::CreateRemoval(CommaLoc); + } } // Eat the }. @@ -3086,7 +3118,7 @@ bool Parser::isTypeQualifier() const { // type-qualifier only in OpenCL case tok::kw_private: - return getLang().OpenCL; + return getLangOpts().OpenCL; // type-qualifier case tok::kw_const: @@ -3113,6 +3145,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw_short: case tok::kw_long: case tok::kw___int64: + case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw__Complex: @@ -3183,6 +3216,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_short: case tok::kw_long: case tok::kw___int64: + case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw__Complex: @@ -3221,7 +3255,7 @@ bool Parser::isTypeSpecifierQualifier() { // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'. case tok::less: - return getLang().ObjC1; + return getLangOpts().ObjC1; case tok::kw___cdecl: case tok::kw___stdcall: @@ -3244,9 +3278,9 @@ bool Parser::isTypeSpecifierQualifier() { return true; case tok::kw_private: - return getLang().OpenCL; + return getLangOpts().OpenCL; - // C1x _Atomic() + // C11 _Atomic() case tok::kw__Atomic: return true; } @@ -3262,15 +3296,16 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { default: return false; case tok::kw_private: - return getLang().OpenCL; + return getLangOpts().OpenCL; case tok::identifier: // foo::bar // Unfortunate hack to support "Class.factoryMethod" notation. - if (getLang().ObjC1 && NextToken().is(tok::period)) + if (getLangOpts().ObjC1 && NextToken().is(tok::period)) return false; if (TryAltiVecVectorToken()) return true; // Fall through. + case tok::kw_decltype: // decltype(T())::type case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. @@ -3317,6 +3352,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_short: case tok::kw_long: case tok::kw___int64: + case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw__Complex: @@ -3366,16 +3402,16 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { return true; // C++0x decltype. - case tok::kw_decltype: + case tok::annot_decltype: return true; - // C1x _Atomic() + // C11 _Atomic() case tok::kw__Atomic: return true; // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'. case tok::less: - return getLang().ObjC1; + return getLangOpts().ObjC1; // typedef-name case tok::annot_typename: @@ -3411,7 +3447,8 @@ bool Parser::isConstructorDeclarator() { // Parse the C++ scope specifier. CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true)) { + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/true)) { TPA.Revert(); return false; } @@ -3426,15 +3463,17 @@ bool Parser::isConstructorDeclarator() { return false; } - // Current class name must be followed by a left parentheses. + // Current class name must be followed by a left parenthesis. if (Tok.isNot(tok::l_paren)) { TPA.Revert(); return false; } ConsumeParen(); - // A right parentheses or ellipsis signals that we have a constructor. - if (Tok.is(tok::r_paren) || Tok.is(tok::ellipsis)) { + // A right parenthesis, or ellipsis followed by a right parenthesis signals + // that we have a constructor. + if (Tok.is(tok::r_paren) || + (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren))) { TPA.Revert(); return true; } @@ -3451,7 +3490,43 @@ bool Parser::isConstructorDeclarator() { // Check whether the next token(s) are part of a declaration // specifier, in which case we have the start of a parameter and, // therefore, we know that this is a constructor. - bool IsConstructor = isDeclarationSpecifier(); + bool IsConstructor = false; + if (isDeclarationSpecifier()) + IsConstructor = true; + else if (Tok.is(tok::identifier) || + (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) { + // We've seen "C ( X" or "C ( X::Y", but "X" / "X::Y" is not a type. + // This might be a parenthesized member name, but is more likely to + // be a constructor declaration with an invalid argument type. Keep + // looking. + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); + ConsumeToken(); + + // If this is not a constructor, we must be parsing a declarator, + // which must have one of the following syntactic forms (see the + // grammar extract at the start of ParseDirectDeclarator): + switch (Tok.getKind()) { + case tok::l_paren: + // C(X ( int)); + case tok::l_square: + // C(X [ 5]); + // C(X [ [attribute]]); + case tok::coloncolon: + // C(X :: Y); + // C(X :: *p); + case tok::r_paren: + // C(X ) + // Assume this isn't a constructor, rather than assuming it's a + // constructor with an unnamed parameter of an ill-formed type. + break; + + default: + IsConstructor = true; + break; + } + } + TPA.Revert(); return IsConstructor; } @@ -3470,15 +3545,12 @@ bool Parser::isConstructorDeclarator() { /// void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool VendorAttributesAllowed, - bool CXX0XAttributesAllowed) { - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { - SourceLocation Loc = Tok.getLocation(); + bool CXX11AttributesAllowed) { + if (getLangOpts().CPlusPlus0x && CXX11AttributesAllowed && + isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); - ParseCXX0XAttributes(attrs); - if (CXX0XAttributesAllowed) - DS.takeAttributesFrom(attrs); - else - Diag(Loc, diag::err_attributes_not_allowed); + ParseCXX11Attributes(attrs); + DS.takeAttributesFrom(attrs); } SourceLocation EndLoc; @@ -3496,20 +3568,20 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID, - getLang()); + getLangOpts()); break; case tok::kw_volatile: isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, - getLang()); + getLangOpts()); break; case tok::kw_restrict: isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, - getLang()); + getLangOpts()); break; // OpenCL qualifiers: case tok::kw_private: - if (!getLang().OpenCL) + if (!getLangOpts().OpenCL) goto DoneWithTypeQuals; case tok::kw___private: case tok::kw___global: @@ -3574,11 +3646,26 @@ void Parser::ParseDeclarator(Declarator &D) { ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); } +static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang) { + if (Kind == tok::star || Kind == tok::caret) + return true; + + // We parse rvalue refs in C++03, because otherwise the errors are scary. + if (!Lang.CPlusPlus) + return false; + + return Kind == tok::amp || Kind == tok::ampamp; +} + /// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator /// is parsed by the function passed to it. Pass null, and the direct-declarator /// isn't parsed at all, making this function effectively parse the C++ /// ptr-operator production. /// +/// If the grammar of this construct is extended, matching changes must also be +/// made to TryParseDeclarator and MightBeDeclarator, and possibly to +/// isConstructorDeclarator. +/// /// declarator: [C99 6.7.5] [C++ 8p4, dcl.decl] /// [C] pointer[opt] direct-declarator /// [C++] direct-declarator @@ -3603,11 +3690,13 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // C++ member pointers start with a '::' or a nested-name. // Member pointers get special handling, since there's no place for the // scope spec in the generic path below. - if (getLang().CPlusPlus && + if (getLangOpts().CPlusPlus && (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope))) { + bool EnteringContext = D.getContext() == Declarator::FileContext || + D.getContext() == Declarator::MemberContext; CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true); // ignore fail + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext); if (SS.isNotEmpty()) { if (Tok.isNot(tok::star)) { @@ -3639,10 +3728,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, tok::TokenKind Kind = Tok.getKind(); // Not a pointer, C++ reference, or block. - if (Kind != tok::star && Kind != tok::caret && - (Kind != tok::amp || !getLang().CPlusPlus) && - // We parse rvalue refs in C++03, because otherwise the errors are scary. - (Kind != tok::ampamp || !getLang().CPlusPlus)) { + if (!isPtrOperatorToken(Kind, getLangOpts())) { if (DirectDeclParser) (this->*DirectDeclParser)(D); return; @@ -3657,6 +3743,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Is a pointer. DeclSpec DS(AttrFactory); + // FIXME: GNU attributes are not allowed here in a new-type-id. ParseTypeQualifierListOpt(DS); D.ExtendWithDeclSpec(DS); @@ -3682,19 +3769,18 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Complain about rvalue references in C++03, but then go on and build // the declarator. - if (Kind == tok::ampamp && !getLang().CPlusPlus0x) - Diag(Loc, diag::ext_rvalue_reference); + if (Kind == tok::ampamp) + Diag(Loc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_rvalue_reference : + diag::ext_rvalue_reference); + + // GNU-style and C++11 attributes are allowed here, as is restrict. + ParseTypeQualifierListOpt(DS); + D.ExtendWithDeclSpec(DS); // C++ 8.3.2p1: cv-qualified references are ill-formed except when the // cv-qualifiers are introduced through the use of a typedef or of a // template type argument, in which case the cv-qualifiers are ignored. - // - // [GNU] Retricted references are allowed. - // [GNU] Attributes on references are allowed. - // [C++0x] Attributes on references are not allowed. - ParseTypeQualifierListOpt(DS, true, false); - D.ExtendWithDeclSpec(DS); - if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(DS.getConstSpecLoc(), @@ -3732,6 +3818,19 @@ void Parser::ParseDeclaratorInternal(Declarator &D, } } +static void diagnoseMisplacedEllipsis(Parser &P, Declarator &D, + SourceLocation EllipsisLoc) { + if (EllipsisLoc.isValid()) { + FixItHint Insertion; + if (!D.getEllipsisLoc().isValid()) { + Insertion = FixItHint::CreateInsertion(D.getIdentifierLoc(), "..."); + D.setEllipsisLoc(EllipsisLoc); + } + P.Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration) + << FixItHint::CreateRemoval(EllipsisLoc) << Insertion << !D.hasName(); + } +} + /// ParseDirectDeclarator /// direct-declarator: [C99 6.7.5] /// [C99] identifier @@ -3742,13 +3841,19 @@ void Parser::ParseDeclaratorInternal(Declarator &D, /// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' /// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' /// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' +/// [C++11] direct-declarator '[' constant-expression[opt] ']' +/// attribute-specifier-seq[opt] /// direct-declarator '(' parameter-type-list ')' /// direct-declarator '(' identifier-list[opt] ')' /// [GNU] direct-declarator '(' parameter-forward-declarations /// parameter-type-list[opt] ')' /// [C++] direct-declarator '(' parameter-declaration-clause ')' /// cv-qualifier-seq[opt] exception-specification[opt] +/// [C++11] direct-declarator '(' parameter-declaration-clause ')' +/// attribute-specifier-seq[opt] cv-qualifier-seq[opt] +/// ref-qualifier[opt] exception-specification[opt] /// [C++] declarator-id +/// [C++11] declarator-id attribute-specifier-seq[opt] /// /// declarator-id: [C++ 8] /// '...'[opt] id-expression @@ -3765,13 +3870,18 @@ void Parser::ParseDeclaratorInternal(Declarator &D, /// '~' class-name /// template-id /// +/// Note, any additional constructs added here may need corresponding changes +/// in isConstructorDeclarator. void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); - if (getLang().CPlusPlus && D.mayHaveIdentifier()) { + if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { // ParseDeclaratorInternal might already have parsed the scope. if (D.getCXXScopeSpec().isEmpty()) { - ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(), true); + bool EnteringContext = D.getContext() == Declarator::FileContext || + D.getContext() == Declarator::MemberContext; + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(), + EnteringContext); } if (D.getCXXScopeSpec().isValid()) { @@ -3788,13 +3898,26 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // abstract-declarator if the type of the parameter names a template // parameter pack that has not been expanded; otherwise, it is parsed // as part of the parameter-declaration-clause. - if (Tok.is(tok::ellipsis) && + if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() && !((D.getContext() == Declarator::PrototypeContext || D.getContext() == Declarator::BlockLiteralContext) && NextToken().is(tok::r_paren) && - !Actions.containsUnexpandedParameterPacks(D))) - D.setEllipsisLoc(ConsumeToken()); - + !Actions.containsUnexpandedParameterPacks(D))) { + SourceLocation EllipsisLoc = ConsumeToken(); + if (isPtrOperatorToken(Tok.getKind(), getLangOpts())) { + // The ellipsis was put in the wrong place. Recover, and explain to + // the user what they should have done. + ParseDeclarator(D); + diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); + return; + } else + D.setEllipsisLoc(EllipsisLoc); + + // The ellipsis can't be followed by a parenthesized declarator. We + // check for that in ParseParenDeclarator, after we have disambiguated + // the l_paren token. + } + if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { // We found something that indicates the start of an unqualified-id. @@ -3810,11 +3933,13 @@ void Parser::ParseDirectDeclarator(Declarator &D) { else AllowConstructorName = (D.getContext() == Declarator::MemberContext); + SourceLocation TemplateKWLoc; if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, AllowConstructorName, ParsedType(), + TemplateKWLoc, D.getName()) || // Once we're past the identifier, if the scope was bad, mark the // whole declarator bad. @@ -3830,14 +3955,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) { goto PastIdentifier; } } else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { - assert(!getLang().CPlusPlus && + assert(!getLangOpts().CPlusPlus && "There's a C++-specific check for tok::identifier above"); assert(Tok.getIdentifierInfo() && "Not an identifier?"); D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); goto PastIdentifier; } - + if (Tok.is(tok::l_paren)) { // direct-declarator: '(' declarator ')' // direct-declarator: '(' attributes declarator ')' @@ -3849,7 +3974,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // the scope already. Re-enter the scope, if we need to. if (D.getCXXScopeSpec().isSet()) { // If there was an error parsing parenthesized declarator, declarator - // scope may have been enterred before. Don't do it again. + // scope may have been entered before. Don't do it again. if (!D.isInvalidType() && Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function @@ -3864,8 +3989,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (D.getContext() == Declarator::MemberContext) Diag(Tok, diag::err_expected_member_name_or_semi) << D.getDeclSpec().getSourceRange(); - else if (getLang().CPlusPlus) - Diag(Tok, diag::err_expected_unqualified_id) << getLang().CPlusPlus; + else if (getLangOpts().CPlusPlus) + Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus; else Diag(Tok, diag::err_expected_ident_lparen); D.SetIdentifier(0, Tok.getLocation()); @@ -3876,16 +4001,20 @@ void Parser::ParseDirectDeclarator(Declarator &D) { assert(D.isPastIdentifier() && "Haven't past the location of the identifier yet?"); - // Don't parse attributes unless we have an identifier. - if (D.getIdentifier()) + // Don't parse attributes unless we have parsed an unparenthesized name. + if (D.hasName() && !D.getNumTypeObjects()) MaybeParseCXX0XAttributes(D); while (1) { if (Tok.is(tok::l_paren)) { + // Enter function-declaration scope, limiting any declarators to the + // function prototype scope, including parameter declarators. + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope|Scope::DeclScope); // The paren may be part of a C++ direct initializer, eg. "int x(1);". // In such a case, check if we actually have a function declarator; if it // is not, the declarator has been fully parsed. - if (getLang().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { + if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { // When not in file scope, warn for ambiguous function declarators, just // in case the author intended it as a variable definition. bool warnIfAmbiguous = D.getContext() != Declarator::FileContext; @@ -3896,13 +4025,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ParseFunctionDeclarator(D, attrs, T); + PrototypeScope.Exit(); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); } else { break; } } -} +} /// ParseParenDeclarator - We parsed the declarator D up to a paren. This is /// only called before the identifier, so these are most likely just grouping @@ -3964,8 +4094,10 @@ void Parser::ParseParenDeclarator(Declarator &D) { // paren, because we haven't seen the identifier yet. isGrouping = true; } else if (Tok.is(tok::r_paren) || // 'int()' is a function. - (getLang().CPlusPlus && Tok.is(tok::ellipsis)) || // C++ int(...) - isDeclarationSpecifier()) { // 'int(int)' is a function. + (getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) && + NextToken().is(tok::r_paren)) || // C++ int(...) + isDeclarationSpecifier() || // 'int(int)' is a function. + isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function. // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is // considered to be a type, not a K&R identifier-list. isGrouping = false; @@ -3978,9 +4110,11 @@ void Parser::ParseParenDeclarator(Declarator &D) { // direct-declarator: '(' declarator ')' // direct-declarator: '(' attributes declarator ')' if (isGrouping) { + SourceLocation EllipsisLoc = D.getEllipsisLoc(); + D.setEllipsisLoc(SourceLocation()); + bool hadGroupingParens = D.hasGroupingParens(); D.setGroupingParens(true); - ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // Match the ')'. T.consumeClose(); @@ -3989,6 +4123,11 @@ void Parser::ParseParenDeclarator(Declarator &D) { attrs, T.getCloseLocation()); D.setGroupingParens(hadGroupingParens); + + // An ellipsis cannot be placed outside parentheses. + if (EllipsisLoc.isValid()) + diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); + return; } @@ -3998,31 +4137,39 @@ void Parser::ParseParenDeclarator(Declarator &D) { // ParseFunctionDeclarator to handle of argument list. D.SetIdentifier(0, Tok.getLocation()); + // Enter function-declaration scope, limiting any declarators to the + // function prototype scope, including parameter declarators. + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope|Scope::DeclScope); ParseFunctionDeclarator(D, attrs, T, RequiresArg); + PrototypeScope.Exit(); } /// ParseFunctionDeclarator - We are after the identifier and have parsed the /// declarator D up to a paren, which indicates that we are parsing function /// arguments. /// -/// If attrs is non-null, then the caller parsed those arguments immediately -/// after the open paren - they should be considered to be the first argument of -/// a parameter. If RequiresArg is true, then the first argument of the -/// function is required to be present and required to not be an identifier -/// list. +/// If FirstArgAttrs is non-null, then the caller parsed those arguments +/// immediately after the open paren - they should be considered to be the +/// first argument of a parameter. +/// +/// If RequiresArg is true, then the first argument of the function is required +/// to be present and required to not be an identifier list. /// -/// For C++, after the parameter-list, it also parses cv-qualifier-seq[opt], -/// (C++0x) ref-qualifier[opt], exception-specification[opt], and -/// (C++0x) trailing-return-type[opt]. +/// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt], +/// (C++11) ref-qualifier[opt], exception-specification[opt], +/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt]. /// -/// [C++0x] exception-specification: +/// [C++11] exception-specification: /// dynamic-exception-specification /// noexcept-specification /// void Parser::ParseFunctionDeclarator(Declarator &D, - ParsedAttributes &attrs, + ParsedAttributes &FirstArgAttrs, BalancedDelimiterTracker &Tracker, bool RequiresArg) { + assert(getCurScope()->isFunctionPrototypeScope() && + "Should call from a Function scope"); // lparen is already consumed! assert(D.isPastIdentifier() && "Should not call before identifier!"); @@ -4037,13 +4184,18 @@ void Parser::ParseFunctionDeclarator(Declarator &D, DeclSpec DS(AttrFactory); bool RefQualifierIsLValueRef = true; SourceLocation RefQualifierLoc; + SourceLocation ConstQualifierLoc; + SourceLocation VolatileQualifierLoc; ExceptionSpecificationType ESpecType = EST_None; SourceRange ESpecRange; SmallVector<ParsedType, 2> DynamicExceptions; SmallVector<SourceRange, 2> DynamicExceptionRanges; ExprResult NoexceptExpr; + ParsedAttributes FnAttrs(AttrFactory); ParsedType TrailingReturnType; - + + Actions.ActOnStartFunctionDeclarator(); + SourceLocation EndLoc; if (isFunctionDeclaratorIdentifierList()) { if (RequiresArg) @@ -4054,35 +4206,36 @@ void Parser::ParseFunctionDeclarator(Declarator &D, Tracker.consumeClose(); EndLoc = Tracker.getCloseLocation(); } else { - // Enter function-declaration scope, limiting any declarators to the - // function prototype scope, including parameter declarators. - ParseScope PrototypeScope(this, - Scope::FunctionPrototypeScope|Scope::DeclScope); - if (Tok.isNot(tok::r_paren)) - ParseParameterDeclarationClause(D, attrs, ParamInfo, EllipsisLoc); + ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc); else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); - HasProto = ParamInfo.size() || getLang().CPlusPlus; + HasProto = ParamInfo.size() || getLangOpts().CPlusPlus; // If we have the closing ')', eat it. Tracker.consumeClose(); EndLoc = Tracker.getCloseLocation(); - if (getLang().CPlusPlus) { - MaybeParseCXX0XAttributes(attrs); + if (getLangOpts().CPlusPlus) { + // FIXME: Accept these components in any order, and produce fixits to + // correct the order if the user gets it wrong. Ideally we should deal + // with the virt-specifier-seq and pure-specifier in the same way. // Parse cv-qualifier-seq[opt]. - ParseTypeQualifierListOpt(DS, false /*no attributes*/); - if (!DS.getSourceRange().getEnd().isInvalid()) - EndLoc = DS.getSourceRange().getEnd(); + ParseTypeQualifierListOpt(DS, false /*no attributes*/, false); + if (!DS.getSourceRange().getEnd().isInvalid()) { + EndLoc = DS.getSourceRange().getEnd(); + ConstQualifierLoc = DS.getConstSpecLoc(); + VolatileQualifierLoc = DS.getVolatileSpecLoc(); + } // Parse ref-qualifier[opt]. if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::ext_ref_qualifier); - + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_ref_qualifier : + diag::ext_ref_qualifier); + RefQualifierIsLValueRef = Tok.is(tok::amp); RefQualifierLoc = ConsumeToken(); EndLoc = RefQualifierLoc; @@ -4096,17 +4249,19 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (ESpecType != EST_None) EndLoc = ESpecRange.getEnd(); + // Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes + // after the exception-specification. + MaybeParseCXX0XAttributes(FnAttrs); + // Parse trailing-return-type[opt]. - if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { + if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) { + Diag(Tok, diag::warn_cxx98_compat_trailing_return_type); SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range).get(); if (Range.getEnd().isValid()) EndLoc = Range.getEnd(); } } - - // Leave prototype scope. - PrototypeScope.Exit(); } // Remember that we parsed a function type, and remember the attributes. @@ -4116,7 +4271,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, ParamInfo.data(), ParamInfo.size(), DS.getTypeQualifiers(), RefQualifierIsLValueRef, - RefQualifierLoc, + RefQualifierLoc, ConstQualifierLoc, + VolatileQualifierLoc, /*MutableLoc=*/SourceLocation(), ESpecType, ESpecRange.getBegin(), DynamicExceptions.data(), @@ -4127,7 +4283,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D, Tracker.getOpenLocation(), EndLoc, D, TrailingReturnType), - attrs, EndLoc); + FnAttrs, EndLoc); + + Actions.ActOnEndFunctionDeclarator(); } /// isFunctionDeclaratorIdentifierList - This parameter list may have an @@ -4136,7 +4294,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, /// Note that identifier-lists are only allowed for normal declarators, not for /// abstract-declarators. bool Parser::isFunctionDeclaratorIdentifierList() { - return !getLang().CPlusPlus + return !getLangOpts().CPlusPlus && Tok.is(tok::identifier) && !TryAltiVecVectorToken() // K&R identifier lists can't have typedefs as identifiers, per C99 @@ -4219,9 +4377,9 @@ void Parser::ParseFunctionDeclaratorIdentifierList( /// after the opening parenthesis. This function will not parse a K&R-style /// identifier list. /// -/// D is the declarator being parsed. If attrs is non-null, then the caller -/// parsed those arguments immediately after the open paren - they should be -/// considered to be the first argument of a parameter. +/// D is the declarator being parsed. If FirstArgAttrs is non-null, then the +/// caller parsed those arguments immediately after the open paren - they should +/// be considered to be part of the first parameter. /// /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will /// be the location of the ellipsis, if any was parsed. @@ -4238,20 +4396,24 @@ void Parser::ParseFunctionDeclaratorIdentifierList( /// parameter-declaration: [C99 6.7.5] /// declaration-specifiers declarator /// [C++] declaration-specifiers declarator '=' assignment-expression +/// [C++11] initializer-clause /// [GNU] declaration-specifiers declarator attributes /// declaration-specifiers abstract-declarator[opt] /// [C++] declaration-specifiers abstract-declarator[opt] /// '=' assignment-expression /// [GNU] declaration-specifiers abstract-declarator[opt] attributes +/// [C++11] attribute-specifier-seq parameter-declaration /// void Parser::ParseParameterDeclarationClause( Declarator &D, - ParsedAttributes &attrs, + ParsedAttributes &FirstArgAttrs, SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo, SourceLocation &EllipsisLoc) { while (1) { if (Tok.is(tok::ellipsis)) { + // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq + // before deciding this was a parameter-declaration-clause. EllipsisLoc = ConsumeToken(); // Consume the ellipsis. break; } @@ -4260,20 +4422,21 @@ void Parser::ParseParameterDeclarationClause( // Just use the ParsingDeclaration "scope" of the declarator. DeclSpec DS(AttrFactory); + // Parse any C++11 attributes. + MaybeParseCXX0XAttributes(DS.getAttributes()); + // Skip any Microsoft attributes before a param. - if (getLang().MicrosoftExt && Tok.is(tok::l_square)) + if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square)) ParseMicrosoftAttributes(DS.getAttributes()); SourceLocation DSStart = Tok.getLocation(); // If the caller parsed attributes for the first argument, add them now. // Take them so that we only apply the attributes to the first parameter. - // FIXME: If we saw an ellipsis first, this code is not reached. Are the - // attributes lost? Should they even be allowed? // FIXME: If we can leave the attributes in the token stream somehow, we can - // get rid of a parameter (attrs) and this statement. It might be too much - // hassle. - DS.takeAttributesFrom(attrs); + // get rid of a parameter (FirstArgAttrs) and this statement. It might be + // too much hassle. + DS.takeAttributesFrom(FirstArgAttrs); ParseDeclarationSpecifiers(DS); @@ -4346,9 +4509,15 @@ void Parser::ParseParameterDeclarationClause( // The argument isn't actually potentially evaluated unless it is // used. EnterExpressionEvaluationContext Eval(Actions, - Sema::PotentiallyEvaluatedIfUsed); - - ExprResult DefArgResult(ParseAssignmentExpression()); + Sema::PotentiallyEvaluatedIfUsed, + Param); + + ExprResult DefArgResult; + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + DefArgResult = ParseBraceInitializer(); + } else + DefArgResult = ParseAssignmentExpression(); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param); SkipUntil(tok::comma, tok::r_paren, true, true); @@ -4370,7 +4539,7 @@ void Parser::ParseParameterDeclarationClause( if (Tok.is(tok::ellipsis)) { EllipsisLoc = ConsumeToken(); // Consume the ellipsis. - if (!getLang().CPlusPlus) { + if (!getLangOpts().CPlusPlus) { // We have ellipsis without a preceding ',', which is ill-formed // in C. Complain and provide the fix. Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis) @@ -4392,7 +4561,12 @@ void Parser::ParseParameterDeclarationClause( /// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' /// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' /// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' +/// [C++11] direct-declarator '[' constant-expression[opt] ']' +/// attribute-specifier-seq[opt] void Parser::ParseBracketDeclarator(Declarator &D) { + if (CheckProhibitedCXX11Attribute()) + return; + BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); @@ -4413,7 +4587,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { } else if (Tok.getKind() == tok::numeric_constant && GetLookAheadToken(1).is(tok::r_square)) { // [4] is very common. Parse the numeric constant expression. - ExprResult ExprRes(Actions.ActOnNumericConstant(Tok)); + ExprResult ExprRes(Actions.ActOnNumericConstant(Tok, getCurScope())); ConsumeToken(); T.consumeClose(); @@ -4468,10 +4642,13 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // Parse the constant-expression or assignment-expression now (depending // on dialect). - if (getLang().CPlusPlus) + if (getLangOpts().CPlusPlus) { NumElements = ParseConstantExpression(); - else + } else { + EnterExpressionEvaluationContext Unevaluated(Actions, + Sema::ConstantEvaluated); NumElements = ParseAssignmentExpression(); + } } // If there was an error parsing the assignment-expression, recover. @@ -4508,6 +4685,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { const bool hasParens = Tok.is(tok::l_paren); + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + bool isCastExpr; ParsedType CastTy; SourceRange CastRange; @@ -4543,6 +4722,13 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { return; } + // We might need to transform the operand if it is potentially evaluated. + Operand = Actions.HandleExprEvaluationContextForTypeof(Operand.get()); + if (Operand.isInvalid()) { + DS.SetTypeSpecError(); + return; + } + const char *PrevSpec = 0; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int typeof(int)"). @@ -4551,7 +4737,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { Diag(StartLoc, DiagID) << PrevSpec; } -/// [C1X] atomic-specifier: +/// [C11] atomic-specifier: /// _Atomic ( type-name ) /// void Parser::ParseAtomicSpecifier(DeclSpec &DS) { diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp index 4339047..b2a65ff 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -18,6 +18,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/PrettyDeclStackTrace.h" +#include "llvm/ADT/SmallString.h" #include "RAIIObjectsForParser.h" using namespace clang; @@ -148,8 +149,9 @@ Decl *Parser::ParseNamespace(unsigned Context, } // If we're still good, complain about inline namespaces in non-C++0x now. - if (!getLang().CPlusPlus0x && InlineLoc.isValid()) - Diag(InlineLoc, diag::ext_inline_namespace); + if (InlineLoc.isValid()) + Diag(InlineLoc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_inline_namespace : diag::ext_inline_namespace); // Enter a scope for the namespace. ParseScope NamespaceScope(this, Scope::DeclScope); @@ -233,7 +235,7 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); if (SS.isInvalid() || Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_namespace_name); @@ -264,12 +266,17 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, /// Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { assert(Tok.is(tok::string_literal) && "Not a string literal!"); - llvm::SmallString<8> LangBuffer; + SmallString<8> LangBuffer; bool Invalid = false; StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid); if (Invalid) return 0; + // FIXME: This is incorrect: linkage-specifiers are parsed in translation + // phase 7, so string-literal concatenation is supposed to occur. + // extern "" "C" "" "+" "+" { } is legal. + if (Tok.hasUDSuffix()) + Diag(Tok, diag::err_invalid_string_udl); SourceLocation Loc = ConsumeStringToken(); ParseScope LinkageScope(this, Scope::DeclScope); @@ -381,7 +388,7 @@ Decl *Parser::ParseUsingDirective(unsigned Context, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); IdentifierInfo *NamespcName = 0; SourceLocation IdentLoc = SourceLocation(); @@ -449,7 +456,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, IsTypeName = false; // Parse nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); // Check nested-name specifier. if (SS.isInvalid()) { @@ -460,12 +467,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // Parse the unqualified-id. We allow parsing of both constructor and // destructor names and allow the action module to diagnose any semantic // errors. + SourceLocation TemplateKWLoc; UnqualifiedId Name; if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/true, /*AllowConstructorName=*/true, ParsedType(), + TemplateKWLoc, Name)) { SkipUntil(tok::semi); return 0; @@ -481,8 +490,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // Where can GNU attributes appear? ConsumeToken(); - if (!getLang().CPlusPlus0x) - Diag(Tok.getLocation(), diag::ext_alias_declaration); + Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_alias_declaration : + diag::ext_alias_declaration); // Type alias templates cannot be specialized. int SpecKind = -1; @@ -571,20 +581,22 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, IsTypeName, TypenameLoc); } -/// ParseStaticAssertDeclaration - Parse C++0x or C1X static_assert-declaration. +/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration. /// /// [C++0x] static_assert-declaration: /// static_assert ( constant-expression , string-literal ) ; /// -/// [C1X] static_assert-declaration: +/// [C11] static_assert-declaration: /// _Static_assert ( constant-expression , string-literal ) ; /// Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ assert((Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) && "Not a static_assert declaration"); - if (Tok.is(tok::kw__Static_assert) && !getLang().C1X) - Diag(Tok, diag::ext_c1x_static_assert); + if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11) + Diag(Tok, diag::ext_c11_static_assert); + if (Tok.is(tok::kw_static_assert)) + Diag(Tok, diag::warn_cxx98_compat_static_assert); SourceLocation StaticAssertLoc = ConsumeToken(); @@ -603,15 +615,17 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi)) return 0; - if (Tok.isNot(tok::string_literal)) { + if (!isTokenStringLiteral()) { Diag(Tok, diag::err_expected_string_literal); SkipUntil(tok::semi); return 0; } ExprResult AssertMessage(ParseStringLiteralExpression()); - if (AssertMessage.isInvalid()) + if (AssertMessage.isInvalid()) { + SkipUntil(tok::semi); return 0; + } T.consumeClose(); @@ -628,39 +642,94 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ /// /// 'decltype' ( expression ) /// -void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { - assert(Tok.is(tok::kw_decltype) && "Not a decltype specifier"); +SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { + assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) + && "Not a decltype specifier"); + - SourceLocation StartLoc = ConsumeToken(); - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, - "decltype", tok::r_paren)) { - return; - } + ExprResult Result; + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; - // Parse the expression + if (Tok.is(tok::annot_decltype)) { + Result = getExprAnnotation(Tok); + EndLoc = Tok.getAnnotationEndLoc(); + ConsumeToken(); + if (Result.isInvalid()) { + DS.SetTypeSpecError(); + return EndLoc; + } + } else { + if (Tok.getIdentifierInfo()->isStr("decltype")) + Diag(Tok, diag::warn_cxx98_compat_decltype); - // C++0x [dcl.type.simple]p4: - // The operand of the decltype specifier is an unevaluated operand. - EnterExpressionEvaluationContext Unevaluated(Actions, - Sema::Unevaluated); - ExprResult Result = ParseExpression(); - if (Result.isInvalid()) { - SkipUntil(tok::r_paren); - return; - } + ConsumeToken(); - // Match the ')' - T.consumeClose(); - if (T.getCloseLocation().isInvalid()) - return; + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, + "decltype", tok::r_paren)) { + DS.SetTypeSpecError(); + return T.getOpenLocation() == Tok.getLocation() ? + StartLoc : T.getOpenLocation(); + } + + // Parse the expression + + // C++0x [dcl.type.simple]p4: + // The operand of the decltype specifier is an unevaluated operand. + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, + 0, /*IsDecltype=*/true); + Result = ParseExpression(); + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + DS.SetTypeSpecError(); + return StartLoc; + } + + // Match the ')' + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) { + DS.SetTypeSpecError(); + // FIXME: this should return the location of the last token + // that was consumed (by "consumeClose()") + return T.getCloseLocation(); + } + + Result = Actions.ActOnDecltypeExpression(Result.take()); + if (Result.isInvalid()) { + DS.SetTypeSpecError(); + return T.getCloseLocation(); + } + + EndLoc = T.getCloseLocation(); + } const char *PrevSpec = 0; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int decltype(a)"). if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec, - DiagID, Result.release())) + DiagID, Result.release())) { Diag(StartLoc, DiagID) << PrevSpec; + DS.SetTypeSpecError(); + } + return EndLoc; +} + +void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // make sure we have a token we can turn into an annotation token + if (PP.isBacktrackEnabled()) + PP.RevertCachedTokens(1); + else + PP.EnterToken(Tok); + + Tok.setKind(tok::annot_decltype); + setExprAnnotation(Tok, DS.getTypeSpecType() == TST_decltype ? + DS.getRepAsExpr() : ExprResult()); + Tok.setAnnotationEndLoc(EndLoc); + Tok.setLocation(StartLoc); + PP.AnnotateCachedTokens(Tok); } void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { @@ -692,18 +761,52 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { Diag(StartLoc, DiagID) << PrevSpec; } -/// ParseClassName - Parse a C++ class-name, which names a class. Note -/// that we only check that the result names a type; semantic analysis -/// will need to verify that the type names a class. The result is -/// either a type or NULL, depending on whether a type name was -/// found. -/// +/// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a +/// class name or decltype-specifier. Note that we only check that the result +/// names a type; semantic analysis will need to verify that the type names a +/// class. The result is either a type or null, depending on whether a type +/// name was found. +/// +/// base-type-specifier: [C++ 10.1] +/// class-or-decltype +/// class-or-decltype: [C++ 10.1] +/// nested-name-specifier[opt] class-name +/// decltype-specifier /// class-name: [C++ 9.1] /// identifier /// simple-template-id /// -Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, - CXXScopeSpec &SS) { +Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, + SourceLocation &EndLocation) { + // Ignore attempts to use typename + if (Tok.is(tok::kw_typename)) { + Diag(Tok, diag::err_expected_class_name_not_template) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + } + + // Parse optional nested-name-specifier + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + + BaseLoc = Tok.getLocation(); + + // Parse decltype-specifier + // tok == kw_decltype is just error recovery, it can only happen when SS + // isn't empty + if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) { + if (SS.isNotEmpty()) + Diag(SS.getBeginLoc(), diag::err_unexpected_scope_on_base_decltype) + << FixItHint::CreateRemoval(SS.getRange()); + // Fake up a Declarator to use with ActOnTypeName. + DeclSpec DS(AttrFactory); + + EndLocation = ParseDecltypeSpecifier(DS); + + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + } + // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); @@ -751,8 +854,8 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, TemplateName.setIdentifier(Id, IdLoc); // Parse the full template-id, then turn it into a type. - if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, - SourceLocation(), true)) + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, true)) return true; if (TNK == TNK_Dependent_template_name) AnnotateTemplateIdTokenAsType(); @@ -773,6 +876,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, // We have an identifier; check whether it is actually a type. ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, false, ParsedType(), + /*IsCtorOrDtorName=*/false, /*NonTrivialTypeSourceInfo=*/true); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); @@ -799,7 +903,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or /// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which /// until we reach the start of a definition or see a token that -/// cannot start a definition. If SuppressDeclarations is true, we do know. +/// cannot start a definition. /// /// class-specifier: [C++ class] /// class-head '{' member-specification[opt] '}' @@ -839,7 +943,8 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation StartLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, - AccessSpecifier AS, bool SuppressDeclarations){ + AccessSpecifier AS, + bool EnteringContext, DeclSpecContext DSC) { DeclSpec::TST TagType; if (TagTokKind == tok::kw_struct) TagType = DeclSpec::TST_struct; @@ -863,12 +968,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // As an extension we do not perform access checking on the names used to // specify explicit specializations either. This is important to allow // specializing traits classes for private types. - bool SuppressingAccessChecks = false; - if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) { - Actions.ActOnStartSuppressingAccessChecks(); - SuppressingAccessChecks = true; - } + Sema::SuppressAccessChecksRAII SuppressAccess(Actions, + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); ParsedAttributes attrs(AttrFactory); // If attributes exist after tag, parse them. @@ -914,11 +1016,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Parse the (optional) nested-name-specifier. CXXScopeSpec &SS = DS.getTypeSpecScope(); - if (getLang().CPlusPlus) { + if (getLangOpts().CPlusPlus) { // "FOO : BAR" is not a potential typo for "FOO::BAR". ColonProtectionRAIIObject X(*this); - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true)) + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) DS.SetTypeSpecError(); if (SS.isSet()) if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) @@ -935,7 +1037,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); - if (Tok.is(tok::less) && getLang().CPlusPlus) { + if (Tok.is(tok::less) && getLangOpts().CPlusPlus) { // The name was supposed to refer to a template, but didn't. // Eat the template argument list and try to continue parsing this as // a class (or template thereof). @@ -997,39 +1099,41 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, DS.SetTypeSpecError(); SkipUntil(tok::semi, false, true); - if (SuppressingAccessChecks) - Actions.ActOnStopSuppressingAccessChecks(); - return; } } // As soon as we're finished parsing the class's template-id, turn access // checking back on. - if (SuppressingAccessChecks) - Actions.ActOnStopSuppressingAccessChecks(); - - // There are four options here. If we have 'struct foo;', then this - // is either a forward declaration or a friend declaration, which - // have to be treated differently. If we have 'struct foo {...', - // 'struct foo :...' or 'struct foo final[opt]' then this is a - // definition. Otherwise we have something like 'struct foo xyz', a reference. - // However, in some contexts, things look like declarations but are just - // references, e.g. - // new struct s; + SuppressAccess.done(); + + // There are four options here. + // - If we are in a trailing return type, this is always just a reference, + // and we must not try to parse a definition. For instance, + // [] () -> struct S { }; + // does not define a type. + // - If we have 'struct foo {...', 'struct foo :...', + // 'struct foo final :' or 'struct foo final {', then this is a definition. + // - If we have 'struct foo;', then this is either a forward declaration + // or a friend declaration, which have to be treated differently. + // - Otherwise we have something like 'struct foo xyz', a reference. + // However, in type-specifier-seq's, things look like declarations but are + // just references, e.g. + // new struct s; // or - // &T::operator struct s; - // For these, SuppressDeclarations is true. + // &T::operator struct s; + // For these, DSC is DSC_type_specifier. Sema::TagUseKind TUK; - if (SuppressDeclarations) + if (DSC == DSC_trailing) TUK = Sema::TUK_Reference; - else if (Tok.is(tok::l_brace) || - (getLang().CPlusPlus && Tok.is(tok::colon)) || - isCXX0XFinalKeyword()) { + else if (Tok.is(tok::l_brace) || + (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || + (isCXX0XFinalKeyword() && + (NextToken().is(tok::l_brace) || NextToken().is(tok::colon)))) { if (DS.isFriendSpecified()) { // C++ [class.friend]p2: // A class shall not be defined in a friend declaration. - Diag(Tok.getLocation(), diag::err_friend_decl_defines_class) + Diag(Tok.getLocation(), diag::err_friend_decl_defines_type) << SourceRange(DS.getFriendSpecLoc()); // Skip everything up to the semicolon, so that this looks like a proper @@ -1040,7 +1144,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Okay, this is a class definition. TUK = Sema::TUK_Definition; } - } else if (Tok.is(tok::semi)) + } else if (Tok.is(tok::semi) && DSC != DSC_type_specifier) TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; else TUK = Sema::TUK_Reference; @@ -1092,14 +1196,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else if (TUK == Sema::TUK_Reference || (TUK == Sema::TUK_Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { - TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, - StartLoc, + TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc, TemplateId->SS, + TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->RAngleLoc); + TemplateId->RAngleLoc); } else { // This is an explicit specialization or a class template // partial specialization. @@ -1191,8 +1295,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, SS, Name, NameLoc, attrs.getList(), AS, DS.getModulePrivateSpecLoc(), - TParams, Owned, IsDependent, false, - false, clang::TypeResult()); + TParams, Owned, IsDependent, + SourceLocation(), false, + clang::TypeResult()); // If ActOnTag said the type was dependent, try again with the // less common call. @@ -1206,9 +1311,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // If there is a body, parse it and inform the actions module. if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || - (getLang().CPlusPlus && Tok.is(tok::colon)) || + (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || isCXX0XFinalKeyword()); - if (getLang().CPlusPlus) + if (getLangOpts().CPlusPlus) ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); else ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); @@ -1290,7 +1395,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, case tok::r_brace: // struct bar { struct foo {...} } // Missing ';' at end of struct is accepted as an extension in C mode. - if (!getLang().CPlusPlus) + if (!getLangOpts().CPlusPlus) ExpectedSemi = false; break; } @@ -1359,9 +1464,9 @@ void Parser::ParseBaseClause(Decl *ClassDecl) { /// base-specifier: [C++ class.derived] /// ::[opt] nested-name-specifier[opt] class-name /// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt] -/// class-name +/// base-type-specifier /// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt] -/// class-name +/// base-type-specifier Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { bool IsVirtual = false; SourceLocation StartLoc = Tok.getLocation(); @@ -1390,16 +1495,10 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { IsVirtual = true; } - // Parse optional '::' and optional nested-name-specifier. - CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); - - // The location of the base class itself. - SourceLocation BaseLoc = Tok.getLocation(); - // Parse the class-name. SourceLocation EndLocation; - TypeResult BaseType = ParseClassName(EndLocation, SS); + SourceLocation BaseLoc; + TypeResult BaseType = ParseBaseTypeSpecifier(BaseLoc, EndLocation); if (BaseType.isInvalid()) return true; @@ -1468,14 +1567,14 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, } } -/// isCXX0XVirtSpecifier - Determine whether the next token is a C++0x +/// isCXX0XVirtSpecifier - Determine whether the given token is a C++0x /// virt-specifier. /// /// virt-specifier: /// override /// final -VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier() const { - if (!getLang().CPlusPlus) +VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const { + if (!getLangOpts().CPlusPlus) return VirtSpecifiers::VS_None; if (Tok.is(tok::identifier)) { @@ -1516,9 +1615,10 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); - if (!getLang().CPlusPlus0x) - Diag(Tok.getLocation(), diag::ext_override_control_keyword) - << VirtSpecifiers::getSpecifierName(Specifier); + Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_override_control_keyword : + diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); ConsumeToken(); } } @@ -1526,7 +1626,7 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { /// isCXX0XFinalKeyword - Determine whether the next token is a C++0x /// contextual 'final' keyword. bool Parser::isCXX0XFinalKeyword() const { - if (!getLang().CPlusPlus) + if (!getLangOpts().CPlusPlus) return false; if (!Tok.is(tok::identifier)) @@ -1581,7 +1681,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *TemplateDiags) { if (Tok.is(tok::at)) { - if (getLang().ObjC1 && NextToken().isObjCAtKeyword(tok::objc_defs)) + if (getLangOpts().ObjC1 && NextToken().isObjCAtKeyword(tok::objc_defs)) Diag(Tok, diag::err_at_defs_cxx); else Diag(Tok, diag::err_at_in_class); @@ -1605,11 +1705,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (isAccessDecl) { // Collect the scope specifier token we annotated earlier. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false); // Try to parse an unqualified-id. + SourceLocation TemplateKWLoc; UnqualifiedId Name; - if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), Name)) { + if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), + TemplateKWLoc, Name)) { SkipUntil(tok::semi); return; } @@ -1684,11 +1787,15 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } + // Hold late-parsed attributes so we can attach a Decl to them later. + LateParsedAttrList CommonLateParsedAttrs; + // decl-specifier-seq: // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this, TemplateDiags); DS.takeAttributesFrom(attrs); - ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, + &CommonLateParsedAttrs); MultiTemplateParamsArg TemplateParams(Actions, TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, @@ -1708,6 +1815,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Hold late-parsed attributes so we can attach a Decl to them later. LateParsedAttrList LateParsedAttrs; + SourceLocation EqualLoc; + bool HasInitializer = false; + ExprResult Init; if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. ColonProtectionRAIIObject X(*this); @@ -1730,39 +1840,42 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // MSVC permits pure specifier on inline functions declared at class scope. // Hence check for =0 before checking for function definition. - ExprResult Init; - if (getLang().MicrosoftExt && Tok.is(tok::equal) && + if (getLangOpts().MicrosoftExt && Tok.is(tok::equal) && DeclaratorInfo.isFunctionDeclarator() && NextToken().is(tok::numeric_constant)) { - ConsumeToken(); + EqualLoc = ConsumeToken(); Init = ParseInitializer(); if (Init.isInvalid()) SkipUntil(tok::comma, true, true); + else + HasInitializer = true; } - bool IsDefinition = false; + FunctionDefinitionKind DefinitionKind = FDK_Declaration; // function-definition: // // In C++11, a non-function declarator followed by an open brace is a // braced-init-list for an in-class member initialization, not an // erroneous function definition. - if (Tok.is(tok::l_brace) && !getLang().CPlusPlus0x) { - IsDefinition = true; + if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus0x) { + DefinitionKind = FDK_Definition; } else if (DeclaratorInfo.isFunctionDeclarator()) { if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) { - IsDefinition = true; + DefinitionKind = FDK_Definition; } else if (Tok.is(tok::equal)) { const Token &KW = NextToken(); - if (KW.is(tok::kw_default) || KW.is(tok::kw_delete)) - IsDefinition = true; + if (KW.is(tok::kw_default)) + DefinitionKind = FDK_Defaulted; + else if (KW.is(tok::kw_delete)) + DefinitionKind = FDK_Deleted; } } - if (IsDefinition) { + if (DefinitionKind) { if (!DeclaratorInfo.isFunctionDeclarator()) { - Diag(Tok, diag::err_func_def_no_params); + Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params); ConsumeBrace(); - SkipUntil(tok::r_brace, true); + SkipUntil(tok::r_brace, /*StopAtSemi*/false); // Consume the optional ';' if (Tok.is(tok::semi)) @@ -1771,12 +1884,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { - Diag(Tok, diag::err_function_declared_typedef); + Diag(DeclaratorInfo.getIdentifierLoc(), + diag::err_function_declared_typedef); // This recovery skips the entire function body. It would be nice // to simply call ParseCXXInlineMethodDef() below, however Sema // assumes the declarator represents a function, not a typedef. ConsumeBrace(); - SkipUntil(tok::r_brace, true); + SkipUntil(tok::r_brace, /*StopAtSemi*/false); // Consume the optional ';' if (Tok.is(tok::semi)) @@ -1786,10 +1900,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Decl *FunDecl = ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo, - VS, Init); + VS, DefinitionKind, Init); + for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { + CommonLateParsedAttrs[i]->addDecl(FunDecl); + } for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { - LateParsedAttrs[i]->setDecl(FunDecl); + LateParsedAttrs[i]->addDecl(FunDecl); } LateParsedAttrs.clear(); @@ -1808,6 +1925,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SmallVector<Decl *, 8> DeclsInGroup; ExprResult BitfieldSize; + bool ExpectSemi = true; while (1) { // member-declarator: @@ -1839,9 +1957,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // goes before or after the GNU attributes and __asm__. ParseOptionalCXX0XVirtSpecifierSeq(VS); - bool HasInitializer = false; bool HasDeferredInitializer = false; - if (Tok.is(tok::equal) || Tok.is(tok::l_brace)) { + if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { if (BitfieldSize.get()) { Diag(Tok, diag::err_bitfield_member_init); SkipUntil(tok::comma, true, true); @@ -1876,40 +1993,45 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } // Set the Decl for any late parsed attributes + for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { + CommonLateParsedAttrs[i]->addDecl(ThisDecl); + } for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { - LateParsedAttrs[i]->setDecl(ThisDecl); + LateParsedAttrs[i]->addDecl(ThisDecl); } LateParsedAttrs.clear(); // Handle the initializer. if (HasDeferredInitializer) { // The initializer was deferred; parse it and cache the tokens. - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension); - + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_nonstatic_member_init : + diag::ext_nonstatic_member_init); + if (DeclaratorInfo.isArrayOfUnknownBound()) { // C++0x [dcl.array]p3: An array bound may also be omitted when the // declarator is followed by an initializer. // // A brace-or-equal-initializer for a member-declarator is not an - // initializer in the gramamr, so this is ill-formed. + // initializer in the grammar, so this is ill-formed. Diag(Tok, diag::err_incomplete_array_member_init); SkipUntil(tok::comma, true, true); - // Avoid later warnings about a class member of incomplete type. - ThisDecl->setInvalidDecl(); + if (ThisDecl) + // Avoid later warnings about a class member of incomplete type. + ThisDecl->setInvalidDecl(); } else ParseCXXNonStaticMemberInitializer(ThisDecl); } else if (HasInitializer) { // Normal initializer. - SourceLocation EqualLoc; - ExprResult Init - = ParseCXXMemberInitializer(DeclaratorInfo.isDeclarationOfFunction(), - EqualLoc); + if (!Init.isUsable()) + Init = ParseCXXMemberInitializer(ThisDecl, + DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); + if (Init.isInvalid()) SkipUntil(tok::comma, true, true); else if (ThisDecl) - Actions.AddInitializerToDecl(ThisDecl, Init.get(), false, - DS.getTypeSpecType() == DeclSpec::TST_auto); + Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(), + DS.getTypeSpecType() == DeclSpec::TST_auto); } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) { // No initializer. Actions.ActOnUninitializedDecl(ThisDecl, @@ -1935,12 +2057,26 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, break; // Consume the comma. - ConsumeToken(); + SourceLocation CommaLoc = ConsumeToken(); + + if (Tok.isAtStartOfLine() && + !MightBeDeclarator(Declarator::MemberContext)) { + // This comma was followed by a line-break and something which can't be + // the start of a declarator. The comma was probably a typo for a + // semicolon. + Diag(CommaLoc, diag::err_expected_semi_declaration) + << FixItHint::CreateReplacement(CommaLoc, ";"); + ExpectSemi = false; + break; + } // Parse the next declarator. DeclaratorInfo.clear(); VS.clear(); BitfieldSize = true; + Init = true; + HasInitializer = false; + DeclaratorInfo.setCommaLoc(CommaLoc); // Attributes are only allowed on the second declarator. MaybeParseGNUAttributes(DeclaratorInfo); @@ -1949,7 +2085,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParseDeclarator(DeclaratorInfo); } - if (ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) { + if (ExpectSemi && + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) { // Skip to end of block or statement. SkipUntil(tok::r_brace, true, true); // If we stopped at a ';', eat it. @@ -1968,26 +2105,29 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, /// /// pure-specifier: /// '= 0' -/// +/// /// brace-or-equal-initializer: /// '=' initializer-expression -/// braced-init-list [TODO] -/// +/// braced-init-list +/// /// initializer-clause: /// assignment-expression -/// braced-init-list [TODO] -/// +/// braced-init-list +/// /// defaulted/deleted function-definition: /// '=' 'default' /// '=' 'delete' /// /// Prior to C++0x, the assignment-expression in an initializer-clause must /// be a constant-expression. -ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction, +ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, SourceLocation &EqualLoc) { assert((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && "Data member initializer not starting with '=' or '{'"); + EnterExpressionEvaluationContext Context(Actions, + Sema::PotentiallyEvaluated, + D); if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); if (Tok.is(tok::kw_delete)) { @@ -2015,9 +2155,8 @@ ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction, return ExprResult(); } - return ParseInitializer(); - } else - return ExprError(Diag(Tok, diag::err_generalized_initializer_lists)); + } + return ParseInitializer(); } /// ParseCXXMemberSpecification - Parse the class definition. @@ -2071,20 +2210,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation FinalLoc; // Parse the optional 'final' keyword. - if (getLang().CPlusPlus && Tok.is(tok::identifier)) { - IdentifierInfo *II = Tok.getIdentifierInfo(); - - // Initialize the contextual keywords. - if (!Ident_final) { - Ident_final = &PP.getIdentifierTable().get("final"); - Ident_override = &PP.getIdentifierTable().get("override"); - } - - if (II == Ident_final) - FinalLoc = ConsumeToken(); + if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { + assert(isCXX0XFinalKeyword() && "not a class definition"); + FinalLoc = ConsumeToken(); - if (!getLang().CPlusPlus0x) - Diag(FinalLoc, diag::ext_override_control_keyword) << "final"; + Diag(FinalLoc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_override_control_keyword : + diag::ext_override_control_keyword) << "final"; } if (Tok.is(tok::colon)) { @@ -2122,7 +2254,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // Each iteration of this loop reads one member-declaration. - if (getLang().MicrosoftExt && (Tok.is(tok::kw___if_exists) || + if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); continue; @@ -2137,6 +2269,16 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } + if (Tok.is(tok::annot_pragma_vis)) { + HandlePragmaVisibility(); + continue; + } + + if (Tok.is(tok::annot_pragma_pack)) { + HandlePragmaPack(); + continue; + } + AccessSpecifier AS = getAccessSpecifierIfPresent(); if (AS != AS_none) { // Current token is a C++ access specifier. @@ -2150,11 +2292,6 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation EndLoc; if (Tok.is(tok::colon)) { EndLoc = Tok.getLocation(); - if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc, - AccessAttrs.getList())) { - // found another attribute than only annotations - AccessAttrs.clear(); - } ConsumeToken(); } else if (Tok.is(tok::semi)) { EndLoc = Tok.getLocation(); @@ -2166,7 +2303,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, Diag(EndLoc, diag::err_expected_colon) << FixItHint::CreateInsertion(EndLoc, ":"); } - Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc); + + if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc, + AccessAttrs.getList())) { + // found another attribute than only annotations + AccessAttrs.clear(); + } + continue; } @@ -2303,7 +2446,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // parse '::'[opt] nested-name-specifier[opt] CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); ParsedType TemplateTypeTy; if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); @@ -2314,18 +2457,33 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { TemplateTypeTy = getTypeAnnotation(Tok); } } - if (!TemplateTypeTy && Tok.isNot(tok::identifier)) { + // Uses of decltype will already have been converted to annot_decltype by + // ParseOptionalCXXScopeSpecifier at this point. + if (!TemplateTypeTy && Tok.isNot(tok::identifier) + && Tok.isNot(tok::annot_decltype)) { Diag(Tok, diag::err_expected_member_or_base_name); return true; } - // Get the identifier. This may be a member name or a class name, - // but we'll let the semantic analysis determine which it is. - IdentifierInfo *II = Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : 0; - SourceLocation IdLoc = ConsumeToken(); + IdentifierInfo *II = 0; + DeclSpec DS(AttrFactory); + SourceLocation IdLoc = Tok.getLocation(); + if (Tok.is(tok::annot_decltype)) { + // Get the decltype expression, if there is one. + ParseDecltypeSpecifier(DS); + } else { + if (Tok.is(tok::identifier)) + // Get the identifier. This may be a member name or a class name, + // but we'll let the semantic analysis determine which it is. + II = Tok.getIdentifierInfo(); + ConsumeToken(); + } + // Parse the '('. - if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + ExprResult InitList = ParseBraceInitializer(); if (InitList.isInvalid()) return true; @@ -2335,8 +2493,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { EllipsisLoc = ConsumeToken(); return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, - TemplateTypeTy, IdLoc, InitList.take(), - EllipsisLoc); + TemplateTypeTy, DS, IdLoc, + InitList.take(), EllipsisLoc); } else if(Tok.is(tok::l_paren)) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); @@ -2356,13 +2514,13 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { EllipsisLoc = ConsumeToken(); return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, - TemplateTypeTy, IdLoc, + TemplateTypeTy, DS, IdLoc, T.getOpenLocation(), ArgExprs.take(), ArgExprs.size(), T.getCloseLocation(), EllipsisLoc); } - Diag(Tok, getLang().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace + Diag(Tok, getLangOpts().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace : diag::err_expected_lparen); return true; } @@ -2396,6 +2554,8 @@ Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange, if (Tok.isNot(tok::kw_noexcept)) return Result; + Diag(Tok, diag::warn_cxx98_compat_noexcept_decl); + // If we already had a dynamic specification, parse the noexcept for, // recovery, but emit a diagnostic and don't store the results. SourceRange NoexceptRange; @@ -2468,7 +2628,7 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( // can throw anything". if (Tok.is(tok::ellipsis)) { SourceLocation EllipsisLoc = ConsumeToken(); - if (!getLang().MicrosoftExt) + if (!getLangOpts().MicrosoftExt) Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec); T.consumeClose(); SpecificationRange.setEnd(T.getCloseLocation()); @@ -2513,14 +2673,7 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) { ConsumeToken(); - // FIXME: Need to suppress declarations when parsing this typename. - // Otherwise in this function definition: - // - // auto f() -> struct X {} - // - // struct X is parsed as class definition because of the trailing - // brace. - return ParseTypeName(&Range); + return ParseTypeName(&Range, Declarator::TrailingReturnContext); } /// \brief We have just started parsing the definition of a new class, @@ -2583,43 +2736,87 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) { Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope(); } -/// ParseCXX0XAttributeSpecifier - Parse a C++0x attribute-specifier. Currently +/// \brief Try to parse an 'identifier' which appears within an attribute-token. +/// +/// \return the parsed identifier on success, and 0 if the next token is not an +/// attribute-token. +/// +/// C++11 [dcl.attr.grammar]p3: +/// If a keyword or an alternative token that satisfies the syntactic +/// requirements of an identifier is contained in an attribute-token, +/// it is considered an identifier. +IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { + switch (Tok.getKind()) { + default: + // Identifiers and keywords have identifier info attached. + if (IdentifierInfo *II = Tok.getIdentifierInfo()) { + Loc = ConsumeToken(); + return II; + } + return 0; + + case tok::ampamp: // 'and' + case tok::pipe: // 'bitor' + case tok::pipepipe: // 'or' + case tok::caret: // 'xor' + case tok::tilde: // 'compl' + case tok::amp: // 'bitand' + case tok::ampequal: // 'and_eq' + case tok::pipeequal: // 'or_eq' + case tok::caretequal: // 'xor_eq' + case tok::exclaim: // 'not' + case tok::exclaimequal: // 'not_eq' + // Alternative tokens do not have identifier info, but their spelling + // starts with an alphabetical character. + llvm::SmallString<8> SpellingBuf; + StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf); + if (std::isalpha(Spelling[0])) { + Loc = ConsumeToken(); + return &PP.getIdentifierTable().get(Spelling.data()); + } + return 0; + } +} + +/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. Currently /// only parses standard attributes. /// -/// [C++0x] attribute-specifier: +/// [C++11] attribute-specifier: /// '[' '[' attribute-list ']' ']' /// alignment-specifier /// -/// [C++0x] attribute-list: +/// [C++11] attribute-list: /// attribute[opt] /// attribute-list ',' attribute[opt] +/// attribute '...' +/// attribute-list ',' attribute '...' /// -/// [C++0x] attribute: +/// [C++11] attribute: /// attribute-token attribute-argument-clause[opt] /// -/// [C++0x] attribute-token: +/// [C++11] attribute-token: /// identifier /// attribute-scoped-token /// -/// [C++0x] attribute-scoped-token: +/// [C++11] attribute-scoped-token: /// attribute-namespace '::' identifier /// -/// [C++0x] attribute-namespace: +/// [C++11] attribute-namespace: /// identifier /// -/// [C++0x] attribute-argument-clause: +/// [C++11] attribute-argument-clause: /// '(' balanced-token-seq ')' /// -/// [C++0x] balanced-token-seq: +/// [C++11] balanced-token-seq: /// balanced-token /// balanced-token-seq balanced-token /// -/// [C++0x] balanced-token: +/// [C++11] balanced-token: /// '(' balanced-token-seq ')' /// '[' balanced-token-seq ']' /// '{' balanced-token-seq '}' /// any token but '(', ')', '[', ']', '{', or '}' -void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, +void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, SourceLocation *endLoc) { if (Tok.is(tok::kw_alignas)) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); @@ -2628,56 +2825,53 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, } assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) - && "Not a C++0x attribute list"); + && "Not a C++11 attribute list"); Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute); ConsumeBracket(); ConsumeBracket(); - if (Tok.is(tok::comma)) { - Diag(Tok.getLocation(), diag::err_expected_ident); - ConsumeToken(); - } - - while (Tok.is(tok::identifier) || Tok.is(tok::comma)) { + while (Tok.isNot(tok::r_square)) { // attribute not present if (Tok.is(tok::comma)) { ConsumeToken(); continue; } - IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo(); - SourceLocation ScopeLoc, AttrLoc = ConsumeToken(); + SourceLocation ScopeLoc, AttrLoc; + IdentifierInfo *ScopeName = 0, *AttrName = 0; + + AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); + if (!AttrName) + // Break out to the "expected ']'" diagnostic. + break; // scoped attribute if (Tok.is(tok::coloncolon)) { ConsumeToken(); - if (!Tok.is(tok::identifier)) { + ScopeName = AttrName; + ScopeLoc = AttrLoc; + + AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); + if (!AttrName) { Diag(Tok.getLocation(), diag::err_expected_ident); SkipUntil(tok::r_square, tok::comma, true, true); continue; } - - ScopeName = AttrName; - ScopeLoc = AttrLoc; - - AttrName = Tok.getIdentifierInfo(); - AttrLoc = ConsumeToken(); } bool AttrParsed = false; // No scoped names are supported; ideally we could put all non-standard // attributes into namespaces. if (!ScopeName) { - switch(AttributeList::getKind(AttrName)) - { + switch (AttributeList::getKind(AttrName)) { // No arguments case AttributeList::AT_carries_dependency: case AttributeList::AT_noreturn: { if (Tok.is(tok::l_paren)) { - Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments) + Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) << AttrName->getName(); break; } @@ -2699,6 +2893,13 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, // SkipUntil maintains the balancedness of tokens. SkipUntil(tok::r_paren, false); } + + if (Tok.is(tok::ellipsis)) { + if (AttrParsed) + Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis) + << AttrName->getName(); + ConsumeToken(); + } } if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) @@ -2709,19 +2910,19 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, SkipUntil(tok::r_square, false); } -/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier-seq. +/// ParseCXX11Attributes - Parse a C++0x attribute-specifier-seq. /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier -void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, +void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc) { SourceLocation StartLoc = Tok.getLocation(), Loc; if (!endLoc) endLoc = &Loc; do { - ParseCXX0XAttributeSpecifier(attrs, endLoc); - } while (isCXX0XAttributeSpecifier()); + ParseCXX11AttributeSpecifier(attrs, endLoc); + } while (isCXX11AttributeSpecifier()); attrs.Range = SourceRange(StartLoc, *endLoc); } @@ -2739,6 +2940,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list"); while (Tok.is(tok::l_square)) { + // FIXME: If this is actually a C++11 attribute, parse it as one. ConsumeBracket(); SkipUntil(tok::r_square, true, true); if (endLoc) *endLoc = Tok.getLocation(); @@ -2748,25 +2950,32 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, AccessSpecifier& CurAS) { - bool Result; + IfExistsCondition Result; if (ParseMicrosoftIfExistsCondition(Result)) return; - if (Tok.isNot(tok::l_brace)) { + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected_lbrace); return; } - ConsumeBrace(); - // Condition is false skip all inside the {}. - if (!Result) { - SkipUntil(tok::r_brace, false); + switch (Result.Behavior) { + case IEB_Parse: + // Parse the declarations below. + break; + + case IEB_Dependent: + Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists) + << Result.IsIfExists; + // Fall through to skip. + + case IEB_Skip: + Braces.skipToEnd(); return; } - // Condition is true, parse the declaration. - while (Tok.isNot(tok::r_brace)) { - + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // __if_exists, __if_not_exists can nest. if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); @@ -2799,10 +3008,6 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, // Parse all the comma separated declarators. ParseCXXClassMemberDeclaration(CurAS, 0); } - - if (Tok.isNot(tok::r_brace)) { - Diag(Tok, diag::err_expected_rbrace); - return; - } - ConsumeBrace(); + + Braces.consumeClose(); } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp index bc8bbf5..7f3a815 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp @@ -23,6 +23,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/TypoCorrection.h" #include "clang/Basic/PrettyStackTrace.h" #include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallVector.h" @@ -174,8 +175,8 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// expression: [C99 6.5.17] /// assignment-expression ...[opt] /// expression ',' assignment-expression ...[opt] -ExprResult Parser::ParseExpression() { - ExprResult LHS(ParseAssignmentExpression()); +ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { + ExprResult LHS(ParseAssignmentExpression(isTypeCast)); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); } @@ -211,7 +212,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { } /// ParseAssignmentExpression - Parse an expr that doesn't include commas. -ExprResult Parser::ParseAssignmentExpression() { +ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); cutOffParsing(); @@ -221,7 +222,9 @@ ExprResult Parser::ParseAssignmentExpression() { if (Tok.is(tok::kw_throw)) return ParseThrowExpression(); - ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false); + ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false, + /*isAddressOfOperand=*/false, + isTypeCast); return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); } @@ -246,15 +249,17 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, } -ExprResult Parser::ParseConstantExpression() { - // C++ [basic.def.odr]p2: +ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { + // C++03 [basic.def.odr]p2: // An expression is potentially evaluated unless it appears where an // integral constant expression is required (see 5.19) [...]. + // C++98 and C++11 have no such rule, but this is only a defect in C++98. EnterExpressionEvaluationContext Unevaluated(Actions, - Sema::Unevaluated); + Sema::ConstantEvaluated); - ExprResult LHS(ParseCastExpression(false)); - return ParseRHSOfBinaryExpression(LHS, prec::Conditional); + ExprResult LHS(ParseCastExpression(false, false, isTypeCast)); + ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + return Actions.ActOnConstantExpression(Res); } /// ParseRHSOfBinaryExpression - Parse a binary expression that starts with @@ -263,7 +268,7 @@ ExprResult Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, - getLang().CPlusPlus0x); + getLangOpts().CPlusPlus0x); SourceLocation ColonLoc; while (1) { @@ -311,8 +316,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { SourceLocation FILoc = Tok.getLocation(); const char *FIText = ": "; const SourceManager &SM = PP.getSourceManager(); - if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc)) { - FILoc = SM.getExpansionLoc(FILoc); + if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc, &FILoc)) { + assert(FILoc.isFileID()); bool IsInvalid = false; const char *SourcePtr = SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid); @@ -347,9 +352,16 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // be a throw-expression, which is not a valid cast-expression. // Therefore we need some special-casing here. // Also note that the third operand of the conditional operator is - // an assignment-expression in C++. + // an assignment-expression in C++, and in C++11, we can have a + // braced-init-list on the RHS of an assignment. For better diagnostics, + // parse as if we were allowed braced-init-lists everywhere, and check that + // they only appear on the RHS of assignments later. ExprResult RHS; - if (getLang().CPlusPlus && NextTokPrec <= prec::Conditional) + bool RHSIsInitList = false; + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + RHS = ParseBraceInitializer(); + RHSIsInitList = true; + } else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional) RHS = ParseAssignmentExpression(); else RHS = ParseCastExpression(false); @@ -361,7 +373,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // operator immediately to the right of the RHS. prec::Level ThisPrec = NextTokPrec; NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, - getLang().CPlusPlus0x); + getLangOpts().CPlusPlus0x); // Assignment and conditional expressions are right-associative. bool isRightAssoc = ThisPrec == prec::Conditional || @@ -371,6 +383,11 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // more tightly with RHS than we do, evaluate it completely first. if (ThisPrec < NextTokPrec || (ThisPrec == NextTokPrec && isRightAssoc)) { + if (!RHS.isInvalid() && RHSIsInitList) { + Diag(Tok, diag::err_init_list_bin_op) + << /*LHS*/0 << PP.getSpelling(Tok) << Actions.getExprRange(RHS.get()); + RHS = ExprError(); + } // If this is left-associative, only parse things on the RHS that bind // more tightly than the current operator. If it is left-associative, it // is okay, to bind exactly as tightly. For example, compile A=B=C=D as @@ -378,15 +395,28 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // The function takes ownership of the RHS. RHS = ParseRHSOfBinaryExpression(RHS, static_cast<prec::Level>(ThisPrec + !isRightAssoc)); + RHSIsInitList = false; if (RHS.isInvalid()) LHS = ExprError(); NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, - getLang().CPlusPlus0x); + getLangOpts().CPlusPlus0x); } assert(NextTokPrec <= ThisPrec && "Recursion didn't work!"); + if (!RHS.isInvalid() && RHSIsInitList) { + if (ThisPrec == prec::Assignment) { + Diag(OpToken, diag::warn_cxx98_compat_generalized_initializer_lists) + << Actions.getExprRange(RHS.get()); + } else { + Diag(OpToken, diag::err_init_list_bin_op) + << /*RHS*/1 << PP.getSpelling(OpToken) + << Actions.getExprRange(RHS.get()); + LHS = ExprError(); + } + } + if (!LHS.isInvalid()) { // Combine the LHS and RHS into the LHS (e.g. build AST). if (TernaryMiddle.isInvalid()) { @@ -416,7 +446,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, - bool isTypeCast) { + TypeCastState isTypeCast) { bool NotCastExpr; ExprResult Res = ParseCastExpression(isUnaryExpression, isAddressOfOperand, @@ -427,6 +457,29 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return move(Res); } +namespace { +class CastExpressionIdValidator : public CorrectionCandidateCallback { + public: + CastExpressionIdValidator(bool AllowTypes, bool AllowNonTypes) + : AllowNonTypes(AllowNonTypes) { + WantTypeSpecifiers = AllowTypes; + } + + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + NamedDecl *ND = candidate.getCorrectionDecl(); + if (!ND) + return candidate.isKeyword(); + + if (isa<TypeDecl>(ND)) + return WantTypeSpecifiers; + return AllowNonTypes; + } + + private: + bool AllowNonTypes; +}; +} + /// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is /// true, parse a unary-expression. isAddressOfOperand exists because an /// id-expression that is the operand of address-of gets special treatment @@ -444,14 +497,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// unary-operator cast-expression /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' -/// [C++0x] 'sizeof' '...' '(' identifier ')' +/// [C++11] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' -/// [C++0x] 'alignof' '(' type-id ')' +/// [C++11] 'alignof' '(' type-id ')' /// [GNU] '&&' identifier +/// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7] /// [C++] new-expression /// [C++] delete-expression -/// [C++0x] 'noexcept' '(' expression ')' /// /// unary-operator: one of /// '&' '*' '+' '-' '~' '!' @@ -463,9 +516,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// constant /// string-literal /// [C++] boolean-literal [C++ 2.13.5] -/// [C++0x] 'nullptr' [C++0x 2.14.7] +/// [C++11] 'nullptr' [C++11 2.14.7] +/// [C++11] user-defined-literal /// '(' expression ')' -/// [C1X] generic-selection +/// [C11] generic-selection /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' /// [GNU] '__PRETTY_FUNCTION__' @@ -482,9 +536,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// [OBJC] '@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] -/// [C++0x] simple-type-specifier braced-init-list [C++ 5.2.3] +/// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3] /// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] -/// [C++0x] typename-specifier braced-init-list [C++ 5.2.3] +/// [C++11] typename-specifier braced-init-list [C++11 5.2.3] /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] @@ -565,6 +619,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '__is_class' /// '__is_empty' [TODO] /// '__is_enum' +/// '__is_final' /// '__is_pod' /// '__is_polymorphic' /// '__is_trivial' @@ -590,7 +645,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, - bool isTypeCast) { + TypeCastState isTypeCast) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); NotCastExpr = false; @@ -611,7 +666,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // If this expression is limited to being a unary-expression, the parent can // not start a cast expression. ParenParseOption ParenExprType = - (isUnaryExpression && !getLang().CPlusPlus)? CompoundLiteral : CastExpr; + (isUnaryExpression && !getLangOpts().CPlusPlus)? CompoundLiteral : CastExpr; ParsedType CastTy; SourceLocation RParenLoc; @@ -621,7 +676,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ColonProtectionRAIIObject X(*this, false); Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, - isTypeCast, CastTy, RParenLoc); + isTypeCast == IsTypeCast, CastTy, RParenLoc); } switch (ParenExprType) { @@ -645,15 +700,20 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // constant: integer-constant // constant: floating-constant - Res = Actions.ActOnNumericConstant(Tok); + Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope()); ConsumeToken(); break; case tok::kw_true: case tok::kw_false: return ParseCXXBoolLiteral(); + + case tok::kw___objc_yes: + case tok::kw___objc_no: + return ParseObjCBoolLiteral(); case tok::kw_nullptr: + Diag(Tok, diag::warn_cxx98_compat_nullptr); return Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); case tok::annot_primary_expr: @@ -662,19 +722,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ConsumeToken(); break; + case tok::kw_decltype: case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant // Turn a potentially qualified name into a annot_typename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. - if (getLang().CPlusPlus) { + if (getLangOpts().CPlusPlus) { // Avoid the unnecessary parse-time lookup in the common case // where the syntax forbids a type. const Token &Next = NextToken(); if (Next.is(tok::coloncolon) || (!ColonIsSacred && Next.is(tok::colon)) || Next.is(tok::less) || - Next.is(tok::l_paren)) { + Next.is(tok::l_paren) || + Next.is(tok::l_brace)) { // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) return ExprError(); @@ -689,13 +751,15 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, SourceLocation ILoc = ConsumeToken(); // Support 'Class.property' and 'super.property' notation. - if (getLang().ObjC1 && Tok.is(tok::period) && + if (getLangOpts().ObjC1 && Tok.is(tok::period) && (Actions.getTypeName(II, ILoc, getCurScope()) || // Allow the base to be 'super' if in an objc-method. (&II == Ident_super && getCurScope()->isInObjcMethodScope()))) { ConsumeToken(); - if (Tok.isNot(tok::identifier)) { + // Allow either an identifier or the keyword 'class' (in C++). + if (Tok.isNot(tok::identifier) && + !(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) { Diag(Tok, diag::err_expected_property_name); return ExprError(); } @@ -711,7 +775,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // the token sequence is ill-formed. However, if there's a ':' or ']' after // that identifier, this is probably a message send with a missing open // bracket. Treat it as such. - if (getLang().ObjC1 && &II == Ident_super && !InMessageExpression && + if (getLangOpts().ObjC1 && &II == Ident_super && !InMessageExpression && getCurScope()->isInObjcMethodScope() && ((Tok.is(tok::identifier) && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) || @@ -726,7 +790,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // send that's missing the opening '['. Recovery // appropriately. Also take this path if we're performing code // completion after an Objective-C class name. - if (getLang().ObjC1 && + if (getLangOpts().ObjC1 && ((Tok.is(tok::identifier) && !InMessageExpression) || Tok.is(tok::code_completion))) { const Token& Next = NextToken(); @@ -764,16 +828,20 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // not. UnqualifiedId Name; CXXScopeSpec ScopeSpec; + SourceLocation TemplateKWLoc; + CastExpressionIdValidator Validator(isTypeCast != NotTypeCast, + isTypeCast != IsTypeCast); Name.setIdentifier(&II, ILoc); - Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, Name, - Tok.is(tok::l_paren), isAddressOfOperand); + Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc, + Name, Tok.is(tok::l_paren), + isAddressOfOperand, &Validator); break; } case tok::char_constant: // constant: character-constant case tok::wide_char_constant: case tok::utf16_char_constant: case tok::utf32_char_constant: - Res = Actions.ActOnCharacterConstant(Tok); + Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope()); ConsumeToken(); break; case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] @@ -787,9 +855,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::utf8_string_literal: case tok::utf16_string_literal: case tok::utf32_string_literal: - Res = ParseStringLiteralExpression(); + Res = ParseStringLiteralExpression(true); break; - case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1] + case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1] Res = ParseGenericSelectionExpression(); break; case tok::kw___builtin_va_arg: @@ -807,7 +875,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // ++ cast-expression // -- cast-expression SourceLocation SavedLoc = ConsumeToken(); - Res = ParseCastExpression(!getLang().CPlusPlus); + Res = ParseCastExpression(!getLangOpts().CPlusPlus); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); @@ -909,6 +977,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, } // Fall through + case tok::annot_decltype: case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: @@ -918,6 +987,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_int: case tok::kw_long: case tok::kw___int64: + case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_half: @@ -927,7 +997,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_typename: case tok::kw_typeof: case tok::kw___vector: { - if (!getLang().CPlusPlus) { + if (!getLangOpts().CPlusPlus) { Diag(Tok, diag::err_expected_expression); return ExprError(); } @@ -945,10 +1015,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, DeclSpec DS(AttrFactory); ParseCXXSimpleTypeSpecifier(DS); if (Tok.isNot(tok::l_paren) && - (!getLang().CPlusPlus0x || Tok.isNot(tok::l_brace))) + (!getLangOpts().CPlusPlus0x || Tok.isNot(tok::l_brace))) return ExprError(Diag(Tok, diag::err_expected_lparen_after_type) << DS.getSourceRange()); + if (Tok.is(tok::l_brace)) + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + Res = ParseCXXTypeConstructExpression(DS); break; } @@ -970,7 +1043,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // type, translate it into a type and continue parsing as a // cast expression. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false); AnnotateTemplateIdTokenAsType(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, isTypeCast); @@ -1028,12 +1102,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ParseCXXDeleteExpression(false, Tok.getLocation()); case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' + Diag(Tok, diag::warn_cxx98_compat_noexcept_expr); SourceLocation KeyLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept")) return ExprError(); - // C++ [expr.unary.noexcept]p1: + // C++11 [expr.unary.noexcept]p1: // The noexcept operator determines whether the evaluation of its operand, // which is an unevaluated operand, can throw an exception. EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); @@ -1081,6 +1156,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_trivial: case tok::kw___is_trivially_copyable: case tok::kw___is_union: + case tok::kw___is_final: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: @@ -1096,8 +1172,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_same: case tok::kw___is_convertible: case tok::kw___is_convertible_to: + case tok::kw___is_trivially_assignable: return ParseBinaryTypeTrait(); + case tok::kw___is_trivially_constructible: + return ParseTypeTrait(); + case tok::kw___array_rank: case tok::kw___array_extent: return ParseArrayTypeTrait(); @@ -1119,17 +1199,22 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ExprError(); } case tok::l_square: - if (getLang().CPlusPlus0x) { - if (getLang().ObjC1) { + if (getLangOpts().CPlusPlus0x) { + if (getLangOpts().ObjC1) { + // C++11 lambda expressions and Objective-C message sends both start with a + // square bracket. There are three possibilities here: + // we have a valid lambda expression, we have an invalid lambda + // expression, or we have something that doesn't appear to be a lambda. + // If we're in the last case, we fall back to ParseObjCMessageExpression. Res = TryParseLambdaExpression(); - if (Res.isInvalid()) + if (!Res.isInvalid() && !Res.get()) Res = ParseObjCMessageExpression(); break; } Res = ParseLambdaExpression(); break; } - if (getLang().ObjC1) { + if (getLangOpts().ObjC1) { Res = ParseObjCMessageExpression(); break; } @@ -1181,7 +1266,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // If we see identifier: after an expression, and we're not already in a // message send, then this is probably a message send with a missing // opening bracket '['. - if (getLang().ObjC1 && !InMessageExpression && + if (getLangOpts().ObjC1 && !InMessageExpression && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), ParsedType(), LHS.get()); @@ -1199,17 +1284,23 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // actually another message send. In this case, do some look-ahead to see // if the contents of the square brackets are obviously not a valid // expression and recover by pretending there is no suffix. - if (getLang().ObjC1 && Tok.isAtStartOfLine() && + if (getLangOpts().ObjC1 && Tok.isAtStartOfLine() && isSimpleObjCMessageExpression()) return move(LHS); - + + // Reject array indices starting with a lambda-expression. '[[' is + // reserved for attributes. + if (CheckProhibitedCXX11Attribute()) + return ExprError(); + BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); Loc = T.getOpenLocation(); ExprResult Idx; - if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Idx = ParseBraceInitializer(); - else + } else Idx = ParseExpression(); SourceLocation RLoc = Tok.getLocation(); @@ -1233,22 +1324,27 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { Expr *ExecConfig = 0; - BalancedDelimiterTracker LLLT(*this, tok::lesslessless); BalancedDelimiterTracker PT(*this, tok::l_paren); if (OpKind == tok::lesslessless) { ExprVector ExecConfigExprs(Actions); CommaLocsTy ExecConfigCommaLocs; - LLLT.consumeOpen(); + SourceLocation OpenLoc = ConsumeToken(); if (ParseExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) { LHS = ExprError(); } - if (LHS.isInvalid()) { + SourceLocation CloseLoc = Tok.getLocation(); + if (Tok.is(tok::greatergreatergreater)) { + ConsumeToken(); + } else if (LHS.isInvalid()) { SkipUntil(tok::greatergreatergreater); - } else if (LLLT.consumeClose()) { + } else { // There was an error closing the brackets + Diag(Tok, diag::err_expected_ggg); + Diag(OpenLoc, diag::note_matching) << "<<<"; + SkipUntil(tok::greatergreatergreater); LHS = ExprError(); } @@ -1261,9 +1357,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (!LHS.isInvalid()) { ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(), - LLLT.getOpenLocation(), + OpenLoc, move_arg(ExecConfigExprs), - LLLT.getCloseLocation()); + CloseLoc); if (ECResult.isInvalid()) LHS = ExprError(); else @@ -1278,7 +1374,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { CommaLocsTy CommaLocs; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteCall(getCurScope(), LHS.get(), 0, 0); + Actions.CodeCompleteCall(getCurScope(), LHS.get(), + llvm::ArrayRef<Expr *>()); cutOffParsing(); return ExprError(); } @@ -1320,14 +1417,15 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { CXXScopeSpec SS; ParsedType ObjectType; bool MayBePseudoDestructor = false; - if (getLang().CPlusPlus && !LHS.isInvalid()) { + if (getLangOpts().CPlusPlus && !LHS.isInvalid()) { LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), LHS.take(), OpLoc, OpKind, ObjectType, MayBePseudoDestructor); if (LHS.isInvalid()) break; - ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, + ParseOptionalCXXScopeSpecifier(SS, ObjectType, + /*EnteringContext=*/false, &MayBePseudoDestructor); if (SS.isNotEmpty()) ObjectType = ParsedType(); @@ -1355,18 +1453,31 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // names a real destructor. // Allow explicit constructor calls in Microsoft mode. // FIXME: Add support for explicit call of template constructor. + SourceLocation TemplateKWLoc; UnqualifiedId Name; - if (ParseUnqualifiedId(SS, - /*EnteringContext=*/false, - /*AllowDestructorName=*/true, - /*AllowConstructorName=*/ getLang().MicrosoftExt, - ObjectType, - Name)) + if (getLangOpts().ObjC2 && OpKind == tok::period && Tok.is(tok::kw_class)) { + // Objective-C++: + // After a '.' in a member access expression, treat the keyword + // 'class' as if it were an identifier. + // + // This hack allows property access to the 'class' method because it is + // such a common method name. For other C++ keywords that are + // Objective-C method names, one must use the message send syntax. + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation Loc = ConsumeToken(); + Name.setIdentifier(Id, Loc); + } else if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/ + getLangOpts().MicrosoftExt, + ObjectType, TemplateKWLoc, Name)) LHS = ExprError(); if (!LHS.isInvalid()) LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.take(), OpLoc, - OpKind, SS, Name, ObjCImpDecl, + OpKind, SS, TemplateKWLoc, Name, + CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : 0, Tok.is(tok::l_paren)); break; } @@ -1419,19 +1530,11 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, // If the operand doesn't start with an '(', it must be an expression. if (Tok.isNot(tok::l_paren)) { isCastExpr = false; - if (OpTok.is(tok::kw_typeof) && !getLang().CPlusPlus) { + if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) { Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo(); return ExprError(); } - // C++0x [expr.sizeof]p1: - // [...] The operand is either an expression, which is an unevaluated - // operand (Clause 5) [...] - // - // The GNU typeof and alignof extensions also behave as unevaluated - // operands. - EnterExpressionEvaluationContext Unevaluated(Actions, - Sema::Unevaluated); Operand = ParseCastExpression(true/*isUnaryExpression*/); } else { // If it starts with a '(', we know that it is either a parenthesized @@ -1441,14 +1544,6 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, ParenParseOption ExprType = CastExpr; SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; - // C++0x [expr.sizeof]p1: - // [...] The operand is either an expression, which is an unevaluated - // operand (Clause 5) [...] - // - // The GNU typeof and alignof extensions also behave as unevaluated - // operands. - EnterExpressionEvaluationContext Unevaluated(Actions, - Sema::Unevaluated); Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, false, CastTy, RParenLoc); CastRange = SourceRange(LParenLoc, RParenLoc); @@ -1460,7 +1555,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, return ExprEmpty(); } - if (getLang().CPlusPlus || OpTok.isNot(tok::kw_typeof)) { + if (getLangOpts().CPlusPlus || OpTok.isNot(tok::kw_typeof)) { // GNU typeof in C requires the expression to be parenthesized. Not so for // sizeof/alignof or in C++. Therefore, the parenthesized expression is // the start of a unary-expression, but doesn't include any postfix @@ -1533,7 +1628,12 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { *Name, NameLoc, RParenLoc); } - + + if (OpTok.is(tok::kw_alignof)) + Diag(OpTok, diag::warn_cxx98_compat_alignof); + + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + bool isCastExpr; ParsedType CastTy; SourceRange CastRange; @@ -1573,7 +1673,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' -/// [OCL] '__builtin_astype' '(' type-name expr ')' +/// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')' /// /// [GNU] offsetof-member-designator: /// [GNU] identifier @@ -1661,6 +1761,9 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { Comps.back().LocEnd = ConsumeToken(); } else if (Tok.is(tok::l_square)) { + if (CheckProhibitedCXX11Attribute()) + return ExprError(); + // offsetof-member-designator: offsetof-member-design '[' expression ']' Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = true; @@ -1803,23 +1906,40 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, return ExprError(); } + // Diagnose use of bridge casts in non-arc mode. + bool BridgeCast = (getLangOpts().ObjC2 && + (Tok.is(tok::kw___bridge) || + Tok.is(tok::kw___bridge_transfer) || + Tok.is(tok::kw___bridge_retained) || + Tok.is(tok::kw___bridge_retain))); + if (BridgeCast && !getLangOpts().ObjCAutoRefCount) { + StringRef BridgeCastName = Tok.getName(); + SourceLocation BridgeKeywordLoc = ConsumeToken(); + if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) + Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc) + << BridgeCastName + << FixItHint::CreateReplacement(BridgeKeywordLoc, ""); + BridgeCast = false; + } + // None of these cases should fall through with an invalid Result // unless they've already reported an error. - if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); + + Actions.ActOnStartStmtExpr(); + ParsedAttributes attrs(AttrFactory); StmtResult Stmt(ParseCompoundStatement(attrs, true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. - if (!Stmt.isInvalid()) + if (!Stmt.isInvalid()) { Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation()); - } else if (ExprType >= CompoundLiteral && - (Tok.is(tok::kw___bridge) || - Tok.is(tok::kw___bridge_transfer) || - Tok.is(tok::kw___bridge_retained) || - Tok.is(tok::kw___bridge_retain))) { + } else { + Actions.ActOnStmtExprError(); + } + } else if (ExprType >= CompoundLiteral && BridgeCast) { tok::TokenKind tokenKind = Tok.getKind(); SourceLocation BridgeKeywordLoc = ConsumeToken(); @@ -1879,7 +1999,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // this is probably an Objective-C message send where the leading '[' is // missing. Recover as if that were the case. if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) && - !InMessageExpression && getLang().ObjC1 && + !InMessageExpression && getLangOpts().ObjC1 && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { TypeResult Ty; { @@ -1922,7 +2042,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, } // Reject the cast of super idiom in ObjC. - if (Tok.is(tok::identifier) && getLang().ObjC1 && + if (Tok.is(tok::identifier) && getLangOpts().ObjC1 && Tok.getIdentifierInfo() == Ident_super && getCurScope()->isInObjcMethodScope() && GetLookAheadToken(1).isNot(tok::period)) { @@ -1935,7 +2055,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // TODO: For cast expression with CastTy. Result = ParseCastExpression(/*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, - /*isTypeCast=*/true); + /*isTypeCast=*/IsTypeCast); if (!Result.isInvalid()) { Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, DeclaratorInfo, CastTy, @@ -1956,13 +2076,13 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, if (!ParseExpressionList(ArgExprs, CommaLocs)) { ExprType = SimpleExpr; - Result = Actions.ActOnParenOrParenListExpr(OpenLoc, Tok.getLocation(), - move_arg(ArgExprs)); + Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), + move_arg(ArgExprs)); } } else { InMessageExpressionRAIIObject InMessage(*this, false); - Result = ParseExpression(); + Result = ParseExpression(MaybeTypeCast); ExprType = SimpleExpr; // Don't build a paren expression unless we actually match a ')'. @@ -1993,7 +2113,7 @@ Parser::ParseCompoundLiteralExpression(ParsedType Ty, SourceLocation LParenLoc, SourceLocation RParenLoc) { assert(Tok.is(tok::l_brace) && "Not a compound literal!"); - if (!getLang().C99) // Compound literals don't exist in C90. + if (!getLangOpts().C99) // Compound literals don't exist in C90. Diag(LParenLoc, diag::ext_c99_compound_literal); ExprResult Result = ParseInitializer(); if (!Result.isInvalid() && Ty) @@ -2007,7 +2127,7 @@ Parser::ParseCompoundLiteralExpression(ParsedType Ty, /// /// primary-expression: [C99 6.5.1] /// string-literal -ExprResult Parser::ParseStringLiteralExpression() { +ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) { assert(isTokenStringLiteral() && "Not a string literal!"); // String concat. Note that keywords like __func__ and __FUNCTION__ are not @@ -2020,11 +2140,12 @@ ExprResult Parser::ParseStringLiteralExpression() { } while (isTokenStringLiteral()); // Pass the set of string tokens, ready for concatenation, to the actions. - return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size()); + return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size(), + AllowUserDefinedLiteral ? getCurScope() : 0); } -/// ParseGenericSelectionExpression - Parse a C1X generic-selection -/// [C1X 6.5.1.1]. +/// ParseGenericSelectionExpression - Parse a C11 generic-selection +/// [C11 6.5.1.1]. /// /// generic-selection: /// _Generic ( assignment-expression , generic-assoc-list ) @@ -2038,8 +2159,8 @@ ExprResult Parser::ParseGenericSelectionExpression() { assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected"); SourceLocation KeyLoc = ConsumeToken(); - if (!getLang().C1X) - Diag(KeyLoc, diag::ext_c1x_generic_selection); + if (!getLangOpts().C11) + Diag(KeyLoc, diag::ext_c11_generic_selection); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen)) @@ -2047,7 +2168,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { ExprResult ControllingExpr; { - // C1X 6.5.1.1p3 "The controlling expression of a generic selection is + // C11 6.5.1.1p3 "The controlling expression of a generic selection is // not evaluated." EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); ControllingExpr = ParseAssignmentExpression(); @@ -2068,7 +2189,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { while (1) { ParsedType Ty; if (Tok.is(tok::kw_default)) { - // C1X 6.5.1.1p2 "A generic selection shall have no more than one default + // C11 6.5.1.1p2 "A generic selection shall have no more than one default // generic association." if (!DefaultLoc.isInvalid()) { Diag(Tok, diag::err_duplicate_default_assoc); @@ -2143,13 +2264,12 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs, SmallVectorImpl<SourceLocation> &CommaLocs, void (Sema::*Completer)(Scope *S, Expr *Data, - Expr **Args, - unsigned NumArgs), + llvm::ArrayRef<Expr *> Args), Expr *Data) { while (1) { if (Tok.is(tok::code_completion)) { if (Completer) - (Actions.*Completer)(getCurScope(), Data, Exprs.data(), Exprs.size()); + (Actions.*Completer)(getCurScope(), Data, Exprs); else Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); cutOffParsing(); @@ -2157,9 +2277,10 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs, } ExprResult Expr; - if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Expr = ParseBraceInitializer(); - else + } else Expr = ParseAssignmentExpression(); if (Tok.is(tok::ellipsis)) @@ -2225,7 +2346,6 @@ ExprResult Parser::ParseBlockLiteralExpression() { // allows determining whether a variable reference inside the block is // within or outside of the block. ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope | - Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope); // Inform sema that we are starting a block. @@ -2270,6 +2390,8 @@ ExprResult Parser::ParseBlockLiteralExpression() { 0, 0, 0, true, SourceLocation(), SourceLocation(), + SourceLocation(), + SourceLocation(), EST_None, SourceLocation(), 0, 0, 0, 0, @@ -2300,3 +2422,12 @@ ExprResult Parser::ParseBlockLiteralExpression() { Actions.ActOnBlockError(CaretLoc, getCurScope()); return move(Result); } + +/// ParseObjCBoolLiteral - This handles the objective-c Boolean literals. +/// +/// '__objc_yes' +/// '__objc_no' +ExprResult Parser::ParseObjCBoolLiteral() { + tok::TokenKind Kind = Tok.getKind(); + return Actions.ActOnObjCBoolLiteral(ConsumeToken(), Kind); +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp index 60166e8..2af7482 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp @@ -14,6 +14,8 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" @@ -136,7 +138,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename) { - assert(getLang().CPlusPlus && + assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { @@ -168,6 +170,22 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, *MayBePseudoDestructor = false; } + if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) { + DeclSpec DS(AttrFactory); + SourceLocation DeclLoc = Tok.getLocation(); + SourceLocation EndLoc = ParseDecltypeSpecifier(DS); + if (Tok.isNot(tok::coloncolon)) { + AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc); + return false; + } + + SourceLocation CCLoc = ConsumeToken(); + if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc)) + SS.SetInvalid(SourceRange(DeclLoc, CCLoc)); + + HasScopeSpecifier = true; + } + while (true) { if (HasScopeSpecifier) { // C++ [basic.lookup.classref]p5: @@ -247,15 +265,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // Commit to parsing the template-id. TPA.Commit(); TemplateTy Template; - if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(getCurScope(), - TemplateKWLoc, - SS, - TemplateName, - ObjectType, - EnteringContext, - Template)) { - if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, - TemplateKWLoc, false)) + if (TemplateNameKind TNK + = Actions.ActOnDependentTemplateName(getCurScope(), + SS, TemplateKWLoc, TemplateName, + ObjectType, EnteringContext, + Template)) { + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, + TemplateName, false)) return true; } else return true; @@ -283,16 +299,15 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); - if (!HasScopeSpecifier) - HasScopeSpecifier = true; + HasScopeSpecifier = true; ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), TemplateId->NumArgs); if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), - /*FIXME:*/SourceLocation(), - SS, + SS, + TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, @@ -381,15 +396,15 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, EnteringContext, Template, MemberOfUnknownSpecialization)) { - // We have found a template name, so annotate this this token + // We have found a template name, so annotate this token // with a template-id annotation. We do not permit the // template-id to be translated into a type annotation, // because some clients (e.g., the parsing of class template // specializations) still want to see the original template-id // token. ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, - SourceLocation(), false)) + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, false)) return true; continue; } @@ -401,7 +416,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // parse correctly as a template, so suggest the keyword 'template' // before 'getAs' and treat this as a dependent template name. unsigned DiagID = diag::err_missing_dependent_template_keyword; - if (getLang().MicrosoftExt) + if (getLangOpts().MicrosoftExt) DiagID = diag::warn_missing_dependent_template_keyword; Diag(Tok.getLocation(), DiagID) @@ -410,14 +425,14 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(getCurScope(), - Tok.getLocation(), SS, + SS, SourceLocation(), TemplateName, ObjectType, EnteringContext, Template)) { // Consume the identifier. ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, - SourceLocation(), false)) - return true; + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, false)) + return true; } else return true; @@ -488,14 +503,16 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // '::' unqualified-id // CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); - + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + + SourceLocation TemplateKWLoc; UnqualifiedId Name; - if (ParseUnqualifiedId(SS, - /*EnteringContext=*/false, - /*AllowDestructorName=*/false, - /*AllowConstructorName=*/false, + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, /*ObjectType=*/ ParsedType(), + TemplateKWLoc, Name)) return ExprError(); @@ -503,10 +520,9 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // followed by a postfix-expression suffix. if (isAddressOfOperand && isPostfixExpressionSuffixStart()) isAddressOfOperand = false; - - return Actions.ActOnIdExpression(getCurScope(), SS, Name, Tok.is(tok::l_paren), - isAddressOfOperand); - + + return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name, + Tok.is(tok::l_paren), isAddressOfOperand); } /// ParseLambdaExpression - Parse a C++0x lambda expression. @@ -548,6 +564,9 @@ ExprResult Parser::ParseLambdaExpression() { if (DiagID) { Diag(Tok, DiagID.getValue()); SkipUntil(tok::r_square); + SkipUntil(tok::l_brace); + SkipUntil(tok::r_brace); + return ExprError(); } return ParseLambdaExpressionAfterIntroducer(Intro); @@ -559,7 +578,7 @@ ExprResult Parser::ParseLambdaExpression() { /// /// If we are not looking at a lambda expression, returns ExprError(). ExprResult Parser::TryParseLambdaExpression() { - assert(getLang().CPlusPlus0x + assert(getLangOpts().CPlusPlus0x && Tok.is(tok::l_square) && "Not at the start of a possible lambda expression."); @@ -576,21 +595,28 @@ ExprResult Parser::TryParseLambdaExpression() { return ParseLambdaExpression(); } - // If lookahead indicates this is an Objective-C message... + // If lookahead indicates an ObjC message send... + // [identifier identifier if (Next.is(tok::identifier) && After.is(tok::identifier)) { - return ExprError(); + return ExprEmpty(); } + // Here, we're stuck: lambda introducers and Objective-C message sends are + // unambiguous, but it requires arbitrary lookhead. [a,b,c,d,e,f,g] is a + // lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send. Instead of + // writing two routines to parse a lambda introducer, just try to parse + // a lambda introducer first, and fall back if that fails. + // (TryParseLambdaIntroducer never produces any diagnostic output.) LambdaIntroducer Intro; if (TryParseLambdaIntroducer(Intro)) - return ExprError(); + return ExprEmpty(); return ParseLambdaExpressionAfterIntroducer(Intro); } /// ParseLambdaExpression - Parse a lambda introducer. /// /// Returns a DiagnosticID if it hit something unexpected. -llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) { +llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro){ typedef llvm::Optional<unsigned> DiagResult; assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['."); @@ -605,28 +631,49 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) if (Tok.is(tok::amp) && (NextToken().is(tok::comma) || NextToken().is(tok::r_square))) { Intro.Default = LCD_ByRef; - ConsumeToken(); + Intro.DefaultLoc = ConsumeToken(); first = false; } else if (Tok.is(tok::equal)) { Intro.Default = LCD_ByCopy; - ConsumeToken(); + Intro.DefaultLoc = ConsumeToken(); first = false; } while (Tok.isNot(tok::r_square)) { if (!first) { - if (Tok.isNot(tok::comma)) + if (Tok.isNot(tok::comma)) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, + /*AfterAmpersand=*/false); + ConsumeCodeCompletionToken(); + break; + } + return DiagResult(diag::err_expected_comma_or_rsquare); + } ConsumeToken(); } - first = false; + if (Tok.is(tok::code_completion)) { + // If we're in Objective-C++ and we have a bare '[', then this is more + // likely to be a message receiver. + if (getLangOpts().ObjC1 && first) + Actions.CodeCompleteObjCMessageReceiver(getCurScope()); + else + Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, + /*AfterAmpersand=*/false); + ConsumeCodeCompletionToken(); + break; + } + first = false; + // Parse capture. LambdaCaptureKind Kind = LCK_ByCopy; SourceLocation Loc; IdentifierInfo* Id = 0; - + SourceLocation EllipsisLoc; + if (Tok.is(tok::kw_this)) { Kind = LCK_This; Loc = ConsumeToken(); @@ -634,11 +681,21 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) if (Tok.is(tok::amp)) { Kind = LCK_ByRef; ConsumeToken(); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, + /*AfterAmpersand=*/true); + ConsumeCodeCompletionToken(); + break; + } } if (Tok.is(tok::identifier)) { Id = Tok.getIdentifierInfo(); Loc = ConsumeToken(); + + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); } else if (Tok.is(tok::kw_this)) { // FIXME: If we want to suggest a fixit here, will need to return more // than just DiagnosticID. Perhaps full DiagnosticBuilder that can be @@ -649,7 +706,7 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) } } - Intro.addCapture(Kind, Loc, Id); + Intro.addCapture(Kind, Loc, Id, EllipsisLoc); } T.consumeClose(); @@ -658,7 +715,7 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) return DiagResult(); } -/// TryParseLambdaExpression - Tentatively parse a lambda introducer. +/// TryParseLambdaIntroducer - Tentatively parse a lambda introducer. /// /// Returns true if it hit something unexpected. bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { @@ -679,9 +736,15 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { /// expression. ExprResult Parser::ParseLambdaExpressionAfterIntroducer( LambdaIntroducer &Intro) { + SourceLocation LambdaBeginLoc = Intro.Range.getBegin(); + Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda); + + PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc, + "lambda expression parsing"); + // Parse lambda-declarator[opt]. DeclSpec DS(AttrFactory); - Declarator D(DS, Declarator::PrototypeContext); + Declarator D(DS, Declarator::LambdaExprContext); if (Tok.is(tok::l_paren)) { ParseScope PrototypeScope(this, @@ -746,6 +809,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DS.getTypeQualifiers(), /*RefQualifierIsLValueRef=*/true, /*RefQualifierLoc=*/SourceLocation(), + /*ConstQualifierLoc=*/SourceLocation(), + /*VolatileQualifierLoc=*/SourceLocation(), MutableLoc, ESpecType, ESpecRange.getBegin(), DynamicExceptions.data(), @@ -756,24 +821,78 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); + } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow)) { + // It's common to forget that one needs '()' before 'mutable' or the + // result type. Deal with this. + Diag(Tok, diag::err_lambda_missing_parens) + << Tok.is(tok::arrow) + << FixItHint::CreateInsertion(Tok.getLocation(), "() "); + SourceLocation DeclLoc = Tok.getLocation(); + SourceLocation DeclEndLoc = DeclLoc; + + // Parse 'mutable', if it's there. + SourceLocation MutableLoc; + if (Tok.is(tok::kw_mutable)) { + MutableLoc = ConsumeToken(); + DeclEndLoc = MutableLoc; + } + + // Parse the return type, if there is one. + ParsedType TrailingReturnType; + if (Tok.is(tok::arrow)) { + SourceRange Range; + TrailingReturnType = ParseTrailingReturnType(Range).get(); + if (Range.getEnd().isValid()) + DeclEndLoc = Range.getEnd(); + } + + ParsedAttributes Attr(AttrFactory); + D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, + /*isVariadic=*/false, + /*EllipsisLoc=*/SourceLocation(), + /*Params=*/0, /*NumParams=*/0, + /*TypeQuals=*/0, + /*RefQualifierIsLValueRef=*/true, + /*RefQualifierLoc=*/SourceLocation(), + /*ConstQualifierLoc=*/SourceLocation(), + /*VolatileQualifierLoc=*/SourceLocation(), + MutableLoc, + EST_None, + /*ESpecLoc=*/SourceLocation(), + /*Exceptions=*/0, + /*ExceptionRanges=*/0, + /*NumExceptions=*/0, + /*NoexceptExpr=*/0, + DeclLoc, DeclEndLoc, D, + TrailingReturnType), + Attr, DeclEndLoc); } + - // Parse compound-statement. - if (Tok.is(tok::l_brace)) { - // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using - // it. - ParseScope BodyScope(this, Scope::BlockScope | Scope::FnScope | - Scope::BreakScope | Scope::ContinueScope | - Scope::DeclScope); + // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using + // it. + unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope; + if (getCurScope()->getFlags() & Scope::ThisScope) + ScopeFlags |= Scope::ThisScope; + ParseScope BodyScope(this, ScopeFlags); - StmtResult Stmt(ParseCompoundStatementBody()); + Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope()); - BodyScope.Exit(); - } else { + // Parse compound-statement. + if (!Tok.is(tok::l_brace)) { Diag(Tok, diag::err_expected_lambda_body); + Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); + return ExprError(); } - return ExprEmpty(); + StmtResult Stmt(ParseCompoundStatementBody()); + BodyScope.Exit(); + + if (!Stmt.isInvalid()) + return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(), getCurScope()); + + Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); + return ExprError(); } /// ParseCXXCasts - This handles the various ways to cast expressions to another @@ -882,10 +1001,10 @@ ExprResult Parser::ParseCXXTypeid() { // operand (Clause 5). // // Note that we can't tell whether the expression is an lvalue of a - // polymorphic class type until after we've parsed the expression, so - // we the expression is potentially potentially evaluated. - EnterExpressionEvaluationContext Unevaluated(Actions, - Sema::PotentiallyPotentiallyEvaluated); + // polymorphic class type until after we've parsed the expression; we + // speculatively assume the subexpression is unevaluated, and fix it up + // later. + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); Result = ParseExpression(); // Match the ')'. @@ -988,6 +1107,8 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); CCLoc = ConsumeToken(); } else if (Tok.is(tok::annot_template_id)) { + // FIXME: retrieve TemplateKWLoc from template-id annotation and + // store it in the pseudo-dtor node (to be used when instantiating it). FirstTypeName.setTemplateId( (TemplateIdAnnotation *)Tok.getAnnotationValue()); ConsumeToken(); @@ -1000,6 +1121,17 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, // Parse the tilde. assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail"); SourceLocation TildeLoc = ConsumeToken(); + + if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid() && SS.isEmpty()) { + DeclSpec DS(AttrFactory); + ParseDecltypeSpecifier(DS); + if (DS.getTypeSpecType() == TST_error) + return ExprError(); + return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, + OpKind, TildeLoc, DS, + Tok.is(tok::l_paren)); + } + if (!Tok.is(tok::identifier)) { Diag(Tok, diag::err_destructor_tilde_identifier); return ExprError(); @@ -1014,9 +1146,10 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, // If there is a '<', the second type name is a template-id. Parse // it as such. if (Tok.is(tok::less) && - ParseUnqualifiedIdTemplateId(SS, Name, NameLoc, false, ObjectType, - SecondTypeName, /*AssumeTemplateName=*/true, - /*TemplateKWLoc*/SourceLocation())) + ParseUnqualifiedIdTemplateId(SS, SourceLocation(), + Name, NameLoc, + false, ObjectType, SecondTypeName, + /*AssumeTemplateName=*/true)) return ExprError(); return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, @@ -1092,14 +1225,17 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); assert((Tok.is(tok::l_paren) || - (getLang().CPlusPlus0x && Tok.is(tok::l_brace))) + (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace))) && "Expected '(' or '{'!"); if (Tok.is(tok::l_brace)) { - - // FIXME: Convert to a proper type construct expression. - return ParseBraceInitializer(); - + ExprResult Init = ParseBraceInitializer(); + if (Init.isInvalid()) + return Init; + Expr *InitList = Init.take(); + return Actions.ActOnCXXTypeConstructExpr(TypeRep, SourceLocation(), + MultiExprArg(&InitList, 1), + SourceLocation()); } else { GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); @@ -1136,6 +1272,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// condition: /// expression /// type-specifier-seq declarator '=' assignment-expression +/// [C++11] type-specifier-seq declarator '=' initializer-clause +/// [C++11] type-specifier-seq declarator braced-init-list /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// @@ -1206,18 +1344,35 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, ExprOut = ExprError(); // '=' assignment-expression - if (isTokenEqualOrMistypedEqualEqual( - diag::err_invalid_equalequal_after_declarator)) { + // If a '==' or '+=' is found, suggest a fixit to '='. + bool CopyInitialization = isTokenEqualOrEqualTypo(); + if (CopyInitialization) ConsumeToken(); - ExprResult AssignExpr(ParseAssignmentExpression()); - if (!AssignExpr.isInvalid()) - Actions.AddInitializerToDecl(DeclOut, AssignExpr.take(), false, - DS.getTypeSpecType() == DeclSpec::TST_auto); + + ExprResult InitExpr = ExprError(); + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok.getLocation(), + diag::warn_cxx98_compat_generalized_initializer_lists); + InitExpr = ParseBraceInitializer(); + } else if (CopyInitialization) { + InitExpr = ParseAssignmentExpression(); + } else if (Tok.is(tok::l_paren)) { + // This was probably an attempt to initialize the variable. + SourceLocation LParen = ConsumeParen(), RParen = LParen; + if (SkipUntil(tok::r_paren, true, /*DontConsume=*/true)) + RParen = ConsumeParen(); + Diag(DeclOut ? DeclOut->getLocation() : LParen, + diag::err_expected_init_in_condition_lparen) + << SourceRange(LParen, RParen); } else { - // FIXME: C++0x allows a braced-init-list - Diag(Tok, diag::err_expected_equal_after_declarator); + Diag(DeclOut ? DeclOut->getLocation() : Tok.getLocation(), + diag::err_expected_init_in_condition); } - + + if (!InitExpr.isInvalid()) + Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization, + DS.getTypeSpecType() == DeclSpec::TST_auto); + // FIXME: Build a reference to this declaration? Convert it to bool? // (This is currently handled by Sema). @@ -1234,6 +1389,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const { case tok::kw_short: case tok::kw_long: case tok::kw___int64: + case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_void: @@ -1312,7 +1468,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an // Objective-C interface. If we don't have Objective-C or a '<', this is // just a normal reference to a typedef name. - if (Tok.is(tok::less) && getLang().ObjC1) + if (Tok.is(tok::less) && getLangOpts().ObjC1) ParseObjCProtocolQualifiers(DS); DS.Finish(Diags, PP); @@ -1344,6 +1500,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw_int: DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; + case tok::kw___int128: + DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID); + break; case tok::kw_half: DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID); break; @@ -1365,8 +1524,11 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw_bool: DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); break; + case tok::annot_decltype: + case tok::kw_decltype: + DS.SetRangeEnd(ParseDecltypeSpecifier(DS)); + return DS.Finish(Diags, PP); - // FIXME: C++0x decltype support. // GNU typeof support. case tok::kw_typeof: ParseTypeofSpecifier(DS); @@ -1393,22 +1555,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { /// type-specifier type-specifier-seq[opt] /// bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { - DS.SetRangeStart(Tok.getLocation()); - const char *PrevSpec = 0; - unsigned DiagID; - bool isInvalid = 0; - - // Parse one or more of the type specifiers. - if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, - ParsedTemplateInfo(), /*SuppressDeclarations*/true)) { - Diag(Tok, diag::err_expected_type); - return true; - } - - while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, - ParsedTemplateInfo(), /*SuppressDeclarations*/true)) - {} - + ParseSpecifierQualifierList(DS, AS_none, DSC_type_specifier); DS.Finish(Diags, PP); return false; } @@ -1446,13 +1593,13 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { /// /// \returns true if a parse error occurred, false otherwise. bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext, ParsedType ObjectType, UnqualifiedId &Id, - bool AssumeTemplateId, - SourceLocation TemplateKWLoc) { + bool AssumeTemplateId) { assert((AssumeTemplateId || Tok.is(tok::less)) && "Expected '<' to finish parsing a template-id"); @@ -1463,7 +1610,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: if (AssumeTemplateId) { - TNK = Actions.ActOnDependentTemplateName(getCurScope(), TemplateKWLoc, SS, + TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, Template); if (TNK == TNK_Non_template) @@ -1494,9 +1641,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword) << Name << FixItHint::CreateInsertion(Id.StartLocation, "template "); - TNK = Actions.ActOnDependentTemplateName(getCurScope(), TemplateKWLoc, - SS, Id, ObjectType, - EnteringContext, Template); + TNK = Actions.ActOnDependentTemplateName(getCurScope(), + SS, TemplateKWLoc, Id, + ObjectType, EnteringContext, + Template); if (TNK == TNK_Non_template) return true; } @@ -1519,9 +1667,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { - TNK = Actions.ActOnDependentTemplateName(getCurScope(), TemplateKWLoc, SS, - TemplateName, ObjectType, - EnteringContext, Template); + TNK = Actions.ActOnDependentTemplateName(getCurScope(), + SS, TemplateKWLoc, TemplateName, + ObjectType, EnteringContext, + Template); if (TNK == TNK_Non_template) return true; } else { @@ -1575,6 +1724,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, } TemplateId->SS = SS; + TemplateId->TemplateKWLoc = TemplateKWLoc; TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; @@ -1591,12 +1741,13 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, // Bundle the template arguments together. ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), TemplateArgs.size()); - + // Constructor and destructor names. TypeResult Type - = Actions.ActOnTemplateIdType(SS, Template, NameLoc, - LAngleLoc, TemplateArgsPtr, - RAngleLoc); + = Actions.ActOnTemplateIdType(SS, TemplateKWLoc, + Template, NameLoc, + LAngleLoc, TemplateArgsPtr, RAngleLoc, + /*IsCtorOrDtorName=*/true); if (Type.isInvalid()) return true; @@ -1666,7 +1817,9 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, bool isNew = Tok.getKind() == tok::kw_new; // Consume the 'new' or 'delete'. SymbolLocations[SymbolIdx++] = ConsumeToken(); - if (Tok.is(tok::l_square)) { + // Check for array new/delete. + if (Tok.is(tok::l_square) && + (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))) { // Consume the '[' and ']'. BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); @@ -1742,18 +1895,68 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // literal-operator-id: [C++0x 13.5.8] // operator "" identifier - if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) { - if (Tok.getLength() != 2) - Diag(Tok.getLocation(), diag::err_operator_string_not_empty); - ConsumeStringToken(); + if (getLangOpts().CPlusPlus0x && isTokenStringLiteral()) { + Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator); - if (Tok.isNot(tok::identifier)) { + SourceLocation DiagLoc; + unsigned DiagId = 0; + + // We're past translation phase 6, so perform string literal concatenation + // before checking for "". + llvm::SmallVector<Token, 4> Toks; + llvm::SmallVector<SourceLocation, 4> TokLocs; + while (isTokenStringLiteral()) { + if (!Tok.is(tok::string_literal) && !DiagId) { + DiagLoc = Tok.getLocation(); + DiagId = diag::err_literal_operator_string_prefix; + } + Toks.push_back(Tok); + TokLocs.push_back(ConsumeStringToken()); + } + + StringLiteralParser Literal(Toks.data(), Toks.size(), PP); + if (Literal.hadError) + return true; + + // Grab the literal operator's suffix, which will be either the next token + // or a ud-suffix from the string literal. + IdentifierInfo *II = 0; + SourceLocation SuffixLoc; + if (!Literal.getUDSuffix().empty()) { + II = &PP.getIdentifierTable().get(Literal.getUDSuffix()); + SuffixLoc = + Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()], + Literal.getUDSuffixOffset(), + PP.getSourceManager(), getLangOpts()); + // This form is not permitted by the standard (yet). + DiagLoc = SuffixLoc; + DiagId = diag::err_literal_operator_missing_space; + } else if (Tok.is(tok::identifier)) { + II = Tok.getIdentifierInfo(); + SuffixLoc = ConsumeToken(); + TokLocs.push_back(SuffixLoc); + } else { Diag(Tok.getLocation(), diag::err_expected_ident); return true; } - IdentifierInfo *II = Tok.getIdentifierInfo(); - Result.setLiteralOperatorId(II, KeywordLoc, ConsumeToken()); + // The string literal must be empty. + if (!Literal.GetString().empty() || Literal.Pascal) { + DiagLoc = TokLocs.front(); + DiagId = diag::err_literal_operator_string_not_empty; + } + + if (DiagId) { + // This isn't a valid literal-operator-id, but we think we know + // what the user meant. Tell them what they should have written. + llvm::SmallString<32> Str; + Str += "\"\" "; + Str += II->getName(); + Diag(DiagLoc, DiagId) << FixItHint::CreateReplacement( + SourceRange(TokLocs.front(), TokLocs.back()), Str); + } + + Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc); return false; } @@ -1823,13 +2026,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, ParsedType ObjectType, + SourceLocation& TemplateKWLoc, UnqualifiedId &Result) { // Handle 'A::template B'. This is for template-ids which have not // already been annotated by ParseOptionalCXXScopeSpecifier(). bool TemplateSpecified = false; - SourceLocation TemplateKWLoc; - if (getLang().CPlusPlus && Tok.is(tok::kw_template) && + if (getLangOpts().CPlusPlus && Tok.is(tok::kw_template) && (ObjectType || SS.isSet())) { TemplateSpecified = true; TemplateKWLoc = ConsumeToken(); @@ -1843,7 +2046,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, IdentifierInfo *Id = Tok.getIdentifierInfo(); SourceLocation IdLoc = ConsumeToken(); - if (!getLang().CPlusPlus) { + if (!getLangOpts().CPlusPlus) { // If we're not in C++, only identifiers matter. Record the // identifier and return. Result.setIdentifier(Id, IdLoc); @@ -1853,11 +2056,12 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, if (AllowConstructorName && Actions.isCurrentClassName(*Id, getCurScope(), &SS)) { // We have parsed a constructor name. - Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, getCurScope(), - &SS, false, false, - ParsedType(), - /*NonTrivialTypeSourceInfo=*/true), - IdLoc, IdLoc); + ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(), + &SS, false, false, + ParsedType(), + /*IsCtorOrDtorName=*/true, + /*NonTrivialTypeSourceInfo=*/true); + Result.setConstructorName(Ty, IdLoc, IdLoc); } else { // We have parsed an identifier. Result.setIdentifier(Id, IdLoc); @@ -1865,9 +2069,9 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // If the next token is a '<', we may have a template. if (TemplateSpecified || Tok.is(tok::less)) - return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext, - ObjectType, Result, - TemplateSpecified, TemplateKWLoc); + return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, Id, IdLoc, + EnteringContext, ObjectType, + Result, TemplateSpecified); return false; } @@ -1890,13 +2094,14 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, << TemplateId->Name << FixItHint::CreateRemoval( SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)); - Result.setConstructorName(Actions.getTypeName(*TemplateId->Name, - TemplateId->TemplateNameLoc, - getCurScope(), - &SS, false, false, - ParsedType(), - /*NontrivialTypeSourceInfo=*/true), - TemplateId->TemplateNameLoc, + ParsedType Ty = Actions.getTypeName(*TemplateId->Name, + TemplateId->TemplateNameLoc, + getCurScope(), + &SS, false, false, + ParsedType(), + /*IsCtorOrDtorName=*/true, + /*NontrivialTypeSourceInfo=*/true); + Result.setConstructorName(Ty, TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); ConsumeToken(); return false; @@ -1910,6 +2115,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // We have already parsed a template-id; consume the annotation token as // our unqualified-id. Result.setTemplateId(TemplateId); + TemplateKWLoc = TemplateId->TemplateKWLoc; ConsumeToken(); return false; } @@ -1929,15 +2135,15 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId || Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) && (TemplateSpecified || Tok.is(tok::less))) - return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), - EnteringContext, ObjectType, - Result, - TemplateSpecified, TemplateKWLoc); + return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, + 0, SourceLocation(), + EnteringContext, ObjectType, + Result, TemplateSpecified); return false; } - if (getLang().CPlusPlus && + if (getLangOpts().CPlusPlus && (AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) { // C++ [expr.unary.op]p10: // There is an ambiguity in the unary-expression ~X(), where X is a @@ -1946,6 +2152,16 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // Parse the '~'. SourceLocation TildeLoc = ConsumeToken(); + + if (SS.isEmpty() && Tok.is(tok::kw_decltype)) { + DeclSpec DS(AttrFactory); + SourceLocation EndLoc = ParseDecltypeSpecifier(DS); + if (ParsedType Type = Actions.getDestructorType(DS, ObjectType)) { + Result.setDestructorName(TildeLoc, Type, EndLoc); + return false; + } + return true; + } // Parse the class-name. if (Tok.isNot(tok::identifier)) { @@ -1959,9 +2175,10 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, if (TemplateSpecified || Tok.is(tok::less)) { Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc); - return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc, - EnteringContext, ObjectType, Result, - TemplateSpecified, TemplateKWLoc); + return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, + ClassName, ClassNameLoc, + EnteringContext, ObjectType, + Result, TemplateSpecified); } // Note that this is a destructor name. @@ -1977,7 +2194,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, } Diag(Tok, diag::err_expected_unqualified_id) - << getLang().CPlusPlus; + << getLangOpts().CPlusPlus; return true; } @@ -2083,10 +2300,11 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { return ExprError(); } - ExprVector ConstructorArgs(Actions); - SourceLocation ConstructorLParen, ConstructorRParen; + ExprResult Initializer; if (Tok.is(tok::l_paren)) { + SourceLocation ConstructorLParen, ConstructorRParen; + ExprVector ConstructorArgs(Actions); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ConstructorLParen = T.getOpenLocation(); @@ -2103,15 +2321,20 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); } - } else if (Tok.is(tok::l_brace)) { - // FIXME: Have to communicate the init-list to ActOnCXXNew. - ParseBraceInitializer(); + Initializer = Actions.ActOnParenListExpr(ConstructorLParen, + ConstructorRParen, + move_arg(ConstructorArgs)); + } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus0x) { + Diag(Tok.getLocation(), + diag::warn_cxx98_compat_generalized_initializer_lists); + Initializer = ParseBraceInitializer(); } + if (Initializer.isInvalid()) + return Initializer; return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen, move_arg(PlacementArgs), PlacementRParen, - TypeIdParens, DeclaratorInfo, ConstructorLParen, - move_arg(ConstructorArgs), ConstructorRParen); + TypeIdParens, DeclaratorInfo, Initializer.take()); } /// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be @@ -2125,6 +2348,10 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { // Parse the array dimensions. bool first = true; while (Tok.is(tok::l_square)) { + // An array-size expression can't start with a lambda. + if (CheckProhibitedCXX11Attribute()) + continue; + BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); @@ -2139,13 +2366,16 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { T.consumeClose(); - ParsedAttributes attrs(AttrFactory); + // Attributes here appertain to the array type. C++11 [expr.new]p5. + ParsedAttributes Attrs(AttrFactory); + MaybeParseCXX0XAttributes(Attrs); + D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, Size.release(), T.getOpenLocation(), T.getCloseLocation()), - attrs, T.getCloseLocation()); + Attrs, T.getCloseLocation()); if (T.getCloseLocation().isInvalid()) return; @@ -2197,7 +2427,11 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { // Array delete? bool ArrayDelete = false; - if (Tok.is(tok::l_square)) { + if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) { + // FIXME: This could be the start of a lambda-expression. We should + // disambiguate this, but that will require arbitrary lookahead if + // the next token is '(': + // delete [](int*){ /* ... */ ArrayDelete = true; BalancedDelimiterTracker T(*this, tok::l_square); @@ -2235,6 +2469,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___is_const: return UTT_IsConst; case tok::kw___is_empty: return UTT_IsEmpty; case tok::kw___is_enum: return UTT_IsEnum; + case tok::kw___is_final: return UTT_IsFinal; case tok::kw___is_floating_point: return UTT_IsFloatingPoint; case tok::kw___is_function: return UTT_IsFunction; case tok::kw___is_fundamental: return UTT_IsFundamental; @@ -2271,6 +2506,15 @@ static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___is_same: return BTT_IsSame; case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible; case tok::kw___is_convertible_to: return BTT_IsConvertibleTo; + case tok::kw___is_trivially_assignable: return BTT_IsTriviallyAssignable; + } +} + +static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) { + switch (kind) { + default: llvm_unreachable("Not a known type trait"); + case tok::kw___is_trivially_constructible: + return TT_IsTriviallyConstructible; } } @@ -2356,6 +2600,58 @@ ExprResult Parser::ParseBinaryTypeTrait() { T.getCloseLocation()); } +/// \brief Parse the built-in type-trait pseudo-functions that allow +/// implementation of the TR1/C++11 type traits templates. +/// +/// primary-expression: +/// type-trait '(' type-id-seq ')' +/// +/// type-id-seq: +/// type-id ...[opt] type-id-seq[opt] +/// +ExprResult Parser::ParseTypeTrait() { + TypeTrait Kind = TypeTraitFromTokKind(Tok.getKind()); + SourceLocation Loc = ConsumeToken(); + + BalancedDelimiterTracker Parens(*this, tok::l_paren); + if (Parens.expectAndConsume(diag::err_expected_lparen)) + return ExprError(); + + llvm::SmallVector<ParsedType, 2> Args; + do { + // Parse the next type. + TypeResult Ty = ParseTypeName(); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return ExprError(); + } + + // Parse the ellipsis, if present. + if (Tok.is(tok::ellipsis)) { + Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken()); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return ExprError(); + } + } + + // Add this type to the list of arguments. + Args.push_back(Ty.get()); + + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + break; + } while (true); + + if (Parens.consumeClose()) + return ExprError(); + + return Actions.ActOnTypeTrait(Kind, Loc, Args, Parens.getCloseLocation()); +} + /// ParseArrayTypeTrait - Parse the built-in array type-trait /// pseudo-functions. /// @@ -2396,10 +2692,8 @@ ExprResult Parser::ParseArrayTypeTrait() { return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), T.getCloseLocation()); } - default: - break; } - return ExprError(); + llvm_unreachable("Invalid ArrayTypeTrait!"); } /// ParseExpressionTrait - Parse built-in expression-trait @@ -2432,7 +2726,7 @@ ExprResult Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ParsedType &CastTy, BalancedDelimiterTracker &Tracker) { - assert(getLang().CPlusPlus && "Should only be called for C++!"); + assert(getLangOpts().CPlusPlus && "Should only be called for C++!"); assert(ExprType == CastExpr && "Compound literals are not ambiguous!"); assert(isTypeIdInParens() && "Not a type-id!"); @@ -2484,7 +2778,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, false/*isAddressofOperand*/, NotCastExpr, // type-id has priority. - true/*isTypeCast*/); + IsTypeCast); } // If we parsed a cast-expression, it's really a type-id, otherwise it's diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp index 33abc93..1c349fd 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp @@ -21,18 +21,92 @@ using namespace clang; -/// MayBeDesignationStart - Return true if this token might be the start of a -/// designator. If we can tell it is impossible that it is a designator, return -/// false. -static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) { - switch (K) { - default: return false; +/// MayBeDesignationStart - Return true if the current token might be the start +/// of a designator. If we can tell it is impossible that it is a designator, +/// return false. +bool Parser::MayBeDesignationStart() { + switch (Tok.getKind()) { + default: + return false; + case tok::period: // designator: '.' identifier - case tok::l_square: // designator: array-designator + return true; + + case tok::l_square: { // designator: array-designator + if (!PP.getLangOpts().CPlusPlus0x) return true; + + // C++11 lambda expressions and C99 designators can be ambiguous all the + // way through the closing ']' and to the next character. Handle the easy + // cases here, and fall back to tentative parsing if those fail. + switch (PP.LookAhead(0).getKind()) { + case tok::equal: + case tok::r_square: + // Definitely starts a lambda expression. + return false; + + case tok::amp: + case tok::kw_this: + case tok::identifier: + // We have to do additional analysis, because these could be the + // start of a constant expression or a lambda capture list. + break; + + default: + // Anything not mentioned above cannot occur following a '[' in a + // lambda expression. + return true; + } + + // Handle the complicated case below. + break; + } case tok::identifier: // designation: identifier ':' return PP.LookAhead(0).is(tok::colon); } + + // Parse up to (at most) the token after the closing ']' to determine + // whether this is a C99 designator or a lambda. + TentativeParsingAction Tentative(*this); + ConsumeBracket(); + while (true) { + switch (Tok.getKind()) { + case tok::equal: + case tok::amp: + case tok::identifier: + case tok::kw_this: + // These tokens can occur in a capture list or a constant-expression. + // Keep looking. + ConsumeToken(); + continue; + + case tok::comma: + // Since a comma cannot occur in a constant-expression, this must + // be a lambda. + Tentative.Revert(); + return false; + + case tok::r_square: { + // Once we hit the closing square bracket, we look at the next + // token. If it's an '=', this is a designator. Otherwise, it's a + // lambda expression. This decision favors lambdas over the older + // GNU designator syntax, which allows one to omit the '=', but is + // consistent with GCC. + ConsumeBracket(); + tok::TokenKind Kind = Tok.getKind(); + Tentative.Revert(); + return Kind == tok::equal; + } + + default: + // Anything else cannot occur in a lambda capture list, so it + // must be a designator. + Tentative.Revert(); + return true; + } + } + + return true; } static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc, @@ -81,7 +155,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { if (Tok.is(tok::identifier)) { const IdentifierInfo *FieldName = Tok.getIdentifierInfo(); - llvm::SmallString<256> NewSyntax; + SmallString<256> NewSyntax; llvm::raw_svector_ostream(NewSyntax) << '.' << FieldName->getName() << " = "; @@ -137,6 +211,11 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { // [foo ... bar] -> array designator // [4][foo bar] -> obsolete GNU designation with objc message send. // + // We do not need to check for an expression starting with [[ here. If it + // contains an Objective-C message send, then it is not an ill-formed + // attribute. If it is a lambda-expression within an array-designator, then + // it will be rejected because a constant-expression cannot begin with a + // lambda-expression. InMessageExpressionRAIIObject InMessage(*this, true); BalancedDelimiterTracker T(*this, tok::l_square); @@ -149,7 +228,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { // send) or send to 'super', parse this as a message send // expression. We handle C++ and C separately, since C++ requires // much more complicated parsing. - if (getLang().ObjC1 && getLang().CPlusPlus) { + if (getLangOpts().ObjC1 && getLangOpts().CPlusPlus) { // Send to 'super'. if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && NextToken().isNot(tok::period) && @@ -184,7 +263,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { // adopt the expression for further analysis below. // FIXME: potentially-potentially evaluated expression above? Idx = ExprResult(static_cast<Expr*>(TypeOrExpr)); - } else if (getLang().ObjC1 && Tok.is(tok::identifier)) { + } else if (getLangOpts().ObjC1 && Tok.is(tok::identifier)) { IdentifierInfo *II = Tok.getIdentifierInfo(); SourceLocation IILoc = Tok.getLocation(); ParsedType ReceiverType; @@ -242,7 +321,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { // tokens are '...' or ']' or an objc message send. If this is an objc // message send, handle it now. An objc-message send is the start of // an assignment-expression production. - if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) && + if (getLangOpts().ObjC1 && Tok.isNot(tok::ellipsis) && Tok.isNot(tok::r_square)) { CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig); return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, @@ -330,7 +409,7 @@ ExprResult Parser::ParseBraceInitializer() { if (Tok.is(tok::r_brace)) { // Empty initializers are a C++ feature and a GNU extension to C. - if (!getLang().CPlusPlus) + if (!getLangOpts().CPlusPlus) Diag(LBraceLoc, diag::ext_gnu_empty_initializer); // Match the '}'. return Actions.ActOnInitList(LBraceLoc, MultiExprArg(Actions), @@ -340,12 +419,23 @@ ExprResult Parser::ParseBraceInitializer() { bool InitExprsOk = true; while (1) { + // Handle Microsoft __if_exists/if_not_exists if necessary. + if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || + Tok.is(tok::kw___if_not_exists))) { + if (ParseMicrosoftIfExistsBraceInitializer(InitExprs, InitExprsOk)) { + if (Tok.isNot(tok::comma)) break; + ConsumeToken(); + } + if (Tok.is(tok::r_brace)) break; + continue; + } + // Parse: designation[opt] initializer // If we know that this cannot be a designation, just parse the nested // initializer directly. ExprResult SubElt; - if (MayBeDesignationStart(Tok.getKind(), PP)) + if (MayBeDesignationStart()) SubElt = ParseInitializerWithPotentialDesignator(); else SubElt = ParseInitializer(); @@ -392,3 +482,66 @@ ExprResult Parser::ParseBraceInitializer() { return ExprError(); // an error occurred. } + +// Return true if a comma (or closing brace) is necessary after the +// __if_exists/if_not_exists statement. +bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs, + bool &InitExprsOk) { + bool trailingComma = false; + IfExistsCondition Result; + if (ParseMicrosoftIfExistsCondition(Result)) + return false; + + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { + Diag(Tok, diag::err_expected_lbrace); + return false; + } + + switch (Result.Behavior) { + case IEB_Parse: + // Parse the declarations below. + break; + + case IEB_Dependent: + Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists) + << Result.IsIfExists; + // Fall through to skip. + + case IEB_Skip: + Braces.skipToEnd(); + return false; + } + + while (Tok.isNot(tok::eof)) { + trailingComma = false; + // If we know that this cannot be a designation, just parse the nested + // initializer directly. + ExprResult SubElt; + if (MayBeDesignationStart()) + SubElt = ParseInitializerWithPotentialDesignator(); + else + SubElt = ParseInitializer(); + + if (Tok.is(tok::ellipsis)) + SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken()); + + // If we couldn't parse the subelement, bail out. + if (!SubElt.isInvalid()) + InitExprs.push_back(SubElt.release()); + else + InitExprsOk = false; + + if (Tok.is(tok::comma)) { + ConsumeToken(); + trailingComma = true; + } + + if (Tok.is(tok::r_brace)) + break; + } + + Braces.consumeClose(); + + return !trailingComma; +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp index 88044d1..789a8ae 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp @@ -42,7 +42,6 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { switch (Tok.getObjCKeywordID()) { case tok::objc_class: return ParseObjCAtClassDeclaration(AtLoc); - break; case tok::objc_interface: { ParsedAttributes attrs(AttrFactory); SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, attrs); @@ -50,15 +49,12 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { } case tok::objc_protocol: { ParsedAttributes attrs(AttrFactory); - SingleDecl = ParseObjCAtProtocolDeclaration(AtLoc, attrs); - break; + return ParseObjCAtProtocolDeclaration(AtLoc, attrs); } case tok::objc_implementation: - SingleDecl = ParseObjCAtImplementationDeclaration(AtLoc); - break; + return ParseObjCAtImplementationDeclaration(AtLoc); case tok::objc_end: return ParseObjCAtEndDeclaration(AtLoc); - break; case tok::objc_compatibility_alias: SingleDecl = ParseObjCAtAliasDeclaration(AtLoc); break; @@ -68,6 +64,12 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { case tok::objc_dynamic: SingleDecl = ParseObjCPropertyDynamic(AtLoc); break; + case tok::objc___experimental_modules_import: + if (getLangOpts().Modules) + return ParseModuleImport(AtLoc); + + // Fall through + default: Diag(AtLoc, diag::err_unexpected_at); SkipUntil(tok::semi); @@ -113,6 +115,25 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ClassNames.size()); } +void Parser::CheckNestedObjCContexts(SourceLocation AtLoc) +{ + Sema::ObjCContainerKind ock = Actions.getObjCContainerKind(); + if (ock == Sema::OCK_None) + return; + + Decl *Decl = Actions.getObjCDeclContext(); + if (CurParsedObjCImpl) { + CurParsedObjCImpl->finish(AtLoc); + } else { + Actions.ActOnAtEnd(getCurScope(), AtLoc); + } + Diag(AtLoc, diag::err_objc_missing_end) + << FixItHint::CreateInsertion(AtLoc, "@end\n"); + if (Decl) + Diag(Decl->getLocStart(), diag::note_objc_container_start) + << (int) ock; +} + /// /// objc-interface: /// objc-class-interface-attributes[opt] objc-class-interface @@ -140,11 +161,13 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { /// __attribute__((deprecated)) /// __attribute__((unavailable)) /// __attribute__((objc_exception)) - used by NSException on 64-bit +/// __attribute__((objc_root_class)) /// -Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, +Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, ParsedAttributes &attrs) { assert(Tok.isObjCAtKeyword(tok::objc_interface) && "ParseObjCAtInterfaceDeclaration(): Expected @interface"); + CheckNestedObjCContexts(AtLoc); ConsumeToken(); // the "interface" identifier // Code completion after '@interface'. @@ -181,7 +204,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, categoryId = Tok.getIdentifierInfo(); categoryLoc = ConsumeToken(); } - else if (!getLang().ObjC2) { + else if (!getLangOpts().ObjC2) { Diag(Tok, diag::err_expected_ident); // missing category name. return 0; } @@ -205,7 +228,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, return 0; Decl *CategoryType = - Actions.ActOnStartCategoryInterface(atLoc, + Actions.ActOnStartCategoryInterface(AtLoc, nameId, nameLoc, categoryId, categoryLoc, ProtocolRefs.data(), @@ -214,7 +237,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, EndProtoLoc); if (Tok.is(tok::l_brace)) - ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, atLoc); + ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc); ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType); return CategoryType; @@ -250,14 +273,14 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, return 0; Decl *ClsType = - Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc, + Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, superClassId, superClassLoc, ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(), EndProtoLoc, attrs.getList()); if (Tok.is(tok::l_brace)) - ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc); + ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc); ParseObjCInterfaceDeclList(tok::objc_interface, ClsType); return ClsType; @@ -266,17 +289,22 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, /// The Objective-C property callback. This should be defined where /// it's used, but instead it's been lifted to here to support VS2005. struct Parser::ObjCPropertyCallback : FieldCallback { +private: + virtual void anchor(); +public: Parser &P; SmallVectorImpl<Decl *> &Props; ObjCDeclSpec &OCDS; SourceLocation AtLoc; + SourceLocation LParenLoc; tok::ObjCKeywordKind MethodImplKind; ObjCPropertyCallback(Parser &P, SmallVectorImpl<Decl *> &Props, ObjCDeclSpec &OCDS, SourceLocation AtLoc, + SourceLocation LParenLoc, tok::ObjCKeywordKind MethodImplKind) : - P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc), + P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc), LParenLoc(LParenLoc), MethodImplKind(MethodImplKind) { } @@ -308,7 +336,8 @@ struct Parser::ObjCPropertyCallback : FieldCallback { FD.D.getIdentifier()); bool isOverridingProperty = false; Decl *Property = - P.Actions.ActOnProperty(P.getCurScope(), AtLoc, FD, OCDS, + P.Actions.ActOnProperty(P.getCurScope(), AtLoc, LParenLoc, + FD, OCDS, GetterSel, SetterSel, &isOverridingProperty, MethodImplKind); @@ -319,6 +348,9 @@ struct Parser::ObjCPropertyCallback : FieldCallback { } }; +void Parser::ObjCPropertyCallback::anchor() { +} + /// objc-interface-decl-list: /// empty /// objc-interface-decl-list objc-property-decl [OBJC2] @@ -348,8 +380,12 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, allMethods.push_back(methodPrototype); // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for // method definitions. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_method_proto, - "", tok::semi); + if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) { + // We didn't find a semi and we error'ed out. Skip until a ';' or '@'. + SkipUntil(tok::at, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } continue; } if (Tok.is(tok::l_paren)) { @@ -372,7 +408,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, // Code completion within an Objective-C interface. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), - ObjCImpDecl? Sema::PCC_ObjCImplementation + CurParsedObjCImpl? Sema::PCC_ObjCImplementation : Sema::PCC_ObjCInterface); return cutOffParsing(); } @@ -394,7 +430,6 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtDirective(getCurScope()); return cutOffParsing(); - break; } tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID(); @@ -425,7 +460,10 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, case tok::objc_implementation: case tok::objc_interface: - Diag(Tok, diag::err_objc_missing_end); + Diag(AtLoc, diag::err_objc_missing_end) + << FixItHint::CreateInsertion(AtLoc, "@end\n"); + Diag(CDecl->getLocStart(), diag::note_objc_container_start) + << (int) Actions.getObjCContainerKind(); ConsumeToken(); break; @@ -440,16 +478,19 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, break; case tok::objc_property: - if (!getLang().ObjC2) + if (!getLangOpts().ObjC2) Diag(AtLoc, diag::err_objc_properties_require_objc2); ObjCDeclSpec OCDS; + SourceLocation LParenLoc; // Parse property attribute list, if any. - if (Tok.is(tok::l_paren)) + if (Tok.is(tok::l_paren)) { + LParenLoc = Tok.getLocation(); ParseObjCPropertyAttribute(OCDS); + } ObjCPropertyCallback Callback(*this, allProperties, - OCDS, AtLoc, MethodImplKind); + OCDS, AtLoc, LParenLoc, MethodImplKind); // Parse all the comma separated declarators. DeclSpec DS(AttrFactory); @@ -465,10 +506,16 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtDirective(getCurScope()); return cutOffParsing(); - } else if (Tok.isObjCAtKeyword(tok::objc_end)) + } else if (Tok.isObjCAtKeyword(tok::objc_end)) { ConsumeToken(); // the "end" identifier - else - Diag(Tok, diag::err_objc_missing_end); + } else { + Diag(Tok, diag::err_objc_missing_end) + << FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n"); + Diag(CDecl->getLocStart(), diag::note_objc_container_start) + << (int) Actions.getObjCContainerKind(); + AtEnd.setBegin(Tok.getLocation()); + AtEnd.setEnd(Tok.getLocation()); + } // Insert collected methods declarations into the @interface object. // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit. @@ -732,7 +779,7 @@ bool Parser::isTokIdentifier_in() const { // FIXME: May have to do additional look-ahead to only allow for // valid tokens following an 'in'; such as an identifier, unary operators, // '[' etc. - return (getLang().ObjC2 && Tok.is(tok::identifier) && + return (getLangOpts().ObjC2 && Tok.is(tok::identifier) && Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]); } @@ -935,7 +982,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // If attributes exist before the method, parse them. ParsedAttributes methodAttrs(AttrFactory); - if (getLang().ObjC2) + if (getLangOpts().ObjC2) MaybeParseGNUAttributes(methodAttrs); if (Tok.is(tok::code_completion)) { @@ -961,7 +1008,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo; if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. - if (getLang().ObjC2) + if (getLangOpts().ObjC2) MaybeParseGNUAttributes(methodAttrs); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); @@ -1004,7 +1051,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // If attributes exist before the argument name, parse them. // Regardless, collect all the attributes we've parsed so far. ArgInfo.ArgAttrs = 0; - if (getLang().ObjC2) { + if (getLangOpts().ObjC2) { MaybeParseGNUAttributes(paramAttrs); ArgInfo.ArgAttrs = paramAttrs.getList(); } @@ -1083,7 +1130,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // FIXME: Add support for optional parameter list... // If attributes exist after the method, parse them. - if (getLang().ObjC2) + if (getLangOpts().ObjC2) MaybeParseGNUAttributes(methodAttrs); if (KeyIdents.size() == 0) @@ -1146,7 +1193,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, return true; } - EndLoc = ConsumeAnyToken(); + EndLoc = ConsumeToken(); // Convert the list of protocols identifiers into a list of protocol decls. Actions.FindProtocolDeclaration(WarnOnDeclarations, @@ -1159,7 +1206,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, /// in a decl-specifier-seq, starting at the '<'. bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'"); - assert(getLang().ObjC1 && "Protocol qualifiers only exist in Objective-C"); + assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C"); SourceLocation LAngleLoc, EndProtoLoc; SmallVector<Decl *, 8> ProtocolDecl; SmallVector<SourceLocation, 8> ProtocolLocs; @@ -1312,8 +1359,9 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, /// "@protocol identifier ;" should be resolved as "@protocol /// identifier-list ;": objc-interface-decl-list may not start with a /// semicolon in the first alternative if objc-protocol-refs are omitted. -Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, - ParsedAttributes &attrs) { +Parser::DeclGroupPtrTy +Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, + ParsedAttributes &attrs) { assert(Tok.isObjCAtKeyword(tok::objc_protocol) && "ParseObjCAtProtocolDeclaration(): Expected @protocol"); ConsumeToken(); // the "protocol" identifier @@ -1321,12 +1369,12 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCProtocolDecl(getCurScope()); cutOffParsing(); - return 0; + return DeclGroupPtrTy(); } if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing protocol name. - return 0; + return DeclGroupPtrTy(); } // Save the protocol name, then consume it. IdentifierInfo *protocolName = Tok.getIdentifierInfo(); @@ -1339,6 +1387,8 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, attrs.getList()); } + CheckNestedObjCContexts(AtLoc); + if (Tok.is(tok::comma)) { // list of forward declarations. SmallVector<IdentifierLocPair, 8> ProtocolRefs; ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc)); @@ -1349,7 +1399,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::semi); - return 0; + return DeclGroupPtrTy(); } ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(), Tok.getLocation())); @@ -1360,7 +1410,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, } // Consume the ';'. if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol")) - return 0; + return DeclGroupPtrTy(); return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtocolRefs[0], @@ -1376,7 +1426,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, LAngleLoc, EndProtoLoc)) - return 0; + return DeclGroupPtrTy(); Decl *ProtoType = Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc, @@ -1386,7 +1436,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, EndProtoLoc, attrs.getList()); ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType); - return ProtoType; + return Actions.ConvertDeclToDeclGroup(ProtoType); } /// objc-implementation: @@ -1399,26 +1449,28 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, /// /// objc-category-implementation-prologue: /// @implementation identifier ( identifier ) -Decl *Parser::ParseObjCAtImplementationDeclaration( - SourceLocation atLoc) { +Parser::DeclGroupPtrTy +Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { assert(Tok.isObjCAtKeyword(tok::objc_implementation) && "ParseObjCAtImplementationDeclaration(): Expected @implementation"); + CheckNestedObjCContexts(AtLoc); ConsumeToken(); // the "implementation" identifier // Code completion after '@implementation'. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCImplementationDecl(getCurScope()); cutOffParsing(); - return 0; + return DeclGroupPtrTy(); } if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. - return 0; + return DeclGroupPtrTy(); } // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); // consume class or category name + Decl *ObjCImpDecl = 0; if (Tok.is(tok::l_paren)) { // we have a category implementation. @@ -1429,7 +1481,7 @@ Decl *Parser::ParseObjCAtImplementationDeclaration( if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc); cutOffParsing(); - return 0; + return DeclGroupPtrTy(); } if (Tok.is(tok::identifier)) { @@ -1437,45 +1489,57 @@ Decl *Parser::ParseObjCAtImplementationDeclaration( categoryLoc = ConsumeToken(); } else { Diag(Tok, diag::err_expected_ident); // missing category name. - return 0; + return DeclGroupPtrTy(); } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); SkipUntil(tok::r_paren, false); // don't stop at ';' - return 0; + return DeclGroupPtrTy(); } rparenLoc = ConsumeParen(); - Decl *ImplCatType = Actions.ActOnStartCategoryImplementation( - atLoc, nameId, nameLoc, categoryId, + ObjCImpDecl = Actions.ActOnStartCategoryImplementation( + AtLoc, nameId, nameLoc, categoryId, categoryLoc); - ObjCImpDecl = ImplCatType; - PendingObjCImpDecl.push_back(ObjCImpDecl); - return 0; - } - // We have a class implementation - SourceLocation superClassLoc; - IdentifierInfo *superClassId = 0; - if (Tok.is(tok::colon)) { - // We have a super class - ConsumeToken(); - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); // missing super class name. - return 0; + } else { + // We have a class implementation + SourceLocation superClassLoc; + IdentifierInfo *superClassId = 0; + if (Tok.is(tok::colon)) { + // We have a super class + ConsumeToken(); + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing super class name. + return DeclGroupPtrTy(); + } + superClassId = Tok.getIdentifierInfo(); + superClassLoc = ConsumeToken(); // Consume super class name } - superClassId = Tok.getIdentifierInfo(); - superClassLoc = ConsumeToken(); // Consume super class name + ObjCImpDecl = Actions.ActOnStartClassImplementation( + AtLoc, nameId, nameLoc, + superClassId, superClassLoc); + + if (Tok.is(tok::l_brace)) // we have ivars + ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc); } - Decl *ImplClsType = Actions.ActOnStartClassImplementation( - atLoc, nameId, nameLoc, - superClassId, superClassLoc); + assert(ObjCImpDecl); - if (Tok.is(tok::l_brace)) // we have ivars - ParseObjCClassInstanceVariables(ImplClsType, tok::objc_private, atLoc); + SmallVector<Decl *, 8> DeclsInGroup; - ObjCImpDecl = ImplClsType; - PendingObjCImpDecl.push_back(ObjCImpDecl); - return 0; + { + ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl); + while (!ObjCImplParsing.isFinished() && Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) { + DeclGroupRef DG = DGP.get(); + DeclsInGroup.append(DG.begin(), DG.end()); + } + } + } + + return Actions.ActOnFinishObjCImplementation(ObjCImpDecl, DeclsInGroup); } Parser::DeclGroupPtrTy @@ -1483,35 +1547,44 @@ Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { assert(Tok.isObjCAtKeyword(tok::objc_end) && "ParseObjCAtEndDeclaration(): Expected @end"); ConsumeToken(); // the "end" identifier - SmallVector<Decl *, 8> DeclsInGroup; - Actions.DefaultSynthesizeProperties(getCurScope(), ObjCImpDecl); - for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) { - Decl *D = ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]); - DeclsInGroup.push_back(D); - } - DeclsInGroup.push_back(ObjCImpDecl); - - if (ObjCImpDecl) { - Actions.ActOnAtEnd(getCurScope(), atEnd); - PendingObjCImpDecl.pop_back(); - } + if (CurParsedObjCImpl) + CurParsedObjCImpl->finish(atEnd); else // missing @implementation - Diag(atEnd.getBegin(), diag::err_expected_implementation); - - LateParsedObjCMethods.clear(); - ObjCImpDecl = 0; - return Actions.BuildDeclaratorGroup( - DeclsInGroup.data(), DeclsInGroup.size(), false); + Diag(atEnd.getBegin(), diag::err_expected_objc_container); + return DeclGroupPtrTy(); } -Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() { - Actions.DiagnoseUseOfUnimplementedSelectors(); - if (PendingObjCImpDecl.empty()) - return Actions.ConvertDeclToDeclGroup(0); - Decl *ImpDecl = PendingObjCImpDecl.pop_back_val(); - Actions.ActOnAtEnd(getCurScope(), SourceRange()); - return Actions.ConvertDeclToDeclGroup(ImpDecl); +Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() { + if (!Finished) { + finish(P.Tok.getLocation()); + if (P.Tok.is(tok::eof)) { + P.Diag(P.Tok, diag::err_objc_missing_end) + << FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n"); + P.Diag(Dcl->getLocStart(), diag::note_objc_container_start) + << Sema::OCK_Implementation; + } + } + P.CurParsedObjCImpl = 0; + assert(LateParsedObjCMethods.empty()); +} + +void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) { + assert(!Finished); + P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl); + for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) + P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]); + + P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd); + + /// \brief Clear and free the cached objc methods. + for (LateParsedObjCMethodContainer::iterator + I = LateParsedObjCMethods.begin(), + E = LateParsedObjCMethods.end(); I != E; ++I) + delete *I; + LateParsedObjCMethods.clear(); + + Finished = true; } /// compatibility-alias-decl: @@ -1850,7 +1923,7 @@ Decl *Parser::ParseObjCMethodDefinition() { // parse optional ';' if (Tok.is(tok::semi)) { - if (ObjCImpDecl) { + if (CurParsedObjCImpl) { Diag(Tok, diag::warn_semicolon_before_method_body) << FixItHint::CreateRemoval(Tok.getLocation()); } @@ -1868,19 +1941,32 @@ Decl *Parser::ParseObjCMethodDefinition() { if (Tok.isNot(tok::l_brace)) return 0; } + + if (!MDecl) { + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi=*/false); + return 0; + } + // Allow the rest of sema to find private method decl implementations. - if (MDecl) - Actions.AddAnyMethodToGlobalPool(MDecl); - - // Consume the tokens and store them for later parsing. - LexedMethod* LM = new LexedMethod(this, MDecl); - LateParsedObjCMethods.push_back(LM); - CachedTokens &Toks = LM->Toks; - // Begin by storing the '{' token. - Toks.push_back(Tok); - ConsumeBrace(); - // Consume everything up to (and including) the matching right brace. - ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + Actions.AddAnyMethodToGlobalPool(MDecl); + + if (CurParsedObjCImpl) { + // Consume the tokens and store them for later parsing. + LexedMethod* LM = new LexedMethod(this, MDecl); + CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM); + CachedTokens &Toks = LM->Toks; + // Begin by storing the '{' token. + Toks.push_back(Tok); + ConsumeBrace(); + // Consume everything up to (and including) the matching right brace. + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + + } else { + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi=*/false); + } + return MDecl; } @@ -1924,9 +2010,62 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { cutOffParsing(); return ExprError(); + case tok::minus: + case tok::plus: { + tok::TokenKind Kind = Tok.getKind(); + SourceLocation OpLoc = ConsumeToken(); + + if (!Tok.is(tok::numeric_constant)) { + const char *Symbol = 0; + switch (Kind) { + case tok::minus: Symbol = "-"; break; + case tok::plus: Symbol = "+"; break; + default: llvm_unreachable("missing unary operator case"); + } + Diag(Tok, diag::err_nsnumber_nonliteral_unary) + << Symbol; + return ExprError(); + } + + ExprResult Lit(Actions.ActOnNumericConstant(Tok)); + if (Lit.isInvalid()) { + return move(Lit); + } + ConsumeToken(); // Consume the literal token. + + Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.take()); + if (Lit.isInvalid()) + return move(Lit); + + return ParsePostfixExpressionSuffix( + Actions.BuildObjCNumericLiteral(AtLoc, Lit.take())); + } + case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc)); + + case tok::char_constant: + return ParsePostfixExpressionSuffix(ParseObjCCharacterLiteral(AtLoc)); + + case tok::numeric_constant: + return ParsePostfixExpressionSuffix(ParseObjCNumericLiteral(AtLoc)); + + case tok::kw_true: // Objective-C++, etc. + case tok::kw___objc_yes: // c/c++/objc/objc++ __objc_yes + return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, true)); + case tok::kw_false: // Objective-C++, etc. + case tok::kw___objc_no: // c/c++/objc/objc++ __objc_no + return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, false)); + + case tok::l_square: + // Objective-C array literal + return ParsePostfixExpressionSuffix(ParseObjCArrayLiteral(AtLoc)); + + case tok::l_brace: + // Objective-C dictionary literal + return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc)); + default: if (Tok.getIdentifierInfo() == 0) return ExprError(Diag(AtLoc, diag::err_unexpected_at)); @@ -2037,14 +2176,14 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { /// This routine will only return true for a subset of valid message-send /// expressions. bool Parser::isSimpleObjCMessageExpression() { - assert(Tok.is(tok::l_square) && getLang().ObjC1 && + assert(Tok.is(tok::l_square) && getLangOpts().ObjC1 && "Incorrect start for isSimpleObjCMessageExpression"); return GetLookAheadToken(1).is(tok::identifier) && GetLookAheadToken(2).is(tok::identifier); } bool Parser::isStartOfObjCClassMessageMissingOpenBracket() { - if (!getLang().ObjC1 || !NextToken().is(tok::identifier) || + if (!getLangOpts().ObjC1 || !NextToken().is(tok::identifier) || InMessageExpression) return false; @@ -2093,7 +2232,7 @@ ExprResult Parser::ParseObjCMessageExpression() { InMessageExpressionRAIIObject InMessage(*this, true); - if (getLang().CPlusPlus) { + if (getLangOpts().CPlusPlus) { // We completely separate the C and C++ cases because C++ requires // more complicated (read: slower) parsing. @@ -2404,6 +2543,134 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { AtStrings.size())); } +/// ParseObjCBooleanLiteral - +/// objc-scalar-literal : '@' boolean-keyword +/// ; +/// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no' +/// ; +ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc, + bool ArgValue) { + SourceLocation EndLoc = ConsumeToken(); // consume the keyword. + return Actions.ActOnObjCBoolLiteral(AtLoc, EndLoc, ArgValue); +} + +/// ParseObjCCharacterLiteral - +/// objc-scalar-literal : '@' character-literal +/// ; +ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) { + ExprResult Lit(Actions.ActOnCharacterConstant(Tok)); + if (Lit.isInvalid()) { + return move(Lit); + } + ConsumeToken(); // Consume the literal token. + return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take())); +} + +/// ParseObjCNumericLiteral - +/// objc-scalar-literal : '@' scalar-literal +/// ; +/// scalar-literal : | numeric-constant /* any numeric constant. */ +/// ; +ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) { + ExprResult Lit(Actions.ActOnNumericConstant(Tok)); + if (Lit.isInvalid()) { + return move(Lit); + } + ConsumeToken(); // Consume the literal token. + return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take())); +} + +ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { + ExprVector ElementExprs(Actions); // array elements. + ConsumeBracket(); // consume the l_square. + + while (Tok.isNot(tok::r_square)) { + // Parse list of array element expressions (all must be id types). + ExprResult Res(ParseAssignmentExpression()); + if (Res.isInvalid()) { + // We must manually skip to a ']', otherwise the expression skipper will + // stop at the ']' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_square); + return move(Res); + } + + // Parse the ellipsis that indicates a pack expansion. + if (Tok.is(tok::ellipsis)) + Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken()); + if (Res.isInvalid()) + return true; + + ElementExprs.push_back(Res.release()); + + if (Tok.is(tok::comma)) + ConsumeToken(); // Eat the ','. + else if (Tok.isNot(tok::r_square)) + return ExprError(Diag(Tok, diag::err_expected_rsquare_or_comma)); + } + SourceLocation EndLoc = ConsumeBracket(); // location of ']' + MultiExprArg Args(Actions, ElementExprs.take(), ElementExprs.size()); + return Owned(Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args)); +} + +ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { + SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements. + ConsumeBrace(); // consume the l_square. + while (Tok.isNot(tok::r_brace)) { + // Parse the comma separated key : value expressions. + ExprResult KeyExpr; + { + ColonProtectionRAIIObject X(*this); + KeyExpr = ParseAssignmentExpression(); + if (KeyExpr.isInvalid()) { + // We must manually skip to a '}', otherwise the expression skipper will + // stop at the '}' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_brace); + return move(KeyExpr); + } + } + + if (Tok.is(tok::colon)) { + ConsumeToken(); + } else { + return ExprError(Diag(Tok, diag::err_expected_colon)); + } + + ExprResult ValueExpr(ParseAssignmentExpression()); + if (ValueExpr.isInvalid()) { + // We must manually skip to a '}', otherwise the expression skipper will + // stop at the '}' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_brace); + return move(ValueExpr); + } + + // Parse the ellipsis that designates this as a pack expansion. + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis) && getLangOpts().CPlusPlus) + EllipsisLoc = ConsumeToken(); + + // We have a valid expression. Collect it in a vector so we can + // build the argument list. + ObjCDictionaryElement Element = { + KeyExpr.get(), ValueExpr.get(), EllipsisLoc, llvm::Optional<unsigned>() + }; + Elements.push_back(Element); + + if (Tok.is(tok::comma)) + ConsumeToken(); // Eat the ','. + else if (Tok.isNot(tok::r_brace)) + return ExprError(Diag(Tok, diag::err_expected_rbrace_or_comma)); + } + SourceLocation EndLoc = ConsumeBrace(); + + // Create the ObjCDictionaryLiteral. + return Owned(Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc), + Elements.data(), + Elements.size())); +} + /// objc-encode-expression: /// @encode ( type-name ) ExprResult @@ -2519,7 +2786,10 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { } Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) { - + + // Save the current token position. + SourceLocation OrigLoc = Tok.getLocation(); + assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!"); // Append the current token at the end of the new token stream so that it // doesn't get lost. @@ -2541,22 +2811,36 @@ Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) { // specified Declarator for the method. Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); - if (PP.isCodeCompletionEnabled()) { - if (trySkippingFunctionBodyForCodeCompletion()) { - BodyScope.Exit(); - return Actions.ActOnFinishFunctionBody(MDecl, 0); - } + if (SkipFunctionBodies && trySkippingFunctionBody()) { + BodyScope.Exit(); + return Actions.ActOnFinishFunctionBody(MDecl, 0); } StmtResult FnBody(ParseCompoundStatementBody()); // If the function body could not be parsed, make a bogus compoundstmt. - if (FnBody.isInvalid()) + if (FnBody.isInvalid()) { + Sema::CompoundScopeRAII CompoundScope(Actions); FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, MultiStmtArg(Actions), false); + } // Leave the function body scope. BodyScope.Exit(); - return Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); + MDecl = Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); + + if (Tok.getLocation() != OrigLoc) { + // Due to parsing error, we either went over the cached tokens or + // there are still cached tokens left. If it's the latter case skip the + // leftover tokens. + // Since this is an uncommon situation that should be avoided, use the + // expensive isBeforeInTranslationUnit call. + if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), + OrigLoc)) + while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); + } + + return MDecl; } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp index 2ccb6ea..eb13e0d 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp @@ -29,6 +29,31 @@ void Parser::HandlePragmaUnused() { ConsumeToken(); // The argument token. } +void Parser::HandlePragmaVisibility() { + assert(Tok.is(tok::annot_pragma_vis)); + const IdentifierInfo *VisType = + static_cast<IdentifierInfo *>(Tok.getAnnotationValue()); + SourceLocation VisLoc = ConsumeToken(); + Actions.ActOnPragmaVisibility(VisType, VisLoc); +} + +struct PragmaPackInfo { + Sema::PragmaPackKind Kind; + IdentifierInfo *Name; + Expr *Alignment; + SourceLocation LParenLoc; + SourceLocation RParenLoc; +}; + +void Parser::HandlePragmaPack() { + assert(Tok.is(tok::annot_pragma_pack)); + PragmaPackInfo *Info = + static_cast<PragmaPackInfo *>(Tok.getAnnotationValue()); + SourceLocation PragmaLoc = ConsumeToken(); + Actions.ActOnPragmaPack(Info->Kind, Info->Name, Info->Alignment, PragmaLoc, + Info->LParenLoc, Info->RParenLoc); +} + // #pragma GCC visibility comes in two variants: // 'push' '(' [visibility] ')' // 'pop' @@ -42,13 +67,10 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, const IdentifierInfo *PushPop = Tok.getIdentifierInfo(); - bool IsPush; const IdentifierInfo *VisType; if (PushPop && PushPop->isStr("pop")) { - IsPush = false; VisType = 0; } else if (PushPop && PushPop->isStr("push")) { - IsPush = true; PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::l_paren)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) @@ -80,7 +102,14 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, return; } - Actions.ActOnPragmaVisibility(IsPush, VisType, VisLoc); + Token *Toks = new Token[1]; + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_vis); + Toks[0].setLocation(VisLoc); + Toks[0].setAnnotationValue( + const_cast<void*>(static_cast<const void*>(VisType))); + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/true); } // #pragma pack(...) comes in the following delicious flavors: @@ -110,6 +139,12 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, return; PP.Lex(Tok); + + // In MSVC/gcc, #pragma pack(4) sets the alignment without affecting + // the push/pop stack. + // In Apple gcc, #pragma pack(4) is equivalent to #pragma pack(push, 4) + if (PP.getLangOpts().ApplePragmaPack) + Kind = Sema::PPK_Push; } else if (Tok.is(tok::identifier)) { const IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("show")) { @@ -159,6 +194,11 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, } } } + } else if (PP.getLangOpts().ApplePragmaPack) { + // In MSVC/gcc, #pragma pack() resets the alignment without affecting + // the push/pop stack. + // In Apple gcc #pragma pack() is equivalent to #pragma pack(pop). + Kind = Sema::PPK_Pop; } if (Tok.isNot(tok::r_paren)) { @@ -173,8 +213,26 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, return; } - Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc, - LParenLoc, RParenLoc); + PragmaPackInfo *Info = + (PragmaPackInfo*) PP.getPreprocessorAllocator().Allocate( + sizeof(PragmaPackInfo), llvm::alignOf<PragmaPackInfo>()); + new (Info) PragmaPackInfo(); + Info->Kind = Kind; + Info->Name = Name; + Info->Alignment = Alignment.release(); + Info->LParenLoc = LParenLoc; + Info->RParenLoc = RParenLoc; + + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 1, llvm::alignOf<Token>()); + new (Toks) Token(); + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_pack); + Toks[0].setLocation(PackLoc); + Toks[0].setAnnotationValue(static_cast<void*>(Info)); + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/false); } // #pragma ms_struct on @@ -203,7 +261,8 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, } if (Tok.isNot(tok::eod)) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "ms_struct"; + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << "ms_struct"; return; } Actions.ActOnPragmaMSStruct(Kind); @@ -348,7 +407,9 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, // This allows us to cache a "#pragma unused" that occurs inside an inline // C++ member function. - Token *Toks = new Token[2*Identifiers.size()]; + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 2 * Identifiers.size(), llvm::alignOf<Token>()); for (unsigned i=0; i != Identifiers.size(); i++) { Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1]; pragmaUnusedTok.startToken(); @@ -356,7 +417,8 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, pragmaUnusedTok.setLocation(UnusedLoc); idTok = Identifiers[i]; } - PP.EnterTokenStream(Toks, 2*Identifiers.size(), /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true); + PP.EnterTokenStream(Toks, 2*Identifiers.size(), + /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); } // #pragma weak identifier @@ -403,6 +465,44 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, } } +// #pragma redefine_extname identifier identifier +void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &RedefToken) { + SourceLocation RedefLoc = RedefToken.getLocation(); + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << + "redefine_extname"; + return; + } + + IdentifierInfo *RedefName = Tok.getIdentifierInfo(), *AliasName = 0; + SourceLocation RedefNameLoc = Tok.getLocation(), AliasNameLoc; + + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "redefine_extname"; + return; + } + AliasName = Tok.getIdentifierInfo(); + AliasNameLoc = Tok.getLocation(); + PP.Lex(Tok); + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << + "redefine_extname"; + return; + } + + Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc, + RedefNameLoc, AliasNameLoc); +} + + void PragmaFPContractHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h index 1d3138f..ebb185a 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h @@ -90,6 +90,16 @@ public: Token &FirstToken); }; +class PragmaRedefineExtnameHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaRedefineExtnameHandler(Sema &A) + : PragmaHandler("redefine_extname"), Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + class PragmaOpenCLExtensionHandler : public PragmaHandler { Sema &Actions; Parser &parser; diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp index a2b7cdd..fdb9788 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp @@ -76,14 +76,15 @@ using namespace clang; /// [OBC] '@' 'throw' ';' /// StmtResult -Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { +Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, + SourceLocation *TrailingElseLoc) { const char *SemiError = 0; StmtResult Res; ParenBraceBracketBalancer BalancerRAIIObj(*this); ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX0XAttributes(attrs); + MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true); // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), @@ -115,7 +116,7 @@ Retry: IdentifierInfo *Name = Tok.getIdentifierInfo(); SourceLocation NameLoc = Tok.getLocation(); - if (getLang().CPlusPlus) + if (getLangOpts().CPlusPlus) CheckForTemplateAndDigraph(Next, ParsedType(), /*EnteringContext=*/false, *Name, SS); @@ -170,7 +171,7 @@ Retry: if (AnnotateTemplateIdToken( TemplateTy::make(Classification.getTemplateName()), Classification.getTemplateNameKind(), - SS, Id, SourceLocation(), + SS, SourceLocation(), Id, /*AllowTypeAnnotation=*/false)) { // Handle errors here by skipping up to the next semicolon or '}', and // eat the semicolon if that's what stopped us. @@ -206,7 +207,7 @@ Retry: } default: { - if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { + if ((getLangOpts().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext, DeclEnd, attrs); @@ -234,18 +235,18 @@ Retry: } case tok::kw_if: // C99 6.8.4.1: if-statement - return ParseIfStatement(attrs); + return ParseIfStatement(attrs, TrailingElseLoc); case tok::kw_switch: // C99 6.8.4.2: switch-statement - return ParseSwitchStatement(attrs); + return ParseSwitchStatement(attrs, TrailingElseLoc); case tok::kw_while: // C99 6.8.5.1: while-statement - return ParseWhileStatement(attrs); + return ParseWhileStatement(attrs, TrailingElseLoc); case tok::kw_do: // C99 6.8.5.2: do-statement Res = ParseDoStatement(attrs); SemiError = "do/while"; break; case tok::kw_for: // C99 6.8.5.3: for-statement - return ParseForStatement(attrs); + return ParseForStatement(attrs, TrailingElseLoc); case tok::kw_goto: // C99 6.8.6.1: goto-statement Res = ParseGotoStatement(attrs); @@ -279,6 +280,14 @@ Retry: case tok::kw___try: return ParseSEHTryBlock(attrs); + + case tok::annot_pragma_vis: + HandlePragmaVisibility(); + return StmtEmpty(); + + case tok::annot_pragma_pack: + HandlePragmaPack(); + return StmtEmpty(); } // If we reached this code, the statement must end in a semicolon. @@ -355,7 +364,8 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { return move(TryBlock); StmtResult Handler; - if(Tok.is(tok::kw___except)) { + if (Tok.is(tok::identifier) && + Tok.getIdentifierInfo() == getSEHExceptKeyword()) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHExceptBlock(Loc); } else if (Tok.is(tok::kw___finally)) { @@ -389,14 +399,14 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope); - if (getLang().Borland) { + if (getLangOpts().Borland) { Ident__exception_info->setIsPoisoned(false); Ident___exception_info->setIsPoisoned(false); Ident_GetExceptionInfo->setIsPoisoned(false); } ExprResult FilterExpr(ParseExpression()); - if (getLang().Borland) { + if (getLangOpts().Borland) { Ident__exception_info->setIsPoisoned(true); Ident___exception_info->setIsPoisoned(true); Ident_GetExceptionInfo->setIsPoisoned(true); @@ -594,7 +604,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, // Nicely diagnose the common error "switch (X) { case 4: }", which is // not valid. SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); - Diag(AfterColonLoc, diag::err_label_end_of_compound_statement); + Diag(AfterColonLoc, diag::err_label_end_of_compound_statement) + << FixItHint::CreateInsertion(AfterColonLoc, " ;"); SubStmt = true; } @@ -636,16 +647,22 @@ StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) { ColonLoc = ExpectedLoc; } - // Diagnose the common error "switch (X) {... default: }", which is not valid. - if (Tok.is(tok::r_brace)) { + StmtResult SubStmt; + + if (Tok.isNot(tok::r_brace)) { + SubStmt = ParseStatement(); + } else { + // Diagnose the common error "switch (X) {... default: }", which is + // not valid. SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); - Diag(AfterColonLoc, diag::err_label_end_of_compound_statement); - return StmtError(); + Diag(AfterColonLoc, diag::err_label_end_of_compound_statement) + << FixItHint::CreateInsertion(AfterColonLoc, " ;"); + SubStmt = true; } - StmtResult SubStmt(ParseStatement()); + // Broken sub-stmt shouldn't prevent forming the case statement properly. if (SubStmt.isInvalid()) - return StmtError(); + SubStmt = Actions.ActOnNullStmt(ColonLoc); return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc, SubStmt.get(), getCurScope()); @@ -698,7 +715,6 @@ StmtResult Parser::ParseCompoundStatement(ParsedAttributes &attrs, return ParseCompoundStatementBody(isStmtExpr); } - /// ParseCompoundStatementBody - Parse a sequence of statements and invoke the /// ActOnCompoundStmt action. This expects the '{' to be the current token, and /// consume the '}' at the end of the block. It does not manipulate the scope @@ -712,6 +728,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { if (T.consumeOpen()) return StmtError(); + Sema::CompoundScopeRAII CompoundScope(Actions); + StmtVector Stmts(Actions); // "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are @@ -752,7 +770,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { continue; } - if (getLang().MicrosoftExt && (Tok.is(tok::kw___if_exists) || + if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { ParseMicrosoftIfExistsStatement(Stmts); continue; @@ -771,7 +789,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { ConsumeToken(); ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX0XAttributes(attrs); + MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true); // If this is the start of a declaration, parse it as such. if (isDeclarationStatement()) { @@ -805,17 +823,20 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { Stmts.push_back(R.release()); } + SourceLocation CloseLoc = Tok.getLocation(); + // We broke out of the while loop because we found a '}' or EOF. if (Tok.isNot(tok::r_brace)) { Diag(Tok, diag::err_expected_rbrace); Diag(T.getOpenLocation(), diag::note_matching) << "{"; - return StmtError(); + // Recover by creating a compound statement with what we parsed so far, + // instead of dropping everything and returning StmtError(); + } else { + if (!T.consumeClose()) + CloseLoc = T.getCloseLocation(); } - if (T.consumeClose()) - return StmtError(); - - return Actions.ActOnCompoundStmt(T.getOpenLocation(), T.getCloseLocation(), + return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc, move_arg(Stmts), isStmtExpr); } @@ -837,7 +858,7 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - if (getLang().CPlusPlus) + if (getLangOpts().CPlusPlus) ParseCXXCondition(ExprResult, DeclResult, Loc, ConvertToBoolean); else { ExprResult = ParseExpression(); @@ -873,7 +894,8 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement /// -StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) { +StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs, + SourceLocation *TrailingElseLoc) { // FIXME: Use attributes? assert(Tok.is(tok::kw_if) && "Not an if stmt!"); @@ -885,7 +907,7 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) { return StmtError(); } - bool C99orCXX = getLang().C99 || getLang().CPlusPlus; + bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; // C99 6.8.4p3 - In C99, the if statement is a block. This is not // the case for C90. @@ -932,7 +954,9 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) { // Read the 'then' stmt. SourceLocation ThenStmtLoc = Tok.getLocation(); - StmtResult ThenStmt(ParseStatement()); + + SourceLocation InnerStatementTrailingElseLoc; + StmtResult ThenStmt(ParseStatement(&InnerStatementTrailingElseLoc)); // Pop the 'if' scope if needed. InnerScope.Exit(); @@ -943,6 +967,9 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) { StmtResult ElseStmt; if (Tok.is(tok::kw_else)) { + if (TrailingElseLoc) + *TrailingElseLoc = Tok.getLocation(); + ElseLoc = ConsumeToken(); ElseStmtLoc = Tok.getLocation(); @@ -966,6 +993,8 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) { Actions.CodeCompleteAfterIf(getCurScope()); cutOffParsing(); return StmtError(); + } else if (InnerStatementTrailingElseLoc.isValid()) { + Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else); } IfScope.Exit(); @@ -999,7 +1028,8 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) { /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement -StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { +StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs, + SourceLocation *TrailingElseLoc) { // FIXME: Use attributes? assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); @@ -1011,7 +1041,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { return StmtError(); } - bool C99orCXX = getLang().C99 || getLang().CPlusPlus; + bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; // C99 6.8.4p3 - In C99, the switch statement is a block. This is // not the case for C90. Start the switch scope. @@ -1067,15 +1097,20 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { C99orCXX && Tok.isNot(tok::l_brace)); // Read the body statement. - StmtResult Body(ParseStatement()); + StmtResult Body(ParseStatement(TrailingElseLoc)); // Pop the scopes. InnerScope.Exit(); SwitchScope.Exit(); - if (Body.isInvalid()) + if (Body.isInvalid()) { // FIXME: Remove the case statement list from the Switch statement. - Body = Actions.ActOnNullStmt(Tok.getLocation()); + + // Put the synthesized null statement on the same line as the end of switch + // condition. + SourceLocation SynthesizedNullStmtLocation = Cond.get()->getLocEnd(); + Body = Actions.ActOnNullStmt(SynthesizedNullStmtLocation); + } return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get()); } @@ -1084,7 +1119,8 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement -StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs) { +StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs, + SourceLocation *TrailingElseLoc) { // FIXME: Use attributes? assert(Tok.is(tok::kw_while) && "Not a while stmt!"); @@ -1097,7 +1133,7 @@ StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs) { return StmtError(); } - bool C99orCXX = getLang().C99 || getLang().CPlusPlus; + bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; // C99 6.8.5p5 - In C99, the while statement is a block. This is not // the case for C90. Start the loop scope. @@ -1142,7 +1178,7 @@ StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs) { C99orCXX && Tok.isNot(tok::l_brace)); // Read the body statement. - StmtResult Body(ParseStatement()); + StmtResult Body(ParseStatement(TrailingElseLoc)); // Pop the body scope if needed. InnerScope.Exit(); @@ -1167,7 +1203,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { // C99 6.8.5p5 - In C99, the do statement is a block. This is not // the case for C90. Start the loop scope. unsigned ScopeFlags; - if (getLang().C99) + if (getLangOpts().C99) ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope; else ScopeFlags = Scope::BreakScope | Scope::ContinueScope; @@ -1183,7 +1219,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { // which is entered and exited each time through the loop. // ParseScope InnerScope(this, Scope::DeclScope, - (getLang().C99 || getLang().CPlusPlus) && + (getLangOpts().C99 || getLangOpts().CPlusPlus) && Tok.isNot(tok::l_brace)); // Read the body statement. @@ -1241,7 +1277,8 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { /// [C++0x] for-range-initializer: /// [C++0x] expression /// [C++0x] braced-init-list [TODO] -StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { +StmtResult Parser::ParseForStatement(ParsedAttributes &attrs, + SourceLocation *TrailingElseLoc) { // FIXME: Use attributes? assert(Tok.is(tok::kw_for) && "Not a for stmt!"); @@ -1253,7 +1290,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { return StmtError(); } - bool C99orCXXorObjC = getLang().C99 || getLang().CPlusPlus || getLang().ObjC1; + bool C99orCXXorObjC = getLangOpts().C99 || getLangOpts().CPlusPlus || getLangOpts().ObjC1; // C99 6.8.5p5 - In C99, the for statement is a block. This is not // the case for C90. Start the loop scope. @@ -1305,7 +1342,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { if (Tok.is(tok::semi)) { // for (; // no first part, eat the ';'. ConsumeToken(); - } else if (isSimpleDeclaration()) { // for (int X = 4; + } else if (isForInitDeclaration()) { // for (int X = 4; // Parse declaration, which eats the ';'. if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode? Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); @@ -1314,7 +1351,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { MaybeParseCXX0XAttributes(attrs); // In C++0x, "for (T NS:a" might not be a typo for :: - bool MightBeForRangeStmt = getLang().CPlusPlus; + bool MightBeForRangeStmt = getLangOpts().CPlusPlus; ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; @@ -1326,8 +1363,8 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (ForRangeInit.ParsedForRangeDecl()) { - if (!getLang().CPlusPlus0x) - Diag(ForRangeInit.ColonLoc, diag::ext_for_range); + Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_for_range : diag::ext_for_range); ForRange = true; } else if (Tok.is(tok::semi)) { // for (int x = 4; @@ -1370,6 +1407,13 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { return StmtError(); } Collection = ParseExpression(); + } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::colon) && FirstPart.get()) { + // User tried to write the reasonable, but ill-formed, for-range-statement + // for (expr : expr) { ... } + Diag(Tok, diag::err_for_range_expected_decl) + << FirstPart.get()->getSourceRange(); + SkipUntil(tok::r_paren, false, true); + SecondPartIsInvalid = true; } else { if (!Value.isInvalid()) { Diag(Tok, diag::err_expected_semi_for); @@ -1390,7 +1434,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { // missing both semicolons. } else { ExprResult Second; - if (getLang().CPlusPlus) + if (getLangOpts().CPlusPlus) ParseCXXCondition(Second, SecondVar, ForLoc, true); else { Second = ParseExpression(); @@ -1458,7 +1502,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { C99orCXXorObjC && Tok.isNot(tok::l_brace)); // Read the body statement. - StmtResult Body(ParseStatement()); + StmtResult Body(ParseStatement(TrailingElseLoc)); // Pop the body scope if needed. InnerScope.Exit(); @@ -1564,13 +1608,12 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) { return StmtError(); } - // FIXME: This is a hack to allow something like C++0x's generalized - // initializer lists, but only enough of this feature to allow Clang to - // parse libstdc++ 4.5's headers. - if (Tok.is(tok::l_brace) && getLang().CPlusPlus) { + if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus) { R = ParseInitializer(); - if (R.isUsable() && !getLang().CPlusPlus0x) - Diag(R.get()->getLocStart(), diag::ext_generalized_initializer_lists) + if (R.isUsable()) + Diag(R.get()->getLocStart(), getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_generalized_initializer_lists : + diag::ext_generalized_initializer_lists) << R.get()->getSourceRange(); } else R = ParseExpression(); @@ -1731,7 +1774,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); SourceLocation AsmLoc = ConsumeToken(); - if (getLang().MicrosoftExt && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { + if (getLangOpts().MicrosoftExt && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { msAsm = true; return ParseMicrosoftAsmStatement(AsmLoc); } @@ -1756,8 +1799,11 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { T.consumeOpen(); ExprResult AsmString(ParseAsmStringLiteral()); - if (AsmString.isInvalid()) + if (AsmString.isInvalid()) { + // Consume up to and including the closing paren. + T.skipToEnd(); return StmtError(); + } SmallVector<IdentifierInfo *, 4> Names; ExprVector Constraints(Actions); @@ -1906,19 +1952,15 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, if (Tok.isNot(tok::comma)) return false; ConsumeToken(); } - - return true; } Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); - if (PP.isCodeCompletionEnabled()) { - if (trySkippingFunctionBodyForCodeCompletion()) { - BodyScope.Exit(); - return Actions.ActOnFinishFunctionBody(Decl, 0); - } + if (SkipFunctionBodies && trySkippingFunctionBody()) { + BodyScope.Exit(); + return Actions.ActOnFinishFunctionBody(Decl, 0); } PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, @@ -1930,9 +1972,11 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { StmtResult FnBody(ParseCompoundStatementBody()); // If the function body could not be parsed, make a bogus compoundstmt. - if (FnBody.isInvalid()) + if (FnBody.isInvalid()) { + Sema::CompoundScopeRAII CompoundScope(Actions); FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); + } BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); @@ -1956,36 +2000,36 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { else Actions.ActOnDefaultCtorInitializers(Decl); - if (PP.isCodeCompletionEnabled()) { - if (trySkippingFunctionBodyForCodeCompletion()) { - BodyScope.Exit(); - return Actions.ActOnFinishFunctionBody(Decl, 0); - } + if (SkipFunctionBodies && trySkippingFunctionBody()) { + BodyScope.Exit(); + return Actions.ActOnFinishFunctionBody(Decl, 0); } SourceLocation LBraceLoc = Tok.getLocation(); StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); // If we failed to parse the try-catch, we just give the function an empty // compound statement as the body. - if (FnBody.isInvalid()) + if (FnBody.isInvalid()) { + Sema::CompoundScopeRAII CompoundScope(Actions); FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); + } BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } -bool Parser::trySkippingFunctionBodyForCodeCompletion() { +bool Parser::trySkippingFunctionBody() { assert(Tok.is(tok::l_brace)); - assert(PP.isCodeCompletionEnabled() && - "Should only be called when in code-completion mode"); + assert(SkipFunctionBodies && + "Should only be called when SkipFunctionBodies is enabled"); // We're in code-completion mode. Skip parsing for all function bodies unless // the body contains the code-completion point. TentativeParsingAction PA(*this); ConsumeBrace(); if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false, - /*StopAtCodeCompletion=*/true)) { + /*StopAtCodeCompletion=*/PP.isCodeCompletionEnabled())) { PA.Commit(); return true; } @@ -2035,10 +2079,13 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { return move(TryBlock); // Borland allows SEH-handlers with 'try' - if(Tok.is(tok::kw___except) || Tok.is(tok::kw___finally)) { + + if((Tok.is(tok::identifier) && + Tok.getIdentifierInfo() == getSEHExceptKeyword()) || + Tok.is(tok::kw___finally)) { // TODO: Factor into common return ParseSEHHandlerCommon(...) StmtResult Handler; - if(Tok.is(tok::kw___except)) { + if(Tok.getIdentifierInfo() == getSEHExceptKeyword()) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHExceptBlock(Loc); } @@ -2130,19 +2177,51 @@ StmtResult Parser::ParseCXXCatchBlock() { } void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { - bool Result; + IfExistsCondition Result; if (ParseMicrosoftIfExistsCondition(Result)) return; - if (Tok.isNot(tok::l_brace)) { + // Handle dependent statements by parsing the braces as a compound statement. + // This is not the same behavior as Visual C++, which don't treat this as a + // compound statement, but for Clang's type checking we can't have anything + // inside these braces escaping to the surrounding code. + if (Result.Behavior == IEB_Dependent) { + if (!Tok.is(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + + ParsedAttributes Attrs(AttrFactory); + StmtResult Compound = ParseCompoundStatement(Attrs); + if (Compound.isInvalid()) + return; + + StmtResult DepResult = Actions.ActOnMSDependentExistsStmt(Result.KeywordLoc, + Result.IsIfExists, + Result.SS, + Result.Name, + Compound.get()); + if (DepResult.isUsable()) + Stmts.push_back(DepResult.get()); + return; + } + + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected_lbrace); return; } - ConsumeBrace(); - // Condition is false skip all inside the {}. - if (!Result) { - SkipUntil(tok::r_brace, false); + switch (Result.Behavior) { + case IEB_Parse: + // Parse the statements below. + break; + + case IEB_Dependent: + llvm_unreachable("Dependent case handled above"); + + case IEB_Skip: + Braces.skipToEnd(); return; } @@ -2152,10 +2231,5 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { if (R.isUsable()) Stmts.push_back(R.release()); } - - if (Tok.isNot(tok::r_brace)) { - Diag(Tok, diag::err_expected_rbrace); - return; - } - ConsumeBrace(); + Braces.consumeClose(); } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp index 3d68a4a..61cd9f2 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp @@ -31,8 +31,9 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context, ObjCDeclContextSwitch ObjCDC(*this); if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) { - return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(), - DeclEnd); + return ParseExplicitInstantiation(Context, + SourceLocation(), ConsumeToken(), + DeclEnd, AS); } return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS, AccessAttrs); @@ -240,6 +241,10 @@ Parser::ParseSingleDeclarationAfterTemplate( return 0; } + LateParsedAttrList LateParsedAttrs; + if (DeclaratorInfo.isFunctionDeclarator()) + MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + // If we have a declaration or declarator list, handle it. if (isDeclarationAfterDeclarator()) { // Parse this declaration. @@ -255,6 +260,8 @@ Parser::ParseSingleDeclarationAfterTemplate( // Eat the semi colon after the declaration. ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + if (LateParsedAttrs.size() > 0) + ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false); DeclaratorInfo.complete(ThisDecl); return ThisDecl; } @@ -262,20 +269,15 @@ Parser::ParseSingleDeclarationAfterTemplate( if (DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo)) { if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { - Diag(Tok, diag::err_function_declared_typedef); - - if (Tok.is(tok::l_brace)) { - // This recovery skips the entire function body. It would be nice - // to simply call ParseFunctionDefinition() below, however Sema - // assumes the declarator represents a function, not a typedef. - ConsumeBrace(); - SkipUntil(tok::r_brace, true); - } else { - SkipUntil(tok::semi); - } - return 0; + // Recover by ignoring the 'typedef'. This was probably supposed to be + // the 'typename' keyword, which we should have already suggested adding + // if it's appropriate. + Diag(DS.getStorageClassSpecLoc(), diag::err_function_declared_typedef) + << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); + DS.ClearStorageClassSpecs(); } - return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo); + return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo, + &LateParsedAttrs); } if (DeclaratorInfo.isFunctionDeclarator()) @@ -307,14 +309,19 @@ bool Parser::ParseTemplateParameters(unsigned Depth, LAngleLoc = ConsumeToken(); // Try to parse the template parameter list. - if (Tok.is(tok::greater)) - RAngleLoc = ConsumeToken(); - else if (ParseTemplateParameterList(Depth, TemplateParams)) { - if (!Tok.is(tok::greater)) { - Diag(Tok.getLocation(), diag::err_expected_greater); - return true; - } + bool Failed = false; + if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) + Failed = ParseTemplateParameterList(Depth, TemplateParams); + + if (Tok.is(tok::greatergreater)) { + Tok.setKind(tok::greater); + RAngleLoc = Tok.getLocation(); + Tok.setLocation(Tok.getLocation().getLocWithOffset(1)); + } else if (Tok.is(tok::greater)) RAngleLoc = ConsumeToken(); + else if (Failed) { + Diag(Tok.getLocation(), diag::err_expected_greater); + return true; } return false; } @@ -337,23 +344,21 @@ Parser::ParseTemplateParameterList(unsigned Depth, } else { // If we failed to parse a template parameter, skip until we find // a comma or closing brace. - SkipUntil(tok::comma, tok::greater, true, true); + SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true); } // Did we find a comma or the end of the template parmeter list? if (Tok.is(tok::comma)) { ConsumeToken(); - } else if (Tok.is(tok::greater)) { + } else if (Tok.is(tok::greater) || Tok.is(tok::greatergreater)) { // Don't consume this... that's done by template parser. break; } else { // Somebody probably forgot to close the template. Skip ahead and // try to get out of the expression. This error is currently // subsumed by whatever goes on in ParseTemplateParameter. - // TODO: This could match >>, and it would be nice to avoid those - // silly errors with template <vec<T>>. Diag(Tok.getLocation(), diag::err_expected_comma_greater); - SkipUntil(tok::greater, true, true); + SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true); return false; } } @@ -476,7 +481,7 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { EllipsisLoc = ConsumeToken(); Diag(EllipsisLoc, - getLang().CPlusPlus0x + getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_variadic_templates : diag::ext_variadic_templates); } @@ -488,7 +493,7 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { ParamName = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); } else if (Tok.is(tok::equal) || Tok.is(tok::comma) || - Tok.is(tok::greater)) { + Tok.is(tok::greater) || Tok.is(tok::greatergreater)) { // Unnamed template parameter. Don't have to do anything here, just // don't consume this token. } else { @@ -503,9 +508,10 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { ParsedType DefaultArg; if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); - DefaultArg = ParseTypeName().get(); + DefaultArg = ParseTypeName(/*Range=*/0, + Declarator::TemplateTypeArgContext).get(); } - + return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, Ellipsis, EllipsisLoc, KeyLoc, ParamName, NameLoc, Depth, Position, EqualLoc, DefaultArg); @@ -536,13 +542,25 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { } // Generate a meaningful error if the user forgot to put class before the - // identifier, comma, or greater. + // identifier, comma, or greater. Provide a fixit if the identifier, comma, + // or greater appear immediately or after 'typename' or 'struct'. In the + // latter case, replace the keyword with 'class'. if (!Tok.is(tok::kw_class)) { - Diag(Tok.getLocation(), diag::err_expected_class_before) - << PP.getSpelling(Tok); - return 0; - } - ConsumeToken(); + bool Replace = Tok.is(tok::kw_typename) || Tok.is(tok::kw_struct); + const Token& Next = Replace ? NextToken() : Tok; + if (Next.is(tok::identifier) || Next.is(tok::comma) || + Next.is(tok::greater) || Next.is(tok::greatergreater) || + Next.is(tok::ellipsis)) + Diag(Tok.getLocation(), diag::err_class_on_template_template_param) + << (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class") + : FixItHint::CreateInsertion(Tok.getLocation(), "class ")); + else + Diag(Tok.getLocation(), diag::err_class_on_template_template_param); + + if (Replace) + ConsumeToken(); + } else + ConsumeToken(); // Parse the ellipsis, if given. SourceLocation EllipsisLoc; @@ -550,7 +568,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { EllipsisLoc = ConsumeToken(); Diag(EllipsisLoc, - getLang().CPlusPlus0x + getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_variadic_templates : diag::ext_variadic_templates); } @@ -561,7 +579,8 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { if (Tok.is(tok::identifier)) { ParamName = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); - } else if (Tok.is(tok::equal) || Tok.is(tok::comma) || Tok.is(tok::greater)) { + } else if (Tok.is(tok::equal) || Tok.is(tok::comma) || + Tok.is(tok::greater) || Tok.is(tok::greatergreater)) { // Unnamed template parameter. Don't have to do anything here, just // don't consume this token. } else { @@ -587,10 +606,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { if (DefaultArg.isInvalid()) { Diag(Tok.getLocation(), diag::err_default_template_template_parameter_not_template); - static const tok::TokenKind EndToks[] = { - tok::comma, tok::greater, tok::greatergreater - }; - SkipUntil(EndToks, 3, true, true); + SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true); } } @@ -618,12 +634,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { Declarator ParamDecl(DS, Declarator::TemplateParamContext); ParseDeclarator(ParamDecl); if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { - // This probably shouldn't happen - and it's more of a Sema thing, but - // basically we didn't parse the type name because we couldn't associate - // it with an AST node. we should just skip to the comma or greater. - // TODO: This is currently a placeholder for some kind of Sema Error. - Diag(Tok.getLocation(), diag::err_parse_error); - SkipUntil(tok::comma, tok::greater, true, true); + Diag(Tok.getLocation(), diag::err_expected_template_parameter); return 0; } @@ -709,15 +720,15 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, RAngleLoc = Tok.getLocation(); if (Tok.is(tok::greatergreater)) { - if (!getLang().CPlusPlus0x) { - const char *ReplaceStr = "> >"; - if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater)) - ReplaceStr = "> > "; - - Diag(Tok.getLocation(), diag::err_two_right_angle_brackets_need_space) - << FixItHint::CreateReplacement( - SourceRange(Tok.getLocation()), ReplaceStr); - } + const char *ReplaceStr = "> >"; + if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater)) + ReplaceStr = "> > "; + + Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_two_right_angle_brackets : + diag::err_two_right_angle_brackets_need_space) + << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), + ReplaceStr); Tok.setKind(tok::greater); if (!ConsumeLastToken) { @@ -770,10 +781,10 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, /// bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, CXXScopeSpec &SS, - UnqualifiedId &TemplateName, SourceLocation TemplateKWLoc, + UnqualifiedId &TemplateName, bool AllowTypeAnnotation) { - assert(getLang().CPlusPlus && "Can only annotate template-ids in C++"); + assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++"); assert(Template && Tok.is(tok::less) && "Parser isn't at the beginning of a template-id"); @@ -803,10 +814,9 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { TypeResult Type - = Actions.ActOnTemplateIdType(SS, + = Actions.ActOnTemplateIdType(SS, TemplateKWLoc, Template, TemplateNameLoc, - LAngleLoc, TemplateArgsPtr, - RAngleLoc); + LAngleLoc, TemplateArgsPtr, RAngleLoc); if (Type.isInvalid()) { // If we failed to parse the template ID but skipped ahead to a >, we're not // going to be able to form a token annotation. Eat the '>' if present. @@ -838,6 +848,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateId->Operator = TemplateName.OperatorFunctionId.Operator; } TemplateId->SS = SS; + TemplateId->TemplateKWLoc = TemplateKWLoc; TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; @@ -883,6 +894,7 @@ void Parser::AnnotateTemplateIdTokenAsType() { TypeResult Type = Actions.ActOnTemplateIdType(TemplateId->SS, + TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, @@ -932,7 +944,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { if (SS.isSet() && Tok.is(tok::kw_template)) { // Parse the optional 'template' keyword following the // nested-name-specifier. - SourceLocation TemplateLoc = ConsumeToken(); + SourceLocation TemplateKWLoc = ConsumeToken(); if (Tok.is(tok::identifier)) { // We appear to have a dependent template name. @@ -949,8 +961,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { // template argument. TemplateTy Template; if (isEndOfTemplateArgument(Tok) && - Actions.ActOnDependentTemplateName(getCurScope(), TemplateLoc, - SS, Name, + Actions.ActOnDependentTemplateName(getCurScope(), + SS, TemplateKWLoc, Name, /*ObjectType=*/ ParsedType(), /*EnteringContext=*/false, Template)) @@ -1033,7 +1045,7 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { // Parse a non-type template argument. SourceLocation Loc = Tok.getLocation(); - ExprResult ExprArg = ParseConstantExpression(); + ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast); if (ExprArg.isInvalid() || !ExprArg.get()) return ParsedTemplateArgument(); @@ -1113,17 +1125,19 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { /// 'extern' [opt] 'template' declaration /// /// Note that the 'extern' is a GNU extension and C++0x feature. -Decl *Parser::ParseExplicitInstantiation(SourceLocation ExternLoc, +Decl *Parser::ParseExplicitInstantiation(unsigned Context, + SourceLocation ExternLoc, SourceLocation TemplateLoc, - SourceLocation &DeclEnd) { + SourceLocation &DeclEnd, + AccessSpecifier AS) { // This isn't really required here. ParsingDeclRAIIObject ParsingTemplateParams(*this); - return ParseSingleDeclarationAfterTemplate(Declarator::FileContext, + return ParseSingleDeclarationAfterTemplate(Context, ParsedTemplateInfo(ExternLoc, TemplateLoc), ParsingTemplateParams, - DeclEnd, AS_none); + DeclEnd, AS); } SourceRange Parser::ParsedTemplateInfo::getSourceRange() const { @@ -1157,29 +1171,27 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { if(!LMT.D) return; - // If this is a member template, introduce the template parameter scope. - ParseScope TemplateScope(this, Scope::TemplateParamScope); - // Get the FunctionDecl. FunctionDecl *FD = 0; if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LMT.D)) FD = FunTmpl->getTemplatedDecl(); else FD = cast<FunctionDecl>(LMT.D); - - // Reinject the template parameters. + + // To restore the context after late parsing. + Sema::ContextRAII GlobalSavedContext(Actions, Actions.CurContext); + SmallVector<ParseScope*, 4> TemplateParamScopeStack; DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD); if (Declarator && Declarator->getNumTemplateParameterLists() != 0) { + TemplateParamScopeStack.push_back(new ParseScope(this, Scope::TemplateParamScope)); Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); } else { - Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); - // Get the list of DeclContext to reenter. SmallVector<DeclContext*, 4> DeclContextToReenter; DeclContext *DD = FD->getLexicalParent(); - while (DD && DD->isRecord()) { + while (DD && !DD->isTranslationUnit()) { DeclContextToReenter.push_back(DD); DD = DD->getLexicalParent(); } @@ -1190,7 +1202,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { for (; II != DeclContextToReenter.rend(); ++II) { if (ClassTemplatePartialSpecializationDecl* MD = dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) { - TemplateParamScopeStack.push_back(new ParseScope(this, + TemplateParamScopeStack.push_back(new ParseScope(this, Scope::TemplateParamScope)); Actions.ActOnReenterTemplateScope(getCurScope(), MD); } else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(*II)) { @@ -1200,8 +1212,14 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { Actions.ActOnReenterTemplateScope(getCurScope(), MD->getDescribedClassTemplate()); } + TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); + Actions.PushDeclContext(Actions.getCurScope(), *II); } + TemplateParamScopeStack.push_back(new ParseScope(this, + Scope::TemplateParamScope)); + Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); } + assert(!LMT.Toks.empty() && "Empty body!"); // Append the current token at the end of the new token stream so that it @@ -1218,8 +1236,8 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { // to be re-used for method bodies as well. ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); - // Recreate the DeclContext. - Sema::ContextRAII SavedContext(Actions, Actions.getContainingDC(FD)); + // Recreate the containing function DeclContext. + Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FD)); if (FunctionTemplateDecl *FunctionTemplate = dyn_cast_or_null<FunctionTemplateDecl>(LMT.D)) @@ -1227,7 +1245,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { FunctionTemplate->getTemplatedDecl()); if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(LMT.D)) Actions.ActOnStartOfFunctionDef(getCurScope(), Function); - + if (Tok.is(tok::kw_try)) { ParseFunctionTryBlock(LMT.D, FnScope); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp index d53839f..28c5e8b 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp @@ -62,7 +62,7 @@ bool Parser::isCXXDeclarationStatement() { return true; // simple-declaration default: - return isCXXSimpleDeclaration(); + return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false); } } @@ -75,7 +75,11 @@ bool Parser::isCXXDeclarationStatement() { /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' /// -bool Parser::isCXXSimpleDeclaration() { +/// (if AllowForRangeDecl specified) +/// for ( for-range-declaration : for-range-initializer ) statement +/// for-range-declaration: +/// attribute-specifier-seqopt type-specifier-seq declarator +bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { // C++ 6.8p1: // There is an ambiguity in the grammar involving expression-statements and // declarations: An expression-statement with a function-style explicit type @@ -112,7 +116,7 @@ bool Parser::isCXXSimpleDeclaration() { // We need tentative parsing... TentativeParsingAction PA(*this); - TPR = TryParseSimpleDeclaration(); + TPR = TryParseSimpleDeclaration(AllowForRangeDecl); PA.Revert(); // In case of an error, let the declaration parsing code handle it. @@ -130,7 +134,12 @@ bool Parser::isCXXSimpleDeclaration() { /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' /// -Parser::TPResult Parser::TryParseSimpleDeclaration() { +/// (if AllowForRangeDecl specified) +/// for ( for-range-declaration : for-range-initializer ) statement +/// for-range-declaration: +/// attribute-specifier-seqopt type-specifier-seq declarator +/// +Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { // We know that we have a simple-type-specifier/typename-specifier followed // by a '('. assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous()); @@ -140,7 +149,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration() { else { ConsumeToken(); - if (getLang().ObjC1 && Tok.is(tok::less)) + if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } @@ -150,7 +159,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration() { if (TPR != TPResult::Ambiguous()) return TPR; - if (Tok.isNot(tok::semi)) + if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon))) return TPResult::False(); return TPResult::Ambiguous(); @@ -224,6 +233,8 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { /// condition: /// expression /// type-specifier-seq declarator '=' assignment-expression +/// [C++11] type-specifier-seq declarator '=' initializer-clause +/// [C++11] type-specifier-seq declarator braced-init-list /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// @@ -247,7 +258,7 @@ bool Parser::isCXXConditionDeclaration() { else { ConsumeToken(); - if (getLang().ObjC1 && Tok.is(tok::less)) + if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } assert(Tok.is(tok::l_paren) && "Expected '('"); @@ -265,6 +276,8 @@ bool Parser::isCXXConditionDeclaration() { if (Tok.is(tok::equal) || Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) TPR = TPResult::True(); + else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) + TPR = TPResult::True(); else TPR = TPResult::False(); } @@ -322,7 +335,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { else { ConsumeToken(); - if (getLang().ObjC1 && Tok.is(tok::less)) + if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } @@ -347,7 +360,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { // ',', this is a type-id. Otherwise, it's an expression. } else if (Context == TypeIdAsTemplateArgument && (Tok.is(tok::greater) || Tok.is(tok::comma) || - (getLang().CPlusPlus0x && Tok.is(tok::greatergreater)))) { + (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) { TPR = TPResult::True(); isAmbiguous = true; @@ -361,91 +374,166 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { return TPR == TPResult::True(); } -/// isCXX0XAttributeSpecifier - returns true if this is a C++0x -/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is -/// performed that will simply return true if a [[ is seen. Currently C++ has no -/// syntactical ambiguities from this check, but it may inhibit error recovery. -/// If CheckClosing is true, a check is made for closing ]] brackets. +/// \brief Returns true if this is a C++11 attribute-specifier. Per +/// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens +/// always introduce an attribute. In Objective-C++11, this rule does not +/// apply if either '[' begins a message-send. +/// +/// If Disambiguate is true, we try harder to determine whether a '[[' starts +/// an attribute-specifier, and return CAK_InvalidAttributeSpecifier if not. /// -/// If given, After is set to the token after the attribute-specifier so that -/// appropriate parsing decisions can be made; it is left untouched if false is -/// returned. +/// If OuterMightBeMessageSend is true, we assume the outer '[' is either an +/// Obj-C message send or the start of an attribute. Otherwise, we assume it +/// is not an Obj-C message send. /// -/// FIXME: If an error is in the closing ]] brackets, the program assumes -/// the absence of an attribute-specifier, which can cause very yucky errors -/// to occur. +/// C++11 [dcl.attr.grammar]: /// -/// [C++0x] attribute-specifier: +/// attribute-specifier: /// '[' '[' attribute-list ']' ']' /// alignment-specifier /// -/// [C++0x] attribute-list: +/// attribute-list: /// attribute[opt] /// attribute-list ',' attribute[opt] +/// attribute '...' +/// attribute-list ',' attribute '...' /// -/// [C++0x] attribute: +/// attribute: /// attribute-token attribute-argument-clause[opt] /// -/// [C++0x] attribute-token: -/// identifier -/// attribute-scoped-token -/// -/// [C++0x] attribute-scoped-token: -/// attribute-namespace '::' identifier -/// -/// [C++0x] attribute-namespace: +/// attribute-token: /// identifier +/// identifier '::' identifier /// -/// [C++0x] attribute-argument-clause: +/// attribute-argument-clause: /// '(' balanced-token-seq ')' -/// -/// [C++0x] balanced-token-seq: -/// balanced-token -/// balanced-token-seq balanced-token -/// -/// [C++0x] balanced-token: -/// '(' balanced-token-seq ')' -/// '[' balanced-token-seq ']' -/// '{' balanced-token-seq '}' -/// any token but '(', ')', '[', ']', '{', or '}' -bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, - tok::TokenKind *After) { +Parser::CXX11AttributeKind +Parser::isCXX11AttributeSpecifier(bool Disambiguate, + bool OuterMightBeMessageSend) { if (Tok.is(tok::kw_alignas)) - return true; + return CAK_AttributeSpecifier; if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) - return false; - - // No tentative parsing if we don't need to look for ]] - if (!CheckClosing && !getLang().ObjC1) - return true; - - struct TentativeReverter { - TentativeParsingAction PA; + return CAK_NotAttributeSpecifier; - TentativeReverter (Parser& P) - : PA(P) - {} - ~TentativeReverter () { - PA.Revert(); - } - } R(*this); + // No tentative parsing if we don't need to look for ']]' or a lambda. + if (!Disambiguate && !getLangOpts().ObjC1) + return CAK_AttributeSpecifier; + + TentativeParsingAction PA(*this); // Opening brackets were checked for above. ConsumeBracket(); - ConsumeBracket(); - // SkipUntil will handle balanced tokens, which are guaranteed in attributes. - SkipUntil(tok::r_square, false); + // Outside Obj-C++11, treat anything with a matching ']]' as an attribute. + if (!getLangOpts().ObjC1) { + ConsumeBracket(); + + bool IsAttribute = SkipUntil(tok::r_square, false); + IsAttribute &= Tok.is(tok::r_square); + + PA.Revert(); + + return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier; + } + + // In Obj-C++11, we need to distinguish four situations: + // 1a) int x[[attr]]; C++11 attribute. + // 1b) [[attr]]; C++11 statement attribute. + // 2) int x[[obj](){ return 1; }()]; Lambda in array size/index. + // 3a) int x[[obj get]]; Message send in array size/index. + // 3b) [[Class alloc] init]; Message send in message send. + // 4) [[obj]{ return self; }() doStuff]; Lambda in message send. + // (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted. + + // If we have a lambda-introducer, then this is definitely not a message send. + // FIXME: If this disambiguation is too slow, fold the tentative lambda parse + // into the tentative attribute parse below. + LambdaIntroducer Intro; + if (!TryParseLambdaIntroducer(Intro)) { + // A lambda cannot end with ']]', and an attribute must. + bool IsAttribute = Tok.is(tok::r_square); + + PA.Revert(); + + if (IsAttribute) + // Case 1: C++11 attribute. + return CAK_AttributeSpecifier; + + if (OuterMightBeMessageSend) + // Case 4: Lambda in message send. + return CAK_NotAttributeSpecifier; + + // Case 2: Lambda in array size / index. + return CAK_InvalidAttributeSpecifier; + } - if (Tok.isNot(tok::r_square)) - return false; ConsumeBracket(); - if (After) - *After = Tok.getKind(); + // If we don't have a lambda-introducer, then we have an attribute or a + // message-send. + bool IsAttribute = true; + while (Tok.isNot(tok::r_square)) { + if (Tok.is(tok::comma)) { + // Case 1: Stray commas can only occur in attributes. + PA.Revert(); + return CAK_AttributeSpecifier; + } + + // Parse the attribute-token, if present. + // C++11 [dcl.attr.grammar]: + // If a keyword or an alternative token that satisfies the syntactic + // requirements of an identifier is contained in an attribute-token, + // it is considered an identifier. + SourceLocation Loc; + if (!TryParseCXX11AttributeIdentifier(Loc)) { + IsAttribute = false; + break; + } + if (Tok.is(tok::coloncolon)) { + ConsumeToken(); + if (!TryParseCXX11AttributeIdentifier(Loc)) { + IsAttribute = false; + break; + } + } - return true; + // Parse the attribute-argument-clause, if present. + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + if (!SkipUntil(tok::r_paren, false)) { + IsAttribute = false; + break; + } + } + + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + } + + // An attribute must end ']]'. + if (IsAttribute) { + if (Tok.is(tok::r_square)) { + ConsumeBracket(); + IsAttribute = Tok.is(tok::r_square); + } else { + IsAttribute = false; + } + } + + PA.Revert(); + + if (IsAttribute) + // Case 1: C++11 statement attribute. + return CAK_AttributeSpecifier; + + // Case 3: Message send. + return CAK_NotAttributeSpecifier; } /// declarator: @@ -540,7 +628,8 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, ConsumeParen(); if (mayBeAbstract && (Tok.is(tok::r_paren) || // 'int()' is a function. - Tok.is(tok::ellipsis) || // 'int(...)' is a function. + // 'int(...)' is a function. + (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) || isDeclarationSpecifier())) { // 'int(int)' is a function. // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] // exception-specification[opt] @@ -670,11 +759,14 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_convertible_to: case tok::kw___is_empty: case tok::kw___is_enum: + case tok::kw___is_final: case tok::kw___is_literal: case tok::kw___is_literal_type: case tok::kw___is_pod: case tok::kw___is_polymorphic: case tok::kw___is_trivial: + case tok::kw___is_trivially_assignable: + case tok::kw___is_trivially_constructible: case tok::kw___is_trivially_copyable: case tok::kw___is_union: case tok::kw___uuidof: @@ -690,6 +782,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_int: case tok::kw_long: case tok::kw___int64: + case tok::kw___int128: case tok::kw_restrict: case tok::kw_short: case tok::kw_signed: @@ -705,7 +798,6 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_wchar_t: case tok::kw_char16_t: case tok::kw_char32_t: - case tok::kw_decltype: case tok::kw___underlying_type: case tok::kw_thread_local: case tok::kw__Decimal32: @@ -825,7 +917,8 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { /// 'volatile' /// [GNU] restrict /// -Parser::TPResult Parser::isCXXDeclarationSpecifier() { +Parser::TPResult +Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { switch (Tok.getKind()) { case tok::identifier: // foo::bar // Check for need to substitute AltiVec __vector keyword @@ -840,21 +933,22 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { return TPResult::Error(); if (Tok.is(tok::identifier)) return TPResult::False(); - return isCXXDeclarationSpecifier(); + return isCXXDeclarationSpecifier(BracedCastResult); case tok::coloncolon: { // ::foo::bar const Token &Next = NextToken(); if (Next.is(tok::kw_new) || // ::new Next.is(tok::kw_delete)) // ::delete return TPResult::False(); - + } + // Fall through. + case tok::kw_decltype: // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); - return isCXXDeclarationSpecifier(); - } - + return isCXXDeclarationSpecifier(BracedCastResult); + // decl-specifier: // storage-class-specifier // type-specifier @@ -940,8 +1034,31 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { // We've already annotated a scope; try to annotate a type. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); - if (!Tok.is(tok::annot_typename)) + if (!Tok.is(tok::annot_typename)) { + // If the next token is an identifier or a type qualifier, then this + // can't possibly be a valid expression either. + if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) { + CXXScopeSpec SS; + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) { + TentativeParsingAction PA(*this); + ConsumeToken(); + ConsumeToken(); + bool isIdentifier = Tok.is(tok::identifier); + TPResult TPR = TPResult::False(); + if (!isIdentifier) + TPR = isCXXDeclarationSpecifier(BracedCastResult); + PA.Revert(); + + if (isIdentifier || + TPR == TPResult::True() || TPR == TPResult::Error()) + return TPResult::Error(); + } + } return TPResult::False(); + } // If that succeeded, fallthrough into the generic simple-type-id case. // The ambiguity resides in a simple-type-specifier/typename-specifier @@ -965,13 +1082,14 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::annot_typename: case_typename: // In Objective-C, we might have a protocol-qualified type. - if (getLang().ObjC1 && NextToken().is(tok::less)) { + if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { // Tentatively parse the TentativeParsingAction PA(*this); ConsumeToken(); // The type token TPResult TPR = TryParseProtocolQualifiers(); bool isFollowedByParen = Tok.is(tok::l_paren); + bool isFollowedByBrace = Tok.is(tok::l_brace); PA.Revert(); @@ -980,6 +1098,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { if (isFollowedByParen) return TPResult::Ambiguous(); + + if (getLangOpts().CPlusPlus0x && isFollowedByBrace) + return BracedCastResult; return TPResult::True(); } @@ -993,15 +1114,26 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_int: case tok::kw_long: case tok::kw___int64: + case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_void: + case tok::annot_decltype: if (NextToken().is(tok::l_paren)) return TPResult::Ambiguous(); + // This is a function-style cast in all cases we disambiguate other than + // one: + // struct S { + // enum E : int { a = 4 }; // enum + // enum E : int { 4 }; // bit-field + // }; + if (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace)) + return BracedCastResult; + if (isStartOfObjCClassMessageMissingOpenBracket()) return TPResult::False(); @@ -1016,6 +1148,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { TPResult TPR = TryParseTypeofSpecifier(); bool isFollowedByParen = Tok.is(tok::l_paren); + bool isFollowedByBrace = Tok.is(tok::l_brace); PA.Revert(); @@ -1025,18 +1158,17 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { if (isFollowedByParen) return TPResult::Ambiguous(); - return TPResult::True(); - } + if (getLangOpts().CPlusPlus0x && isFollowedByBrace) + return BracedCastResult; - // C++0x decltype support. - case tok::kw_decltype: return TPResult::True(); + } // C++0x type traits support case tok::kw___underlying_type: return TPResult::True(); - // C1x _Atomic + // C11 _Atomic case tok::kw__Atomic: return TPResult::True(); @@ -1096,7 +1228,7 @@ Parser::TPResult Parser::TryParseDeclarationSpecifier() { else { ConsumeToken(); - if (getLang().ObjC1 && Tok.is(tok::less)) + if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } @@ -1160,11 +1292,13 @@ bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) { /// parameter-declaration-list ',' parameter-declaration /// /// parameter-declaration: -/// decl-specifier-seq declarator attributes[opt] -/// decl-specifier-seq declarator attributes[opt] '=' assignment-expression -/// decl-specifier-seq abstract-declarator[opt] attributes[opt] -/// decl-specifier-seq abstract-declarator[opt] attributes[opt] +/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] +/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] /// '=' assignment-expression +/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] +/// attributes[opt] +/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] +/// attributes[opt] '=' assignment-expression /// Parser::TPResult Parser::TryParseParameterDeclarationClause() { @@ -1182,13 +1316,23 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { // '...'[opt] if (Tok.is(tok::ellipsis)) { ConsumeToken(); - return TPResult::True(); // '...' is a sign of a function declarator. + if (Tok.is(tok::r_paren)) + return TPResult::True(); // '...)' is a sign of a function declarator. + else + return TPResult::False(); } + // An attribute-specifier-seq here is a sign of a function declarator. + if (isCXX11AttributeSpecifier(/*Disambiguate*/false, + /*OuterMightBeMessageSend*/true)) + return TPResult::True(); + ParsedAttributes attrs(AttrFactory); MaybeParseMicrosoftAttributes(attrs); // decl-specifier-seq + // A parameter-declaration's initializer must be preceded by an '=', so + // decl-specifier-seq '{' is not a parameter in C++11. TPResult TPR = TryParseDeclarationSpecifier(); if (TPR != TPResult::Ambiguous()) return TPR; @@ -1206,14 +1350,17 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { if (Tok.is(tok::equal)) { // '=' assignment-expression // Parse through assignment-expression. - tok::TokenKind StopToks[2] ={ tok::comma, tok::r_paren }; - if (!SkipUntil(StopToks, 2, true/*StopAtSemi*/, true/*DontConsume*/)) + if (!SkipUntil(tok::comma, tok::r_paren, true/*StopAtSemi*/, + true/*DontConsume*/)) return TPResult::Error(); } if (Tok.is(tok::ellipsis)) { ConsumeToken(); - return TPResult::True(); // '...' is a sign of a function declarator. + if (Tok.is(tok::r_paren)) + return TPResult::True(); // '...)' is a sign of a function declarator. + else + return TPResult::False(); } if (Tok.isNot(tok::comma)) diff --git a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp index c909643..054a8fd 100644 --- a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp @@ -23,15 +23,24 @@ #include "clang/AST/ASTConsumer.h" using namespace clang; -Parser::Parser(Preprocessor &pp, Sema &actions) +IdentifierInfo *Parser::getSEHExceptKeyword() { + // __except is accepted as a (contextual) keyword + if (!Ident__except && (getLangOpts().MicrosoftExt || getLangOpts().Borland)) + Ident__except = PP.getIdentifierInfo("__except"); + + return Ident__except; +} + +Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies) : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), ColonIsSacred(false), - InMessageExpression(false), TemplateParameterDepth(0) { + InMessageExpression(false), TemplateParameterDepth(0), + SkipFunctionBodies(SkipFunctionBodies) { Tok.setKind(tok::eof); Actions.CurScope = 0; NumCachedScopes = 0; ParenCount = BracketCount = BraceCount = 0; - ObjCImpDecl = 0; + CurParsedObjCImpl = 0; // Add #pragma handlers. These are removed and destroyed in the // destructor. @@ -56,10 +65,13 @@ Parser::Parser(Preprocessor &pp, Sema &actions) WeakHandler.reset(new PragmaWeakHandler(actions)); PP.AddPragmaHandler(WeakHandler.get()); + RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler(actions)); + PP.AddPragmaHandler(RedefineExtnameHandler.get()); + FPContractHandler.reset(new PragmaFPContractHandler(actions, *this)); PP.AddPragmaHandler("STDC", FPContractHandler.get()); - if (getLang().OpenCL) { + if (getLangOpts().OpenCL) { OpenCLExtensionHandler.reset( new PragmaOpenCLExtensionHandler(actions, *this)); PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get()); @@ -202,15 +214,14 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) { /// /// If SkipUntil finds the specified token, it returns true, otherwise it /// returns false. -bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, - bool StopAtSemi, bool DontConsume, - bool StopAtCodeCompletion) { +bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi, + bool DontConsume, bool StopAtCodeCompletion) { // We always want this function to skip at least one token if the first token // isn't T and if not at EOF. bool isFirstTokenSkipped = true; while (1) { // If we found one of the tokens, stop and return true. - for (unsigned i = 0; i != NumToks; ++i) { + for (unsigned i = 0, NumToks = Toks.size(); i != NumToks; ++i) { if (Tok.is(Toks[i])) { if (DontConsume) { // Noop, don't consume the token. @@ -276,9 +287,6 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, ConsumeStringToken(); break; - case tok::at: - return false; - case tok::semi: if (StopAtSemi) return false; @@ -377,8 +385,10 @@ Parser::~Parser() { UnusedHandler.reset(); PP.RemovePragmaHandler(WeakHandler.get()); WeakHandler.reset(); + PP.RemovePragmaHandler(RedefineExtnameHandler.get()); + RedefineExtnameHandler.reset(); - if (getLang().OpenCL) { + if (getLangOpts().OpenCL) { PP.RemovePragmaHandler("OPENCL", OpenCLExtensionHandler.get()); OpenCLExtensionHandler.reset(); PP.RemovePragmaHandler("OPENCL", FPContractHandler.get()); @@ -401,12 +411,12 @@ void Parser::Initialize() { ConsumeToken(); if (Tok.is(tok::eof) && - !getLang().CPlusPlus) // Empty source file is an extension in C + !getLangOpts().CPlusPlus) // Empty source file is an extension in C Diag(Tok, diag::ext_empty_source_file); // Initialization for Objective-C context sensitive keywords recognition. // Referenced in Parser::ParseObjCTypeQualifierList. - if (getLang().ObjC1) { + if (getLangOpts().ObjC1) { ObjCTypeQuals[objc_in] = &PP.getIdentifierTable().get("in"); ObjCTypeQuals[objc_out] = &PP.getIdentifierTable().get("out"); ObjCTypeQuals[objc_inout] = &PP.getIdentifierTable().get("inout"); @@ -421,7 +431,7 @@ void Parser::Initialize() { Ident_super = &PP.getIdentifierTable().get("super"); - if (getLang().AltiVec) { + if (getLangOpts().AltiVec) { Ident_vector = &PP.getIdentifierTable().get("vector"); Ident_pixel = &PP.getIdentifierTable().get("pixel"); } @@ -431,11 +441,13 @@ void Parser::Initialize() { Ident_obsoleted = 0; Ident_unavailable = 0; + Ident__except = 0; + Ident__exception_code = Ident__exception_info = Ident__abnormal_termination = 0; Ident___exception_code = Ident___exception_info = Ident___abnormal_termination = 0; Ident_GetExceptionCode = Ident_GetExceptionInfo = Ident_AbnormalTermination = 0; - if(getLang().Borland) { + if(getLangOpts().Borland) { Ident__exception_info = PP.getIdentifierInfo("_exception_info"); Ident___exception_info = PP.getIdentifierInfo("__exception_info"); Ident_GetExceptionInfo = PP.getIdentifierInfo("GetExceptionInformation"); @@ -463,23 +475,30 @@ void Parser::Initialize() { bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool); + // Skip over the EOF token, flagging end of previous input for incremental + // processing + if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) + ConsumeToken(); + while (Tok.is(tok::annot_pragma_unused)) HandlePragmaUnused(); Result = DeclGroupPtrTy(); if (Tok.is(tok::eof)) { // Late template parsing can begin. - if (getLang().DelayedTemplateParsing) + if (getLangOpts().DelayedTemplateParsing) Actions.SetLateTemplateParser(LateTemplateParserCallback, this); + if (!PP.isIncrementalProcessingEnabled()) + Actions.ActOnEndOfTranslationUnit(); + //else don't tell Sema that we ended parsing: more input might come. - Actions.ActOnEndOfTranslationUnit(); return true; } ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); - + Result = ParseExternalDeclaration(attrs); return false; } @@ -534,16 +553,22 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, Decl *SingleDecl = 0; switch (Tok.getKind()) { + case tok::annot_pragma_vis: + HandlePragmaVisibility(); + return DeclGroupPtrTy(); + case tok::annot_pragma_pack: + HandlePragmaPack(); + return DeclGroupPtrTy(); case tok::semi: - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::ext_top_level_semi) - << FixItHint::CreateRemoval(Tok.getLocation()); + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_top_level_semi : diag::ext_top_level_semi) + << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); // TODO: Invoke action for top-level semicolon. return DeclGroupPtrTy(); case tok::r_brace: - Diag(Tok, diag::err_expected_external_declaration); + Diag(Tok, diag::err_extraneous_closing_brace); ConsumeBrace(); return DeclGroupPtrTy(); case tok::eof: @@ -572,10 +597,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, } case tok::at: return ParseObjCAtDirectives(); - break; case tok::minus: case tok::plus: - if (!getLang().ObjC1) { + if (!getLangOpts().ObjC1) { Diag(Tok, diag::err_expected_external_declaration); ConsumeToken(); return DeclGroupPtrTy(); @@ -584,7 +608,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, break; case tok::code_completion: Actions.CodeCompleteOrdinaryName(getCurScope(), - ObjCImpDecl? Sema::PCC_ObjCImplementation + CurParsedObjCImpl? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); cutOffParsing(); return DeclGroupPtrTy(); @@ -605,7 +629,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw_static: // Parse (then ignore) 'static' prior to a template instantiation. This is // a GCC extension that we intentionally do not support. - if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) { + if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_template)) { Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) << 0; SourceLocation DeclEnd; @@ -615,7 +639,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, goto dont_know; case tok::kw_inline: - if (getLang().CPlusPlus) { + if (getLangOpts().CPlusPlus) { tok::TokenKind NextKind = NextToken().getKind(); // Inline namespaces. Allowed as an extension even in C++03. @@ -638,13 +662,17 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, goto dont_know; case tok::kw_extern: - if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) { + if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_template)) { // Extern templates SourceLocation ExternLoc = ConsumeToken(); SourceLocation TemplateLoc = ConsumeToken(); + Diag(ExternLoc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_extern_template : + diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc); SourceLocation DeclEnd; return Actions.ConvertDeclToDeclGroup( - ParseExplicitInstantiation(ExternLoc, TemplateLoc, DeclEnd)); + ParseExplicitInstantiation(Declarator::FileContext, + ExternLoc, TemplateLoc, DeclEnd)); } // FIXME: Detect C++ linkage specifications here? goto dont_know; @@ -653,9 +681,6 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw___if_not_exists: ParseMicrosoftIfExistsExternalDeclaration(); return DeclGroupPtrTy(); - - case tok::kw___import_module__: - return ParseModuleImport(); default: dont_know: @@ -677,7 +702,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, /// declarator, continues a declaration or declaration list. bool Parser::isDeclarationAfterDeclarator() { // Check for '= delete' or '= default' - if (getLang().CPlusPlus && Tok.is(tok::equal)) { + if (getLangOpts().CPlusPlus && Tok.is(tok::equal)) { const Token &KW = NextToken(); if (KW.is(tok::kw_default) || KW.is(tok::kw_delete)) return false; @@ -688,7 +713,7 @@ bool Parser::isDeclarationAfterDeclarator() { Tok.is(tok::semi) || // int X(); -> not a function def Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def Tok.is(tok::kw___attribute) || // int X() __attr__ -> not a function def - (getLang().CPlusPlus && + (getLangOpts().CPlusPlus && Tok.is(tok::l_paren)); // int X(0) -> not a function def [C++] } @@ -700,11 +725,11 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { return true; // Handle K&R C argument lists: int X(f) int f; {} - if (!getLang().CPlusPlus && + if (!getLangOpts().CPlusPlus && Declarator.getFunctionTypeInfo().isKNRPrototype()) return isDeclarationSpecifier(); - if (getLang().CPlusPlus && Tok.is(tok::equal)) { + if (getLangOpts().CPlusPlus && Tok.is(tok::equal)) { const Token &KW = NextToken(); return KW.is(tok::kw_default) || KW.is(tok::kw_delete); } @@ -747,7 +772,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, // ObjC2 allows prefix attributes on class interfaces and protocols. // FIXME: This still needs better diagnostics. We should only accept // attributes here, no types, etc. - if (getLang().ObjC2 && Tok.is(tok::at)) { + if (getLangOpts().ObjC2 && Tok.is(tok::at)) { SourceLocation AtLoc = ConsumeToken(); // the "@" if (!Tok.isObjCAtKeyword(tok::objc_interface) && !Tok.isObjCAtKeyword(tok::objc_protocol)) { @@ -763,18 +788,17 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID)) Diag(AtLoc, DiagID) << PrevSpec; - Decl *TheDecl = 0; if (Tok.isObjCAtKeyword(tok::objc_protocol)) - TheDecl = ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes()); - else - TheDecl = ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()); - return Actions.ConvertDeclToDeclGroup(TheDecl); + return ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes()); + + return Actions.ConvertDeclToDeclGroup( + ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes())); } // If the declspec consisted only of 'extern' and we have a string // literal following it, this must be a C++ linkage specifier like // 'extern "C"'. - if (Tok.is(tok::string_literal) && getLang().CPlusPlus && + if (Tok.is(tok::string_literal) && getLangOpts().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { Decl *TheDecl = ParseLinkage(DS, Declarator::FileContext); @@ -812,7 +836,8 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, /// decl-specifier-seq[opt] declarator function-try-block /// Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, - const ParsedTemplateInfo &TemplateInfo) { + const ParsedTemplateInfo &TemplateInfo, + LateParsedAttrList *LateParsedAttrs) { // Poison the SEH identifiers so they are flagged as illegal in function bodies PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); @@ -820,7 +845,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // If this is C90 and the declspecs were completely missing, fudge in an // implicit int. We do this here because this is the only place where // declaration-specifiers are completely optional in the grammar. - if (getLang().ImplicitInt && D.getDeclSpec().isEmpty()) { + if (getLangOpts().ImplicitInt && D.getDeclSpec().isEmpty()) { const char *PrevSpec; unsigned DiagID; D.getMutableDeclSpec().SetTypeSpecType(DeclSpec::TST_int, @@ -835,11 +860,10 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, if (FTI.isKNRPrototype()) ParseKNRParamDeclarations(D); - // We should have either an opening brace or, in a C++ constructor, // we may have a colon. if (Tok.isNot(tok::l_brace) && - (!getLang().CPlusPlus || + (!getLangOpts().CPlusPlus || (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try) && Tok.isNot(tok::equal)))) { Diag(Tok, diag::err_expected_fn_body); @@ -852,9 +876,22 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, return 0; } + // Check to make sure that any normal attributes are allowed to be on + // a definition. Late parsed attributes are checked at the end. + if (Tok.isNot(tok::equal)) { + AttributeList *DtorAttrs = D.getAttributes(); + while (DtorAttrs) { + if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName())) { + Diag(DtorAttrs->getLoc(), diag::warn_attribute_on_function_definition) + << DtorAttrs->getName()->getName(); + } + DtorAttrs = DtorAttrs->getNext(); + } + } + // In delayed template parsing mode, for function template we consume the // tokens and store them for late parsing at the end of the translation unit. - if (getLang().DelayedTemplateParsing && + if (getLangOpts().DelayedTemplateParsing && TemplateInfo.Kind == ParsedTemplateInfo::Template) { MultiTemplateParamsArg TemplateParameterLists(Actions, TemplateInfo.TemplateParams->data(), @@ -863,14 +900,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); Scope *ParentScope = getCurScope()->getParent(); - D.setFunctionDefinition(true); + D.setFunctionDefinitionKind(FDK_Definition); Decl *DP = Actions.HandleDeclarator(ParentScope, D, move(TemplateParameterLists)); D.complete(DP); D.getMutableDeclSpec().abort(); if (DP) { - LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(this, DP); + LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(DP); FunctionDecl *FnD = 0; if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(DP)) @@ -910,7 +947,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, D.getMutableDeclSpec().abort(); if (Tok.is(tok::equal)) { - assert(getLang().CPlusPlus && "Only C++ function definitions have '='"); + assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); ConsumeToken(); Actions.ActOnFinishFunctionBody(Res, 0, false); @@ -918,15 +955,17 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, bool Delete = false; SourceLocation KWLoc; if (Tok.is(tok::kw_delete)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::warn_deleted_function_accepted_as_extension); + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_deleted_function : + diag::ext_deleted_function); KWLoc = ConsumeToken(); Actions.SetDeclDeleted(Res, KWLoc); Delete = true; } else if (Tok.is(tok::kw_default)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::warn_defaulted_function_accepted_as_extension); + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_defaulted_function : + diag::ext_defaulted_function); KWLoc = ConsumeToken(); Actions.SetDeclDefaulted(Res, KWLoc); @@ -963,6 +1002,10 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, } else Actions.ActOnDefaultCtorInitializers(Res); + // Late attributes are parsed in the same scope as the function body. + if (LateParsedAttrs) + ParseLexedAttributeList(*LateParsedAttrs, Res, false, true); + return ParseFunctionStatementBody(Res, BodyScope); } @@ -1056,18 +1099,19 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { if (Tok.isNot(tok::comma)) break; + ParmDeclarator.clear(); + // Consume the comma. - ConsumeToken(); + ParmDeclarator.setCommaLoc(ConsumeToken()); // Parse the next declarator. - ParmDeclarator.clear(); ParseDeclarator(ParmDeclarator); } if (Tok.is(tok::semi)) { ConsumeToken(); } else { - Diag(Tok, diag::err_parse_error); + Diag(Tok, diag::err_expected_semi_declaration); // Skip to end of block or statement SkipUntil(tok::semi, true); if (Tok.is(tok::semi)) @@ -1087,17 +1131,25 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { /// string-literal /// Parser::ExprResult Parser::ParseAsmStringLiteral() { - if (!isTokenStringLiteral()) { - Diag(Tok, diag::err_expected_string_literal); - return ExprError(); + switch (Tok.getKind()) { + case tok::string_literal: + break; + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: + case tok::wide_string_literal: { + SourceLocation L = Tok.getLocation(); + Diag(Tok, diag::err_asm_operand_wide_string_literal) + << (Tok.getKind() == tok::wide_string_literal) + << SourceRange(L, L); + return ExprError(); + } + default: + Diag(Tok, diag::err_expected_string_literal); + return ExprError(); } - ExprResult Res(ParseStringLiteralExpression()); - if (Res.isInvalid()) return move(Res); - - // TODO: Diagnose: wide string literal in 'asm' - - return move(Res); + return ParseStringLiteralExpression(); } /// ParseSimpleAsm @@ -1178,8 +1230,8 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) { /// as the current tokens, so only call it in contexts where these are invalid. bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) - || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) && - "Cannot be a type or scope token!"); + || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) + || Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!"); if (Tok.is(tok::kw_typename)) { // Parse a C++ typename-specifier, e.g., "typename T::type". @@ -1190,11 +1242,12 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { // simple-template-id SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), false, + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), + /*EnteringContext=*/false, 0, /*IsTypename*/true)) return true; if (!SS.isSet()) { - if (getLang().MicrosoftExt) + if (getLangOpts().MicrosoftExt) Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename); else Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); @@ -1218,13 +1271,13 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), TemplateId->NumArgs); - + Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, - /*FIXME:*/SourceLocation(), + TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, - TemplateArgsPtr, + TemplateArgsPtr, TemplateId->RAngleLoc); } else { Diag(Tok, diag::err_expected_type_name_after_typename) @@ -1245,7 +1298,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { bool wasScopeAnnotation = Tok.is(tok::annot_cxxscope); CXXScopeSpec SS; - if (getLang().CPlusPlus) + if (getLangOpts().CPlusPlus) if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) return true; @@ -1257,6 +1310,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { &SS, false, NextToken().is(tok::period), ParsedType(), + /*IsCtorOrDtorName=*/false, /*NonTrivialTypeSourceInfo*/true, NeedType ? &CorrectedII : NULL)) { // A FixIt was applied as a result of typo correction @@ -1276,7 +1330,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { return false; } - if (!getLang().CPlusPlus) { + if (!getLangOpts().CPlusPlus) { // If we're in C, we can't have :: tokens at all (the lexer won't return // them). If the identifier is not a type, then it can't be scope either, // just early exit. @@ -1297,7 +1351,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { Template, MemberOfUnknownSpecialization)) { // Consume the identifier. ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName)) { + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName)) { // If an unrecoverable error occurred, we need to return true here, // because the token stream is in a damaged state. We may not return // a valid identifier. @@ -1354,11 +1409,11 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { - assert(getLang().CPlusPlus && + assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || - (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)))&& - "Cannot be a type or scope token!"); + (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) || + Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!"); CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) @@ -1382,18 +1437,31 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { return false; } -bool Parser::isTokenEqualOrMistypedEqualEqual(unsigned DiagID) { - if (Tok.is(tok::equalequal)) { - // We have '==' in a context that we would expect a '='. - // The user probably made a typo, intending to type '='. Emit diagnostic, - // fixit hint to turn '==' -> '=' and continue as if the user typed '='. - Diag(Tok, DiagID) - << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), - getTokenSimpleSpelling(tok::equal)); +bool Parser::isTokenEqualOrEqualTypo() { + tok::TokenKind Kind = Tok.getKind(); + switch (Kind) { + default: + return false; + case tok::ampequal: // &= + case tok::starequal: // *= + case tok::plusequal: // += + case tok::minusequal: // -= + case tok::exclaimequal: // != + case tok::slashequal: // /= + case tok::percentequal: // %= + case tok::lessequal: // <= + case tok::lesslessequal: // <<= + case tok::greaterequal: // >= + case tok::greatergreaterequal: // >>= + case tok::caretequal: // ^= + case tok::pipeequal: // |= + case tok::equalequal: // == + Diag(Tok, diag::err_invalid_token_after_declarator_suggest_equal) + << getTokenSimpleSpelling(Kind) + << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "="); + case tok::equal: return true; } - - return Tok.is(tok::equal); } SourceLocation Parser::handleUnexpectedCodeCompletionToken() { @@ -1455,98 +1523,134 @@ void Parser::CodeCompleteNaturalLanguage() { Actions.CodeCompleteNaturalLanguage(); } -bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) { +bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) { assert((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists)) && "Expected '__if_exists' or '__if_not_exists'"); - Token Condition = Tok; - SourceLocation IfExistsLoc = ConsumeToken(); + Result.IsIfExists = Tok.is(tok::kw___if_exists); + Result.KeywordLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.consumeOpen()) { - Diag(Tok, diag::err_expected_lparen_after) << IfExistsLoc; - SkipUntil(tok::semi); + Diag(Tok, diag::err_expected_lparen_after) + << (Result.IsIfExists? "__if_exists" : "__if_not_exists"); return true; } // Parse nested-name-specifier. - CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + ParseOptionalCXXScopeSpecifier(Result.SS, ParsedType(), + /*EnteringContext=*/false); // Check nested-name specifier. - if (SS.isInvalid()) { - SkipUntil(tok::semi); + if (Result.SS.isInvalid()) { + T.skipToEnd(); return true; } - // Parse the unqualified-id. - UnqualifiedId Name; - if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), Name)) { - SkipUntil(tok::semi); + // Parse the unqualified-id. + SourceLocation TemplateKWLoc; // FIXME: parsed, but unused. + if (ParseUnqualifiedId(Result.SS, false, true, true, ParsedType(), + TemplateKWLoc, Result.Name)) { + T.skipToEnd(); return true; } - T.consumeClose(); - if (T.getCloseLocation().isInvalid()) + if (T.consumeClose()) return true; - + // Check if the symbol exists. - bool Exist = Actions.CheckMicrosoftIfExistsSymbol(SS, Name); + switch (Actions.CheckMicrosoftIfExistsSymbol(getCurScope(), Result.KeywordLoc, + Result.IsIfExists, Result.SS, + Result.Name)) { + case Sema::IER_Exists: + Result.Behavior = Result.IsIfExists ? IEB_Parse : IEB_Skip; + break; - Result = ((Condition.is(tok::kw___if_exists) && Exist) || - (Condition.is(tok::kw___if_not_exists) && !Exist)); + case Sema::IER_DoesNotExist: + Result.Behavior = !Result.IsIfExists ? IEB_Parse : IEB_Skip; + break; + + case Sema::IER_Dependent: + Result.Behavior = IEB_Dependent; + break; + + case Sema::IER_Error: + return true; + } return false; } void Parser::ParseMicrosoftIfExistsExternalDeclaration() { - bool Result; + IfExistsCondition Result; if (ParseMicrosoftIfExistsCondition(Result)) return; - if (Tok.isNot(tok::l_brace)) { + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected_lbrace); return; } - ConsumeBrace(); - // Condition is false skip all inside the {}. - if (!Result) { - SkipUntil(tok::r_brace, false); + switch (Result.Behavior) { + case IEB_Parse: + // Parse declarations below. + break; + + case IEB_Dependent: + llvm_unreachable("Cannot have a dependent external declaration"); + + case IEB_Skip: + Braces.skipToEnd(); return; } - // Condition is true, parse the declaration. - while (Tok.isNot(tok::r_brace)) { + // Parse the declarations. + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); DeclGroupPtrTy Result = ParseExternalDeclaration(attrs); if (Result && !getCurScope()->getParent()) Actions.getASTConsumer().HandleTopLevelDecl(Result.get()); - } - - if (Tok.isNot(tok::r_brace)) { - Diag(Tok, diag::err_expected_rbrace); - return; - } - ConsumeBrace(); + } + Braces.consumeClose(); } -Parser::DeclGroupPtrTy Parser::ParseModuleImport() { - assert(Tok.is(tok::kw___import_module__) && +Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { + assert(Tok.isObjCAtKeyword(tok::objc___experimental_modules_import) && "Improper start to module import"); SourceLocation ImportLoc = ConsumeToken(); - // Parse the module name. - if (!Tok.is(tok::identifier)) { - Diag(Tok, diag::err_module_expected_ident); - SkipUntil(tok::semi); - return DeclGroupPtrTy(); - } + llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; - IdentifierInfo &ModuleName = *Tok.getIdentifierInfo(); - SourceLocation ModuleNameLoc = ConsumeToken(); - DeclResult Import = Actions.ActOnModuleImport(ImportLoc, ModuleName, ModuleNameLoc); + // Parse the module path. + do { + if (!Tok.is(tok::identifier)) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteModuleImport(ImportLoc, Path); + ConsumeCodeCompletionToken(); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + + Diag(Tok, diag::err_module_expected_ident); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + + // Record this part of the module path. + Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation())); + ConsumeToken(); + + if (Tok.is(tok::period)) { + ConsumeToken(); + continue; + } + + break; + } while (true); + + DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path); ExpectAndConsumeSemi(diag::err_module_expected_semi); if (Import.isInvalid()) return DeclGroupPtrTy(); @@ -1554,63 +1658,43 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport() { return Actions.ConvertDeclToDeclGroup(Import.get()); } -bool Parser::BalancedDelimiterTracker::consumeOpen() { - // Try to consume the token we are holding - if (P.Tok.is(Kind)) { - P.QuantityTracker.push(Kind); - Cleanup = true; - if (P.QuantityTracker.getDepth(Kind) < MaxDepth) { - LOpen = P.ConsumeAnyToken(); - return false; - } else { - P.Diag(P.Tok, diag::err_parser_impl_limit_overflow); - P.SkipUntil(tok::eof); - } - } - return true; +bool Parser::BalancedDelimiterTracker::diagnoseOverflow() { + P.Diag(P.Tok, diag::err_parser_impl_limit_overflow); + P.SkipUntil(tok::eof); + return true; } bool Parser::BalancedDelimiterTracker::expectAndConsume(unsigned DiagID, const char *Msg, tok::TokenKind SkipToToc ) { LOpen = P.Tok.getLocation(); - if (!P.ExpectAndConsume(Kind, DiagID, Msg, SkipToToc)) { - P.QuantityTracker.push(Kind); - Cleanup = true; - if (P.QuantityTracker.getDepth(Kind) < MaxDepth) { - return false; - } else { - P.Diag(P.Tok, diag::err_parser_impl_limit_overflow); - P.SkipUntil(tok::eof); - } - } - return true; + if (P.ExpectAndConsume(Kind, DiagID, Msg, SkipToToc)) + return true; + + if (getDepth() < MaxDepth) + return false; + + return diagnoseOverflow(); } -bool Parser::BalancedDelimiterTracker::consumeClose() { - if (P.Tok.is(Close)) { - LClose = P.ConsumeAnyToken(); - if (Cleanup) - P.QuantityTracker.pop(Kind); - - Cleanup = false; - return false; - } else { - const char *LHSName = "unknown"; - diag::kind DID = diag::err_parse_error; - switch (Close) { - default: break; - case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break; - case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break; - case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break; - case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break; - case tok::greatergreatergreater: - LHSName = "<<<"; DID = diag::err_expected_ggg; break; - } - P.Diag(P.Tok, DID); - P.Diag(LOpen, diag::note_matching) << LHSName; - if (P.SkipUntil(Close)) - LClose = P.Tok.getLocation(); +bool Parser::BalancedDelimiterTracker::diagnoseMissingClose() { + assert(!P.Tok.is(Close) && "Should have consumed closing delimiter"); + + const char *LHSName = "unknown"; + diag::kind DID; + switch (Close) { + default: llvm_unreachable("Unexpected balanced token"); + case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break; + case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break; + case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break; } + P.Diag(P.Tok, DID); + P.Diag(LOpen, diag::note_matching) << LHSName; + if (P.SkipUntil(Close)) + LClose = P.Tok.getLocation(); return true; } + +void Parser::BalancedDelimiterTracker::skipToEnd() { + P.SkipUntil(Close, false); +} |