diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
commit | bfef399519ca9b8a4b4c6b563253bad7e0eeffe0 (patch) | |
tree | df8df0b0067b381eab470a3b8f28d14a552a6340 /lib/Parse | |
parent | 6a0372513edbc473b538d2f724efac50405d6fef (diff) | |
download | src-bfef399519ca9b8a4b4c6b563253bad7e0eeffe0.tar.gz src-bfef399519ca9b8a4b4c6b563253bad7e0eeffe0.zip |
Vendor import of clang release_34 branch r197841 (effectively, 3.4 RC3):vendor/clang/clang-release_34-r197841
Notes
Notes:
svn path=/vendor/clang/dist/; revision=259701
svn path=/vendor/clang/clang-release_34-r197841/; revision=259703; tag=vendor/clang/clang-release_34-r197841
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/CMakeLists.txt | 3 | ||||
-rw-r--r-- | lib/Parse/ParseAST.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 548 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 723 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 421 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 172 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 252 | ||||
-rw-r--r-- | lib/Parse/ParseInit.cpp | 10 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 109 | ||||
-rw-r--r-- | lib/Parse/ParseOpenMP.cpp | 347 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 85 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.h | 15 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 209 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 115 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 418 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 184 | ||||
-rw-r--r-- | lib/Parse/RAIIObjectsForParser.h | 7 |
17 files changed, 2672 insertions, 948 deletions
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index 01c0694d0359..08bf4e196155 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -17,10 +17,11 @@ add_clang_library(clangParse add_dependencies(clangParse ClangAttrClasses - ClangAttrExprArgs + ClangAttrIdentifierArg ClangAttrLateParsed ClangAttrList ClangAttrParsedAttrList + ClangAttrTypeArg ClangCommentNodes ClangDeclNodes ClangDiagnosticCommon diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index 7cd8a21ac451..5678ece0c822 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -145,7 +145,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { } // Process any TopLevelDecls generated by #pragma weak. - for (SmallVector<Decl*,2>::iterator + for (SmallVectorImpl<Decl *>::iterator I = S.WeakTopLevelDecls().begin(), E = S.WeakTopLevelDecls().end(); I != E; ++I) Consumer->HandleTopLevelDecl(DeclGroupRef(*I)); diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 5fc4189742cf..779230516532 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -55,11 +55,10 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, TemplateParams, 0, VS, ICIS_NoInit); if (FnD) { - Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, - false, true); + Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs); bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType(); if (Init.isUsable()) - Actions.AddInitializerToDecl(FnD, Init.get(), false, + Actions.AddInitializerToDecl(FnD, Init.get(), false, TypeSpecContainsAuto); else Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto); @@ -110,28 +109,27 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, return FnD; } - + // In delayed template parsing mode, if we are within a class template // or if we are about to parse function member template then consume // the tokens and store them for parsing at the end of the translation unit. - if (getLangOpts().DelayedTemplateParsing && - DefinitionKind == FDK_Definition && + if (getLangOpts().DelayedTemplateParsing && + DefinitionKind == FDK_Definition && + !D.getDeclSpec().isConstexprSpecified() && + !(FnD && getFunctionDecl(FnD) && + getFunctionDecl(FnD)->getResultType()->getContainedAutoType()) && ((Actions.CurContext->isDependentContext() || - TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) && - !Actions.IsInsideALocalClassWithinATemplateFunction())) { + (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + TemplateInfo.Kind != ParsedTemplateInfo::ExplicitSpecialization)) && + !Actions.IsInsideALocalClassWithinATemplateFunction())) { - if (FnD) { - LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD); + CachedTokens Toks; + LexTemplateFunctionForLateParsing(Toks); + if (FnD) { FunctionDecl *FD = getFunctionDecl(FnD); Actions.CheckForFunctionRedefinition(FD); - - LateParsedTemplateMap[FD] = LPT; - Actions.MarkAsLateParsedTemplate(FD); - LexTemplateFunctionForLateParsing(LPT->Toks); - } else { - CachedTokens Toks; - LexTemplateFunctionForLateParsing(Toks); + Actions.MarkAsLateParsedTemplate(FD, FnD, Toks); } return FnD; @@ -151,9 +149,9 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, // We didn't find the left-brace we expected after the // 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(); + // Skip over the rest of the decl and back to somewhere that looks + // reasonable. + SkipMalformedDecl(); delete getCurrentClass().LateParsedDeclarations.back(); getCurrentClass().LateParsedDeclarations.pop_back(); return FnD; @@ -170,27 +168,28 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, } } - - if (!FnD) { + if (FnD) { + // If this is a friend function, mark that it's late-parsed so that + // it's still known to be a definition even before we attach the + // parsed body. Sema needs to treat friend function definitions + // differently during template instantiation, and it's possible for + // the containing class to be instantiated before all its member + // function definitions are parsed. + // + // If you remove this, you can remove the code that clears the flag + // after parsing the member. + if (D.getDeclSpec().isFriendSpecified()) { + FunctionDecl *FD = getFunctionDecl(FnD); + Actions.CheckForFunctionRedefinition(FD); + FD->setLateTemplateParsed(true); + } + } else { // If semantic analysis could not build a function declaration, // just throw away the late-parsed declaration. delete getCurrentClass().LateParsedDeclarations.back(); getCurrentClass().LateParsedDeclarations.pop_back(); } - // If this is a friend function, mark that it's late-parsed so that - // it's still known to be a definition even before we attach the - // parsed body. Sema needs to treat friend function definitions - // differently during template instantiation, and it's possible for - // the containing class to be instantiated before all its member - // function definitions are parsed. - // - // If you remove this, you can remove the code that clears the flag - // after parsing the member. - if (D.getDeclSpec().isFriendSpecified()) { - getFunctionDecl(FnD)->setLateTemplateParsed(true); - } - return FnD; } @@ -222,8 +221,7 @@ void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) { ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/true); } else { // Consume everything up to (but excluding) the comma or semicolon. - ConsumeAndStoreUntil(tok::comma, Toks, /*StopAtSemi=*/true, - /*ConsumeFinalToken=*/false); + ConsumeAndStoreInitializer(Toks, CIK_DefaultInitializer); } // Store an artificial EOF token to ensure that we don't run off the end of @@ -352,8 +350,15 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { else { if (Tok.is(tok::cxx_defaultarg_end)) ConsumeToken(); - else - Diag(Tok.getLocation(), diag::err_default_arg_unparsed); + else { + // The last two tokens are the terminator and the saved value of + // Tok; the last token in the default argument is the one before + // those. + assert(Toks->size() >= 3 && "expected a token in default arg"); + Diag(Tok.getLocation(), diag::err_default_arg_unparsed) + << SourceRange(Tok.getLocation(), + (*Toks)[Toks->size() - 3].getLocation()); + } Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, DefArgResult.take()); } @@ -653,83 +658,444 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, /// the opening brace of the function body. The opening brace will be consumed /// if and only if there was no error. /// -/// \return True on error. +/// \return True on error. bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { if (Tok.is(tok::kw_try)) { Toks.push_back(Tok); ConsumeToken(); } - bool ReadInitializer = false; - if (Tok.is(tok::colon)) { - // Initializers can contain braces too. + + if (Tok.isNot(tok::colon)) { + // Easy case, just a function body. + + // 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. + ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks, + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false); + if (Tok.isNot(tok::l_brace)) + return Diag(Tok.getLocation(), diag::err_expected_lbrace); + Toks.push_back(Tok); - ConsumeToken(); + ConsumeBrace(); + return false; + } - while (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { - if (Tok.is(tok::eof) || Tok.is(tok::semi)) - return Diag(Tok.getLocation(), diag::err_expected_lbrace); + Toks.push_back(Tok); + ConsumeToken(); - // Grab the identifier. - if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks, - /*StopAtSemi=*/true, - /*ConsumeFinalToken=*/false)) - return Diag(Tok.getLocation(), diag::err_expected_lparen); + // We can't reliably skip over a mem-initializer-id, because it could be + // a template-id involving not-yet-declared names. Given: + // + // S ( ) : a < b < c > ( e ) + // + // 'e' might be an initializer or part of a template argument, depending + // on whether 'b' is a template. + + // Track whether we might be inside a template argument. We can give + // significantly better diagnostics if we know that we're not. + bool MightBeTemplateArgument = false; - tok::TokenKind kind = Tok.getKind(); + while (true) { + // Skip over the mem-initializer-id, if possible. + if (Tok.is(tok::kw_decltype)) { Toks.push_back(Tok); - bool IsLParen = (kind == tok::l_paren); - SourceLocation LOpen = Tok.getLocation(); + SourceLocation OpenLoc = ConsumeToken(); + if (Tok.isNot(tok::l_paren)) + return Diag(Tok.getLocation(), diag::err_expected_lparen_after) + << "decltype"; + Toks.push_back(Tok); + ConsumeParen(); + if (!ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/true)) { + Diag(Tok.getLocation(), diag::err_expected_rparen); + Diag(OpenLoc, diag::note_matching) << "("; + return true; + } + } + do { + // Walk over a component of a nested-name-specifier. + if (Tok.is(tok::coloncolon)) { + Toks.push_back(Tok); + ConsumeToken(); - if (IsLParen) { - ConsumeParen(); + if (Tok.is(tok::kw_template)) { + Toks.push_back(Tok); + ConsumeToken(); + } + } + + if (Tok.is(tok::identifier) || Tok.is(tok::kw_template)) { + Toks.push_back(Tok); + ConsumeToken(); + } else if (Tok.is(tok::code_completion)) { + Toks.push_back(Tok); + ConsumeCodeCompletionToken(); + // Consume the rest of the initializers permissively. + // FIXME: We should be able to perform code-completion here even if + // there isn't a subsequent '{' token. + MightBeTemplateArgument = true; + break; } 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; we'll diagnose it later. - if (!getLangOpts().CPlusPlus11) - return false; + break; } + } while (Tok.is(tok::coloncolon)); + + if (Tok.is(tok::less)) + MightBeTemplateArgument = true; + + if (MightBeTemplateArgument) { + // We may be inside a template argument list. Grab up to the start of the + // next parenthesized initializer or braced-init-list. This *might* be the + // initializer, or it might be a subexpression in the template argument + // list. + // FIXME: Count angle brackets, and clear MightBeTemplateArgument + // if all angles are closed. + if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks, + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false)) { + // We're not just missing the initializer, we're also missing the + // function body! + return Diag(Tok.getLocation(), diag::err_expected_lbrace); + } + } else if (Tok.isNot(tok::l_paren) && Tok.isNot(tok::l_brace)) { + // We found something weird in a mem-initializer-id. + return Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 + ? diag::err_expected_lparen_or_lbrace + : diag::err_expected_lparen); + } + + tok::TokenKind kind = Tok.getKind(); + Toks.push_back(Tok); + bool IsLParen = (kind == tok::l_paren); + SourceLocation OpenLoc = Tok.getLocation(); + + if (IsLParen) { + ConsumeParen(); + } 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; we'll diagnose it later. + if (!getLangOpts().CPlusPlus11) + return false; + } - // Grab the initializer - 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 ? "(" : "{"); + // Grab the initializer (or the subexpression of the template argument). + // FIXME: If we support lambdas here, we'll need to set StopAtSemi to false + // if we might be inside the braces of a lambda-expression. + if (!ConsumeAndStoreUntil(IsLParen ? tok::r_paren : tok::r_brace, + Toks, /*StopAtSemi=*/true)) { + Diag(Tok, IsLParen ? diag::err_expected_rparen : + diag::err_expected_rbrace); + Diag(OpenLoc, diag::note_matching) << (IsLParen ? "(" : "{"); + return true; + } + + // Grab pack ellipsis, if present. + if (Tok.is(tok::ellipsis)) { + Toks.push_back(Tok); + ConsumeToken(); + } + + // If we know we just consumed a mem-initializer, we must have ',' or '{' + // next. + if (Tok.is(tok::comma)) { + Toks.push_back(Tok); + ConsumeToken(); + } else if (Tok.is(tok::l_brace)) { + // This is the function body if the ')' or '}' is immediately followed by + // a '{'. That cannot happen within a template argument, apart from the + // case where a template argument contains a compound literal: + // + // S ( ) : a < b < c > ( d ) { } + // // End of declaration, or still inside the template argument? + // + // ... and the case where the template argument contains a lambda: + // + // S ( ) : a < 0 && b < c > ( d ) + [ ] ( ) { return 0; } + // ( ) > ( ) { } + // + // FIXME: Disambiguate these cases. Note that the latter case is probably + // going to be made ill-formed by core issue 1607. + Toks.push_back(Tok); + ConsumeBrace(); + return false; + } else if (!MightBeTemplateArgument) { + return Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma); + } + } +} + +/// \brief Consume and store tokens from the '?' to the ':' in a conditional +/// expression. +bool Parser::ConsumeAndStoreConditional(CachedTokens &Toks) { + // Consume '?'. + assert(Tok.is(tok::question)); + Toks.push_back(Tok); + ConsumeToken(); + + while (Tok.isNot(tok::colon)) { + if (!ConsumeAndStoreUntil(tok::question, tok::colon, Toks, /*StopAtSemi*/true, + /*ConsumeFinalToken*/false)) + return false; + + // If we found a nested conditional, consume it. + if (Tok.is(tok::question) && !ConsumeAndStoreConditional(Toks)) + return false; + } + + // Consume ':'. + Toks.push_back(Tok); + ConsumeToken(); + return true; +} + +/// \brief A tentative parsing action that can also revert token annotations. +class Parser::UnannotatedTentativeParsingAction : public TentativeParsingAction { +public: + explicit UnannotatedTentativeParsingAction(Parser &Self, + tok::TokenKind EndKind) + : TentativeParsingAction(Self), Self(Self), EndKind(EndKind) { + // Stash away the old token stream, so we can restore it once the + // tentative parse is complete. + TentativeParsingAction Inner(Self); + Self.ConsumeAndStoreUntil(EndKind, Toks, true, /*ConsumeFinalToken*/false); + Inner.Revert(); + } + + void RevertAnnotations() { + Revert(); + + // Put back the original tokens. + Self.SkipUntil(EndKind, StopAtSemi | StopBeforeMatch); + if (Toks.size()) { + Token *Buffer = new Token[Toks.size()]; + std::copy(Toks.begin() + 1, Toks.end(), Buffer); + Buffer[Toks.size() - 1] = Self.Tok; + Self.PP.EnterTokenStream(Buffer, Toks.size(), true, /*Owned*/true); + + Self.Tok = Toks.front(); + } + } + +private: + Parser &Self; + CachedTokens Toks; + tok::TokenKind EndKind; +}; + +/// ConsumeAndStoreInitializer - Consume and store the token at the passed token +/// container until the end of the current initializer expression (either a +/// default argument or an in-class initializer for a non-static data member). +/// The final token is not consumed. +bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, + CachedInitKind CIK) { + // We always want this function to consume at least one token if not at EOF. + bool IsFirstTokenConsumed = true; + + // Number of possible unclosed <s we've seen so far. These might be templates, + // and might not, but if there were none of them (or we know for sure that + // we're within a template), we can avoid a tentative parse. + unsigned AngleCount = 0; + unsigned KnownTemplateCount = 0; + + while (1) { + switch (Tok.getKind()) { + case tok::comma: + // If we might be in a template, perform a tentative parse to check. + if (!AngleCount) + // Not a template argument: this is the end of the initializer. return true; + if (KnownTemplateCount) + goto consume_token; + + // We hit a comma inside angle brackets. This is the hard case. The + // rule we follow is: + // * For a default argument, if the tokens after the comma form a + // syntactically-valid parameter-declaration-clause, in which each + // parameter has an initializer, then this comma ends the default + // argument. + // * For a default initializer, if the tokens after the comma form a + // syntactically-valid init-declarator-list, then this comma ends + // the default initializer. + { + UnannotatedTentativeParsingAction PA(*this, + CIK == CIK_DefaultInitializer + ? tok::semi : tok::r_paren); + Sema::TentativeAnalysisScope Scope(Actions); + + TPResult Result = TPResult::Error(); + ConsumeToken(); + switch (CIK) { + case CIK_DefaultInitializer: + Result = TryParseInitDeclaratorList(); + // If we parsed a complete, ambiguous init-declarator-list, this + // is only syntactically-valid if it's followed by a semicolon. + if (Result == TPResult::Ambiguous() && Tok.isNot(tok::semi)) + Result = TPResult::False(); + break; + + case CIK_DefaultArgument: + bool InvalidAsDeclaration = false; + Result = TryParseParameterDeclarationClause( + &InvalidAsDeclaration, /*VersusTemplateArgument*/true); + // If this is an expression or a declaration with a missing + // 'typename', assume it's not a declaration. + if (Result == TPResult::Ambiguous() && InvalidAsDeclaration) + Result = TPResult::False(); + break; + } + + // If what follows could be a declaration, it is a declaration. + if (Result != TPResult::False() && Result != TPResult::Error()) { + PA.Revert(); + return true; + } + + // In the uncommon case that we decide the following tokens are part + // of a template argument, revert any annotations we've performed in + // those tokens. We're not going to look them up until we've parsed + // the rest of the class, and that might add more declarations. + PA.RevertAnnotations(); } - // Grab pack ellipsis, if present - if (Tok.is(tok::ellipsis)) { + // Keep going. We know we're inside a template argument list now. + ++KnownTemplateCount; + goto consume_token; + + case tok::eof: + // Ran out of tokens. + return false; + + case tok::less: + // FIXME: A '<' can only start a template-id if it's preceded by an + // identifier, an operator-function-id, or a literal-operator-id. + ++AngleCount; + goto consume_token; + + case tok::question: + // In 'a ? b : c', 'b' can contain an unparenthesized comma. If it does, + // that is *never* the end of the initializer. Skip to the ':'. + if (!ConsumeAndStoreConditional(Toks)) + return false; + break; + + case tok::greatergreatergreater: + if (!getLangOpts().CPlusPlus11) + goto consume_token; + if (AngleCount) --AngleCount; + if (KnownTemplateCount) --KnownTemplateCount; + // Fall through. + case tok::greatergreater: + if (!getLangOpts().CPlusPlus11) + goto consume_token; + if (AngleCount) --AngleCount; + if (KnownTemplateCount) --KnownTemplateCount; + // Fall through. + case tok::greater: + if (AngleCount) --AngleCount; + if (KnownTemplateCount) --KnownTemplateCount; + goto consume_token; + + case tok::kw_template: + // 'template' identifier '<' is known to start a template argument list, + // and can be used to disambiguate the parse. + // FIXME: Support all forms of 'template' unqualified-id '<'. + Toks.push_back(Tok); + ConsumeToken(); + if (Tok.is(tok::identifier)) { Toks.push_back(Tok); ConsumeToken(); + if (Tok.is(tok::less)) { + ++KnownTemplateCount; + Toks.push_back(Tok); + ConsumeToken(); + } } + break; - // Grab the separating comma, if any. - if (Tok.is(tok::comma)) { + case tok::kw_operator: + // If 'operator' precedes other punctuation, that punctuation loses + // its special behavior. + Toks.push_back(Tok); + ConsumeToken(); + switch (Tok.getKind()) { + case tok::comma: + case tok::greatergreatergreater: + case tok::greatergreater: + case tok::greater: + case tok::less: Toks.push_back(Tok); ConsumeToken(); - } else if (Tok.isNot(tok::l_brace)) { - ReadInitializer = true; + break; + default: break; } - } - } + break; - // 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. - 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); - } + case tok::l_paren: + // Recursively consume properly-nested parens. + Toks.push_back(Tok); + ConsumeParen(); + ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); + break; + case tok::l_square: + // Recursively consume properly-nested square brackets. + Toks.push_back(Tok); + ConsumeBracket(); + ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false); + break; + case tok::l_brace: + // Recursively consume properly-nested braces. + Toks.push_back(Tok); + ConsumeBrace(); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + break; - Toks.push_back(Tok); - ConsumeBrace(); - return false; + // Okay, we found a ']' or '}' or ')', which we think should be balanced. + // Since the user wasn't looking for this token (if they were, it would + // already be handled), this isn't balanced. If there is a LHS token at a + // higher level, we will assume that this matches the unbalanced token + // and return it. Otherwise, this is a spurious RHS token, which we skip. + case tok::r_paren: + if (CIK == CIK_DefaultArgument) + return true; // End of the default argument. + if (ParenCount && !IsFirstTokenConsumed) + return false; // Matches something. + goto consume_token; + case tok::r_square: + if (BracketCount && !IsFirstTokenConsumed) + return false; // Matches something. + goto consume_token; + case tok::r_brace: + if (BraceCount && !IsFirstTokenConsumed) + return false; // Matches something. + goto consume_token; + + case tok::code_completion: + Toks.push_back(Tok); + ConsumeCodeCompletionToken(); + break; + + case tok::string_literal: + case tok::wide_string_literal: + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: + Toks.push_back(Tok); + ConsumeStringToken(); + break; + case tok::semi: + if (CIK == CIK_DefaultInitializer) + return true; // End of the default initializer. + // FALL THROUGH. + default: + consume_token: + Toks.push_back(Tok); + ConsumeToken(); + break; + } + IsFirstTokenConsumed = false; + } } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 6a87b78879e8..7b8093408bfd 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/OpenCL.h" @@ -99,18 +100,21 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) { /// typequal /// storageclass /// -/// FIXME: The GCC grammar/code for this construct implies we need two -/// token lookahead. Comment from gcc: "If they start with an identifier -/// which is followed by a comma or close parenthesis, then the arguments -/// start with that identifier; otherwise they are an expression list." +/// Whether an attribute takes an 'identifier' is determined by the +/// attrib-name. GCC's behavior here is not worth imitating: /// -/// GCC does not require the ',' between attribs in an attribute-list. +/// * In C mode, if the attribute argument list starts with an identifier +/// followed by a ',' or an ')', and the identifier doesn't resolve to +/// a type, it is parsed as an identifier. If the attribute actually +/// wanted an expression, it's out of luck (but it turns out that no +/// attributes work that way, because C constant expressions are very +/// limited). +/// * In C++ mode, if the attribute argument list starts with an identifier, +/// and the attribute *wants* an identifier, it is parsed as an identifier. +/// At block scope, any additional tokens between the identifier and the +/// ',' or ')' are ignored, otherwise they produce a parse error. /// -/// 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 -/// a pressing need to implement the 2 token lookahead. - +/// We follow the C++ model, but don't allow junk after the identifier. void Parser::ParseGNUAttributes(ParsedAttributes &attrs, SourceLocation *endLoc, LateParsedAttrList *LateAttrs) { @@ -120,11 +124,11 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "attribute")) { - SkipUntil(tok::r_paren, true); // skip until ) or ; + SkipUntil(tok::r_paren, StopAtSemi); // skip until ) or ; return; } if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) { - SkipUntil(tok::r_paren, true); // skip until ) or ; + SkipUntil(tok::r_paren, StopAtSemi); // skip until ) or ; return; } // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) @@ -163,28 +167,76 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, 0, SourceLocation(), AttributeList::AS_GNU); } } else { - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, AttributeList::AS_GNU); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_GNU); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) - SkipUntil(tok::r_paren, false); + SkipUntil(tok::r_paren, StopAtSemi); SourceLocation Loc = Tok.getLocation(); - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { - SkipUntil(tok::r_paren, false); - } + if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + SkipUntil(tok::r_paren, StopAtSemi); if (endLoc) *endLoc = Loc; } } -/// \brief Determine whether the given attribute has all expression arguments. -static bool attributeHasExprArgs(const IdentifierInfo &II) { - return llvm::StringSwitch<bool>(II.getName()) -#include "clang/Parse/AttrExprArgs.inc" +/// \brief Normalizes an attribute name by dropping prefixed and suffixed __. +static StringRef normalizeAttrName(StringRef Name) { + if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) + Name = Name.drop_front(2).drop_back(2); + return Name; +} + +/// \brief Determine whether the given attribute has an identifier argument. +static bool attributeHasIdentifierArg(const IdentifierInfo &II) { + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrIdentifierArg.inc" + .Default(false); +} + +/// \brief Determine whether the given attribute parses a type argument. +static bool attributeIsTypeArgAttr(const IdentifierInfo &II) { + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrTypeArg.inc" .Default(false); } +IdentifierLoc *Parser::ParseIdentifierLoc() { + assert(Tok.is(tok::identifier) && "expected an identifier"); + IdentifierLoc *IL = IdentifierLoc::create(Actions.Context, + Tok.getLocation(), + Tok.getIdentifierInfo()); + ConsumeToken(); + return IL; +} + +void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc) { + BalancedDelimiterTracker Parens(*this, tok::l_paren); + Parens.consumeOpen(); + + TypeResult T; + if (Tok.isNot(tok::r_paren)) + T = ParseTypeName(); + + if (Parens.consumeClose()) + return; + + if (T.isInvalid()) + return; + + if (T.isUsable()) + Attrs.addNewTypeAttr(&AttrName, + SourceRange(AttrNameLoc, Parens.getCloseLocation()), 0, + AttrNameLoc, T.get(), AttributeList::AS_GNU); + else + Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), + 0, AttrNameLoc, 0, 0, AttributeList::AS_GNU); +} + /// Parse the arguments to a parameterized GNU attribute or /// a C++11 attribute in "gnu" namespace. void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, @@ -197,89 +249,65 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); + AttributeList::Kind AttrKind = + AttributeList::getKind(AttrName, ScopeName, Syntax); + // Availability attributes have their own grammar. - if (AttrName->isStr("availability")) { + // FIXME: All these cases fail to pass in the syntax and scope, and might be + // written as C++11 gnu:: attributes. + if (AttrKind == AttributeList::AT_Availability) { ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); return; } - // Thread safety attributes fit into the FIXME case above, so we - // just parse the arguments as a list of expressions + // Thread safety attributes are parsed in an unevaluated context. + // FIXME: Share the bulk of the parsing code here and just pull out + // the unevaluated context. if (IsThreadSafetyAttribute(AttrName->getName())) { ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); return; } // Type safety attributes have their own grammar. - if (AttrName->isStr("type_tag_for_datatype")) { + if (AttrKind == AttributeList::AT_TypeTagForDatatype) { ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); return; } + // Some attributes expect solely a type parameter. + if (attributeIsTypeArgAttr(*AttrName)) { + ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc); + return; + } - ConsumeParen(); // ignore the left paren loc for now - - IdentifierInfo *ParmName = 0; - SourceLocation ParmLoc; - bool BuiltinType = false; + // Ignore the left paren location for now. + ConsumeParen(); - TypeResult T; - SourceRange TypeRange; - bool TypeParsed = false; + ArgsVector ArgExprs; - 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) )) - BuiltinType = true; - T = ParseTypeName(&TypeRange); - TypeParsed = true; - break; - - case tok::identifier: - if (AttrName->isStr("vec_type_hint")) { - T = ParseTypeName(&TypeRange); - TypeParsed = true; - break; + if (Tok.is(tok::identifier)) { + // If this attribute wants an 'identifier' argument, make it so. + bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName); + + // If we don't know how to parse this attribute, but this is the only + // token in this argument, assume it's meant to be an identifier. + if (AttrKind == AttributeList::UnknownAttribute || + AttrKind == AttributeList::IgnoredAttribute) { + const Token &Next = NextToken(); + IsIdentifierArg = Next.is(tok::r_paren) || Next.is(tok::comma); } - // If the attribute has all expression arguments, and not a "parameter", - // break out to handle it below. - if (attributeHasExprArgs(*AttrName)) - break; - ParmName = Tok.getIdentifierInfo(); - ParmLoc = ConsumeToken(); - break; - default: - break; + if (IsIdentifierArg) + ArgExprs.push_back(ParseIdentifierLoc()); } - ExprVector ArgExprs; - bool isInvalid = false; - bool isParmType = false; - - if (!BuiltinType && !AttrName->isStr("vec_type_hint") && - (ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) { + if (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren)) { // Eat the comma. - if (ParmLoc.isValid()) + if (!ArgExprs.empty()) ConsumeToken(); // Parse the non-empty comma-separated list of expressions. while (1) { ExprResult ArgExpr(ParseAssignmentExpression()); if (ArgExpr.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } ArgExprs.push_back(ArgExpr.release()); @@ -288,48 +316,12 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, ConsumeToken(); // Eat the comma, move to the next argument } } - 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; - if (Tok.is(tok::comma)) { - ConsumeToken(); - continue; - } - } - if (Tok.isNot(tok::greater)) - Diag(Tok, diag::err_iboutletcollection_with_protocol); - SkipUntil(tok::r_paren, false, true); // skip until ')' - } - } else if (AttrName->isStr("vec_type_hint")) { - if (T.get() && !T.isInvalid()) - isParmType = true; - else { - if (Tok.is(tok::identifier)) - ConsumeToken(); - if (TypeParsed) - isInvalid = true; - } - } SourceLocation RParen = Tok.getLocation(); - if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen) && - !isInvalid) { + if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc; - if (isParmType) { - Attrs.addNewTypeAttr(AttrName, SourceRange(AttrLoc, RParen), ScopeName, - ScopeLoc, ParmName, ParmLoc, T.get(), Syntax); - } else { - AttributeList *attr = Attrs.addNew( - AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, ParmName, - ParmLoc, ArgExprs.data(), ArgExprs.size(), Syntax); - if (BuiltinType && - attr->getKind() == AttributeList::AT_IBOutletCollection) - Diag(Tok, diag::err_iboutletcollection_builtintype); - } + Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, + ArgExprs.data(), ArgExprs.size(), Syntax); } } @@ -349,9 +341,9 @@ void Parser::ParseMicrosoftDeclSpecWithSingleArg(IdentifierInfo *AttrName, T.skipToEnd(); return; } - Expr *ExprList = ArgExpr.take(); - Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), - &ExprList, 1, AttributeList::AS_Declspec); + ArgsUnion ExprList = ArgExpr.take(); + Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, &ExprList, 1, + AttributeList::AS_Declspec); T.consumeClose(); } @@ -399,8 +391,7 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, if (Tok.getKind() == tok::l_paren) ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs); else - Attrs.addNew(Ident, Loc, 0, Loc, 0, SourceLocation(), 0, 0, - AttributeList::AS_Declspec); + Attrs.addNew(Ident, Loc, 0, Loc, 0, 0, AttributeList::AS_Declspec); } else if (Ident->getName() == "property") { // The property declspec is more complex in that it can take one or two // assignment expressions as a parameter, but the lhs of the assignment @@ -513,8 +504,7 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, // Only add the property attribute if it was well-formed. if (!HasInvalidAccessor) { - Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(), 0, - SourceLocation(), + Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(), AccessorNames[AK_Get], AccessorNames[AK_Put], AttributeList::AS_Declspec); } @@ -588,8 +578,8 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) { // // Alternatively, if the identifier is a simple one, then it requires no // arguments and can be turned into an attribute directly. - Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), - 0, 0, AttributeList::AS_Declspec); + Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_Declspec); else ParseComplexMicrosoftDeclSpec(AttrName, AttrNameLoc, Attrs); } @@ -601,11 +591,12 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || - Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) { + Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned) || + Tok.is(tok::kw___sptr) || Tok.is(tok::kw___uptr)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_Keyword); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_Keyword); } } @@ -614,8 +605,8 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___pascal)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_Keyword); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_Keyword); } } @@ -624,8 +615,8 @@ void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___kernel)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_Keyword); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_Keyword); } } @@ -692,7 +683,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { if (!Tok.is(tok::numeric_constant)) { Diag(Tok, diag::err_expected_version); - SkipUntil(tok::comma, tok::r_paren, true, true, true); + SkipUntil(tok::comma, tok::r_paren, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); return VersionTuple(); } @@ -720,7 +712,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { if (AfterMajor == 0) { Diag(Tok, diag::err_expected_version); - SkipUntil(tok::comma, tok::r_paren, true, true, true); + SkipUntil(tok::comma, tok::r_paren, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); return VersionTuple(); } @@ -738,7 +731,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) { Diag(Tok, diag::err_expected_version); - SkipUntil(tok::comma, tok::r_paren, true, true, true); + SkipUntil(tok::comma, tok::r_paren, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); return VersionTuple(); } @@ -765,7 +759,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { // If what follows is not a '.', we have a problem. if (ThisTokBegin[AfterMinor] != '.') { Diag(Tok, diag::err_expected_version); - SkipUntil(tok::comma, tok::r_paren, true, true, true); + SkipUntil(tok::comma, tok::r_paren, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); return VersionTuple(); } @@ -779,7 +774,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { if (AfterSubminor != ActualLength) { Diag(Tok, diag::err_expected_version); - SkipUntil(tok::comma, tok::r_paren, true, true, true); + SkipUntil(tok::comma, tok::r_paren, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); return VersionTuple(); } ConsumeToken(); @@ -809,9 +805,6 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, SourceLocation AvailabilityLoc, ParsedAttributes &attrs, SourceLocation *endLoc) { - SourceLocation PlatformLoc; - IdentifierInfo *Platform = 0; - enum { Introduced, Deprecated, Obsoleted, Unknown }; AvailabilityChange Changes[Unknown]; ExprResult MessageExpr; @@ -826,11 +819,10 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, // Parse the platform name, if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_availability_expected_platform); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } - Platform = Tok.getIdentifierInfo(); - PlatformLoc = ConsumeToken(); + IdentifierLoc *Platform = ParseIdentifierLoc(); // Parse the ',' following the platform name. if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren)) @@ -851,7 +843,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, do { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_availability_expected_change); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } IdentifierInfo *Keyword = Tok.getIdentifierInfo(); @@ -874,15 +866,15 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, if (Tok.isNot(tok::equal)) { Diag(Tok, diag::err_expected_equal_after) << Keyword; - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } ConsumeToken(); if (Keyword == Ident_message) { - if (!isTokenStringLiteral()) { + if (Tok.isNot(tok::string_literal)) { // Also reject wide string literals. Diag(Tok, diag::err_expected_string_literal) << /*Source='availability attribute'*/2; - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } MessageExpr = ParseStringLiteralExpression(); @@ -893,7 +885,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, VersionTuple Version = ParseVersionTuple(VersionRange); if (Version.empty()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } @@ -959,7 +951,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, attrs.addNew(&Availability, SourceRange(AvailabilityLoc, T.getCloseLocation()), 0, AvailabilityLoc, - Platform, PlatformLoc, + Platform, Changes[Introduced], Changes[Deprecated], Changes[Obsoleted], @@ -1062,9 +1054,8 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext()); // Allow 'this' within late-parsed attributes. - Sema::CXXThisScopeRAII ThisScope(Actions, RD, - /*TypeQuals=*/0, - ND && RD && ND->isCXXInstanceMember()); + Sema::CXXThisScopeRAII ThisScope(Actions, RD, /*TypeQuals=*/0, + ND && ND->isCXXInstanceMember()); if (LA.Decls.size() == 1) { // If the Decl is templatized, add template parameters to scope. @@ -1161,7 +1152,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - ExprVector ArgExprs; + ArgsVector ArgExprs; bool ArgExprsOk = true; // now parse the list of expressions @@ -1181,8 +1172,8 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, } // Match the ')'. if (ArgExprsOk && !T.consumeClose()) { - Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), - ArgExprs.data(), ArgExprs.size(), AttributeList::AS_GNU); + Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, ArgExprs.data(), + ArgExprs.size(), AttributeList::AS_GNU); } if (EndLoc) *EndLoc = T.getCloseLocation(); @@ -1202,8 +1193,7 @@ void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, T.skipToEnd(); return; } - IdentifierInfo *ArgumentKind = Tok.getIdentifierInfo(); - SourceLocation ArgumentKindLoc = ConsumeToken(); + IdentifierLoc *ArgumentKind = ParseIdentifierLoc(); if (Tok.isNot(tok::comma)) { Diag(Tok, diag::err_expected_comma); @@ -1243,9 +1233,9 @@ void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, if (!T.consumeClose()) { Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, 0, AttrNameLoc, - ArgumentKind, ArgumentKindLoc, - MatchingCType.release(), LayoutCompatible, - MustBeNull, AttributeList::AS_GNU); + ArgumentKind, MatchingCType.release(), + LayoutCompatible, MustBeNull, + AttributeList::AS_GNU); } if (EndLoc) @@ -1276,7 +1266,7 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() { // Parse and discard the attributes. SourceLocation BeginLoc = ConsumeBracket(); ConsumeBracket(); - SkipUntil(tok::r_square, /*StopAtSemi*/ false); + SkipUntil(tok::r_square); assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied"); SourceLocation EndLoc = ConsumeBracket(); Diag(BeginLoc, diag::err_attributes_not_allowed) @@ -1412,8 +1402,14 @@ Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context, // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, - getDeclSpecContextFromDeclaratorContext(Context)); + DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext); + + // If we had a free-standing type definition with a missing semicolon, we + // may get this far before the problem becomes obvious. + if (DS.hasTagDefinition() && + DiagnoseMissingSemiAfterTagDefinition(DS, AS_none, DSContext)) + return DeclGroupPtrTy(); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' @@ -1507,7 +1503,7 @@ void Parser::SkipMalformedDecl() { // 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); + SkipUntil(tok::r_brace); if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) { // This declaration isn't over yet. Keep skipping. continue; @@ -1518,12 +1514,12 @@ void Parser::SkipMalformedDecl() { case tok::l_square: ConsumeBracket(); - SkipUntil(tok::r_square, /*StopAtSemi*/false); + SkipUntil(tok::r_square); continue; case tok::l_paren: ConsumeParen(); - SkipUntil(tok::r_paren, /*StopAtSemi*/false); + SkipUntil(tok::r_paren); continue; case tok::r_brace: @@ -1636,7 +1632,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } else { if (Tok.is(tok::l_brace)) { Diag(Tok, diag::err_function_definition_not_allowed); - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); } } } @@ -1666,7 +1662,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, Actions.ActOnCXXForRangeDecl(ThisDecl); Actions.FinalizeDeclaration(ThisDecl); D.complete(ThisDecl); - return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1); + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, ThisDecl); } SmallVector<Decl *, 8> DeclsInGroup; @@ -1727,15 +1723,13 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // declaration specifier, just assume it was missing and continue parsing. // Otherwise things are very confused and we skip to recover. if (!isDeclarationSpecifier()) { - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); } } - return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, - DeclsInGroup.data(), - DeclsInGroup.size()); + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); } /// Parse an optional simple-asm-expr and attributes, and attach them to a @@ -1746,7 +1740,7 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { SourceLocation Loc; ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { - SkipUntil(tok::semi, true, true); + SkipUntil(tok::semi, StopBeforeMatch); return true; } @@ -1798,24 +1792,53 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, break; case ParsedTemplateInfo::Template: - case ParsedTemplateInfo::ExplicitSpecialization: + case ParsedTemplateInfo::ExplicitSpecialization: { ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), *TemplateInfo.TemplateParams, D); + if (VarTemplateDecl *VT = dyn_cast_or_null<VarTemplateDecl>(ThisDecl)) + // Re-direct this decl to refer to the templated decl so that we can + // initialize it. + ThisDecl = VT->getTemplatedDecl(); break; - + } case ParsedTemplateInfo::ExplicitInstantiation: { - DeclResult ThisRes - = Actions.ActOnExplicitInstantiation(getCurScope(), - TemplateInfo.ExternLoc, - TemplateInfo.TemplateLoc, - D); - if (ThisRes.isInvalid()) { - SkipUntil(tok::semi, true, true); - return 0; + if (Tok.is(tok::semi)) { + DeclResult ThisRes = Actions.ActOnExplicitInstantiation( + getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, D); + if (ThisRes.isInvalid()) { + SkipUntil(tok::semi, StopBeforeMatch); + return 0; + } + ThisDecl = ThisRes.get(); + } else { + // FIXME: This check should be for a variable template instantiation only. + + // Check that this is a valid instantiation + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { + // If the declarator-id is not a template-id, issue a diagnostic and + // recover by ignoring the 'template' keyword. + Diag(Tok, diag::err_template_defn_explicit_instantiation) + << 2 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc); + ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); + } else { + SourceLocation LAngleLoc = + PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(D.getIdentifierLoc(), + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Recover as if it were an explicit specialization. + TemplateParameterLists FakedParamLists; + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, + LAngleLoc)); + + ThisDecl = + Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D); + } } - - ThisDecl = ThisRes.get(); break; } } @@ -1826,6 +1849,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, // If a '==' or '+=' is found, suggest a fixit to '='. if (isTokenEqualOrEqualTypo()) { ConsumeToken(); + if (Tok.is(tok::kw_delete)) { if (D.isFunctionDeclarator()) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) @@ -1859,7 +1883,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, } if (Init.isInvalid()) { - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); Actions.ActOnInitializerError(ThisDecl); } else Actions.AddInitializerToDecl(ThisDecl, Init.take(), @@ -1880,7 +1904,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, if (ParseExpressionList(Exprs, CommaLocs)) { Actions.ActOnInitializerError(ThisDecl); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); @@ -2063,6 +2087,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, DS.getStorageClassSpec() == DeclSpec::SCS_auto) { // Don't require a type specifier if we have the 'auto' storage class // specifier in C++98 -- we'll promote it to a type specifier. + if (SS) + AnnotateScopeToken(*SS, /*IsNewAnnotation*/false); return false; } @@ -2124,16 +2150,6 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // Look ahead to the next token to try to figure out what this declaration // was supposed to be. switch (NextToken().getKind()) { - case tok::comma: - case tok::equal: - case tok::kw_asm: - case tok::l_brace: - case tok::l_square: - case tok::semi: - // This looks like a variable declaration. The type is probably missing. - // We're done parsing decl-specifiers. - return false; - case tok::l_paren: { // static x(4); // 'x' is not a type // x(int n); // 'x' is not a type @@ -2146,12 +2162,37 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, ConsumeToken(); TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false); PA.Revert(); - if (TPR == TPResult::False()) - return false; - // The identifier is followed by a parenthesized declarator. - // It's supposed to be a type. - break; + + if (TPR != TPResult::False()) { + // The identifier is followed by a parenthesized declarator. + // It's supposed to be a type. + break; + } + + // If we're in a context where we could be declaring a constructor, + // check whether this is a constructor declaration with a bogus name. + if (DSC == DSC_class || (DSC == DSC_top_level && SS)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (Actions.isCurrentClassNameTypo(II, SS)) { + Diag(Loc, diag::err_constructor_bad_name) + << Tok.getIdentifierInfo() << II + << FixItHint::CreateReplacement(Tok.getLocation(), II->getName()); + Tok.setIdentifierInfo(II); + } + } + // Fall through. } + case tok::comma: + case tok::equal: + case tok::kw_asm: + case tok::l_brace: + case tok::l_square: + case tok::semi: + // This looks like a variable or function declaration. The type is + // probably missing. We're done parsing decl-specifiers. + if (SS) + AnnotateScopeToken(*SS, /*IsNewAnnotation*/false); + return false; default: // This is probably supposed to be a type. This includes cases like: @@ -2270,7 +2311,7 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation EllipsisLoc; ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc); if (ArgExpr.isInvalid()) { - SkipUntil(tok::r_paren); + T.skipToEnd(); return; } @@ -2278,10 +2319,105 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, if (EndLoc) *EndLoc = T.getCloseLocation(); - ExprVector ArgExprs; + ArgsVector ArgExprs; ArgExprs.push_back(ArgExpr.release()); - Attrs.addNew(KWName, KWLoc, 0, KWLoc, 0, T.getOpenLocation(), - ArgExprs.data(), 1, AttributeList::AS_Keyword, EllipsisLoc); + Attrs.addNew(KWName, KWLoc, 0, KWLoc, ArgExprs.data(), 1, + AttributeList::AS_Keyword, EllipsisLoc); +} + +/// Determine whether we're looking at something that might be a declarator +/// in a simple-declaration. If it can't possibly be a declarator, maybe +/// diagnose a missing semicolon after a prior tag definition in the decl +/// specifier. +/// +/// \return \c true if an error occurred and this can't be any kind of +/// declaration. +bool +Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, + DeclSpecContext DSContext, + LateParsedAttrList *LateAttrs) { + assert(DS.hasTagDefinition() && "shouldn't call this"); + + bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); + bool HasMissingSemi = false; + + if (getLangOpts().CPlusPlus && + (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) && + TryAnnotateCXXScopeToken(EnteringContext)) { + SkipMalformedDecl(); + return true; + } + + // Determine whether the following tokens could possibly be a + // declarator. + if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { + const Token &Next = NextToken(); + // These tokens cannot come after the declarator-id in a + // simple-declaration, and are likely to come after a type-specifier. + HasMissingSemi = Next.is(tok::star) || Next.is(tok::amp) || + Next.is(tok::ampamp) || Next.is(tok::identifier) || + Next.is(tok::annot_cxxscope) || + Next.is(tok::coloncolon); + } else if (Tok.is(tok::annot_cxxscope) && + NextToken().is(tok::identifier) && + DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { + // We almost certainly have a missing semicolon. Look up the name and + // check; if it names a type, we're missing a semicolon. + CXXScopeSpec SS; + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), SS); + const Token &Next = NextToken(); + IdentifierInfo *Name = Next.getIdentifierInfo(); + Sema::NameClassification Classification = + Actions.ClassifyName(getCurScope(), SS, Name, Next.getLocation(), + NextToken(), /*IsAddressOfOperand*/false); + switch (Classification.getKind()) { + case Sema::NC_Error: + SkipMalformedDecl(); + return true; + + case Sema::NC_Keyword: + case Sema::NC_NestedNameSpecifier: + llvm_unreachable("typo correction and nested name specifiers not " + "possible here"); + + case Sema::NC_Type: + case Sema::NC_TypeTemplate: + // Not a previously-declared non-type entity. + HasMissingSemi = true; + break; + + case Sema::NC_Unknown: + case Sema::NC_Expression: + case Sema::NC_VarTemplate: + case Sema::NC_FunctionTemplate: + // Might be a redeclaration of a prior entity. + HasMissingSemi = false; + break; + } + } else if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) { + HasMissingSemi = true; + } + + if (!HasMissingSemi) + return false; + + Diag(PP.getLocForEndOfToken(DS.getRepAsDecl()->getLocEnd()), + diag::err_expected_semi_after_tagdecl) + << DeclSpec::getSpecifierName(DS.getTypeSpecType()); + + // Try to recover from the typo, by dropping the tag definition and parsing + // the problematic tokens as a type. + // + // FIXME: Split the DeclSpec into pieces for the standalone + // declaration and pieces for the following declaration, instead + // of assuming that all the other pieces attach to new declaration, + // and call ParsedFreeStandingDeclSpec as appropriate. + DS.ClearTypeSpecType(); + ParsedTemplateInfo NotATemplate; + ParseDeclarationSpecifiers(DS, NotATemplate, AS, DSContext, LateAttrs); + return false; } /// ParseDeclarationSpecifiers @@ -2402,7 +2538,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::coloncolon: // ::foo::bar // C++ scope specifier. Annotate and loop, or bail out on error. - if (TryAnnotateCXXScopeToken(true)) { + if (TryAnnotateCXXScopeToken(EnteringContext)) { if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); goto DoneWithDeclSpec; @@ -2524,7 +2660,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // erroneous: We already checked about that it has no type specifier, and // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the // typename. - if (TypeRep == 0) { + if (!TypeRep) { ConsumeToken(); // Eat the scope spec so the identifier is current. ParsedAttributesWithRange Attrs(AttrFactory); if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) { @@ -2552,6 +2688,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } case tok::annot_typename: { + // If we've previously seen a tag definition, we were almost surely + // missing a semicolon after it. + if (DS.hasTypeSpecifier() && DS.hasTagDefinition()) + goto DoneWithDeclSpec; + if (Tok.getAnnotationValue()) { ParsedType T = getTypeAnnotation(Tok); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, @@ -2584,10 +2725,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // then treat __is_signed as an identifier rather than as a keyword. if (DS.getTypeSpecType() == TST_bool && DS.getTypeQualifiers() == DeclSpec::TQ_const && - DS.getStorageClassSpec() == DeclSpec::SCS_static) { - Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); - Tok.setKind(tok::identifier); - } + DS.getStorageClassSpec() == DeclSpec::SCS_static) + TryKeywordIdentFallback(true); // We're done with the declaration-specifiers. goto DoneWithDeclSpec; @@ -2598,7 +2737,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // 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 (getLangOpts().CPlusPlus) { - if (TryAnnotateCXXScopeToken(true)) { + if (TryAnnotateCXXScopeToken(EnteringContext)) { if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); goto DoneWithDeclSpec; @@ -2701,16 +2840,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Microsoft single token adornments. case tok::kw___forceinline: { - isInvalid = DS.setFunctionSpecInline(Loc); + isInvalid = DS.setFunctionSpecForceInline(Loc, PrevSpec, DiagID); IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = Tok.getLocation(); // FIXME: This does not work correctly if it is set to be a declspec // attribute, and a GNU attribute is simply incorrect. - DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_GNU); + DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_GNU); break; } + case tok::kw___sptr: + case tok::kw___uptr: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___w64: @@ -2791,18 +2932,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // function-specifier case tok::kw_inline: - isInvalid = DS.setFunctionSpecInline(Loc); + isInvalid = DS.setFunctionSpecInline(Loc, PrevSpec, DiagID); break; case tok::kw_virtual: - isInvalid = DS.setFunctionSpecVirtual(Loc); + isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID); break; case tok::kw_explicit: - isInvalid = DS.setFunctionSpecExplicit(Loc); + isInvalid = DS.setFunctionSpecExplicit(Loc, PrevSpec, DiagID); break; case tok::kw__Noreturn: if (!getLangOpts().C11) Diag(Loc, diag::ext_c11_noreturn); - isInvalid = DS.setFunctionSpecNoreturn(Loc); + isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID); break; // alignment-specifier @@ -3168,7 +3309,7 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) { ConsumeToken(); ExprResult Res(ParseConstantExpression()); if (Res.isInvalid()) - SkipUntil(tok::semi, true, true); + SkipUntil(tok::semi, StopBeforeMatch); else DeclaratorInfo.BitfieldSize = Res.release(); } @@ -3214,12 +3355,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); - // Empty structs are an extension in C (C99 6.7.2.1p7). - if (Tok.is(tok::r_brace)) { - 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; // While we still have something to read, read the declarations in the struct. @@ -3276,14 +3411,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ConsumeToken(); if (!Tok.isObjCAtKeyword(tok::objc_defs)) { Diag(Tok, diag::err_unexpected_at); - SkipUntil(tok::semi, true); + SkipUntil(tok::semi); continue; } ConsumeToken(); ExpectAndConsume(tok::l_paren, diag::err_expected_lparen); if (!Tok.is(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::semi, true); + SkipUntil(tok::semi); continue; } SmallVector<Decl *, 16> Fields; @@ -3302,7 +3437,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, } else { ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); // Skip to end of block or statement to avoid ext-warning on extra ';'. - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // If we stopped at a ';', eat it. if (Tok.is(tok::semi)) ConsumeToken(); } @@ -3426,7 +3561,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.isNot(tok::l_brace)) { // Has no name and is not a definition. // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); + SkipUntil(tok::comma, StopAtSemi); return; } } @@ -3438,7 +3573,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Diag(Tok, diag::err_expected_ident_lbrace); // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); + SkipUntil(tok::comma, StopAtSemi); return; } @@ -3556,7 +3691,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Diag(Tok.getLocation(), diag::err_friend_decl_defines_type) << SourceRange(DS.getFriendSpecLoc()); ConsumeBrace(); - SkipUntil(tok::r_brace); + SkipUntil(tok::r_brace, StopAtSemi); TUK = Sema::TUK_Friend; } else { TUK = Sema::TUK_Definition; @@ -3589,7 +3724,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (!getLangOpts().CPlusPlus11 || !SS.isSet()) { // Skip the rest of this declarator, up until the comma or semicolon. Diag(Tok, diag::err_enum_template); - SkipUntil(tok::comma, true); + SkipUntil(tok::comma, StopAtSemi); return; } @@ -3612,7 +3747,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Diag(Tok, diag::err_enumerator_unnamed_no_def); // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); + SkipUntil(tok::comma, StopAtSemi); return; } @@ -3656,7 +3791,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // definition, consume the entire definition. if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { ConsumeBrace(); - SkipUntil(tok::r_brace); + SkipUntil(tok::r_brace, StopAtSemi); } DS.SetTypeSpecError(); @@ -3717,7 +3852,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { EqualLoc = ConsumeToken(); AssignedVal = ParseConstantExpression(); if (AssignedVal.isInvalid()) - SkipUntil(tok::comma, tok::r_brace, true, true); + SkipUntil(tok::comma, tok::r_brace, StopAtSemi | StopBeforeMatch); } // Install the enumerator constant into EnumDecl. @@ -4145,6 +4280,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___w64: + case tok::kw___sptr: + case tok::kw___uptr: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___forceinline: @@ -4199,6 +4336,15 @@ bool Parser::isConstructorDeclarator() { return true; } + // A C++11 attribute here signals that we have a constructor, and is an + // attribute on the first constructor parameter. + if (getLangOpts().CPlusPlus11 && + isCXX11AttributeSpecifier(/*Disambiguate*/ false, + /*OuterMightBeMessageSend*/ true)) { + TPA.Revert(); + return true; + } + // If we need to, enter the specified scope. DeclaratorScopeObj DeclScopeObj(*this, SS); if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS)) @@ -4267,7 +4413,8 @@ bool Parser::isConstructorDeclarator() { void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool VendorAttributesAllowed, bool CXX11AttributesAllowed, - bool AtomicAllowed) { + bool AtomicAllowed, + bool IdentifierRequired) { if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); @@ -4321,6 +4468,15 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, ParseOpenCLQualifiers(DS); break; + case tok::kw___uptr: + // GNU libc headers in C mode use '__uptr' as an identifer which conflicts + // with the MS modifier keyword. + if (VendorAttributesAllowed && !getLangOpts().CPlusPlus && + IdentifierRequired && DS.isEmpty() && NextToken().is(tok::semi)) { + if (TryKeywordIdentFallback(false)) + continue; + } + case tok::kw___sptr: case tok::kw___w64: case tok::kw___ptr64: case tok::kw___ptr32: @@ -4476,7 +4632,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, DeclSpec DS(AttrFactory); // FIXME: GNU attributes are not allowed here in a new-type-id. - ParseTypeQualifierListOpt(DS); + ParseTypeQualifierListOpt(DS, true, true, true, !D.mayOmitIdentifier()); D.ExtendWithDeclSpec(DS); // Recursively parse the declarator. @@ -4636,6 +4792,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // as part of the parameter-declaration-clause. if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() && !((D.getContext() == Declarator::PrototypeContext || + D.getContext() == Declarator::LambdaExprParameterContext || D.getContext() == Declarator::BlockLiteralContext) && NextToken().is(tok::r_paren) && !D.hasGroupingParens() && @@ -4697,6 +4854,17 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); goto PastIdentifier; + } else if (Tok.is(tok::identifier) && D.diagnoseIdentifier()) { + // A virt-specifier isn't treated as an identifier if it appears after a + // trailing-return-type. + if (D.getContext() != Declarator::TrailingReturnContext || + !isCXX11VirtSpecifier(Tok)) { + Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id) + << FixItHint::CreateRemoval(Tok.getLocation()); + D.SetIdentifier(0, Tok.getLocation()); + ConsumeToken(); + goto PastIdentifier; + } } if (Tok.is(tok::l_paren)) { @@ -4736,8 +4904,15 @@ void Parser::ParseDirectDeclarator(Declarator &D) { else if (getLangOpts().CPlusPlus) { if (Tok.is(tok::period) || Tok.is(tok::arrow)) Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow); - else - Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus; + else { + SourceLocation Loc = D.getCXXScopeSpec().getEndLoc(); + if (Tok.isAtStartOfLine() && Loc.isValid()) + Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id) + << getLangOpts().CPlusPlus; + else + Diag(Tok, diag::err_expected_unqualified_id) + << getLangOpts().CPlusPlus; + } } else Diag(Tok, diag::err_expected_ident_lparen); D.SetIdentifier(0, Tok.getLocation()); @@ -4948,7 +5123,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D, TypeResult TrailingReturnType; Actions.ActOnStartFunctionDeclarator(); - /* LocalEndLoc is the end location for the local FunctionTypeLoc. EndLoc is the end location for the function declarator. They differ for trailing return types. */ @@ -4969,7 +5143,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, EndLoc = RParenLoc; } else { if (Tok.isNot(tok::r_paren)) - ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc); + ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, + EllipsisLoc); else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); @@ -5117,7 +5292,7 @@ bool Parser::isFunctionDeclaratorIdentifierList() { /// void Parser::ParseFunctionDeclaratorIdentifierList( Declarator &D, - SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo) { + SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo) { // If there was no identifier specified for the declarator, either we are in // an abstract-declarator, or we are in a parameter declarator which was found // to be abstract. In abstract-declarators, identifier lists are not valid: @@ -5132,7 +5307,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList( // If this isn't an identifier, report the error and skip until ')'. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true); + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); // Forget we parsed anything. ParamInfo.clear(); return; @@ -5198,9 +5373,8 @@ void Parser::ParseFunctionDeclaratorIdentifierList( void Parser::ParseParameterDeclarationClause( Declarator &D, ParsedAttributes &FirstArgAttrs, - SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo, + SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, SourceLocation &EllipsisLoc) { - while (1) { if (Tok.is(tok::ellipsis)) { // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq @@ -5230,16 +5404,21 @@ void Parser::ParseParameterDeclarationClause( ParseDeclarationSpecifiers(DS); - // Parse the declarator. This is "PrototypeContext", because we must - // accept either 'declarator' or 'abstract-declarator' here. - Declarator ParmDecl(DS, Declarator::PrototypeContext); - ParseDeclarator(ParmDecl); + + // Parse the declarator. This is "PrototypeContext" or + // "LambdaExprParameterContext", because we must accept either + // 'declarator' or 'abstract-declarator' here. + Declarator ParmDeclarator(DS, + D.getContext() == Declarator::LambdaExprContext ? + Declarator::LambdaExprParameterContext : + Declarator::PrototypeContext); + ParseDeclarator(ParmDeclarator); // Parse GNU attributes, if present. - MaybeParseGNUAttributes(ParmDecl); + MaybeParseGNUAttributes(ParmDeclarator); // Remember this parsed parameter in ParamInfo. - IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); // DefArgToks is used when the parsing of default arguments needs // to be delayed. @@ -5247,8 +5426,8 @@ void Parser::ParseParameterDeclarationClause( // If no parameter was specified, verify that *something* was specified, // otherwise we have a missing type and identifier. - if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 && - ParmDecl.getNumTypeObjects() == 0) { + if (DS.isEmpty() && ParmDeclarator.getIdentifier() == 0 && + ParmDeclarator.getNumTypeObjects() == 0) { // Completely missing, emit error. Diag(DSStart, diag::err_missing_param); } else { @@ -5257,8 +5436,8 @@ void Parser::ParseParameterDeclarationClause( // Inform the actions module about the parameter declarator, so it gets // added to the current scope. - Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); - + Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), + ParmDeclarator); // Parse the default argument, if any. We parse the default // arguments in all dialects; the semantic analysis in // ActOnParamDefaultArgument will reject the default argument in @@ -5274,9 +5453,7 @@ void Parser::ParseParameterDeclarationClause( // FIXME: Can we use a smart pointer for Toks? DefArgToks = new CachedTokens; - if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks, - /*StopAtSemi=*/true, - /*ConsumeFinalToken=*/false)) { + if (!ConsumeAndStoreInitializer(*DefArgToks, CIK_DefaultArgument)) { delete DefArgToks; DefArgToks = 0; Actions.ActOnParamDefaultArgumentError(Param); @@ -5309,7 +5486,7 @@ void Parser::ParseParameterDeclarationClause( DefArgResult = ParseAssignmentExpression(); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param); - SkipUntil(tok::comma, tok::r_paren, true, true); + SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch); } else { // Inform the actions module about the default argument Actions.ActOnParamDefaultArgument(Param, EqualLoc, @@ -5319,8 +5496,8 @@ void Parser::ParseParameterDeclarationClause( } ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, - ParmDecl.getIdentifierLoc(), Param, - DefArgToks)); + ParmDeclarator.getIdentifierLoc(), + Param, DefArgToks)); } // If the next token is a comma, consume it and keep reading arguments. @@ -5444,7 +5621,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { if (NumElements.isInvalid()) { D.setInvalidType(true); // If the expression was invalid, skip it. - SkipUntil(tok::r_square); + SkipUntil(tok::r_square, StopAtSemi); return; } @@ -5541,7 +5718,7 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) { TypeResult Result = ParseTypeName(); if (Result.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } @@ -5586,6 +5763,10 @@ bool Parser::TryAltiVecVectorTokenOutOfLine() { Tok.setKind(tok::kw___vector); return true; } + if (Next.getIdentifierInfo() == Ident_bool) { + Tok.setKind(tok::kw___vector); + return true; + } return false; } } @@ -5614,6 +5795,10 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); return true; } + if (Next.getIdentifierInfo() == Ident_bool) { + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + return true; + } break; default: break; @@ -5622,6 +5807,10 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, DS.isTypeAltiVecVector()) { isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); return true; + } else if ((Tok.getIdentifierInfo() == Ident_bool) && + DS.isTypeAltiVecVector()) { + isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID); + return true; } return false; } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f1fbbb15fed5..16d06d7d152c 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -15,6 +15,7 @@ #include "RAIIObjectsForParser.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/OperatorKinds.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" @@ -123,13 +124,13 @@ Decl *Parser::ParseNamespace(unsigned Context, << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); } Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope); - SkipUntil(tok::r_brace, false); + SkipUntil(tok::r_brace); return 0; } if (!ExtraIdent.empty()) { TentativeParsingAction TPA(*this); - SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true); + SkipUntil(tok::r_brace, StopBeforeMatch); Token rBraceToken = Tok; TPA.Revert(); @@ -451,20 +452,18 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, Decl **OwnedType) { CXXScopeSpec SS; SourceLocation TypenameLoc; - bool IsTypeName = false; - ParsedAttributesWithRange Attrs(AttrFactory); + bool HasTypenameKeyword = false; - // FIXME: Simply skip the attributes and diagnose, don't bother parsing them. - MaybeParseCXX11Attributes(Attrs); - ProhibitAttributes(Attrs); - Attrs.clear(); - Attrs.Range = SourceRange(); + // Check for misplaced attributes before the identifier in an + // alias-declaration. + ParsedAttributesWithRange MisplacedAttrs(AttrFactory); + MaybeParseCXX11Attributes(MisplacedAttrs); // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { TypenameLoc = ConsumeToken(); - IsTypeName = true; + HasTypenameKeyword = true; } // Parse nested-name-specifier. @@ -508,13 +507,25 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseGNUAttributes(Attrs); MaybeParseCXX11Attributes(Attrs); // Maybe this is an alias-declaration. - bool IsAliasDecl = Tok.is(tok::equal); TypeResult TypeAlias; + bool IsAliasDecl = Tok.is(tok::equal); if (IsAliasDecl) { - // TODO: Can GNU attributes appear here? + // If we had any misplaced attributes from earlier, this is where they + // should have been written. + if (MisplacedAttrs.Range.isValid()) { + Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed) + << FixItHint::CreateInsertionFromRange( + Tok.getLocation(), + CharSourceRange::getTokenRange(MisplacedAttrs.Range)) + << FixItHint::CreateRemoval(MisplacedAttrs.Range); + Attrs.takeAllFrom(MisplacedAttrs); + } + ConsumeToken(); Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? @@ -549,7 +560,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // No removal fixit: can't recover from this. SkipUntil(tok::semi); return 0; - } else if (IsTypeName) + } else if (HasTypenameKeyword) Diag(TypenameLoc, diag::err_alias_declaration_not_identifier) << FixItHint::CreateRemoval(SourceRange(TypenameLoc, SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc)); @@ -564,6 +575,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, } else { // C++11 attributes are not allowed on a using-declaration, but GNU ones // are. + ProhibitAttributes(MisplacedAttrs); ProhibitAttributes(Attrs); // Parse (optional) attributes (most likely GNU strong-using extension). @@ -593,11 +605,11 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // "typename" keyword is allowed for identifiers only, // because it may be a type definition. - if (IsTypeName && Name.getKind() != UnqualifiedId::IK_Identifier) { + if (HasTypenameKeyword && Name.getKind() != UnqualifiedId::IK_Identifier) { Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only) << FixItHint::CreateRemoval(SourceRange(TypenameLoc)); - // Proceed parsing, but reset the IsTypeName flag. - IsTypeName = false; + // Proceed parsing, but reset the HasTypenameKeyword flag. + HasTypenameKeyword = false; } if (IsAliasDecl) { @@ -610,9 +622,10 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, TypeAlias); } - return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, - Name, Attrs.getList(), - IsTypeName, TypenameLoc); + return Actions.ActOnUsingDeclaration(getCurScope(), AS, + /* HasUsingKeyword */ true, UsingLoc, + SS, Name, Attrs.getList(), + HasTypenameKeyword, TypenameLoc); } /// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration. @@ -729,8 +742,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { Result = ParseExpression(); if (Result.isInvalid()) { DS.SetTypeSpecError(); - if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, - /*DontConsume=*/true)) { + if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) { EndLoc = ConsumeParen(); } else { if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) { @@ -813,7 +825,7 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { TypeResult Result = ParseTypeName(); if (Result.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } @@ -827,6 +839,7 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec, DiagID, Result.release())) Diag(StartLoc, DiagID) << PrevSpec; + DS.setTypeofParensRange(T.getRange()); } /// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a @@ -917,8 +930,13 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, << Id; } - if (!Template) + if (!Template) { + TemplateArgList TemplateArgs; + SourceLocation LAngleLoc, RAngleLoc; + ParseTemplateIdAfterTemplateName(TemplateTy(), IdLoc, SS, + true, LAngleLoc, TemplateArgs, RAngleLoc); return true; + } // Form the template name UnqualifiedId TemplateName; @@ -979,8 +997,8 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { Tok.is(tok::kw___virtual_inheritance)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_GNU); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_GNU); } } @@ -1140,8 +1158,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ParsedAttributesWithRange attrs(AttrFactory); // If attributes exist after tag, parse them. - if (Tok.is(tok::kw___attribute)) - ParseGNUAttributes(attrs); + MaybeParseGNUAttributes(attrs); // If declspecs exist after tag, parse them. while (Tok.is(tok::kw___declspec)) @@ -1151,7 +1168,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.is(tok::kw___single_inheritance) || Tok.is(tok::kw___multiple_inheritance) || Tok.is(tok::kw___virtual_inheritance)) - ParseMicrosoftInheritanceClassAttributes(attrs); + ParseMicrosoftInheritanceClassAttributes(attrs); // If C++0x attributes exist here, parse them. // FIXME: Are we consistent with the ordering of parsing of different @@ -1180,15 +1197,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Tok.is(tok::kw___is_scalar) || Tok.is(tok::kw___is_signed) || Tok.is(tok::kw___is_unsigned) || - Tok.is(tok::kw___is_void))) { + Tok.is(tok::kw___is_void))) // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the // name of struct templates, but some are keywords in GCC >= 4.3 // and Clang. Therefore, when we see the token sequence "struct // X", make X into a normal identifier rather than a keyword, to // allow libstdc++ 4.2 and libc++ to work properly. - Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); - Tok.setKind(tok::identifier); - } + TryKeywordIdentFallback(true); // Parse the (optional) nested-name-specifier. CXXScopeSpec &SS = DS.getTypeSpecScope(); @@ -1231,7 +1246,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) << (TagType == DeclSpec::TST_class? 0 : TagType == DeclSpec::TST_struct? 1 - : TagType == DeclSpec::TST_interface? 2 + : TagType == DeclSpec::TST_union? 2 : 3) << Name << SourceRange(LAngleLoc, RAngleLoc); @@ -1272,10 +1287,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Range.setBegin(SS.getBeginLoc()); Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template) - << Name << static_cast<int>(TemplateId->Kind) << Range; + << TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range; DS.SetTypeSpecError(); - SkipUntil(tok::semi, false, true); + SkipUntil(tok::semi, StopBeforeMatch); return; } } @@ -1323,7 +1338,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Skip everything up to the semicolon, so that this looks like a proper // friend class (or template thereof) declaration. - SkipUntil(tok::semi, true, true); + SkipUntil(tok::semi, StopBeforeMatch); TUK = Sema::TUK_Friend; } else { // Okay, this is a class definition. @@ -1342,12 +1357,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, while (true) { if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) { ConsumeBracket(); - if (!SkipUntil(tok::r_square)) + if (!SkipUntil(tok::r_square, StopAtSemi)) break; } else if (Tok.is(tok::kw_alignas) && NextToken().is(tok::l_paren)) { ConsumeToken(); ConsumeParen(); - if (!SkipUntil(tok::r_paren)) + if (!SkipUntil(tok::r_paren, StopAtSemi)) break; } else { break; @@ -1412,7 +1427,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, << DeclSpec::getSpecifierName(TagType); } - SkipUntil(tok::comma, true); + SkipUntil(tok::comma, StopAtSemi); return; } @@ -1465,7 +1480,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // This is an explicit specialization or a class template // partial specialization. TemplateParameterLists FakedParamLists; - if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { // This looks like an explicit instantiation, because we have // something like @@ -1475,25 +1489,31 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // but it actually has a definition. Most likely, this was // meant to be an explicit specialization, but the user forgot // the '<>' after 'template'. - assert(TUK == Sema::TUK_Definition && "Expected a definition here"); - - SourceLocation LAngleLoc - = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); - Diag(TemplateId->TemplateNameLoc, - diag::err_explicit_instantiation_with_definition) - << SourceRange(TemplateInfo.TemplateLoc) - << FixItHint::CreateInsertion(LAngleLoc, "<>"); - - // Create a fake template parameter list that contains only - // "template<>", so that we treat this construct as a class - // template specialization. - FakedParamLists.push_back( - Actions.ActOnTemplateParameterList(0, SourceLocation(), - TemplateInfo.TemplateLoc, - LAngleLoc, - 0, 0, - LAngleLoc)); - TemplateParams = &FakedParamLists; + // It this is friend declaration however, since it cannot have a + // template header, it is most likely that the user meant to + // remove the 'template' keyword. + assert((TUK == Sema::TUK_Definition || TUK == Sema::TUK_Friend) && + "Expected a definition here"); + + if (TUK == Sema::TUK_Friend) { + Diag(DS.getFriendSpecLoc(), diag::err_friend_explicit_instantiation); + TemplateParams = 0; + } else { + SourceLocation LAngleLoc = + PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(TemplateId->TemplateNameLoc, + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Create a fake template parameter list that contains only + // "template<>", so that we treat this construct as a class + // template specialization. + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, + LAngleLoc)); + TemplateParams = &FakedParamLists; + } } // Build the class template specialization. @@ -1540,6 +1560,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition) ProhibitAttributes(attrs); + if (TUK == Sema::TUK_Definition && + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + // If the declarator-id is not a template-id, issue a diagnostic and + // recover by ignoring the 'template' keyword. + Diag(Tok, diag::err_template_defn_explicit_instantiation) + << 1 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc); + TemplateParams = 0; + } + bool IsDependent = false; // Don't pass down template parameter lists if this is just a tag @@ -1641,7 +1670,7 @@ void Parser::ParseBaseClause(Decl *ClassDecl) { if (Result.isInvalid()) { // Skip the rest of this base specifier, up until the comma or // opening brace. - SkipUntil(tok::comma, tok::l_brace, true, true); + SkipUntil(tok::comma, tok::l_brace, StopAtSemi | StopBeforeMatch); } else { // Add this to our array of base specifiers. BaseInfo.push_back(Result.get()); @@ -1800,12 +1829,17 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { // Initialize the contextual keywords. if (!Ident_final) { Ident_final = &PP.getIdentifierTable().get("final"); + if (getLangOpts().MicrosoftExt) + Ident_sealed = &PP.getIdentifierTable().get("sealed"); Ident_override = &PP.getIdentifierTable().get("override"); } if (II == Ident_override) return VirtSpecifiers::VS_Override; + if (II == Ident_sealed) + return VirtSpecifiers::VS_Sealed; + if (II == Ident_final) return VirtSpecifiers::VS_Final; } @@ -1833,14 +1867,18 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); - if (IsInterface && Specifier == VirtSpecifiers::VS_Final) { + if (IsInterface && (Specifier == VirtSpecifiers::VS_Final || + Specifier == VirtSpecifiers::VS_Sealed)) { Diag(Tok.getLocation(), diag::err_override_control_interface) << VirtSpecifiers::getSpecifierName(Specifier); + } else if (Specifier == VirtSpecifiers::VS_Sealed) { + Diag(Tok.getLocation(), diag::ext_ms_sealed_keyword); } else { - Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_override_control_keyword : - diag::ext_override_control_keyword) - << VirtSpecifiers::getSpecifierName(Specifier); + Diag(Tok.getLocation(), + getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_override_control_keyword + : diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); } ConsumeToken(); } @@ -1858,10 +1896,13 @@ bool Parser::isCXX11FinalKeyword() const { // Initialize the contextual keywords. if (!Ident_final) { Ident_final = &PP.getIdentifierTable().get("final"); + if (getLangOpts().MicrosoftExt) + Ident_sealed = &PP.getIdentifierTable().get("sealed"); Ident_override = &PP.getIdentifierTable().get("override"); } - - return Tok.getIdentifierInfo() == Ident_final; + + return Tok.getIdentifierInfo() == Ident_final || + Tok.getIdentifierInfo() == Ident_sealed; } /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. @@ -1892,6 +1933,7 @@ bool Parser::isCXX11FinalKeyword() const { /// virt-specifier: /// override /// final +/// [MS] sealed /// /// pure-specifier: /// '= 0' @@ -1908,12 +1950,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Diag(Tok, diag::err_at_defs_cxx); else Diag(Tok, diag::err_at_in_class); - + ConsumeToken(); - SkipUntil(tok::r_brace); + SkipUntil(tok::r_brace, StopAtSemi); return; } - + // Access declarations. bool MalformedTypeSpec = false; if (!TemplateInfo.Kind && @@ -1952,10 +1994,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; Actions.ActOnUsingDeclaration(getCurScope(), AS, - false, SourceLocation(), + /* HasUsingKeyword */ false, + SourceLocation(), SS, Name, /* AttrList */ 0, - /* IsTypeName */ false, + /* HasTypenameKeyword */ false, SourceLocation()); return; } @@ -2010,7 +2053,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::kw_namespace)) { Diag(UsingLoc, diag::err_using_namespace_in_class); - SkipUntil(tok::semi, true, true); + SkipUntil(tok::semi, StopBeforeMatch); } else { SourceLocation DeclEnd; // Otherwise, it must be a using-declaration or an alias-declaration. @@ -2032,6 +2075,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, &CommonLateParsedAttrs); + // If we had a free-standing type definition with a missing semicolon, we + // may get this far before the problem becomes obvious. + if (DS.hasTagDefinition() && + TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate && + DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class, + &CommonLateParsedAttrs)) + return; + MultiTemplateParamsArg TemplateParams( TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); @@ -2066,7 +2117,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); return; @@ -2085,7 +2136,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, EqualLoc = ConsumeToken(); Init = ParseInitializer(); if (Init.isInvalid()) - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); else HasInitializer = true; } @@ -2123,7 +2174,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (!DeclaratorInfo.isFunctionDeclarator()) { Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params); ConsumeBrace(); - SkipUntil(tok::r_brace, /*StopAtSemi*/false); + SkipUntil(tok::r_brace); // Consume the optional ';' if (Tok.is(tok::semi)) @@ -2143,11 +2194,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo, 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]->addDecl(FunDecl); + if (FunDecl) { + 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]->addDecl(FunDecl); + } } LateParsedAttrs.clear(); @@ -2176,7 +2229,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ConsumeToken(); BitfieldSize = ParseConstantExpression(); if (BitfieldSize.isInvalid()) - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); } // If a simple-asm-expr is present, parse it. @@ -2184,7 +2237,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SourceLocation Loc; ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); DeclaratorInfo.setAsmLabel(AsmLabel.release()); DeclaratorInfo.SetRangeEnd(Loc); @@ -2201,7 +2254,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, 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); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); } else { HasInitializer = true; if (!DeclaratorInfo.isDeclarationOfFunction() && @@ -2225,7 +2278,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SmallVector<SourceRange, 4> Ranges; DeclaratorInfo.getCXX11AttributeRanges(Ranges); if (!Ranges.empty()) { - for (SmallVector<SourceRange, 4>::iterator I = Ranges.begin(), + for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I; @@ -2241,28 +2294,25 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, TemplateParams, BitfieldSize.release(), VS, HasInClassInit); - if (AccessAttrs) - Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, - false, true); - } - - // 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]->addDecl(ThisDecl); + + if (VarTemplateDecl *VT = + ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : 0) + // Re-direct this decl to refer to the templated decl so that we can + // initialize it. + ThisDecl = VT->getTemplatedDecl(); + + if (ThisDecl && AccessAttrs) + Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs); } - LateParsedAttrs.clear(); // Handle the initializer. if (HasInClassInit != ICIS_NoInit && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) { // The initializer was deferred; parse it and cache the tokens. - Diag(Tok, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_nonstatic_member_init : - diag::ext_nonstatic_member_init); + Diag(Tok, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_nonstatic_member_init + : diag::ext_nonstatic_member_init); if (DeclaratorInfo.isArrayOfUnknownBound()) { // C++11 [dcl.array]p3: An array bound may also be omitted when the @@ -2271,38 +2321,46 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // A brace-or-equal-initializer for a member-declarator is not an // initializer in the grammar, so this is ill-formed. Diag(Tok, diag::err_incomplete_array_member_init); - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); + + // Avoid later warnings about a class member of incomplete type. if (ThisDecl) - // Avoid later warnings about a class member of incomplete type. ThisDecl->setInvalidDecl(); } else ParseCXXNonStaticMemberInitializer(ThisDecl); } else if (HasInitializer) { // Normal initializer. if (!Init.isUsable()) - Init = ParseCXXMemberInitializer(ThisDecl, - DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); - + Init = ParseCXXMemberInitializer( + ThisDecl, DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); + if (Init.isInvalid()) - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); else if (ThisDecl) Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(), DS.containsPlaceholderType()); - } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) { + } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) // No initializer. Actions.ActOnUninitializedDecl(ThisDecl, DS.containsPlaceholderType()); - } - + if (ThisDecl) { + if (!ThisDecl->isInvalidDecl()) { + // 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]->addDecl(ThisDecl); + } Actions.FinalizeDeclaration(ThisDecl); DeclsInGroup.push_back(ThisDecl); + + if (DeclaratorInfo.isFunctionDeclarator() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() != + DeclSpec::SCS_typedef) + HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl); } - - if (ThisDecl && DeclaratorInfo.isFunctionDeclarator() && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_typedef) { - HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl); - } + LateParsedAttrs.clear(); DeclaratorInfo.complete(ThisDecl); @@ -2343,14 +2401,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (ExpectSemi && ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) { // Skip to end of block or statement. - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // If we stopped at a ';', eat it. if (Tok.is(tok::semi)) ConsumeToken(); return; } - Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup.data(), - DeclsInGroup.size()); + Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); } /// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or @@ -2369,7 +2426,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, /// assignment-expression /// braced-init-list /// -/// defaulted/deleted function-definition: +/// defaulted/deleted function-definition: /// '=' 'default' /// '=' 'delete' /// @@ -2476,20 +2533,27 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); SourceLocation FinalLoc; + bool IsFinalSpelledSealed = false; // Parse the optional 'final' keyword. if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { - assert(isCXX11FinalKeyword() && "not a class definition"); + VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok); + assert((Specifier == VirtSpecifiers::VS_Final || + Specifier == VirtSpecifiers::VS_Sealed) && + "not a class definition"); FinalLoc = ConsumeToken(); + IsFinalSpelledSealed = Specifier == VirtSpecifiers::VS_Sealed; - if (TagType == DeclSpec::TST_interface) { + if (TagType == DeclSpec::TST_interface) Diag(FinalLoc, diag::err_override_control_interface) - << "final"; - } else { - Diag(FinalLoc, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_override_control_keyword : - diag::ext_override_control_keyword) << "final"; - } + << VirtSpecifiers::getSpecifierName(Specifier); + else if (Specifier == VirtSpecifiers::VS_Final) + Diag(FinalLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_override_control_keyword + : diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); + else if (Specifier == VirtSpecifiers::VS_Sealed) + Diag(FinalLoc, diag::ext_ms_sealed_keyword); // Parse any C++11 attributes after 'final' keyword. // These attributes are not allowed to appear here, @@ -2516,6 +2580,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc, + IsFinalSpelledSealed, T.getOpenLocation()); // C++ 11p3: Members of a class defined with the keyword class are private @@ -2565,6 +2630,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } + // If we see a namespace here, a close brace was missing somewhere. + if (Tok.is(tok::kw_namespace)) { + DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl)); + break; + } + AccessSpecifier AS = getAccessSpecifierIfPresent(); if (AS != AS_none) { // Current token is a C++ access specifier. @@ -2606,15 +2677,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } - // FIXME: Make sure we don't have a template here. - // Parse all the comma separated declarators. ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList()); } T.consumeClose(); } else { - SkipUntil(tok::r_brace, false, false); + SkipUntil(tok::r_brace); } // If attributes exist after class contents, parse them. @@ -2658,6 +2727,27 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, ClassScope.Exit(); } +void Parser::DiagnoseUnexpectedNamespace(NamedDecl *D) { + assert(Tok.is(tok::kw_namespace)); + + // FIXME: Suggest where the close brace should have gone by looking + // at indentation changes within the definition body. + Diag(D->getLocation(), + diag::err_missing_end_of_definition) << D; + Diag(Tok.getLocation(), + diag::note_missing_end_of_definition_before) << D; + + // Push '};' onto the token stream to recover. + PP.EnterToken(Tok); + + Tok.startToken(); + Tok.setLocation(PP.getLocForEndOfToken(PrevTokLocation)); + Tok.setKind(tok::semi); + PP.EnterToken(Tok); + + Tok.setKind(tok::r_brace); +} + /// ParseConstructorInitializer - Parse a C++ constructor initializer, /// which explicitly initializes the members or base classes of a /// class (C++ [class.base.init]). For example, the three initializers @@ -2691,9 +2781,8 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { do { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteConstructorInitializer(ConstructorDecl, - MemInitializers.data(), - MemInitializers.size()); + Actions.CodeCompleteConstructorInitializer(ConstructorDecl, + MemInitializers); return cutOffParsing(); } else { MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); @@ -2716,7 +2805,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { } else { // Skip over garbage, until we get to '{'. Don't eat the '{'. Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma); - SkipUntil(tok::l_brace, true, true); + SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch); break; } } while (true); @@ -2797,7 +2886,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { ExprVector ArgExprs; CommaLocsTy CommaLocs; if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return true; } @@ -2809,9 +2898,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, TemplateTypeTy, DS, IdLoc, - T.getOpenLocation(), ArgExprs.data(), - ArgExprs.size(), T.getCloseLocation(), - EllipsisLoc); + T.getOpenLocation(), ArgExprs, + T.getCloseLocation(), EllipsisLoc); } Diag(Tok, getLangOpts().CPlusPlus11 ? diag::err_expected_lparen_or_lbrace @@ -2894,6 +2982,16 @@ Parser::tryParseExceptionSpecification( return Result; } +static void diagnoseDynamicExceptionSpecification( + Parser &P, const SourceRange &Range, bool IsNoexcept) { + if (P.getLangOpts().CPlusPlus11) { + const char *Replacement = IsNoexcept ? "noexcept" : "noexcept(false)"; + P.Diag(Range.getBegin(), diag::warn_exception_spec_deprecated) << Range; + P.Diag(Range.getBegin(), diag::note_exception_spec_deprecated) + << Replacement << FixItHint::CreateReplacement(Range, Replacement); + } +} + /// ParseDynamicExceptionSpecification - Parse a C++ /// dynamic-exception-specification (C++ [except.spec]). /// @@ -2927,6 +3025,7 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec); T.consumeClose(); SpecificationRange.setEnd(T.getCloseLocation()); + diagnoseDynamicExceptionSpecification(*this, SpecificationRange, false); return EST_MSAny; } @@ -2958,6 +3057,8 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( T.consumeClose(); SpecificationRange.setEnd(T.getCloseLocation()); + diagnoseDynamicExceptionSpecification(*this, SpecificationRange, + Exceptions.empty()); return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic; } @@ -3167,7 +3268,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); if (!AttrName) { Diag(Tok.getLocation(), diag::err_expected_ident); - SkipUntil(tok::r_square, tok::comma, true, true); + SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch); continue; } } @@ -3193,7 +3294,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, // FIXME: handle other formats of c++11 attribute arguments ConsumeParen(); - SkipUntil(tok::r_paren, false); + SkipUntil(tok::r_paren); } } @@ -3201,8 +3302,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, attrs.addNew(AttrName, SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc), - ScopeName, ScopeLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_CXX11); + ScopeName, ScopeLoc, 0, 0, AttributeList::AS_CXX11); if (Tok.is(tok::ellipsis)) { ConsumeToken(); @@ -3213,11 +3313,11 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, } if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) - SkipUntil(tok::r_square, false); + SkipUntil(tok::r_square); if (endLoc) *endLoc = Tok.getLocation(); if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) - SkipUntil(tok::r_square, false); + SkipUntil(tok::r_square); } /// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq. @@ -3239,6 +3339,37 @@ void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, attrs.Range = SourceRange(StartLoc, *endLoc); } +void Parser::DiagnoseAndSkipCXX11Attributes() { + if (!isCXX11AttributeSpecifier()) + return; + + // Start and end location of an attribute or an attribute list. + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; + + do { + if (Tok.is(tok::l_square)) { + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + T.skipToEnd(); + EndLoc = T.getCloseLocation(); + } else { + assert(Tok.is(tok::kw_alignas) && "not an attribute specifier"); + ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (!T.consumeOpen()) + T.skipToEnd(); + EndLoc = T.getCloseLocation(); + } + } while (isCXX11AttributeSpecifier()); + + if (EndLoc.isValid()) { + SourceRange Range(StartLoc, EndLoc); + Diag(StartLoc, diag::err_attributes_not_allowed) + << Range; + } +} + /// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr] /// /// [MS] ms-attribute: @@ -3254,7 +3385,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, 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); + SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch); if (endLoc) *endLoc = Tok.getLocation(); ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 9521ffbc0e3f..45f1b1da2e7f 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -389,7 +389,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // parentheses so that the code remains well-formed in C++0x. if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater)) SuggestParentheses(OpToken.getLocation(), - diag::warn_cxx0x_right_shift_in_template_arg, + diag::warn_cxx11_right_shift_in_template_arg, SourceRange(Actions.getExprRange(LHS.get()).getBegin(), Actions.getExprRange(RHS.get()).getEnd())); @@ -491,6 +491,8 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// [C11] generic-selection /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' +/// [MS] '__FUNCDNAME__' +/// [MS] 'L__FUNCTION__' /// [GNU] '__PRETTY_FUNCTION__' /// [GNU] '(' compound-statement ')' /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' @@ -591,6 +593,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// '__is_final' /// '__is_pod' /// '__is_polymorphic' +/// '__is_sealed' [MS] /// '__is_trivial' /// '__is_union' /// @@ -741,19 +744,19 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, REVERTABLE_TYPE_TRAIT(__is_void); #undef REVERTABLE_TYPE_TRAIT #undef RTT_JOIN - } + } - // If we find that this is in fact the name of a type trait, - // update the token kind in place and parse again to treat it as - // the appropriate kind of type trait. - llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known - = RevertableTypeTraits.find(II); - if (Known != RevertableTypeTraits.end()) { - Tok.setKind(Known->second); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); - } + // If we find that this is in fact the name of a type trait, + // update the token kind in place and parse again to treat it as + // the appropriate kind of type trait. + llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known + = RevertableTypeTraits.find(II); + if (Known != RevertableTypeTraits.end()) { + Tok.setKind(Known->second); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, isTypeCast); } + } if (Next.is(tok::coloncolon) || (!ColonIsSacred && Next.is(tok::colon)) || @@ -869,6 +872,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, break; case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] + case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS] case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS] case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); @@ -888,6 +892,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: case tok::kw___builtin_astype: // primary-expression: [OCL] as_type() + case tok::kw___builtin_convertvector: return ParseBuiltinPrimaryExpression(); case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); @@ -1042,12 +1047,18 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // typename-specifier braced-init-list if (TryAnnotateTypeOrScopeToken()) return ExprError(); + + if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) + // We are trying to parse a simple-type-specifier but might not get such + // a token after error recovery. + return ExprError(); } // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' // simple-type-specifier braced-init-list // DeclSpec DS(AttrFactory); + ParseCXXSimpleTypeSpecifier(DS); if (Tok.isNot(tok::l_paren) && (!getLangOpts().CPlusPlus11 || Tok.isNot(tok::l_brace))) @@ -1193,6 +1204,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_trivially_copyable: case tok::kw___is_union: case tok::kw___is_final: + case tok::kw___is_sealed: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_move_constructor: case tok::kw___has_trivial_copy: @@ -1371,7 +1383,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { CommaLocsTy ExecConfigCommaLocs; SourceLocation OpenLoc = ConsumeToken(); - if (ParseExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) { + if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) { LHS = ExprError(); } @@ -1379,12 +1391,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (Tok.is(tok::greatergreatergreater)) { ConsumeToken(); } else if (LHS.isInvalid()) { - SkipUntil(tok::greatergreatergreater); + SkipUntil(tok::greatergreatergreater, StopAtSemi); } else { // There was an error closing the brackets Diag(Tok, diag::err_expected_ggg); Diag(OpenLoc, diag::note_matching) << "<<<"; - SkipUntil(tok::greatergreatergreater); + SkipUntil(tok::greatergreatergreater, StopAtSemi); LHS = ExprError(); } @@ -1430,7 +1442,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Match the ')'. if (LHS.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); } else if (Tok.isNot(tok::r_paren)) { PT.consumeClose(); LHS = ExprError(); @@ -1457,7 +1469,18 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { ParsedType ObjectType; bool MayBePseudoDestructor = false; if (getLangOpts().CPlusPlus && !LHS.isInvalid()) { - LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), LHS.take(), + Expr *Base = LHS.take(); + const Type* BaseType = Base->getType().getTypePtrOrNull(); + if (BaseType && Tok.is(tok::l_paren) && + (BaseType->isFunctionType() || + BaseType->isSpecificPlaceholderType(BuiltinType::BoundMember))) { + Diag(OpLoc, diag::err_function_is_not_record) + << (OpKind == tok::arrow) << Base->getSourceRange() + << FixItHint::CreateRemoval(OpLoc); + return ParsePostfixExpressionSuffix(Base); + } + + LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), Base, OpLoc, OpKind, ObjectType, MayBePseudoDestructor); if (LHS.isInvalid()) @@ -1570,6 +1593,28 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, // If the operand doesn't start with an '(', it must be an expression. if (Tok.isNot(tok::l_paren)) { + // If construct allows a form without parenthesis, user may forget to put + // pathenthesis around type name. + if (OpTok.is(tok::kw_sizeof) || OpTok.is(tok::kw___alignof) || + OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof)) { + bool isAmbiguousTypeId; + if (isTypeIdInParens(isAmbiguousTypeId)) { + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS); + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + ParseDeclarator(DeclaratorInfo); + + SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation()); + SourceLocation RParenLoc = PP.getLocForEndOfToken(PrevTokLocation); + Diag(LParenLoc, diag::err_expected_parentheses_around_typename) + << OpTok.getName() + << FixItHint::CreateInsertion(LParenLoc, "(") + << FixItHint::CreateInsertion(RParenLoc, ")"); + isCastExpr = true; + return ExprEmpty(); + } + } + isCastExpr = false; if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) { Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo(); @@ -1651,7 +1696,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { RParenLoc = PP.getLocForEndOfToken(NameLoc); } else { Diag(Tok, diag::err_expected_parameter_pack); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); } } else if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); @@ -1669,6 +1714,9 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { if (!Name) return ExprError(); + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, + Sema::ReuseLambdaContextDecl); + return Actions.ActOnSizeofParameterPackExpr(getCurScope(), OpTok.getLocation(), *Name, NameLoc, @@ -1774,7 +1822,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { SourceLocation TypeLoc = Tok.getLocation(); TypeResult Ty = ParseTypeName(); if (Ty.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -1784,7 +1832,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { // We must have at least one identifier here. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -1806,7 +1854,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); @@ -1824,7 +1872,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { Comps.back().LocStart = ST.getOpenLocation(); Res = ParseExpression(); if (Res.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return Res; } Comps.back().U.E = Res.release(); @@ -1851,7 +1899,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { case tok::kw___builtin_choose_expr: { ExprResult Cond(ParseAssignmentExpression()); if (Cond.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return Cond; } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) @@ -1859,7 +1907,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { ExprResult Expr1(ParseAssignmentExpression()); if (Expr1.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return Expr1; } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) @@ -1867,7 +1915,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { ExprResult Expr2(ParseAssignmentExpression()); if (Expr2.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return Expr2; } if (Tok.isNot(tok::r_paren)) { @@ -1882,7 +1930,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { // The first argument is an expression to be converted, followed by a comma. ExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -1898,7 +1946,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { // Attempt to consume the r-paren. if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -1906,6 +1954,34 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { ConsumeParen()); break; } + case tok::kw___builtin_convertvector: { + // The first argument is an expression to be converted, followed by a comma. + ExprResult Expr(ParseAssignmentExpression()); + if (Expr.isInvalid()) { + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", + tok::r_paren)) + return ExprError(); + + // Second argument is the type to bitcast to. + TypeResult DestTy = ParseTypeName(); + if (DestTy.isInvalid()) + return ExprError(); + + // Attempt to consume the r-paren. + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + Res = Actions.ActOnConvertVectorExpr(Expr.take(), DestTy.get(), StartLoc, + ConsumeParen()); + break; + } } if (Res.isInvalid()) @@ -2129,7 +2205,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, ExprVector ArgExprs; CommaLocsTy CommaLocs; - if (!ParseExpressionList(ArgExprs, CommaLocs)) { + if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) { ExprType = SimpleExpr; Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), ArgExprs); @@ -2147,7 +2223,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Match the ')'. if (Result.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2233,13 +2309,13 @@ ExprResult Parser::ParseGenericSelectionExpression() { EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); ControllingExpr = ParseAssignmentExpression(); if (ControllingExpr.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2254,7 +2330,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { if (!DefaultLoc.isInvalid()) { Diag(Tok, diag::err_duplicate_default_assoc); Diag(DefaultLoc, diag::note_previous_default_assoc); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } DefaultLoc = ConsumeToken(); @@ -2263,7 +2339,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { ColonProtectionRAIIObject X(*this); TypeResult TR = ParseTypeName(); if (TR.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } Ty = TR.release(); @@ -2271,7 +2347,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { Types.push_back(Ty); if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2279,7 +2355,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { // evaluated context. ExprResult ER(ParseAssignmentExpression()); if (ER.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } Exprs.push_back(ER.release()); @@ -2358,6 +2434,32 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs, } } +/// ParseSimpleExpressionList - A simple comma-separated list of expressions, +/// used for misc language extensions. +/// +/// \verbatim +/// simple-expression-list: +/// assignment-expression +/// simple-expression-list , assignment-expression +/// \endverbatim +bool +Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs, + SmallVectorImpl<SourceLocation> &CommaLocs) { + while (1) { + ExprResult Expr = ParseAssignmentExpression(); + if (Expr.isInvalid()) + return true; + + Exprs.push_back(Expr.release()); + + if (Tok.isNot(tok::comma)) + return false; + + // Move to the next argument, remember where the comma was. + CommaLocs.push_back(ConsumeToken()); + } +} + /// ParseBlockId - Parse a block-id, which roughly looks like int (int x). /// /// \verbatim diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index f259d5f59b48..5fe47fc9711c 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -10,7 +10,7 @@ // This file implements the Expression parsing implementation for C++. // //===----------------------------------------------------------------------===// - +#include "clang/AST/DeclTemplate.h" #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" #include "clang/Basic/PrettyStackTrace.h" @@ -21,6 +21,7 @@ #include "clang/Sema/Scope.h" #include "llvm/Support/ErrorHandling.h" + using namespace clang; static int SelectDigraphErrorMessage(tok::TokenKind Kind) { @@ -195,6 +196,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } + if (Tok.is(tok::annot_template_id)) { + // If the current token is an annotated template id, it may already have + // a scope specifier. Restore it. + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + SS = TemplateId->SS; + } + if (LastII) *LastII = 0; @@ -465,8 +473,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TemplateName, false)) return true; continue; - } - + } + if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && (IsTypename || IsTemplateArgumentList(1))) { // We have something like t::getAs<T>, where getAs is a @@ -583,7 +591,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { Tok.is(tok::l_paren), isAddressOfOperand); } -/// ParseLambdaExpression - Parse a C++0x lambda expression. +/// ParseLambdaExpression - Parse a C++11 lambda expression. /// /// lambda-expression: /// lambda-introducer lambda-declarator[opt] compound-statement @@ -605,10 +613,18 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { /// capture-list ',' capture /// /// capture: +/// simple-capture +/// init-capture [C++1y] +/// +/// simple-capture: /// identifier /// '&' identifier /// 'this' /// +/// init-capture: [C++1y] +/// identifier initializer +/// '&' identifier initializer +/// /// lambda-declarator: /// '(' parameter-declaration-clause ')' attribute-specifier[opt] /// 'mutable'[opt] exception-specification[opt] @@ -617,13 +633,12 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { ExprResult Parser::ParseLambdaExpression() { // Parse lambda-introducer. LambdaIntroducer Intro; - - Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro)); + Optional<unsigned> DiagID = ParseLambdaIntroducer(Intro); if (DiagID) { Diag(Tok, DiagID.getValue()); - SkipUntil(tok::r_square); - SkipUntil(tok::l_brace); - SkipUntil(tok::r_brace); + SkipUntil(tok::r_square, StopAtSemi); + SkipUntil(tok::l_brace, StopAtSemi); + SkipUntil(tok::r_brace, StopAtSemi); return ExprError(); } @@ -658,7 +673,7 @@ ExprResult Parser::TryParseLambdaExpression() { if (Next.is(tok::identifier) && After.is(tok::identifier)) { 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 @@ -668,13 +683,21 @@ ExprResult Parser::TryParseLambdaExpression() { LambdaIntroducer Intro; if (TryParseLambdaIntroducer(Intro)) return ExprEmpty(); + return ParseLambdaExpressionAfterIntroducer(Intro); } -/// ParseLambdaExpression - Parse a lambda introducer. -/// -/// Returns a DiagnosticID if it hit something unexpected. -Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) { +/// \brief Parse a lambda introducer. +/// \param Intro A LambdaIntroducer filled in with information about the +/// contents of the lambda-introducer. +/// \param SkippedInits If non-null, we are disambiguating between an Obj-C +/// message send and a lambda expression. In this mode, we will +/// sometimes skip the initializers for init-captures and not fully +/// populate \p Intro. This flag will be set to \c true if we do so. +/// \return A DiagnosticID if it hit something unexpected. The location for +/// for the diagnostic is that of the current token. +Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, + bool *SkippedInits) { typedef Optional<unsigned> DiagResult; assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['."); @@ -737,6 +760,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) { SourceLocation Loc; IdentifierInfo* Id = 0; SourceLocation EllipsisLoc; + ExprResult Init; if (Tok.is(tok::kw_this)) { Kind = LCK_This; @@ -757,9 +781,6 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) { 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 @@ -768,14 +789,139 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) { } else { return DiagResult(diag::err_expected_capture); } - } - Intro.addCapture(Kind, Loc, Id, EllipsisLoc); + if (Tok.is(tok::l_paren)) { + BalancedDelimiterTracker Parens(*this, tok::l_paren); + Parens.consumeOpen(); + + ExprVector Exprs; + CommaLocsTy Commas; + if (SkippedInits) { + Parens.skipToEnd(); + *SkippedInits = true; + } else if (ParseExpressionList(Exprs, Commas)) { + Parens.skipToEnd(); + Init = ExprError(); + } else { + Parens.consumeClose(); + Init = Actions.ActOnParenListExpr(Parens.getOpenLocation(), + Parens.getCloseLocation(), + Exprs); + } + } else if (Tok.is(tok::l_brace) || Tok.is(tok::equal)) { + // Each lambda init-capture forms its own full expression, which clears + // Actions.MaybeODRUseExprs. So create an expression evaluation context + // to save the necessary state, and restore it later. + EnterExpressionEvaluationContext EC(Actions, + Sema::PotentiallyEvaluated); + if (Tok.is(tok::equal)) + ConsumeToken(); + + if (!SkippedInits) + Init = ParseInitializer(); + else if (Tok.is(tok::l_brace)) { + BalancedDelimiterTracker Braces(*this, tok::l_brace); + Braces.consumeOpen(); + Braces.skipToEnd(); + *SkippedInits = true; + } else { + // We're disambiguating this: + // + // [..., x = expr + // + // We need to find the end of the following expression in order to + // determine whether this is an Obj-C message send's receiver, or a + // lambda init-capture. + // + // Parse the expression to find where it ends, and annotate it back + // onto the tokens. We would have parsed this expression the same way + // in either case: both the RHS of an init-capture and the RHS of an + // assignment expression are parsed as an initializer-clause, and in + // neither case can anything be added to the scope between the '[' and + // here. + // + // FIXME: This is horrible. Adding a mechanism to skip an expression + // would be much cleaner. + // FIXME: If there is a ',' before the next ']' or ':', we can skip to + // that instead. (And if we see a ':' with no matching '?', we can + // classify this as an Obj-C message send.) + SourceLocation StartLoc = Tok.getLocation(); + InMessageExpressionRAIIObject MaybeInMessageExpression(*this, true); + Init = ParseInitializer(); + + if (Tok.getLocation() != StartLoc) { + // Back out the lexing of the token after the initializer. + PP.RevertCachedTokens(1); + + // Replace the consumed tokens with an appropriate annotation. + Tok.setLocation(StartLoc); + Tok.setKind(tok::annot_primary_expr); + setExprAnnotation(Tok, Init); + Tok.setAnnotationEndLoc(PP.getLastCachedTokenLocation()); + PP.AnnotateCachedTokens(Tok); + + // Consume the annotated initializer. + ConsumeToken(); + } + } + } else if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + } + // If this is an init capture, process the initialization expression + // right away. For lambda init-captures such as the following: + // const int x = 10; + // auto L = [i = x+1](int a) { + // return [j = x+2, + // &k = x](char b) { }; + // }; + // keep in mind that each lambda init-capture has to have: + // - its initialization expression executed in the context + // of the enclosing/parent decl-context. + // - but the variable itself has to be 'injected' into the + // decl-context of its lambda's call-operator (which has + // not yet been created). + // Each init-expression is a full-expression that has to get + // Sema-analyzed (for capturing etc.) before its lambda's + // call-operator's decl-context, scope & scopeinfo are pushed on their + // respective stacks. Thus if any variable is odr-used in the init-capture + // it will correctly get captured in the enclosing lambda, if one exists. + // The init-variables above are created later once the lambdascope and + // call-operators decl-context is pushed onto its respective stack. + + // Since the lambda init-capture's initializer expression occurs in the + // context of the enclosing function or lambda, therefore we can not wait + // till a lambda scope has been pushed on before deciding whether the + // variable needs to be captured. We also need to process all + // lvalue-to-rvalue conversions and discarded-value conversions, + // so that we can avoid capturing certain constant variables. + // For e.g., + // void test() { + // const int x = 10; + // auto L = [&z = x](char a) { <-- don't capture by the current lambda + // return [y = x](int i) { <-- don't capture by enclosing lambda + // return y; + // } + // }; + // If x was not const, the second use would require 'L' to capture, and + // that would be an error. + + ParsedType InitCaptureParsedType; + if (Init.isUsable()) { + // Get the pointer and store it in an lvalue, so we can use it as an + // out argument. + Expr *InitExpr = Init.get(); + // This performs any lvalue-to-rvalue conversions if necessary, which + // can affect what gets captured in the containing decl-context. + QualType InitCaptureType = Actions.performLambdaInitCaptureInitialization( + Loc, Kind == LCK_ByRef, Id, InitExpr); + Init = InitExpr; + InitCaptureParsedType.set(InitCaptureType); + } + Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init, InitCaptureParsedType); } T.consumeClose(); Intro.Range.setEnd(T.getCloseLocation()); - return DiagResult(); } @@ -785,13 +931,23 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) { bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { TentativeParsingAction PA(*this); - Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro)); + bool SkippedInits = false; + Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro, &SkippedInits)); if (DiagID) { PA.Revert(); return true; } + if (SkippedInits) { + // Parse it again, but this time parse the init-captures too. + PA.Revert(); + Intro = LambdaIntroducer(); + DiagID = ParseLambdaIntroducer(Intro); + assert(!DiagID && "parsing lambda-introducer failed on reparse"); + return false; + } + PA.Commit(); return false; } @@ -806,9 +962,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc, "lambda expression parsing"); + + + // FIXME: Call into Actions to add any init-capture declarations to the + // scope while parsing the lambda-declarator and compound-statement. + // Parse lambda-declarator[opt]. DeclSpec DS(AttrFactory); Declarator D(DS, Declarator::LambdaExprContext); + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + Actions.PushLambdaScope(); if (Tok.is(tok::l_paren)) { ParseScope PrototypeScope(this, @@ -826,9 +989,15 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo; SourceLocation EllipsisLoc; - if (Tok.isNot(tok::r_paren)) + + if (Tok.isNot(tok::r_paren)) { + Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth); ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); - + // For a generic lambda, each 'auto' within the parameter declaration + // clause creates a template type parameter, so increment the depth. + if (Actions.getCurGenericLambda()) + ++CurTemplateDepthTracker; + } T.consumeClose(); SourceLocation RParenLoc = T.getCloseLocation(); DeclEndLoc = RParenLoc; @@ -1089,7 +1258,7 @@ ExprResult Parser::ParseCXXTypeid() { // Match the ')'. if (Result.isInvalid()) - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); else { T.consumeClose(); RParenLoc = T.getCloseLocation(); @@ -1139,7 +1308,7 @@ ExprResult Parser::ParseCXXUuidof() { // Match the ')'. if (Result.isInvalid()) - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); else { T.consumeClose(); @@ -1325,7 +1494,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(Exprs, CommaLocs)) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } } @@ -1411,7 +1580,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, SourceLocation Loc; ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { - SkipUntil(tok::semi); + SkipUntil(tok::semi, StopAtSemi); return true; } DeclaratorInfo.setAsmLabel(AsmLabel.release()); @@ -1443,7 +1612,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, } 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)) + if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) RParen = ConsumeParen(); Diag(DeclOut ? DeclOut->getLocation() : LParen, diag::err_expected_init_in_condition_lparen) @@ -2303,14 +2472,14 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { T.consumeOpen(); PlacementLParen = T.getOpenLocation(); if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) { - SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } T.consumeClose(); PlacementRParen = T.getCloseLocation(); if (PlacementRParen.isInvalid()) { - SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } @@ -2353,7 +2522,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { } } if (DeclaratorInfo.isInvalidType()) { - SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } @@ -2368,14 +2537,14 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { if (Tok.isNot(tok::r_paren)) { CommaLocsTy CommaLocs; if (ParseExpressionList(ConstructorArgs, CommaLocs)) { - SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } } T.consumeClose(); ConstructorRParen = T.getCloseLocation(); if (ConstructorRParen.isInvalid()) { - SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } Initializer = Actions.ActOnParenListExpr(ConstructorLParen, @@ -2416,7 +2585,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { : ParseConstantExpression()); if (Size.isInvalid()) { // Recover - SkipUntil(tok::r_square); + SkipUntil(tok::r_square, StopAtSemi); return; } first = false; @@ -2553,6 +2722,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___is_reference: return UTT_IsReference; case tok::kw___is_rvalue_reference: return UTT_IsRvalueReference; case tok::kw___is_scalar: return UTT_IsScalar; + case tok::kw___is_sealed: return UTT_IsSealed; case tok::kw___is_signed: return UTT_IsSigned; case tok::kw___is_standard_layout: return UTT_IsStandardLayout; case tok::kw___is_trivial: return UTT_IsTrivial; @@ -2645,18 +2815,18 @@ ExprResult Parser::ParseBinaryTypeTrait() { TypeResult LhsTy = ParseTypeName(); if (LhsTy.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } TypeResult RhsTy = ParseTypeName(); if (RhsTy.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2735,8 +2905,8 @@ ExprResult Parser::ParseArrayTypeTrait() { TypeResult Ty = ParseTypeName(); if (Ty.isInvalid()) { - SkipUntil(tok::comma); - SkipUntil(tok::r_paren); + SkipUntil(tok::comma, StopAtSemi); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2748,7 +2918,7 @@ ExprResult Parser::ParseArrayTypeTrait() { } case ATT_ArrayExtent: { if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2905,7 +3075,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // Match the ')'. if (Result.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 8311aa22075e..37f74bbcd51b 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -244,7 +244,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { bool IsExpr; void *TypeOrExpr; if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { - SkipUntil(tok::r_square); + SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } @@ -285,7 +285,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { 0); ConsumeToken(); // the identifier if (!ReceiverType) { - SkipUntil(tok::r_square); + SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } @@ -312,7 +312,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { if (!Idx.get()) { Idx = ParseAssignmentExpression(); if (Idx.isInvalid()) { - SkipUntil(tok::r_square); + SkipUntil(tok::r_square, StopAtSemi); return Idx; } } @@ -340,7 +340,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { ExprResult RHS(ParseConstantExpression()); if (RHS.isInvalid()) { - SkipUntil(tok::r_square); + SkipUntil(tok::r_square, StopAtSemi); return RHS; } Desig.AddDesignator(Designator::getArrayRange(Idx.release(), @@ -457,7 +457,7 @@ ExprResult Parser::ParseBraceInitializer() { // immediately, it can't be an error, since there is no other way of // leaving this loop except through this if. if (Tok.isNot(tok::comma)) { - SkipUntil(tok::r_brace, false, true); + SkipUntil(tok::r_brace, StopBeforeMatch); break; } } diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 4a572f199328..86f38cfee37a 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -289,6 +289,9 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, LAngleLoc, EndProtoLoc)) return 0; + if (Tok.isNot(tok::less)) + Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc); + Decl *ClsType = Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, superClassId, superClassLoc, @@ -348,9 +351,10 @@ public: if (SetterName) SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName); else - SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(), - P.PP.getSelectorTable(), - FD.D.getIdentifier()); + SetterSel = + SelectorTable::constructSetterSelector(P.PP.getIdentifierTable(), + P.PP.getSelectorTable(), + FD.D.getIdentifier()); bool isOverridingProperty = false; Decl *Property = P.Actions.ActOnProperty(P.getCurScope(), AtLoc, LParenLoc, @@ -399,7 +403,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, // method definitions. 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); + SkipUntil(tok::at, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); } @@ -472,7 +476,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, // or something like that. Diag(AtLoc, diag::err_objc_illegal_interface_qual); // Skip until we see an '@' or '}' or ';'. - SkipUntil(tok::r_brace, tok::at); + SkipUntil(tok::r_brace, tok::at, StopAtSemi); break; case tok::objc_implementation: @@ -536,10 +540,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, // Insert collected methods declarations into the @interface object. // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit. - Actions.ActOnAtEnd(getCurScope(), AtEnd, - allMethods.data(), allMethods.size(), - allProperties.data(), allProperties.size(), - allTUVariables.data(), allTUVariables.size()); + Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables); } /// Parse property attribute declarations. @@ -627,7 +628,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { if (!SelIdent) { Diag(Tok, diag::err_objc_expected_selector_for_getter_setter) << IsSetter; - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } @@ -645,7 +646,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { } } else { Diag(AttrName, diag::err_objc_expected_property_attr) << II; - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } @@ -942,7 +943,7 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, else if (Tok.getLocation() == TypeStartLoc) { // If we didn't eat any tokens, then this isn't a type. Diag(Tok, diag::err_expected_type); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); } else { // Otherwise, we found *something*, but didn't get a ')' in the right // place. Emit an error then return what we have as the type. @@ -1019,7 +1020,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, Diag(Tok, diag::err_expected_selector_for_method) << SourceRange(mLoc, Tok.getLocation()); // Skip until we get a ; or @. - SkipUntil(tok::at, true /*StopAtSemi*/, true /*don't consume*/); + SkipUntil(tok::at, StopAtSemi | StopBeforeMatch); return 0; } @@ -1079,9 +1080,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(), mType == tok::minus, /*AtParameterName=*/true, - ReturnType, - KeyIdents.data(), - KeyIdents.size()); + ReturnType, KeyIdents); cutOffParsing(); return 0; } @@ -1107,9 +1106,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(), mType == tok::minus, /*AtParameterName=*/false, - ReturnType, - KeyIdents.data(), - KeyIdents.size()); + ReturnType, KeyIdents); cutOffParsing(); return 0; } @@ -1202,7 +1199,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::greater); + SkipUntil(tok::greater, StopAtSemi); return true; } ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(), @@ -1375,7 +1372,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, } else { Diag(Tok, diag::err_expected_semi_decl_list); // Skip to end of block or statement - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); } } HelperActionsForIvarDeclarations(interfaceDecl, atLoc, @@ -1537,10 +1534,16 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); - SkipUntil(tok::r_paren, false); // don't stop at ';' + SkipUntil(tok::r_paren); // don't stop at ';' return DeclGroupPtrTy(); } rparenLoc = ConsumeParen(); + if (Tok.is(tok::less)) { // we have illegal '<' try to recover + Diag(Tok, diag::err_unexpected_protocol_qualifier); + AttributeFactory attr; + DeclSpec DS(attr); + (void)ParseObjCProtocolQualifiers(DS); + } ObjCImpDecl = Actions.ActOnStartCategoryImplementation( AtLoc, nameId, nameLoc, categoryId, categoryLoc); @@ -1806,7 +1809,7 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { Diag(Tok, diag::err_expected_rparen); // Skip forward until we see a left brace, but don't consume it. - SkipUntil(tok::l_brace, true, true); + SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch); } // Require a compound statement. @@ -1896,7 +1899,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { if (Tok.is(tok::r_paren)) RParenLoc = ConsumeParen(); else // Skip over garbage, until we get to ')'. Eat the ')'. - SkipUntil(tok::r_paren, true, false); + SkipUntil(tok::r_paren, StopAtSemi); StmtResult CatchBody(true); if (Tok.is(tok::l_brace)) @@ -2029,7 +2032,7 @@ Decl *Parser::ParseObjCMethodDefinition() { Diag(Tok, diag::err_expected_method_body); // Skip over garbage, until we get to '{'. Don't eat the '{'. - SkipUntil(tok::l_brace, true, true); + SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch); // If we didn't find the '{', bail out. if (Tok.isNot(tok::l_brace)) @@ -2038,7 +2041,7 @@ Decl *Parser::ParseObjCMethodDefinition() { if (!MDecl) { ConsumeBrace(); - SkipUntil(tok::r_brace, /*StopAtSemi=*/false); + SkipUntil(tok::r_brace); return 0; } @@ -2348,7 +2351,7 @@ ExprResult Parser::ParseObjCMessageExpression() { bool IsExpr; void *TypeOrExpr = NULL; if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { - SkipUntil(tok::r_square); + SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } @@ -2376,7 +2379,7 @@ ExprResult Parser::ParseObjCMessageExpression() { case Sema::ObjCClassMessage: if (!ReceiverType) { - SkipUntil(tok::r_square); + SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } @@ -2394,7 +2397,7 @@ ExprResult Parser::ParseObjCMessageExpression() { // Otherwise, an arbitrary expression can be the receiver of a send. ExprResult Res(ParseExpression()); if (Res.isInvalid()) { - SkipUntil(tok::r_square); + SkipUntil(tok::r_square, StopAtSemi); return Res; } @@ -2449,14 +2452,14 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, if (Tok.is(tok::code_completion)) { if (SuperLoc.isValid()) - Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, 0, 0, + Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None, false); else if (ReceiverType) - Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, 0, 0, + Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, None, false); else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, - 0, 0, false); + None, false); cutOffParsing(); return ExprError(); } @@ -2480,7 +2483,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // 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); + SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } @@ -2490,18 +2493,15 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, if (Tok.is(tok::code_completion)) { if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, - KeyIdents.data(), - KeyIdents.size(), + KeyIdents, /*AtArgumentEpression=*/true); else if (ReceiverType) Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, - KeyIdents.data(), - KeyIdents.size(), + KeyIdents, /*AtArgumentEpression=*/true); else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, - KeyIdents.data(), - KeyIdents.size(), + KeyIdents, /*AtArgumentEpression=*/true); cutOffParsing(); @@ -2520,7 +2520,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // 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); + SkipUntil(tok::r_square, StopAtSemi); return Res; } @@ -2531,18 +2531,15 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, if (Tok.is(tok::code_completion)) { if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, - KeyIdents.data(), - KeyIdents.size(), + KeyIdents, /*AtArgumentEpression=*/false); else if (ReceiverType) Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, - KeyIdents.data(), - KeyIdents.size(), + KeyIdents, /*AtArgumentEpression=*/false); else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, - KeyIdents.data(), - KeyIdents.size(), + KeyIdents, /*AtArgumentEpression=*/false); cutOffParsing(); return ExprError(); @@ -2567,7 +2564,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // 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); + SkipUntil(tok::r_square, StopAtSemi); return Res; } @@ -2580,7 +2577,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // 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); + SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } @@ -2592,7 +2589,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // 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); + SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } @@ -2718,7 +2715,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { // 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); + SkipUntil(tok::r_square, StopAtSemi); return Res; } @@ -2753,7 +2750,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { // 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); + SkipUntil(tok::r_brace, StopAtSemi); return KeyExpr; } } @@ -2762,7 +2759,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { ConsumeToken(); } else { Diag(Tok, diag::err_expected_colon); - SkipUntil(tok::r_brace); + SkipUntil(tok::r_brace, StopAtSemi); return ExprError(); } @@ -2771,7 +2768,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { // 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); + SkipUntil(tok::r_brace, StopAtSemi); return ValueExpr; } @@ -2864,8 +2861,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { T.consumeOpen(); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(), - KeyIdents.size()); + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents); cutOffParsing(); return ExprError(); } @@ -2891,8 +2887,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { break; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(), - KeyIdents.size()); + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents); cutOffParsing(); return ExprError(); } diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index 507a6b1bcd87..89e4147e285c 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -12,8 +12,11 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTConsumer.h" -#include "clang/Parse/Parser.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/Scope.h" +#include "llvm/ADT/PointerIntPair.h" #include "RAIIObjectsForParser.h" using namespace clang; @@ -21,98 +24,358 @@ using namespace clang; // OpenMP declarative directives. //===----------------------------------------------------------------------===// -/// \brief Parses OpenMP declarative directive -/// threadprivate-directive -/// annot_pragma_openmp threadprivate simple-variable-list +/// \brief Parsing of declarative OpenMP directives. +/// +/// threadprivate-directive: +/// annot_pragma_openmp 'threadprivate' simple-variable-list /// Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + ParenBraceBracketBalancer BalancerRAIIObj(*this); SourceLocation Loc = ConsumeToken(); - SmallVector<DeclarationNameInfo, 5> Identifiers; - OpenMPDirectiveKind Kind = Tok.isAnnotation() ? - OMPD_unknown : - getOpenMPDirectiveKind(PP.getSpelling(Tok)); - switch(Kind) { + SmallVector<Expr *, 5> Identifiers; + OpenMPDirectiveKind DKind = Tok.isAnnotation() ? + OMPD_unknown : + getOpenMPDirectiveKind(PP.getSpelling(Tok)); + + switch (DKind) { case OMPD_threadprivate: ConsumeToken(); - if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) { + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::warn_omp_extra_tokens_at_eol) << getOpenMPDirectiveName(OMPD_threadprivate); - SkipUntil(tok::annot_pragma_openmp_end, false, true); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } + // Skip the last annot_pragma_openmp_end. ConsumeToken(); return Actions.ActOnOpenMPThreadprivateDirective(Loc, - getCurScope(), Identifiers); } break; case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; - default: + case OMPD_parallel: + case OMPD_task: + case NUM_OPENMP_DIRECTIVES: Diag(Tok, diag::err_omp_unexpected_directive) - << getOpenMPDirectiveName(Kind); + << getOpenMPDirectiveName(DKind); break; } - SkipUntil(tok::annot_pragma_openmp_end, false); + SkipUntil(tok::annot_pragma_openmp_end); return DeclGroupPtrTy(); } +/// \brief Parsing of declarative or executable OpenMP directives. +/// +/// threadprivate-directive: +/// annot_pragma_openmp 'threadprivate' simple-variable-list +/// annot_pragma_openmp_end +/// +/// parallel-directive: +/// annot_pragma_openmp 'parallel' {clause} annot_pragma_openmp_end +/// +StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() { + assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + ParenBraceBracketBalancer BalancerRAIIObj(*this); + SmallVector<Expr *, 5> Identifiers; + SmallVector<OMPClause *, 5> Clauses; + SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, NUM_OPENMP_CLAUSES> + FirstClauses(NUM_OPENMP_CLAUSES); + const unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | + Scope::OpenMPDirectiveScope; + SourceLocation Loc = ConsumeToken(), EndLoc; + OpenMPDirectiveKind DKind = Tok.isAnnotation() ? + OMPD_unknown : + getOpenMPDirectiveKind(PP.getSpelling(Tok)); + // Name of critical directive. + DeclarationNameInfo DirName; + StmtResult Directive = StmtError(); + + switch (DKind) { + case OMPD_threadprivate: + ConsumeToken(); + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_threadprivate); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + } + DeclGroupPtrTy Res = + Actions.ActOnOpenMPThreadprivateDirective(Loc, + Identifiers); + Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); + } + SkipUntil(tok::annot_pragma_openmp_end); + break; + case OMPD_parallel: { + ConsumeToken(); + + Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope()); + + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = Tok.isAnnotation() ? + OMPC_unknown : + getOpenMPClauseKind(PP.getSpelling(Tok)); + OMPClause *Clause = ParseOpenMPClause(DKind, CKind, + !FirstClauses[CKind].getInt()); + FirstClauses[CKind].setInt(true); + if (Clause) { + FirstClauses[CKind].setPointer(Clause); + Clauses.push_back(Clause); + } + + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + } + // End location of the directive. + EndLoc = Tok.getLocation(); + // Consume final annot_pragma_openmp_end. + ConsumeToken(); + + StmtResult AssociatedStmt; + bool CreateDirective = true; + ParseScope OMPDirectiveScope(this, ScopeFlags); + { + // The body is a block scope like in Lambdas and Blocks. + Sema::CompoundScopeRAII CompoundScope(Actions); + Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_OpenMP, 1); + Actions.ActOnStartOfCompoundStmt(); + // Parse statement + AssociatedStmt = ParseStatement(); + Actions.ActOnFinishOfCompoundStmt(); + if (!AssociatedStmt.isUsable()) { + Actions.ActOnCapturedRegionError(); + CreateDirective = false; + } else { + AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.take()); + CreateDirective = AssociatedStmt.isUsable(); + } + } + if (CreateDirective) + Directive = Actions.ActOnOpenMPExecutableDirective(DKind, Clauses, + AssociatedStmt.take(), + Loc, EndLoc); + + // Exit scope. + Actions.EndOpenMPDSABlock(Directive.get()); + OMPDirectiveScope.Exit(); + } + break; + case OMPD_unknown: + Diag(Tok, diag::err_omp_unknown_directive); + SkipUntil(tok::annot_pragma_openmp_end); + break; + case OMPD_task: + case NUM_OPENMP_DIRECTIVES: + Diag(Tok, diag::err_omp_unexpected_directive) + << getOpenMPDirectiveName(DKind); + SkipUntil(tok::annot_pragma_openmp_end); + break; + } + return Directive; +} + /// \brief Parses list of simple variables for '#pragma omp threadprivate' -/// directive -/// simple-variable-list: -/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end +/// directive. +/// +/// simple-variable-list: +/// '(' id-expression {, id-expression} ')' /// -bool Parser::ParseOpenMPSimpleVarList( - OpenMPDirectiveKind Kind, - SmallVectorImpl<DeclarationNameInfo> &IdList) { +bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, + SmallVectorImpl<Expr *> &VarList, + bool AllowScopeSpecifier) { + VarList.clear(); // Parse '('. - bool IsCorrect = true; - BalancedDelimiterTracker T(*this, tok::l_paren); + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(Kind))) { - SkipUntil(tok::annot_pragma_openmp_end, false, true); - return false; - } + getOpenMPDirectiveName(Kind))) + return true; + bool IsCorrect = true; + bool NoIdentIsFound = true; // Read tokens while ')' or annot_pragma_openmp_end is not found. - do { + while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { CXXScopeSpec SS; SourceLocation TemplateKWLoc; UnqualifiedId Name; // Read var name. Token PrevTok = Tok; + NoIdentIsFound = false; - if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), - TemplateKWLoc, Name)) { + if (AllowScopeSpecifier && getLangOpts().CPlusPlus && + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, - false, true); - } - else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && - Tok.isNot(tok::annot_pragma_openmp_end)) { + StopBeforeMatch); + } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), + TemplateKWLoc, Name)) { + IsCorrect = false; + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, - false, true); - Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id) - << getLangOpts().CPlusPlus + StopBeforeMatch); + Diag(PrevTok.getLocation(), diag::err_expected_ident) << SourceRange(PrevTok.getLocation(), PrevTokLocation); } else { - IdList.push_back(Actions.GetNameFromUnqualifiedId(Name)); + DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name); + ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS, + NameInfo); + if (Res.isUsable()) + VarList.push_back(Res.take()); } // Consume ','. if (Tok.is(tok::comma)) { ConsumeToken(); } - } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)); + } + + if (NoIdentIsFound) { + Diag(Tok, diag::err_expected_ident); + IsCorrect = false; + } - if (IsCorrect || Tok.is(tok::r_paren)) { - IsCorrect = !T.consumeClose() && IsCorrect; + // Parse ')'. + IsCorrect = !T.consumeClose() && IsCorrect; + + return !IsCorrect && VarList.empty(); +} + +/// \brief Parsing of OpenMP clauses. +/// +/// clause: +/// default-clause|private-clause|firstprivate-clause|shared-clause +/// +OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, + OpenMPClauseKind CKind, bool FirstClause) { + OMPClause *Clause = 0; + bool ErrorFound = false; + // Check if clause is allowed for the given directive. + if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) { + Diag(Tok, diag::err_omp_unexpected_clause) + << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); + ErrorFound = true; } - return !IsCorrect && IdList.empty(); + switch (CKind) { + case OMPC_default: + // OpenMP [2.9.3.1, Restrictions] + // Only a single default clause may be specified on a parallel or task + // directive. + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind); + } + + Clause = ParseOpenMPSimpleClause(CKind); + break; + case OMPC_private: + case OMPC_firstprivate: + case OMPC_shared: + Clause = ParseOpenMPVarListClause(CKind); + break; + case OMPC_unknown: + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(DKind); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + break; + case OMPC_threadprivate: + case NUM_OPENMP_CLAUSES: + Diag(Tok, diag::err_omp_unexpected_clause) + << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); + SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch); + break; + } + return ErrorFound ? 0 : Clause; } + +/// \brief Parsing of simple OpenMP clauses like 'default'. +/// +/// default-clause: +/// 'default' '(' 'none' | 'shared' ') +/// +OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) { + SourceLocation Loc = Tok.getLocation(); + SourceLocation LOpen = ConsumeToken(); + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(Kind))) + return 0; + + unsigned Type = Tok.isAnnotation() ? + unsigned(OMPC_DEFAULT_unknown) : + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + SourceLocation TypeLoc = Tok.getLocation(); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + + // Parse ')'. + T.consumeClose(); + + return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc, + Tok.getLocation()); +} + +/// \brief Parsing of OpenMP clause 'private', 'firstprivate', +/// 'shared', 'copyin', or 'reduction'. +/// +/// private-clause: +/// 'private' '(' list ')' +/// firstprivate-clause: +/// 'firstprivate' '(' list ')' +/// shared-clause: +/// 'shared' '(' list ')' +/// +OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { + SourceLocation Loc = Tok.getLocation(); + SourceLocation LOpen = ConsumeToken(); + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(Kind))) + return 0; + + SmallVector<Expr *, 5> Vars; + bool IsComma = true; + while (IsComma || (Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end))) { + // Parse variable + ExprResult VarExpr = ParseAssignmentExpression(); + if (VarExpr.isUsable()) { + Vars.push_back(VarExpr.take()); + } else { + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } + // Skip ',' if any + IsComma = Tok.is(tok::comma); + if (IsComma) { + ConsumeToken(); + } else if (Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::err_omp_expected_punc) + << 1 << getOpenMPClauseName(Kind); + } + } + + // Parse ')'. + T.consumeClose(); + if (Vars.empty()) + return 0; + + return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen, + Tok.getLocation()); +} + diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 3d1249aa684a..8a374e0fce61 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -728,6 +728,7 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); return; } + SourceLocation StateLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.isNot(tok::eod)) { @@ -747,6 +748,10 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, Toks[0].setAnnotationValue(data.getOpaqueValue()); PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); + + if (PP.getPPCallbacks()) + PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, ename, + StateLoc, state); } /// \brief Handle '#pragma omp ...' when OpenMP is disabled. @@ -794,6 +799,63 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true); } +/// \brief Handle the Microsoft \#pragma detect_mismatch extension. +/// +/// The syntax is: +/// \code +/// #pragma detect_mismatch("name", "value") +/// \endcode +/// Where 'name' and 'value' are quoted strings. The values are embedded in +/// the object file and passed along to the linker. If the linker detects a +/// mismatch in the object file's values for the given name, a LNK2038 error +/// is emitted. See MSDN for more details. +void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + SourceLocation CommentLoc = Tok.getLocation(); + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(CommentLoc, diag::err_expected_lparen); + return; + } + + // Read the name to embed, which must be a string literal. + std::string NameString; + if (!PP.LexStringLiteral(Tok, NameString, + "pragma detect_mismatch", + /*MacroExpansion=*/true)) + return; + + // Read the comma followed by a second string literal. + std::string ValueString; + if (Tok.isNot(tok::comma)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed); + return; + } + + if (!PP.LexStringLiteral(Tok, ValueString, "pragma detect_mismatch", + /*MacroExpansion=*/true)) + return; + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::err_expected_rparen); + return; + } + PP.Lex(Tok); // Eat the r_paren. + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed); + return; + } + + // If the pragma is lexically sound, notify any interested PPCallbacks. + if (PP.getPPCallbacks()) + PP.getPPCallbacks()->PragmaDetectMismatch(CommentLoc, NameString, + ValueString); + + Actions.ActOnPragmaDetectMismatch(NameString, ValueString); +} + /// \brief Handle the microsoft \#pragma comment extension. /// /// The syntax is: @@ -821,10 +883,16 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, } // Verify that this is one of the 5 whitelisted options. - // FIXME: warn that 'exestr' is deprecated. - const IdentifierInfo *II = Tok.getIdentifierInfo(); - if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") && - !II->isStr("linker") && !II->isStr("user")) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + Sema::PragmaMSCommentKind Kind = + llvm::StringSwitch<Sema::PragmaMSCommentKind>(II->getName()) + .Case("linker", Sema::PCK_Linker) + .Case("lib", Sema::PCK_Lib) + .Case("compiler", Sema::PCK_Compiler) + .Case("exestr", Sema::PCK_ExeStr) + .Case("user", Sema::PCK_User) + .Default(Sema::PCK_Unknown); + if (Kind == Sema::PCK_Unknown) { PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); return; } @@ -837,11 +905,12 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, /*MacroExpansion=*/true)) return; + // FIXME: warn that 'exestr' is deprecated. // FIXME: If the kind is "compiler" warn if the string is present (it is // ignored). - // FIXME: 'lib' requires a comment string. - // FIXME: 'linker' requires a comment string, and has a specific list of - // things that are allowable. + // The MSDN docs say that "lib" and "linker" require a string and have a short + // whitelist of linker options they support, but in practice MSVC doesn't + // issue a diagnostic. Therefore neither does clang. if (Tok.isNot(tok::r_paren)) { PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); @@ -857,4 +926,6 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, // If the pragma is lexically sound, notify any interested PPCallbacks. if (PP.getPPCallbacks()) PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString); + + Actions.ActOnPragmaMSComment(Kind, ArgumentString); } diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index d9560f3181d6..b41450f4eadf 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -116,9 +116,22 @@ public: /// PragmaCommentHandler - "\#pragma comment ...". class PragmaCommentHandler : public PragmaHandler { public: - PragmaCommentHandler() : PragmaHandler("comment") {} + PragmaCommentHandler(Sema &Actions) + : PragmaHandler("comment"), Actions(Actions) {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); +private: + Sema &Actions; +}; + +class PragmaDetectMismatchHandler : public PragmaHandler { +public: + PragmaDetectMismatchHandler(Sema &Actions) + : PragmaHandler("detect_mismatch"), Actions(Actions) {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +private: + Sema &Actions; }; } // end namespace clang diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 43b6965d314f..d1f2138db48f 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -41,6 +41,21 @@ using namespace clang; // C99 6.8: Statements and Blocks. //===----------------------------------------------------------------------===// +/// \brief Parse a standalone statement (for instance, as the body of an 'if', +/// 'while', or 'for'). +StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc) { + StmtResult Res; + + // We may get back a null statement if we found a #pragma. Keep going until + // we get an actual statement. + do { + StmtVector Stmts; + Res = ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc); + } while (!Res.isInvalid() && !Res.get()); + + return Res; +} + /// ParseStatementOrDeclaration - Read 'statement' or 'declaration'. /// StatementOrDeclaration: /// statement @@ -111,6 +126,38 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, return Actions.ProcessStmtAttributes(Res.get(), Attrs.getList(), Attrs.Range); } +namespace { +class StatementFilterCCC : public CorrectionCandidateCallback { +public: + StatementFilterCCC(Token nextTok) : NextToken(nextTok) { + WantTypeSpecifiers = nextTok.is(tok::l_paren) || nextTok.is(tok::less) || + nextTok.is(tok::identifier) || nextTok.is(tok::star) || + nextTok.is(tok::amp) || nextTok.is(tok::l_square); + WantExpressionKeywords = nextTok.is(tok::l_paren) || + nextTok.is(tok::identifier) || + nextTok.is(tok::arrow) || nextTok.is(tok::period); + WantRemainingKeywords = nextTok.is(tok::l_paren) || nextTok.is(tok::semi) || + nextTok.is(tok::identifier) || + nextTok.is(tok::l_brace); + WantCXXNamedCasts = false; + } + + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + if (FieldDecl *FD = candidate.getCorrectionDeclAs<FieldDecl>()) + return !candidate.getCorrectionSpecifier() || isa<ObjCIvarDecl>(FD); + if (NextToken.is(tok::equal)) + return candidate.getCorrectionDeclAs<VarDecl>(); + if (NextToken.is(tok::period) && + candidate.getCorrectionDeclAs<NamespaceDecl>()) + return false; + return CorrectionCandidateCallback::ValidateCandidate(candidate); + } + +private: + Token NextToken; +}; +} + StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts, bool OnlyStatement, SourceLocation *TrailingElseLoc, @@ -149,25 +196,12 @@ Retry: if (Next.isNot(tok::coloncolon)) { // Try to limit which sets of keywords should be included in typo // correction based on what the next token is. - // FIXME: Pass the next token into the CorrectionCandidateCallback and - // do this filtering in a more fine-grained manner. - CorrectionCandidateCallback DefaultValidator; - DefaultValidator.WantTypeSpecifiers = - Next.is(tok::l_paren) || Next.is(tok::less) || - Next.is(tok::identifier) || Next.is(tok::star) || - Next.is(tok::amp) || Next.is(tok::l_square); - DefaultValidator.WantExpressionKeywords = - Next.is(tok::l_paren) || Next.is(tok::identifier) || - Next.is(tok::arrow) || Next.is(tok::period); - DefaultValidator.WantRemainingKeywords = - Next.is(tok::l_paren) || Next.is(tok::semi) || - Next.is(tok::identifier) || Next.is(tok::l_brace); - DefaultValidator.WantCXXNamedCasts = false; - if (TryAnnotateName(/*IsAddressOfOperand*/false, &DefaultValidator) + StatementFilterCCC Validator(Next); + if (TryAnnotateName(/*IsAddressOfOperand*/false, &Validator) == ANK_Error) { // Handle errors here by skipping up to the next semicolon or '}', and // eat the semicolon if that's what stopped us. - SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); return StmtError(); @@ -293,6 +327,7 @@ Retry: return StmtEmpty(); case tok::annot_pragma_fp_contract: + ProhibitAttributes(Attrs); Diag(Tok, diag::err_pragma_fp_contract_scope); ConsumeToken(); return StmtError(); @@ -303,12 +338,13 @@ Retry: return StmtEmpty(); case tok::annot_pragma_captured: + ProhibitAttributes(Attrs); return HandlePragmaCaptured(); case tok::annot_pragma_openmp: - SourceLocation DeclStart = Tok.getLocation(); - DeclGroupPtrTy Res = ParseOpenMPDeclarativeDirective(); - return Actions.ActOnDeclStmt(Res, DeclStart, Tok.getLocation()); + ProhibitAttributes(Attrs); + return ParseOpenMPDeclarativeOrExecutableDirective(); + } // If we reached this code, the statement must end in a semicolon. @@ -320,7 +356,7 @@ Retry: // succeed. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, SemiError); // Skip until we see a } or ;, but don't eat it. - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); } return Res; @@ -337,7 +373,7 @@ StmtResult Parser::ParseExprStatement() { // If the expression is invalid, skip ahead to the next semicolon or '}'. // Not doing this opens us up to the possibility of infinite loops if // ParseExpression does not consume any tokens. - SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); return Actions.ActOnExprStmtError(); @@ -480,11 +516,40 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) { // identifier ':' statement SourceLocation ColonLoc = ConsumeToken(); - // Read label attributes, if present. attrs will contain both C++11 and GNU - // attributes (if present) after this point. - MaybeParseGNUAttributes(attrs); + // Read label attributes, if present. + StmtResult SubStmt; + if (Tok.is(tok::kw___attribute)) { + ParsedAttributesWithRange TempAttrs(AttrFactory); + ParseGNUAttributes(TempAttrs); + + // In C++, GNU attributes only apply to the label if they are followed by a + // semicolon, to disambiguate label attributes from attributes on a labeled + // declaration. + // + // This doesn't quite match what GCC does; if the attribute list is empty + // and followed by a semicolon, GCC will reject (it appears to parse the + // attributes as part of a statement in that case). That looks like a bug. + if (!getLangOpts().CPlusPlus || Tok.is(tok::semi)) + attrs.takeAllFrom(TempAttrs); + else if (isDeclarationStatement()) { + StmtVector Stmts; + // FIXME: We should do this whether or not we have a declaration + // statement, but that doesn't work correctly (because ProhibitAttributes + // can't handle GNU attributes), so only call it in the one case where + // GNU attributes are allowed. + SubStmt = ParseStatementOrDeclarationAfterAttributes( + Stmts, /*OnlyStmts*/ true, 0, TempAttrs); + if (!TempAttrs.empty() && !SubStmt.isInvalid()) + SubStmt = Actions.ProcessStmtAttributes( + SubStmt.get(), TempAttrs.getList(), TempAttrs.Range); + } else { + Diag(Tok, diag::err_expected_semi_after) << "__attribute__"; + } + } - StmtResult SubStmt(ParseStatement()); + // If we've not parsed a statement yet, parse one now. + if (!SubStmt.isInvalid() && !SubStmt.isUsable()) + SubStmt = ParseStatement(); // Broken substmt shouldn't prevent the label from being added to the AST. if (SubStmt.isInvalid()) @@ -521,7 +586,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { // out of stack space in our recursive descent parser. As a special case, // flatten this recursion into an iterative loop. This is complex and gross, // but all the grossness is constrained to ParseCaseStatement (and some - // wierdness in the actions), so this is just local grossness :). + // weirdness in the actions), so this is just local grossness :). // TopLevelCase - This is the highest level we have parsed. 'case 1' in the // example above. @@ -552,7 +617,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { ExprResult LHS(MissingCase ? Expr : ParseConstantExpression()); MissingCase = false; if (LHS.isInvalid()) { - SkipUntil(tok::colon); + SkipUntil(tok::colon, StopAtSemi); return StmtError(); } @@ -565,7 +630,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { RHS = ParseConstantExpression(); if (RHS.isInvalid()) { - SkipUntil(tok::colon); + SkipUntil(tok::colon, StopAtSemi); return StmtError(); } } @@ -798,7 +863,6 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { // only allowed at the start of a compound stmt regardless of the language. while (Tok.is(tok::kw___label__)) { SourceLocation LabelLoc = ConsumeToken(); - Diag(LabelLoc, diag::ext_gnu_local_label); SmallVector<Decl *, 8> DeclsInGroup; while (1) { @@ -817,8 +881,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { } DeclSpec DS(AttrFactory); - DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS, - DeclsInGroup.data(), DeclsInGroup.size()); + DeclGroupPtrTy Res = + Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation()); ExpectAndConsumeSemi(diag::err_expected_semi_declaration); @@ -1132,7 +1196,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { // will have no place to connect back with the switch. if (Tok.is(tok::l_brace)) { ConsumeBrace(); - SkipUntil(tok::r_brace, false, false); + SkipUntil(tok::r_brace); } else SkipUntil(tok::semi); return Switch; @@ -1283,7 +1347,7 @@ StmtResult Parser::ParseDoStatement() { if (!Body.isInvalid()) { Diag(Tok, diag::err_expected_while); Diag(DoLoc, diag::note_matching) << "do"; - SkipUntil(tok::semi, false, true); + SkipUntil(tok::semi, StopBeforeMatch); } return StmtError(); } @@ -1291,18 +1355,16 @@ StmtResult Parser::ParseDoStatement() { if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "do/while"; - SkipUntil(tok::semi, false, true); + SkipUntil(tok::semi, StopBeforeMatch); return StmtError(); } - // Parse the parenthesized condition. + // Parse the parenthesized expression. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - // FIXME: Do not just parse the attribute contents and throw them away - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); - ProhibitAttributes(attrs); + // A do-while expression is not a condition, so can't have attributes. + DiagnoseAndSkipCXX11Attributes(); ExprResult Cond = ParseExpression(); T.consumeClose(); @@ -1469,14 +1531,14 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { // for (expr : expr) { ... } Diag(Tok, diag::err_for_range_expected_decl) << FirstPart.get()->getSourceRange(); - SkipUntil(tok::r_paren, false, true); + SkipUntil(tok::r_paren, StopBeforeMatch); SecondPartIsInvalid = true; } else { if (!Value.isInvalid()) { Diag(Tok, diag::err_expected_semi_for); } else { // Skip until semicolon or rparen, don't consume it. - SkipUntil(tok::r_paren, true, true); + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); } @@ -1508,7 +1570,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { Diag(Tok, diag::err_expected_semi_for); else // Skip until semicolon or rparen, don't consume it. - SkipUntil(tok::r_paren, true, true); + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); } if (Tok.is(tok::semi)) { @@ -1610,7 +1672,7 @@ StmtResult Parser::ParseGotoStatement() { SourceLocation StarLoc = ConsumeToken(); ExprResult R(ParseExpression()); if (R.isInvalid()) { // Skip to the semicolon, but don't consume it. - SkipUntil(tok::semi, false, true); + SkipUntil(tok::semi, StopBeforeMatch); return StmtError(); } Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.take()); @@ -1669,7 +1731,7 @@ StmtResult Parser::ParseReturnStatement() { } else R = ParseExpression(); if (R.isInvalid()) { // Skip to the semicolon, but don't consume it. - SkipUntil(tok::semi, false, true); + SkipUntil(tok::semi, StopBeforeMatch); return StmtError(); } } @@ -2067,14 +2129,22 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { // We need an actual supported target. llvm::Triple TheTriple = Actions.Context.getTargetInfo().getTriple(); llvm::Triple::ArchType ArchTy = TheTriple.getArch(); + const std::string &TT = TheTriple.getTriple(); + const llvm::Target *TheTarget = 0; bool UnsupportedArch = (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64); - if (UnsupportedArch) + if (UnsupportedArch) { Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName(); - + } else { + std::string Error; + TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error); + if (!TheTarget) + Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error; + } + // If we don't support assembly, or the assembly is empty, we don't // need to instantiate the AsmParser, etc. - if (UnsupportedArch || AsmToks.empty()) { + if (!TheTarget || AsmToks.empty()) { return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(), /*NumOutputs*/ 0, /*NumInputs*/ 0, ConstraintRefs, ClobberRefs, Exprs, EndLoc); @@ -2086,19 +2156,16 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) return StmtError(); - // Find the target and create the target specific parser. - std::string Error; - const std::string &TT = TheTriple.getTriple(); - const llvm::Target *TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error); - - OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT)); OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); + OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT)); + // Get the instruction descriptor. + const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); OwningPtr<llvm::MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TT, "", "")); llvm::SourceMgr TempSrcMgr; - llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &TempSrcMgr); + llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr); llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>"); @@ -2109,10 +2176,8 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { OwningPtr<llvm::MCAsmParser> Parser(createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI)); OwningPtr<llvm::MCTargetAsmParser> - TargetParser(TheTarget->createMCAsmParser(*STI, *Parser)); + TargetParser(TheTarget->createMCAsmParser(*STI, *Parser, *MII)); - // Get the instruction descriptor. - const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); llvm::MCInstPrinter *IP = TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI); @@ -2214,7 +2279,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "asm"; - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return StmtError(); } BalancedDelimiterTracker T(*this, tok::l_paren); @@ -2333,7 +2398,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return true; } @@ -2347,14 +2412,14 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, ExprResult Constraint(ParseAsmStringLiteral()); if (Constraint.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return true; } Constraints.push_back(Constraint.release()); if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "asm operand"; - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return true; } @@ -2364,7 +2429,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, ExprResult Res(ParseExpression()); T.consumeClose(); if (Res.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return true; } Exprs.push_back(Res.release()); @@ -2395,8 +2460,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { // If the function body could not be parsed, make a bogus compoundstmt. if (FnBody.isInvalid()) { Sema::CompoundScopeRAII CompoundScope(Actions); - FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, - MultiStmtArg(), false); + FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false); } BodyScope.Exit(); @@ -2433,8 +2497,7 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { // compound statement as the body. if (FnBody.isInvalid()) { Sema::CompoundScopeRAII CompoundScope(Actions); - FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, - MultiStmtArg(), false); + FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false); } BodyScope.Exit(); @@ -2448,7 +2511,7 @@ bool Parser::trySkippingFunctionBody() { if (!PP.isCodeCompletionEnabled()) { ConsumeBrace(); - SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false); + SkipUntil(tok::r_brace); return true; } @@ -2456,8 +2519,7 @@ bool Parser::trySkippingFunctionBody() { // the body contains the code-completion point. TentativeParsingAction PA(*this); ConsumeBrace(); - if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false, - /*StopAtCodeCompletion=*/true)) { + if (SkipUntil(tok::r_brace, StopAtCodeCompletion)) { PA.Commit(); return true; } @@ -2530,9 +2592,10 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { } else { StmtVector Handlers; - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); - ProhibitAttributes(attrs); + + // C++11 attributes can't appear here, despite this context seeming + // statement-like. + DiagnoseAndSkipCXX11Attributes(); if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); @@ -2546,7 +2609,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { if (Handlers.empty()) return StmtError(); - return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(),Handlers); + return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), Handlers); } } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 84b7df7295f6..076edb93fa11 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -120,7 +120,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), TemplateParams, LAngleLoc, RAngleLoc)) { // Skip until the semi-colon or a }. - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); return 0; @@ -216,7 +216,7 @@ Parser::ParseSingleDeclarationAfterTemplate( // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); return 0; @@ -236,6 +236,35 @@ Parser::ParseSingleDeclarationAfterTemplate( << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); DS.ClearStorageClassSpecs(); } + + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + if (DeclaratorInfo.getName().getKind() != UnqualifiedId::IK_TemplateId) { + // If the declarator-id is not a template-id, issue a diagnostic and + // recover by ignoring the 'template' keyword. + Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0; + return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(), + &LateParsedAttrs); + } else { + SourceLocation LAngleLoc + = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(DeclaratorInfo.getIdentifierLoc(), + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Recover as if it were an explicit specialization. + TemplateParameterLists FakedParamLists; + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, + LAngleLoc)); + + return ParseFunctionDefinition( + DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists, + /*isSpecialization=*/true, + /*LastParamListWasEmpty=*/true), + &LateParsedAttrs); + } + } return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo, &LateParsedAttrs); } @@ -247,7 +276,7 @@ Parser::ParseSingleDeclarationAfterTemplate( if (Tok.is(tok::comma)) { Diag(Tok, diag::err_multiple_template_declarators) << (int)TemplateInfo.Kind; - SkipUntil(tok::semi, true, false); + SkipUntil(tok::semi); return ThisDecl; } @@ -320,7 +349,8 @@ 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, tok::greatergreater, true, true); + SkipUntil(tok::comma, tok::greater, tok::greatergreater, + StopAtSemi | StopBeforeMatch); } // Did we find a comma or the end of the template parameter list? @@ -334,7 +364,8 @@ Parser::ParseTemplateParameterList(unsigned Depth, // try to get out of the expression. This error is currently // subsumed by whatever goes on in ParseTemplateParameter. Diag(Tok.getLocation(), diag::err_expected_comma_greater); - SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true); + SkipUntil(tok::comma, tok::greater, tok::greatergreater, + StopAtSemi | StopBeforeMatch); return false; } } @@ -582,7 +613,8 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { if (DefaultArg.isInvalid()) { Diag(Tok.getLocation(), diag::err_default_template_template_parameter_not_template); - SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true); + SkipUntil(tok::comma, tok::greater, tok::greatergreater, + StopAtSemi | StopBeforeMatch); } } @@ -632,7 +664,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { DefaultArg = ParseAssignmentExpression(); if (DefaultArg.isInvalid()) - SkipUntil(tok::comma, tok::greater, true, true); + SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); } // Create the parameter. @@ -650,6 +682,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { /// \param RAngleLoc the location of the consumed '>'. /// /// \param ConsumeLastToken if true, the '>' is not consumed. +/// +/// \returns true, if current token does not start with '>', false otherwise. bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, bool ConsumeLastToken) { // What will be left once we've consumed the '>'. @@ -794,8 +828,10 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, if (Invalid) { // Try to find the closing '>'. - SkipUntil(tok::greater, true, !ConsumeLastToken); - + if (ConsumeLastToken) + SkipUntil(tok::greater, StopAtSemi); + else + SkipUntil(tok::greater, StopAtSemi | StopBeforeMatch); return true; } } @@ -1160,7 +1196,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { } if (Arg.isInvalid()) { - SkipUntil(tok::comma, tok::greater, true, true); + SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); return true; } @@ -1212,30 +1248,19 @@ SourceRange Parser::ParsedTemplateInfo::getSourceRange() const { return R; } -void Parser::LateTemplateParserCallback(void *P, const FunctionDecl *FD) { - ((Parser*)P)->LateTemplateParser(FD); -} - - -void Parser::LateTemplateParser(const FunctionDecl *FD) { - LateParsedTemplatedFunction *LPT = LateParsedTemplateMap[FD]; - if (LPT) { - ParseLateTemplatedFuncDef(*LPT); - return; - } - - llvm_unreachable("Late templated function without associated lexed tokens"); +void Parser::LateTemplateParserCallback(void *P, LateParsedTemplate &LPT) { + ((Parser *)P)->ParseLateTemplatedFuncDef(LPT); } /// \brief Late parse a C++ function template in Microsoft mode. -void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { - if(!LMT.D) +void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { + if (!LPT.D) return; // Get the FunctionDecl. - FunctionTemplateDecl *FunTmplD = dyn_cast<FunctionTemplateDecl>(LMT.D); + FunctionTemplateDecl *FunTmplD = dyn_cast<FunctionTemplateDecl>(LPT.D); FunctionDecl *FunD = - FunTmplD ? FunTmplD->getTemplatedDecl() : cast<FunctionDecl>(LMT.D); + FunTmplD ? FunTmplD->getTemplatedDecl() : cast<FunctionDecl>(LPT.D); // Track template parameter depth. TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); @@ -1253,7 +1278,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { } // Reenter template scopes from outermost to innermost. - SmallVector<DeclContext*, 4>::reverse_iterator II = + SmallVectorImpl<DeclContext *>::reverse_iterator II = DeclContextsToReenter.rbegin(); for (; II != DeclContextsToReenter.rend(); ++II) { if (ClassTemplatePartialSpecializationDecl *MD = @@ -1263,12 +1288,14 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { Actions.ActOnReenterTemplateScope(getCurScope(), MD); ++CurTemplateDepthTracker; } else if (CXXRecordDecl *MD = dyn_cast_or_null<CXXRecordDecl>(*II)) { - bool ManageScope = MD->getDescribedClassTemplate() != 0; + bool IsClassTemplate = MD->getDescribedClassTemplate() != 0; TemplateParamScopeStack.push_back( - new ParseScope(this, Scope::TemplateParamScope, ManageScope)); + new ParseScope(this, Scope::TemplateParamScope, + /*ManageScope*/IsClassTemplate)); Actions.ActOnReenterTemplateScope(getCurScope(), MD->getDescribedClassTemplate()); - ++CurTemplateDepthTracker; + if (IsClassTemplate) + ++CurTemplateDepthTracker; } TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); Actions.PushDeclContext(Actions.getCurScope(), *II); @@ -1281,15 +1308,15 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); ++CurTemplateDepthTracker; } - Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + Actions.ActOnReenterTemplateScope(getCurScope(), LPT.D); ++CurTemplateDepthTracker; - assert(!LMT.Toks.empty() && "Empty body!"); + assert(!LPT.Toks.empty() && "Empty body!"); // Append the current token at the end of the new token stream so that it // doesn't get lost. - LMT.Toks.push_back(Tok); - PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false); + LPT.Toks.push_back(Tok); + PP.EnterTokenStream(LPT.Toks.data(), LPT.Toks.size(), true, false); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); @@ -1306,34 +1333,30 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { Actions.ActOnStartOfFunctionDef(getCurScope(), FunD); if (Tok.is(tok::kw_try)) { - ParseFunctionTryBlock(LMT.D, FnScope); + ParseFunctionTryBlock(LPT.D, FnScope); } else { if (Tok.is(tok::colon)) - ParseConstructorInitializer(LMT.D); + ParseConstructorInitializer(LPT.D); else - Actions.ActOnDefaultCtorInitializers(LMT.D); + Actions.ActOnDefaultCtorInitializers(LPT.D); if (Tok.is(tok::l_brace)) { assert((!FunTmplD || FunTmplD->getTemplateParameters()->getDepth() < TemplateParameterDepth) && "TemplateParameterDepth should be greater than the depth of " "current template being instantiated!"); - ParseFunctionStatementBody(LMT.D, FnScope); - Actions.MarkAsLateParsedTemplate(FunD, false); + ParseFunctionStatementBody(LPT.D, FnScope); + Actions.UnmarkAsLateParsedTemplate(FunD); } else - Actions.ActOnFinishFunctionBody(LMT.D, 0); + Actions.ActOnFinishFunctionBody(LPT.D, 0); } // Exit scopes. FnScope.Exit(); - SmallVector<ParseScope*, 4>::reverse_iterator I = + SmallVectorImpl<ParseScope *>::reverse_iterator I = TemplateParamScopeStack.rbegin(); for (; I != TemplateParamScopeStack.rend(); ++I) delete *I; - - DeclGroupPtrTy grp = Actions.ConvertDeclToDeclGroup(LMT.D); - if (grp) - Actions.getASTConsumer().HandleTopLevelDecl(grp.get()); } /// \brief Lex a delayed template function for late parsing. diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index dff3b64c5b3f..a1d6b13fdab8 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -142,6 +142,82 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { return TPR == TPResult::True(); } +/// Try to consume a token sequence that we've already identified as +/// (potentially) starting a decl-specifier. +Parser::TPResult Parser::TryConsumeDeclarationSpecifier() { + switch (Tok.getKind()) { + case tok::kw__Atomic: + if (NextToken().isNot(tok::l_paren)) { + ConsumeToken(); + break; + } + // Fall through. + case tok::kw_typeof: + case tok::kw___attribute: + case tok::kw___underlying_type: { + ConsumeToken(); + if (Tok.isNot(tok::l_paren)) + return TPResult::Error(); + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + break; + } + + case tok::kw_class: + case tok::kw_struct: + case tok::kw_union: + case tok::kw___interface: + case tok::kw_enum: + // elaborated-type-specifier: + // class-key attribute-specifier-seq[opt] + // nested-name-specifier[opt] identifier + // class-key nested-name-specifier[opt] template[opt] simple-template-id + // enum nested-name-specifier[opt] identifier + // + // FIXME: We don't support class-specifiers nor enum-specifiers here. + ConsumeToken(); + + // Skip attributes. + while (Tok.is(tok::l_square) || Tok.is(tok::kw___attribute) || + Tok.is(tok::kw___declspec) || Tok.is(tok::kw_alignas)) { + if (Tok.is(tok::l_square)) { + ConsumeBracket(); + if (!SkipUntil(tok::r_square)) + return TPResult::Error(); + } else { + ConsumeToken(); + if (Tok.isNot(tok::l_paren)) + return TPResult::Error(); + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + } + } + + if (TryAnnotateCXXScopeToken()) + return TPResult::Error(); + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) + return TPResult::Error(); + ConsumeToken(); + break; + + case tok::annot_cxxscope: + ConsumeToken(); + // Fall through. + default: + ConsumeToken(); + + if (getLangOpts().ObjC1 && Tok.is(tok::less)) + return TryParseProtocolQualifiers(); + break; + } + + return TPResult::Ambiguous(); +} + /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' /// @@ -151,16 +227,8 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { /// attribute-specifier-seqopt type-specifier-seq declarator /// Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - if (Tok.is(tok::annot_cxxscope)) - ConsumeToken(); - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } + if (TryConsumeDeclarationSpecifier() == TPResult::Error()) + return TPResult::Error(); // Two decl-specifiers in a row conclusively disambiguate this as being a // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the @@ -226,14 +294,14 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { if (Tok.is(tok::l_paren)) { // Parse through the parens. ConsumeParen(); - if (!SkipUntil(tok::r_paren)) + if (!SkipUntil(tok::r_paren, StopAtSemi)) return TPResult::Error(); } else if (Tok.is(tok::l_brace)) { // A left-brace here is sufficient to disambiguate the parse; an // expression can never be followed directly by a braced-init-list. return TPResult::True(); } else if (Tok.is(tok::equal) || isTokIdentifier_in()) { - // MSVC and g++ won't examine the rest of declarators if '=' is + // MSVC and g++ won't examine the rest of declarators if '=' is // encountered; they just conclude that we have a declaration. // EDG parses the initializer completely, which is the proper behavior // for this case. @@ -241,12 +309,14 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { // At present, Clang follows MSVC and g++, since the parser does not have // the ability to parse an expression fully without recording the // results of that parse. - // Also allow 'in' after on objective-c declaration as in: - // for (int (^b)(void) in array). Ideally this should be done in the + // FIXME: Handle this case correctly. + // + // Also allow 'in' after an Objective-C declaration as in: + // for (int (^b)(void) in array). Ideally this should be done in the // context of parsing for-init-statement of a foreach statement only. But, // in any other context 'in' is invalid after a declaration and parser // issues the error regardless of outcome of this decision. - // FIXME. Change if above assumption does not hold. + // FIXME: Change if above assumption does not hold. return TPResult::True(); } @@ -286,14 +356,7 @@ bool Parser::isCXXConditionDeclaration() { TentativeParsingAction PA(*this); // type-specifier-seq - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } + TryConsumeDeclarationSpecifier(); assert(Tok.is(tok::l_paren) && "Expected '('"); // declarator @@ -363,15 +426,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { TentativeParsingAction PA(*this); // type-specifier-seq - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } - + TryConsumeDeclarationSpecifier(); assert(Tok.is(tok::l_paren) && "Expected '('"); // declarator @@ -462,7 +517,7 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, if (!getLangOpts().ObjC1) { ConsumeBracket(); - bool IsAttribute = SkipUntil(tok::r_square, false); + bool IsAttribute = SkipUntil(tok::r_square); IsAttribute &= Tok.is(tok::r_square); PA.Revert(); @@ -534,7 +589,7 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, // Parse the attribute-argument-clause, if present. if (Tok.is(tok::l_paren)) { ConsumeParen(); - if (!SkipUntil(tok::r_paren, false)) { + if (!SkipUntil(tok::r_paren)) { IsAttribute = false; break; } @@ -569,6 +624,121 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, return CAK_NotAttributeSpecifier; } +Parser::TPResult Parser::TryParsePtrOperatorSeq() { + while (true) { + if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier)) + if (TryAnnotateCXXScopeToken(true)) + return TPResult::Error(); + + if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) || + Tok.is(tok::ampamp) || + (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { + // ptr-operator + ConsumeToken(); + while (Tok.is(tok::kw_const) || + Tok.is(tok::kw_volatile) || + Tok.is(tok::kw_restrict)) + ConsumeToken(); + } else { + return TPResult::True(); + } + } +} + +/// operator-function-id: +/// 'operator' operator +/// +/// operator: one of +/// new delete new[] delete[] + - * / % ^ [...] +/// +/// conversion-function-id: +/// 'operator' conversion-type-id +/// +/// conversion-type-id: +/// type-specifier-seq conversion-declarator[opt] +/// +/// conversion-declarator: +/// ptr-operator conversion-declarator[opt] +/// +/// literal-operator-id: +/// 'operator' string-literal identifier +/// 'operator' user-defined-string-literal +Parser::TPResult Parser::TryParseOperatorId() { + assert(Tok.is(tok::kw_operator)); + ConsumeToken(); + + // Maybe this is an operator-function-id. + switch (Tok.getKind()) { + case tok::kw_new: case tok::kw_delete: + ConsumeToken(); + if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) { + ConsumeBracket(); + ConsumeBracket(); + } + return TPResult::True(); + +#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemOnly) \ + case tok::Token: +#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemOnly) +#include "clang/Basic/OperatorKinds.def" + ConsumeToken(); + return TPResult::True(); + + case tok::l_square: + if (NextToken().is(tok::r_square)) { + ConsumeBracket(); + ConsumeBracket(); + return TPResult::True(); + } + break; + + case tok::l_paren: + if (NextToken().is(tok::r_paren)) { + ConsumeParen(); + ConsumeParen(); + return TPResult::True(); + } + break; + + default: + break; + } + + // Maybe this is a literal-operator-id. + if (getLangOpts().CPlusPlus11 && isTokenStringLiteral()) { + bool FoundUDSuffix = false; + do { + FoundUDSuffix |= Tok.hasUDSuffix(); + ConsumeStringToken(); + } while (isTokenStringLiteral()); + + if (!FoundUDSuffix) { + if (Tok.is(tok::identifier)) + ConsumeToken(); + else + return TPResult::Error(); + } + return TPResult::True(); + } + + // Maybe this is a conversion-function-id. + bool AnyDeclSpecifiers = false; + while (true) { + TPResult TPR = isCXXDeclarationSpecifier(); + if (TPR == TPResult::Error()) + return TPR; + if (TPR == TPResult::False()) { + if (!AnyDeclSpecifiers) + return TPResult::Error(); + break; + } + if (TryConsumeDeclarationSpecifier() == TPResult::Error()) + return TPResult::Error(); + AnyDeclSpecifiers = true; + } + return TryParsePtrOperatorSeq(); +} + /// declarator: /// direct-declarator /// ptr-operator declarator @@ -615,9 +785,11 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, /// /// unqualified-id: /// identifier -/// operator-function-id [TODO] -/// conversion-function-id [TODO] +/// operator-function-id +/// conversion-function-id +/// literal-operator-id /// '~' class-name [TODO] +/// '~' decltype-specifier [TODO] /// template-id [TODO] /// Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, @@ -625,40 +797,28 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // declarator: // direct-declarator // ptr-operator declarator - - while (1) { - if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier)) - if (TryAnnotateCXXScopeToken(true)) - return TPResult::Error(); - - if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) || - Tok.is(tok::ampamp) || - (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { - // ptr-operator - ConsumeToken(); - while (Tok.is(tok::kw_const) || - Tok.is(tok::kw_volatile) || - Tok.is(tok::kw_restrict)) - ConsumeToken(); - } else { - break; - } - } + if (TryParsePtrOperatorSeq() == TPResult::Error()) + return TPResult::Error(); // direct-declarator: // direct-abstract-declarator: if (Tok.is(tok::ellipsis)) ConsumeToken(); - - if ((Tok.is(tok::identifier) || - (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) && + + if ((Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || + (Tok.is(tok::annot_cxxscope) && (NextToken().is(tok::identifier) || + NextToken().is(tok::kw_operator)))) && mayHaveIdentifier) { // declarator-id if (Tok.is(tok::annot_cxxscope)) ConsumeToken(); - else + else if (Tok.is(tok::identifier)) TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo()); - ConsumeToken(); + if (Tok.is(tok::kw_operator)) { + if (TryParseOperatorId() == TPResult::Error()) + return TPResult::Error(); + } else + ConsumeToken(); } else if (Tok.is(tok::l_paren)) { ConsumeParen(); if (mayBeAbstract && @@ -780,6 +940,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___imag: case tok::kw___real: case tok::kw___FUNCTION__: + case tok::kw___FUNCDNAME__: case tok::kw_L__FUNCTION__: case tok::kw___PRETTY_FUNCTION__: case tok::kw___has_nothrow_assign: @@ -802,6 +963,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_literal_type: case tok::kw___is_pod: case tok::kw___is_polymorphic: + case tok::kw___is_sealed: case tok::kw___is_trivial: case tok::kw___is_trivially_assignable: case tok::kw___is_trivially_constructible: @@ -836,14 +998,15 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_wchar_t: case tok::kw_char16_t: case tok::kw_char32_t: - case tok::kw___underlying_type: case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: + case tok::kw___interface: case tok::kw___thread: case tok::kw_thread_local: case tok::kw__Thread_local: case tok::kw_typeof: + case tok::kw___underlying_type: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: @@ -1103,6 +1266,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw_class: case tok::kw_struct: case tok::kw_union: + case tok::kw___interface: // enum-specifier case tok::kw_enum: // cv-qualifier @@ -1122,6 +1286,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___w64: + case tok::kw___sptr: + case tok::kw___uptr: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___forceinline: @@ -1323,6 +1489,56 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, } } +bool Parser::isCXXDeclarationSpecifierAType() { + switch (Tok.getKind()) { + // typename-specifier + case tok::annot_decltype: + case tok::annot_template_id: + case tok::annot_typename: + case tok::kw_typeof: + case tok::kw___underlying_type: + return true; + + // elaborated-type-specifier + case tok::kw_class: + case tok::kw_struct: + case tok::kw_union: + case tok::kw___interface: + case tok::kw_enum: + return true; + + // simple-type-specifier + 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_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw_void: + case tok::kw___unknown_anytype: + return true; + + case tok::kw_auto: + return getLangOpts().CPlusPlus11; + + case tok::kw__Atomic: + // "_Atomic foo" + return NextToken().is(tok::l_paren); + + default: + return false; + } +} + /// [GNU] typeof-specifier: /// 'typeof' '(' expressions ')' /// 'typeof' '(' type-name ')' @@ -1334,7 +1550,7 @@ Parser::TPResult Parser::TryParseTypeofSpecifier() { assert(Tok.is(tok::l_paren) && "Expected '('"); // Parse through the parens after 'typeof'. ConsumeParen(); - if (!SkipUntil(tok::r_paren)) + if (!SkipUntil(tok::r_paren, StopAtSemi)) return TPResult::Error(); return TPResult::Ambiguous(); @@ -1364,27 +1580,6 @@ Parser::TPResult Parser::TryParseProtocolQualifiers() { return TPResult::Error(); } -Parser::TPResult -Parser::TryParseDeclarationSpecifier(bool *HasMissingTypename) { - TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(), - HasMissingTypename); - if (TPR != TPResult::Ambiguous()) - return TPR; - - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - if (Tok.is(tok::annot_cxxscope)) - ConsumeToken(); - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } - - return TPResult::Ambiguous(); -} - /// isCXXFunctionDeclarator - Disambiguates between a function declarator or /// a constructor-style initializer, when parsing declaration statements. /// Returns true for function declarator and false for constructor-style @@ -1459,7 +1654,8 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) { /// attributes[opt] '=' assignment-expression /// Parser::TPResult -Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) { +Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, + bool VersusTemplateArgument) { if (Tok.is(tok::r_paren)) return TPResult::Ambiguous(); @@ -1492,8 +1688,32 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) { // 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(InvalidAsDeclaration); - if (TPR != TPResult::Ambiguous()) + TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(), + InvalidAsDeclaration); + + if (VersusTemplateArgument && TPR == TPResult::True()) { + // Consume the decl-specifier-seq. We have to look past it, since a + // type-id might appear here in a template argument. + bool SeenType = false; + do { + SeenType |= isCXXDeclarationSpecifierAType(); + if (TryConsumeDeclarationSpecifier() == TPResult::Error()) + return TPResult::Error(); + + // If we see a parameter name, this can't be a template argument. + if (SeenType && Tok.is(tok::identifier)) + return TPResult::True(); + + TPR = isCXXDeclarationSpecifier(TPResult::False(), + InvalidAsDeclaration); + if (TPR == TPResult::Error()) + return TPR; + } while (TPR != TPResult::False()); + } else if (TPR == TPResult::Ambiguous()) { + // Disambiguate what follows the decl-specifier. + if (TryConsumeDeclarationSpecifier() == TPResult::Error()) + return TPResult::Error(); + } else return TPR; // declarator @@ -1506,11 +1726,25 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) { if (Tok.is(tok::kw___attribute)) return TPResult::True(); + // If we're disambiguating a template argument in a default argument in + // a class definition versus a parameter declaration, an '=' here + // disambiguates the parse one way or the other. + // If this is a parameter, it must have a default argument because + // (a) the previous parameter did, and + // (b) this must be the first declaration of the function, so we can't + // inherit any default arguments from elsewhere. + // If we see an ')', then we've reached the end of a + // parameter-declaration-clause, and the last param is missing its default + // argument. + if (VersusTemplateArgument) + return (Tok.is(tok::equal) || Tok.is(tok::r_paren)) ? TPResult::True() + : TPResult::False(); + if (Tok.is(tok::equal)) { // '=' assignment-expression // Parse through assignment-expression. - if (!SkipUntil(tok::comma, tok::r_paren, true/*StopAtSemi*/, - true/*DontConsume*/)) + // FIXME: assignment-expression may contain an unparenthesized comma. + if (!SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch)) return TPResult::Error(); } @@ -1554,7 +1788,7 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { return TPR; // Parse through the parens. - if (!SkipUntil(tok::r_paren)) + if (!SkipUntil(tok::r_paren, StopAtSemi)) return TPResult::Error(); // cv-qualifier-seq @@ -1575,7 +1809,7 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { // Parse through the parens after 'throw'. ConsumeParen(); - if (!SkipUntil(tok::r_paren)) + if (!SkipUntil(tok::r_paren, StopAtSemi)) return TPResult::Error(); } if (Tok.is(tok::kw_noexcept)) { @@ -1584,7 +1818,7 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { if (Tok.is(tok::l_paren)) { // Find the matching rparen. ConsumeParen(); - if (!SkipUntil(tok::r_paren)) + if (!SkipUntil(tok::r_paren, StopAtSemi)) return TPResult::Error(); } } @@ -1596,7 +1830,7 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { /// Parser::TPResult Parser::TryParseBracketDeclarator() { ConsumeBracket(); - if (!SkipUntil(tok::r_square)) + if (!SkipUntil(tok::r_square, StopAtSemi)) return TPResult::Error(); return TPResult::Ambiguous(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 455139b881aa..457dd36cbe9b 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -103,8 +103,10 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) PP.AddPragmaHandler(OpenMPHandler.get()); if (getLangOpts().MicrosoftExt) { - MSCommentHandler.reset(new PragmaCommentHandler()); + MSCommentHandler.reset(new PragmaCommentHandler(actions)); PP.AddPragmaHandler(MSCommentHandler.get()); + MSDetectMismatchHandler.reset(new PragmaDetectMismatchHandler(actions)); + PP.AddPragmaHandler(MSDetectMismatchHandler.get()); } CommentSemaHandler.reset(new ActionCommentHandler(actions)); @@ -188,7 +190,7 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, Diag(Tok, DiagID) << Msg; if (SkipToTok != tok::unknown) - SkipUntil(SkipToTok); + SkipUntil(SkipToTok, StopAtSemi); return true; } @@ -251,16 +253,19 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) { // Error recovery. //===----------------------------------------------------------------------===// +static bool HasFlagsSet(Parser::SkipUntilFlags L, Parser::SkipUntilFlags R) { + return (static_cast<unsigned>(L) & static_cast<unsigned>(R)) != 0; +} + /// SkipUntil - Read tokens until we get to the specified token, then consume -/// it (unless DontConsume is true). Because we cannot guarantee that the +/// it (unless no flag StopBeforeMatch). Because we cannot guarantee that the /// token will ever occur, this skips to the next token, or to some likely /// good stopping point. If StopAtSemi is true, skipping will stop at a ';' /// character. /// /// If SkipUntil finds the specified token, it returns true, otherwise it /// returns false. -bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi, - bool DontConsume, bool StopAtCodeCompletion) { +bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { // 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; @@ -268,7 +273,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi, // If we found one of the tokens, stop and return true. for (unsigned i = 0, NumToks = Toks.size(); i != NumToks; ++i) { if (Tok.is(Toks[i])) { - if (DontConsume) { + if (HasFlagsSet(Flags, StopBeforeMatch)) { // Noop, don't consume the token. } else { ConsumeAnyToken(); @@ -277,30 +282,50 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi, } } + // Important special case: The caller has given up and just wants us to + // skip the rest of the file. Do this without recursing, since we can + // get here precisely because the caller detected too much recursion. + if (Toks.size() == 1 && Toks[0] == tok::eof && + !HasFlagsSet(Flags, StopAtSemi) && + !HasFlagsSet(Flags, StopAtCodeCompletion)) { + while (Tok.getKind() != tok::eof) + ConsumeAnyToken(); + return true; + } + switch (Tok.getKind()) { case tok::eof: // Ran out of tokens. return false; case tok::code_completion: - if (!StopAtCodeCompletion) + if (!HasFlagsSet(Flags, StopAtCodeCompletion)) ConsumeToken(); return false; case tok::l_paren: // Recursively skip properly-nested parens. ConsumeParen(); - SkipUntil(tok::r_paren, false, false, StopAtCodeCompletion); + if (HasFlagsSet(Flags, StopAtCodeCompletion)) + SkipUntil(tok::r_paren, StopAtCodeCompletion); + else + SkipUntil(tok::r_paren); break; case tok::l_square: // Recursively skip properly-nested square brackets. ConsumeBracket(); - SkipUntil(tok::r_square, false, false, StopAtCodeCompletion); + if (HasFlagsSet(Flags, StopAtCodeCompletion)) + SkipUntil(tok::r_square, StopAtCodeCompletion); + else + SkipUntil(tok::r_square); break; case tok::l_brace: // Recursively skip properly-nested braces. ConsumeBrace(); - SkipUntil(tok::r_brace, false, false, StopAtCodeCompletion); + if (HasFlagsSet(Flags, StopAtCodeCompletion)) + SkipUntil(tok::r_brace, StopAtCodeCompletion); + else + SkipUntil(tok::r_brace); break; // Okay, we found a ']' or '}' or ')', which we think should be balanced. @@ -333,7 +358,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi, break; case tok::semi: - if (StopAtSemi) + if (HasFlagsSet(Flags, StopAtSemi)) return false; // FALL THROUGH. default: @@ -410,11 +435,6 @@ Parser::~Parser() { for (unsigned i = 0, e = NumCachedScopes; i != e; ++i) delete ScopeCache[i]; - // Free LateParsedTemplatedFunction nodes. - for (LateParsedTemplateMapT::iterator it = LateParsedTemplateMap.begin(); - it != LateParsedTemplateMap.end(); ++it) - delete it->second; - // Remove the pragma handlers we installed. PP.RemovePragmaHandler(AlignHandler.get()); AlignHandler.reset(); @@ -444,6 +464,8 @@ Parser::~Parser() { if (getLangOpts().MicrosoftExt) { PP.RemovePragmaHandler(MSCommentHandler.get()); MSCommentHandler.reset(); + PP.RemovePragmaHandler(MSDetectMismatchHandler.get()); + MSDetectMismatchHandler.reset(); } PP.RemovePragmaHandler("STDC", FPContractHandler.get()); @@ -477,6 +499,7 @@ void Parser::Initialize() { Ident_instancetype = 0; Ident_final = 0; + Ident_sealed = 0; Ident_override = 0; Ident_super = &PP.getIdentifierTable().get("super"); @@ -484,6 +507,7 @@ void Parser::Initialize() { if (getLangOpts().AltiVec) { Ident_vector = &PP.getIdentifierTable().get("vector"); Ident_pixel = &PP.getIdentifierTable().get("pixel"); + Ident_bool = &PP.getIdentifierTable().get("bool"); } Ident_introduced = 0; @@ -555,19 +579,30 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) ConsumeToken(); - while (Tok.is(tok::annot_pragma_unused)) + Result = DeclGroupPtrTy(); + switch (Tok.getKind()) { + case tok::annot_pragma_unused: HandlePragmaUnused(); + return false; - Result = DeclGroupPtrTy(); - if (Tok.is(tok::eof)) { + case tok::annot_module_include: + Actions.ActOnModuleInclude(Tok.getLocation(), + reinterpret_cast<Module *>( + Tok.getAnnotationValue())); + ConsumeToken(); + return false; + + case tok::eof: // Late template parsing can begin. 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. - return true; + + default: + break; } ParsedAttributesWithRange attrs(AttrFactory); @@ -840,6 +875,12 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, // Parse the common declaration-specifiers piece. ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level); + // If we had a free-standing type definition with a missing semicolon, we + // may get this far before the problem becomes obvious. + if (DS.hasTagDefinition() && + DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_top_level)) + return DeclGroupPtrTy(); + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { @@ -908,6 +949,26 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs, } } + +static inline bool isFunctionDeclaratorRequiringReturnTypeDeduction( + const Declarator &D) { + if (!D.isFunctionDeclarator() || !D.getDeclSpec().containsPlaceholderType()) + return false; + for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { + unsigned chunkIndex = E - I - 1; + const DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); + if (DeclType.Kind == DeclaratorChunk::Function) { + const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; + if (!FTI.hasTrailingReturnType()) + return true; + QualType TrailingRetType = FTI.getTrailingReturnType().get(); + return TrailingRetType->getCanonicalTypeInternal() + ->getContainedAutoType(); + } + } + return false; +} + /// ParseFunctionDefinition - We parsed and verified that the specified /// Declarator is well formed. If this is a K&R-style function, read the /// parameters declaration-list, then start the compound-statement. @@ -956,7 +1017,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, Diag(Tok, diag::err_expected_fn_body); // Skip over garbage, until we get to '{'. Don't eat the '{'. - SkipUntil(tok::l_brace, true, true); + SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch); // If we didn't find the '{', bail out. if (Tok.isNot(tok::l_brace)) @@ -979,9 +1040,10 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // 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 (getLangOpts().DelayedTemplateParsing && - Tok.isNot(tok::equal) && - TemplateInfo.Kind == ParsedTemplateInfo::Template) { + if (getLangOpts().DelayedTemplateParsing && Tok.isNot(tok::equal) && + TemplateInfo.Kind == ParsedTemplateInfo::Template && + !D.getDeclSpec().isConstexprSpecified() && + !isFunctionDeclaratorRequiringReturnTypeDeduction(D)) { MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams); ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); @@ -993,22 +1055,18 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, D.complete(DP); D.getMutableDeclSpec().abort(); - if (DP) { - LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(DP); + CachedTokens Toks; + LexTemplateFunctionForLateParsing(Toks); + if (DP) { FunctionDecl *FnD = 0; if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(DP)) FnD = FunTmpl->getTemplatedDecl(); else FnD = cast<FunctionDecl>(DP); - Actions.CheckForFunctionRedefinition(FnD); - LateParsedTemplateMap[FnD] = LPT; - Actions.MarkAsLateParsedTemplate(FnD); - LexTemplateFunctionForLateParsing(LPT->Toks); - } else { - CachedTokens Toks; - LexTemplateFunctionForLateParsing(Toks); + Actions.CheckForFunctionRedefinition(FnD); + Actions.MarkAsLateParsedTemplate(FnD, DP, Toks); } return DP; } @@ -1215,7 +1273,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { if (ExpectAndConsumeSemi(diag::err_expected_semi_declaration)) { // Skip to end of block or statement - SkipUntil(tok::semi, true); + SkipUntil(tok::semi); if (Tok.is(tok::semi)) ConsumeToken(); } @@ -1283,7 +1341,7 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { ExprResult Result(ParseAsmStringLiteral()); if (Result.isInvalid()) { - SkipUntil(tok::r_paren, true, true); + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); if (EndLoc) *EndLoc = Tok.getLocation(); ConsumeAnyToken(); @@ -1422,8 +1480,9 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, return ANK_TemplateName; } // Fall through. + case Sema::NC_VarTemplate: case Sema::NC_FunctionTemplate: { - // We have a type or function template followed by '<'. + // We have a type, variable or function template followed by '<'. ConsumeToken(); UnqualifiedId Id; Id.setIdentifier(Name, NameLoc); @@ -1444,6 +1503,17 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, return ANK_Unresolved; } +bool Parser::TryKeywordIdentFallback(bool DisableKeyword) { + assert(Tok.isNot(tok::identifier)); + Diag(Tok, diag::ext_keyword_as_ident) + << PP.getSpelling(Tok) + << DisableKeyword; + if (DisableKeyword) + Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); + Tok.setKind(tok::identifier); + return true; +} + /// TryAnnotateTypeOrScopeToken - If the current token position is on a /// typename (possibly qualified in C++) or a C++ scope specifier not followed /// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens @@ -1473,6 +1543,23 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { && "Cannot be a type or scope token!"); if (Tok.is(tok::kw_typename)) { + // MSVC lets you do stuff like: + // typename typedef T_::D D; + // + // We will consume the typedef token here and put it back after we have + // parsed the first identifier, transforming it into something more like: + // typename T_::D typedef D; + if (getLangOpts().MicrosoftMode && NextToken().is(tok::kw_typedef)) { + Token TypedefToken; + PP.Lex(TypedefToken); + bool Result = TryAnnotateTypeOrScopeToken(EnteringContext, NeedType); + PP.EnterToken(Tok); + Tok = TypedefToken; + if (!Result) + Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename); + return Result; + } + // Parse a C++ typename-specifier, e.g., "typename T::type". // // typename-specifier: @@ -1491,7 +1578,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { // Attempt to recover by skipping the invalid 'typename' if (Tok.is(tok::annot_decltype) || (!TryAnnotateTypeOrScopeToken(EnteringContext, NeedType) && - Tok.isAnnotation())) { + Tok.isAnnotation())) { unsigned DiagID = diag::err_expected_qualified_after_typename; // MS compatibility: MSVC permits using known types with typename. // e.g. "typedef typename T* pointer_type" @@ -1638,7 +1725,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, // annotation token to a type annotation token now. AnnotateTemplateIdTokenAsType(); return false; - } + } else if (TemplateId->Kind == TNK_Var_template) + return false; } if (SS.isEmpty()) @@ -1884,7 +1972,13 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { break; } while (true); - + + if (PP.hadModuleLoaderFatalFailure()) { + // With a fatal failure in the module loader, we abort parsing. + cutOffParsing(); + return DeclGroupPtrTy(); + } + DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path); ExpectAndConsumeSemi(diag::err_module_expected_semi); if (Import.isInvalid()) @@ -1927,11 +2021,19 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() { } P.Diag(P.Tok, DID); P.Diag(LOpen, diag::note_matching) << LHSName; - if (P.SkipUntil(Close, /*StopAtSemi*/ true, /*DontConsume*/ true)) + + // If we're not already at some kind of closing bracket, skip to our closing + // token. + if (P.Tok.isNot(tok::r_paren) && P.Tok.isNot(tok::r_brace) && + P.Tok.isNot(tok::r_square) && + P.SkipUntil(Close, FinalToken, + Parser::StopAtSemi | Parser::StopBeforeMatch) && + P.Tok.is(Close)) LClose = P.ConsumeAnyToken(); return true; } void BalancedDelimiterTracker::skipToEnd() { - P.SkipUntil(Close, false); + P.SkipUntil(Close, Parser::StopBeforeMatch); + consumeClose(); } diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index 213950a6db92..f68a2e09fe91 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/lib/Parse/RAIIObjectsForParser.h @@ -358,7 +358,7 @@ namespace clang { /// pair, such as braces { ... } or parentheses ( ... ). class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { Parser& P; - tok::TokenKind Kind, Close; + tok::TokenKind Kind, Close, FinalToken; SourceLocation (Parser::*Consumer)(); SourceLocation LOpen, LClose; @@ -377,9 +377,10 @@ namespace clang { bool diagnoseMissingClose(); public: - BalancedDelimiterTracker(Parser& p, tok::TokenKind k) + BalancedDelimiterTracker(Parser& p, tok::TokenKind k, + tok::TokenKind FinalToken = tok::semi) : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), - P(p), Kind(k) + P(p), Kind(k), FinalToken(FinalToken) { switch (Kind) { default: llvm_unreachable("Unexpected balanced token"); |