diff options
author | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
commit | 9cedb8bb69b89b0f0c529937247a6a80cabdbaec (patch) | |
tree | c978f0e9ec1ab92dc8123783f30b08a7fd1e2a39 /contrib/llvm/tools/clang/lib/Parse | |
parent | 03fdc2934eb61c44c049a02b02aa974cfdd8a0eb (diff) | |
download | FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.zip FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.tar.gz |
MFC 261991:
Upgrade our copy of llvm/clang to 3.4 release. This version supports
all of the features in the current working draft of the upcoming C++
standard, provisionally named C++1y.
The code generator's performance is greatly increased, and the loop
auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The
PowerPC backend has made several major improvements to code generation
quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ
backends have all seen major feature work.
Release notes for llvm and clang can be found here:
<http://llvm.org/releases/3.4/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html>
MFC 262121 (by emaste):
Update lldb for clang/llvm 3.4 import
This commit largely restores the lldb source to the upstream r196259
snapshot with the addition of threaded inferior support and a few bug
fixes.
Specific upstream lldb revisions restored include:
SVN git
181387 779e6ac
181703 7bef4e2
182099 b31044e
182650 f2dcf35
182683 0d91b80
183862 15c1774
183929 99447a6
184177 0b2934b
184948 4dc3761
184954 007e7bc
186990 eebd175
Sponsored by: DARPA, AFRL
MFC 262186 (by emaste):
Fix mismerge in r262121
A break statement was lost in the merge. The error had no functional
impact, but restore it to reduce the diff against upstream.
MFC 262303:
Pull in r197521 from upstream clang trunk (by rdivacky):
Use the integrated assembler by default on FreeBSD/ppc and ppc64.
Requested by: jhibbits
MFC 262611:
Pull in r196874 from upstream llvm trunk:
Fix a crash that occurs when PWD is invalid.
MCJIT needs to be able to run in hostile environments, even when PWD
is invalid. There's no need to crash MCJIT in this case.
The obvious fix is to simply leave MCContext's CompilationDir empty
when PWD can't be determined. This way, MCJIT clients,
and other clients that link with LLVM don't need a valid working directory.
If we do want to guarantee valid CompilationDir, that should be done
only for clients of getCompilationDir(). This is as simple as checking
for an empty string.
The only current use of getCompilationDir is EmitGenDwarfInfo, which
won't conceivably run with an invalid working dir. However, in the
purely hypothetically and untestable case that this happens, the
AT_comp_dir will be omitted from the compilation_unit DIE.
This should help fix assertions occurring with ports-mgmt/tinderbox,
when it is using jails, and sometimes invalidates clang's current
working directory.
Reported by: decke
MFC 262809:
Pull in r203007 from upstream clang trunk:
Don't produce an alias between destructors with different calling conventions.
Fixes pr19007.
(Please note that is an LLVM PR identifier, not a FreeBSD one.)
This should fix Firefox and/or libxul crashes (due to problems with
regparm/stdcall calling conventions) on i386.
Reported by: multiple users on freebsd-current
PR: bin/187103
MFC 263048:
Repair recognition of "CC" as an alias for the C++ compiler, since it
was silently broken by upstream for a Windows-specific use-case.
Apparently some versions of CMake still rely on this archaic feature...
Reported by: rakuco
MFC 263049:
Garbage collect the old way of adding the libstdc++ include directories
in clang's InitHeaderSearch.cpp. This has been superseded by David
Chisnall's commit in r255321.
Moreover, if libc++ is used, the libstdc++ include directories should
not be in the search path at all. These directories are now only used
if you pass -stdlib=libstdc++.
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse')
16 files changed, 2676 insertions, 947 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp index 7cd8a21..5678ece 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp index 5fc4189..7792305 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index 6a87b78..7b80934 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp index f1fbbb1..dd29f99 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm/tools/clang/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,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, << DeclSpec::getSpecifierName(TagType); } - SkipUntil(tok::comma, true); + // If we are parsing a definition and stop at a base-clause, continue on + // until the semicolon. Continuing from the comma will just trick us into + // thinking we are seeing a variable declaration. + if (TUK == Sema::TUK_Definition && Tok.is(tok::colon)) + SkipUntil(tok::semi, StopBeforeMatch); + else + SkipUntil(tok::comma, StopAtSemi); return; } @@ -1465,7 +1486,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 +1495,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 +1566,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 +1676,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 +1835,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 +1873,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 +1902,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 +1939,7 @@ bool Parser::isCXX11FinalKeyword() const { /// virt-specifier: /// override /// final +/// [MS] sealed /// /// pure-specifier: /// '= 0' @@ -1908,12 +1956,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 +2000,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 +2059,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 +2081,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 +2123,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 +2142,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 +2180,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 +2200,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 +2235,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 +2243,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 +2260,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 +2284,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 +2300,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 +2327,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 +2407,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 +2432,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, /// assignment-expression /// braced-init-list /// -/// defaulted/deleted function-definition: +/// defaulted/deleted function-definition: /// '=' 'default' /// '=' 'delete' /// @@ -2476,20 +2539,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 +2586,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 +2636,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 +2683,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 +2733,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 +2787,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 +2811,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 +2892,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 +2904,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 +2988,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 +3031,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 +3063,8 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( T.consumeClose(); SpecificationRange.setEnd(T.getCloseLocation()); + diagnoseDynamicExceptionSpecification(*this, SpecificationRange, + Exceptions.empty()); return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic; } @@ -3167,7 +3274,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 +3300,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 +3308,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 +3319,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 +3345,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 +3391,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/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp index 9521ffb..45f1b1d 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp index f259d5f..5fe47fc 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp index 8311aa2..37f74bb 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp index 4a572f1..86f38cf 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp index 507a6b1..89e4147 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp index 3d1249a..8a374e0 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h index d9560f3..b41450f 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp index 43b6965..d1f2138 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp index 84b7df7..076edb9 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp index dff3b64..a1d6b13 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/Parser.cpp b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp index 455139b..457dd36 100644 --- a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h b/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h index 213950a..f68a2e0 100644 --- a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h +++ b/contrib/llvm/tools/clang/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"); |