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