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