Update aosp/master Clang for rebase to r222490.
Change-Id: Ic557ac55e97fbf6ee08771c7b7c3594777b0aefd
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt
index 9933025..b868696 100644
--- a/lib/Parse/CMakeLists.txt
+++ b/lib/Parse/CMakeLists.txt
@@ -1,6 +1,6 @@
set(LLVM_LINK_COMPONENTS
- MCParser
MC
+ MCParser
Support
)
@@ -22,8 +22,8 @@
Parser.cpp
LINK_LIBS
- clangBasic
clangAST
+ clangBasic
clangLex
clangSema
)
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 310e2b4..e1a5b8e 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -336,8 +336,10 @@
DefArgResult = ParseBraceInitializer();
} else
DefArgResult = ParseAssignmentExpression();
+ DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult);
if (DefArgResult.isInvalid())
- Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param);
+ Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param,
+ EqualLoc);
else {
if (!TryConsumeToken(tok::cxx_defaultarg_end)) {
// The last two tokens are the terminator and the saved value of
@@ -365,6 +367,75 @@
}
}
+ // Parse a delayed exception-specification, if there is one.
+ if (CachedTokens *Toks = LM.ExceptionSpecTokens) {
+ // Save the current token position.
+ SourceLocation origLoc = Tok.getLocation();
+
+ // Parse the default argument from its saved token stream.
+ Toks->push_back(Tok); // So that the current token doesn't get lost
+ PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);
+
+ // Consume the previously-pushed token.
+ ConsumeAnyToken();
+
+ // C++11 [expr.prim.general]p3:
+ // If a declaration declares a member function or member function
+ // template of a class X, the expression this is a prvalue of type
+ // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
+ // and the end of the function-definition, member-declarator, or
+ // declarator.
+ CXXMethodDecl *Method;
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(LM.Method))
+ Method = cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ Method = cast<CXXMethodDecl>(LM.Method);
+
+ Sema::CXXThisScopeRAII ThisScope(Actions, Method->getParent(),
+ Method->getTypeQualifiers(),
+ getLangOpts().CPlusPlus11);
+
+ // Parse the exception-specification.
+ SourceRange SpecificationRange;
+ SmallVector<ParsedType, 4> DynamicExceptions;
+ SmallVector<SourceRange, 4> DynamicExceptionRanges;
+ ExprResult NoexceptExpr;
+ CachedTokens *ExceptionSpecTokens;
+
+ ExceptionSpecificationType EST
+ = tryParseExceptionSpecification(/*Delayed=*/false, SpecificationRange,
+ DynamicExceptions,
+ DynamicExceptionRanges, NoexceptExpr,
+ ExceptionSpecTokens);
+
+ // Clean up the remaining tokens.
+ if (Tok.is(tok::cxx_exceptspec_end))
+ ConsumeToken();
+ else if (EST != EST_None)
+ Diag(Tok.getLocation(), diag::err_except_spec_unparsed);
+
+ // Attach the exception-specification to the method.
+ Actions.actOnDelayedExceptionSpecification(LM.Method, EST,
+ SpecificationRange,
+ DynamicExceptions,
+ DynamicExceptionRanges,
+ NoexceptExpr.isUsable()?
+ NoexceptExpr.get() : nullptr);
+
+ assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
+ Tok.getLocation()) &&
+ "tryParseExceptionSpecification went over the exception tokens!");
+
+ // There could be leftover tokens (e.g. because of an error).
+ // Skip through until we reach the original token position.
+ while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+
+ delete Toks;
+ LM.ExceptionSpecTokens = nullptr;
+ }
+
PrototypeScope.Exit();
// Finish the delayed C++ method declaration.
@@ -539,11 +610,13 @@
// The next token should be our artificial terminating EOF token.
if (Tok.isNot(tok::eof)) {
- SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
- if (!EndLoc.isValid())
- EndLoc = Tok.getLocation();
- // No fixit; we can't recover as if there were a semicolon here.
- Diag(EndLoc, diag::err_expected_semi_decl_list);
+ if (!Init.isInvalid()) {
+ SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
+ if (!EndLoc.isValid())
+ EndLoc = Tok.getLocation();
+ // No fixit; we can't recover as if there were a semicolon here.
+ Diag(EndLoc, diag::err_expected_semi_decl_list);
+ }
// Consume tokens until we hit the artificial EOF.
while (Tok.isNot(tok::eof))
@@ -890,11 +963,13 @@
/// ConsumeAndStoreInitializer - Consume and store the token at the passed token
/// container until the end of the current initializer expression (either a
/// default argument or an in-class initializer for a non-static data member).
-/// The final token is not consumed.
+///
+/// Returns \c true if we reached the end of something initializer-shaped,
+/// \c false if we bailed out.
bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
CachedInitKind CIK) {
// We always want this function to consume at least one token if not at EOF.
- bool IsFirstTokenConsumed = true;
+ bool IsFirstToken = true;
// Number of possible unclosed <s we've seen so far. These might be templates,
// and might not, but if there were none of them (or we know for sure that
@@ -1013,6 +1088,7 @@
Toks.push_back(Tok);
ConsumeToken();
if (Tok.is(tok::less)) {
+ ++AngleCount;
++KnownTemplateCount;
Toks.push_back(Tok);
ConsumeToken();
@@ -1062,21 +1138,28 @@
// Since the user wasn't looking for this token (if they were, it would
// already be handled), this isn't balanced. If there is a LHS token at a
// higher level, we will assume that this matches the unbalanced token
- // and return it. Otherwise, this is a spurious RHS token, which we skip.
+ // and return it. Otherwise, this is a spurious RHS token, which we
+ // consume and pass on to downstream code to diagnose.
case tok::r_paren:
if (CIK == CIK_DefaultArgument)
return true; // End of the default argument.
- if (ParenCount && !IsFirstTokenConsumed)
- return false; // Matches something.
- goto consume_token;
+ if (ParenCount && !IsFirstToken)
+ return false;
+ Toks.push_back(Tok);
+ ConsumeParen();
+ continue;
case tok::r_square:
- if (BracketCount && !IsFirstTokenConsumed)
- return false; // Matches something.
- goto consume_token;
+ if (BracketCount && !IsFirstToken)
+ return false;
+ Toks.push_back(Tok);
+ ConsumeBracket();
+ continue;
case tok::r_brace:
- if (BraceCount && !IsFirstTokenConsumed)
- return false; // Matches something.
- goto consume_token;
+ if (BraceCount && !IsFirstToken)
+ return false;
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ continue;
case tok::code_completion:
Toks.push_back(Tok);
@@ -1101,6 +1184,6 @@
ConsumeToken();
break;
}
- IsFirstTokenConsumed = false;
+ IsFirstToken = false;
}
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 09f78e5..518197e 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -238,7 +238,10 @@
void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
- SourceLocation *EndLoc) {
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax) {
BalancedDelimiterTracker Parens(*this, tok::l_paren);
Parens.consumeOpen();
@@ -255,10 +258,10 @@
if (T.isUsable())
Attrs.addNewTypeAttr(&AttrName,
SourceRange(AttrNameLoc, Parens.getCloseLocation()),
- nullptr, AttrNameLoc, T.get(), AttributeList::AS_GNU);
+ ScopeName, ScopeLoc, T.get(), Syntax);
else
Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()),
- nullptr, AttrNameLoc, nullptr, 0, AttributeList::AS_GNU);
+ ScopeName, ScopeLoc, nullptr, 0, Syntax);
}
unsigned Parser::ParseAttributeArgsCommon(
@@ -299,7 +302,8 @@
Unevaluated.reset(
new EnterExpressionEvaluationContext(Actions, Sema::Unevaluated));
- ExprResult ArgExpr(ParseAssignmentExpression());
+ ExprResult ArgExpr(
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
if (ArgExpr.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return 0;
@@ -338,28 +342,21 @@
AttributeList::Kind AttrKind =
AttributeList::getKind(AttrName, ScopeName, Syntax);
- // Availability attributes have their own grammar.
- // FIXME: All these cases fail to pass in the syntax and scope, and might be
- // written as C++11 gnu:: attributes.
if (AttrKind == AttributeList::AT_Availability) {
- ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
+ ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+ ScopeLoc, Syntax);
return;
- }
-
- if (AttrKind == AttributeList::AT_ObjCBridgeRelated) {
- ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
+ } else if (AttrKind == AttributeList::AT_ObjCBridgeRelated) {
+ ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, Syntax);
return;
- }
-
- // Type safety attributes have their own grammar.
- if (AttrKind == AttributeList::AT_TypeTagForDatatype) {
- ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
+ } else if (AttrKind == AttributeList::AT_TypeTagForDatatype) {
+ ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, Syntax);
return;
- }
-
- // Some attributes expect solely a type parameter.
- if (attributeIsTypeArgAttr(*AttrName)) {
- ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc);
+ } else if (attributeIsTypeArgAttr(*AttrName)) {
+ ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+ ScopeLoc, Syntax);
return;
}
@@ -592,15 +589,28 @@
void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
// Treat these like attributes
- while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) ||
- Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) ||
- Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) ||
- Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned) ||
- Tok.is(tok::kw___sptr) || Tok.is(tok::kw___uptr)) {
- IdentifierInfo *AttrName = Tok.getIdentifierInfo();
- SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
- AttributeList::AS_Keyword);
+ while (true) {
+ switch (Tok.getKind()) {
+ case tok::kw___fastcall:
+ case tok::kw___stdcall:
+ case tok::kw___thiscall:
+ case tok::kw___cdecl:
+ case tok::kw___vectorcall:
+ case tok::kw___ptr64:
+ case tok::kw___w64:
+ case tok::kw___ptr32:
+ case tok::kw___unaligned:
+ case tok::kw___sptr:
+ case tok::kw___uptr: {
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+ attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ AttributeList::AS_Keyword);
+ break;
+ }
+ default:
+ return;
+ }
}
}
@@ -631,6 +641,10 @@
AttributeList::AS_Keyword);
}
+static bool VersionNumberSeparator(const char Separator) {
+ return (Separator == '.' || Separator == '_');
+}
+
/// \brief Parse a version number.
///
/// version:
@@ -688,7 +702,9 @@
return VersionTuple(Major);
}
- if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) {
+ const char AfterMajorSeparator = ThisTokBegin[AfterMajor];
+ if (!VersionNumberSeparator(AfterMajorSeparator)
+ || (AfterMajor + 1 == ActualLength)) {
Diag(Tok, diag::err_expected_version);
SkipUntil(tok::comma, tok::r_paren,
StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
@@ -712,16 +728,21 @@
return VersionTuple();
}
- return VersionTuple(Major, Minor);
+ return VersionTuple(Major, Minor, (AfterMajorSeparator == '_'));
}
- // If what follows is not a '.', we have a problem.
- if (ThisTokBegin[AfterMinor] != '.') {
+ const char AfterMinorSeparator = ThisTokBegin[AfterMinor];
+ // If what follows is not a '.' or '_', we have a problem.
+ if (!VersionNumberSeparator(AfterMinorSeparator)) {
Diag(Tok, diag::err_expected_version);
SkipUntil(tok::comma, tok::r_paren,
StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
return VersionTuple();
}
+
+ // Warn if separators, be it '.' or '_', do not match.
+ if (AfterMajorSeparator != AfterMinorSeparator)
+ Diag(Tok, diag::warn_expected_consistent_version_separator);
// Parse the subminor version.
unsigned AfterSubminor = AfterMinor + 1;
@@ -738,7 +759,7 @@
return VersionTuple();
}
ConsumeToken();
- return VersionTuple(Major, Minor, Subminor);
+ return VersionTuple(Major, Minor, Subminor, (AfterMajorSeparator == '_'));
}
/// \brief Parse the contents of the "availability" attribute.
@@ -763,7 +784,10 @@
void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
SourceLocation AvailabilityLoc,
ParsedAttributes &attrs,
- SourceLocation *endLoc) {
+ SourceLocation *endLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax) {
enum { Introduced, Deprecated, Obsoleted, Unknown };
AvailabilityChange Changes[Unknown];
ExprResult MessageExpr;
@@ -826,16 +850,40 @@
}
ConsumeToken();
if (Keyword == Ident_message) {
- if (Tok.isNot(tok::string_literal)) { // Also reject wide string literals.
+ if (Tok.isNot(tok::string_literal)) {
Diag(Tok, diag::err_expected_string_literal)
<< /*Source='availability attribute'*/2;
SkipUntil(tok::r_paren, StopAtSemi);
return;
}
MessageExpr = ParseStringLiteralExpression();
+ // Also reject wide string literals.
+ if (StringLiteral *MessageStringLiteral =
+ cast_or_null<StringLiteral>(MessageExpr.get())) {
+ if (MessageStringLiteral->getCharByteWidth() != 1) {
+ Diag(MessageStringLiteral->getSourceRange().getBegin(),
+ diag::err_expected_string_literal)
+ << /*Source='availability attribute'*/ 2;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ }
break;
}
+ // Special handling of 'NA' only when applied to introduced or
+ // deprecated.
+ if ((Keyword == Ident_introduced || Keyword == Ident_deprecated) &&
+ Tok.is(tok::identifier)) {
+ IdentifierInfo *NA = Tok.getIdentifierInfo();
+ if (NA->getName() == "NA") {
+ ConsumeToken();
+ if (Keyword == Ident_introduced)
+ UnavailableLoc = KeywordLoc;
+ continue;
+ }
+ }
+
SourceRange VersionRange;
VersionTuple Version = ParseVersionTuple(VersionRange);
@@ -901,13 +949,13 @@
// Record this attribute
attrs.addNew(&Availability,
SourceRange(AvailabilityLoc, T.getCloseLocation()),
- nullptr, AvailabilityLoc,
+ ScopeName, ScopeLoc,
Platform,
Changes[Introduced],
Changes[Deprecated],
Changes[Obsoleted],
UnavailableLoc, MessageExpr.get(),
- AttributeList::AS_GNU);
+ Syntax);
}
/// \brief Parse the contents of the "objc_bridge_related" attribute.
@@ -924,7 +972,10 @@
void Parser::ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
SourceLocation ObjCBridgeRelatedLoc,
ParsedAttributes &attrs,
- SourceLocation *endLoc) {
+ SourceLocation *endLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax) {
// Opening '('.
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.consumeOpen()) {
@@ -983,11 +1034,11 @@
// Record this attribute
attrs.addNew(&ObjCBridgeRelated,
SourceRange(ObjCBridgeRelatedLoc, T.getCloseLocation()),
- nullptr, ObjCBridgeRelatedLoc,
+ ScopeName, ScopeLoc,
RelatedClass,
ClassMethod,
InstanceMethod,
- AttributeList::AS_GNU);
+ Syntax);
}
// Late Parsed Attributes:
@@ -1139,7 +1190,10 @@
void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
- SourceLocation *EndLoc) {
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax) {
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -1186,10 +1240,9 @@
}
if (!T.consumeClose()) {
- Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, nullptr, AttrNameLoc,
+ Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, ScopeName, ScopeLoc,
ArgumentKind, MatchingCType.get(),
- LayoutCompatible, MustBeNull,
- AttributeList::AS_GNU);
+ LayoutCompatible, MustBeNull, Syntax);
}
if (EndLoc)
@@ -1282,8 +1335,7 @@
/// [C++11/C11] static_assert-declaration
/// others... [FIXME]
///
-Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
- unsigned Context,
+Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -1307,7 +1359,7 @@
SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc);
break;
}
- return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs,
+ return ParseSimpleDeclaration(Context, DeclEnd, attrs,
true);
case tok::kw_namespace:
ProhibitAttributes(attrs);
@@ -1323,7 +1375,7 @@
SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
break;
default:
- return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, true);
+ return ParseSimpleDeclaration(Context, DeclEnd, attrs, true);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -1349,7 +1401,7 @@
/// of a simple-declaration. If we find that we are, we also parse the
/// for-range-initializer, and place it here.
Parser::DeclGroupPtrTy
-Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
+Parser::ParseSimpleDeclaration(unsigned Context,
SourceLocation &DeclEnd,
ParsedAttributesWithRange &Attrs,
bool RequireSemi, ForRangeInit *FRI) {
@@ -1550,9 +1602,30 @@
// appropriate function scope after the function Decl has been constructed.
// These will be parsed in ParseFunctionDefinition or ParseLexedAttrList.
LateParsedAttrList LateParsedAttrs(true);
- if (D.isFunctionDeclarator())
+ if (D.isFunctionDeclarator()) {
MaybeParseGNUAttributes(D, &LateParsedAttrs);
+ // The _Noreturn keyword can't appear here, unlike the GNU noreturn
+ // attribute. If we find the keyword here, tell the user to put it
+ // at the start instead.
+ if (Tok.is(tok::kw__Noreturn)) {
+ SourceLocation Loc = ConsumeToken();
+ const char *PrevSpec;
+ unsigned DiagID;
+
+ // We can offer a fixit if it's valid to mark this function as _Noreturn
+ // and we don't have any other declarators in this declaration.
+ bool Fixit = !DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID);
+ MaybeParseGNUAttributes(D, &LateParsedAttrs);
+ Fixit &= Tok.is(tok::semi) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try);
+
+ Diag(Loc, diag::err_c11_noreturn_misplaced)
+ << (Fixit ? FixItHint::CreateRemoval(Loc) : FixItHint())
+ << (Fixit ? FixItHint::CreateInsertion(D.getLocStart(), "_Noreturn ")
+ : FixItHint());
+ }
+ }
+
// Check to see if we have a function *definition* which must have a body.
if (D.isFunctionDeclarator() &&
// Look at the next token to make sure that this isn't a function
@@ -2434,8 +2507,11 @@
DeclSpecContext DSContext,
LateParsedAttrList *LateAttrs) {
if (DS.getSourceRange().isInvalid()) {
+ // Start the range at the current token but make the end of the range
+ // invalid. This will make the entire range invalid unless we successfully
+ // consume a token.
DS.SetRangeStart(Tok.getLocation());
- DS.SetRangeEnd(Tok.getLocation());
+ DS.SetRangeEnd(SourceLocation());
}
bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
@@ -2713,26 +2789,26 @@
goto DoneWithDeclSpec;
// typedef-name
+ case tok::kw___super:
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 (getLangOpts().CPlusPlus) {
- if (TryAnnotateCXXScopeToken(EnteringContext)) {
- if (!DS.hasTypeSpecifier())
- DS.SetTypeSpecError();
- goto DoneWithDeclSpec;
- }
- if (!Tok.is(tok::identifier))
- continue;
- }
-
// This identifier can only be a typedef name if we haven't already seen
// a type-specifier. Without this check we misparse:
// typedef int X; struct Y { short X; }; as 'short int'.
if (DS.hasTypeSpecifier())
goto DoneWithDeclSpec;
+ // In C++, check to see if this is a scope specifier like foo::bar::, if
+ // so handle it as such. This is important for ctor parsing.
+ if (getLangOpts().CPlusPlus) {
+ if (TryAnnotateCXXScopeToken(EnteringContext)) {
+ DS.SetTypeSpecError();
+ goto DoneWithDeclSpec;
+ }
+ if (!Tok.is(tok::identifier))
+ continue;
+ }
+
// Check for need to substitute AltiVec keyword tokens.
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
break;
@@ -2848,6 +2924,7 @@
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___unaligned:
ParseMicrosoftTypeAttributes(DS.getAttributes());
continue;
@@ -3218,14 +3295,15 @@
/// declarator[opt] ':' constant-expression
/// [GNU] declarator[opt] ':' constant-expression attributes[opt]
///
-void Parser::
-ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) {
+void Parser::ParseStructDeclaration(
+ ParsingDeclSpec &DS,
+ llvm::function_ref<void(ParsingFieldDeclarator &)> FieldsCallback) {
if (Tok.is(tok::kw___extension__)) {
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken();
- return ParseStructDeclaration(DS, Fields);
+ return ParseStructDeclaration(DS, FieldsCallback);
}
// Parse the common specifier-qualifiers-list piece.
@@ -3257,7 +3335,8 @@
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
ColonProtectionRAIIObject X(*this);
ParseDeclarator(DeclaratorInfo.D);
- }
+ } else
+ DeclaratorInfo.D.SetIdentifier(nullptr, Tok.getLocation());
if (TryConsumeToken(tok::colon)) {
ExprResult Res(ParseConstantExpression());
@@ -3271,7 +3350,7 @@
MaybeParseGNUAttributes(DeclaratorInfo.D);
// We're done with this declarator; invoke the callback.
- Fields.invoke(DeclaratorInfo);
+ FieldsCallback(DeclaratorInfo);
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
@@ -3335,28 +3414,19 @@
}
if (!Tok.is(tok::at)) {
- struct CFieldCallback : FieldCallback {
- Parser &P;
- Decl *TagDecl;
- SmallVectorImpl<Decl *> &FieldDecls;
-
- CFieldCallback(Parser &P, Decl *TagDecl,
- SmallVectorImpl<Decl *> &FieldDecls) :
- P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {}
-
- void invoke(ParsingFieldDeclarator &FD) override {
- // Install the declarator into the current TagDecl.
- Decl *Field = P.Actions.ActOnField(P.getCurScope(), TagDecl,
- FD.D.getDeclSpec().getSourceRange().getBegin(),
- FD.D, FD.BitfieldSize);
- FieldDecls.push_back(Field);
- FD.complete(Field);
- }
- } Callback(*this, TagDecl, FieldDecls);
+ auto CFieldCallback = [&](ParsingFieldDeclarator &FD) {
+ // Install the declarator into the current TagDecl.
+ Decl *Field =
+ Actions.ActOnField(getCurScope(), TagDecl,
+ FD.D.getDeclSpec().getSourceRange().getBegin(),
+ FD.D, FD.BitfieldSize);
+ FieldDecls.push_back(Field);
+ FD.complete(Field);
+ };
// Parse all the comma separated declarators.
ParsingDeclSpec DS(*this);
- ParseStructDeclaration(DS, Callback);
+ ParseStructDeclaration(DS, CFieldCallback);
} else { // Handle @defs
ConsumeToken();
if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
@@ -3764,8 +3834,8 @@
/// enumerator
/// enumerator-list ',' enumerator
/// enumerator:
-/// enumeration-constant
-/// enumeration-constant '=' constant-expression
+/// enumeration-constant attributes[opt]
+/// enumeration-constant attributes[opt] '=' constant-expression
/// enumeration-constant:
/// identifier
///
@@ -3802,8 +3872,13 @@
// If attributes exist after the enumerator, parse them.
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
- MaybeParseCXX11Attributes(attrs);
- ProhibitAttributes(attrs);
+ ProhibitAttributes(attrs); // GNU-style attributes are prohibited.
+ if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+ if (!getLangOpts().CPlusPlus1z)
+ Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute)
+ << 1 /*enumerator*/;
+ ParseCXX11Attributes(attrs);
+ }
SourceLocation EqualLoc;
ExprResult AssignedVal;
@@ -4045,6 +4120,7 @@
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___w64:
case tok::kw___ptr64:
case tok::kw___ptr32:
@@ -4213,6 +4289,7 @@
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___w64:
case tok::kw___sptr:
case tok::kw___uptr:
@@ -4359,20 +4436,18 @@
/// type-qualifier-list: [C99 6.7.5]
/// type-qualifier
/// [vendor] attributes
-/// [ only if VendorAttributesAllowed=true ]
+/// [ only if AttrReqs & AR_VendorAttributesParsed ]
/// type-qualifier-list type-qualifier
/// [vendor] type-qualifier-list attributes
-/// [ only if VendorAttributesAllowed=true ]
+/// [ only if AttrReqs & AR_VendorAttributesParsed ]
/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq
-/// [ only if CXX11AttributesAllowed=true ]
-/// Note: vendor can be GNU, MS, etc.
-///
-void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
- bool VendorAttributesAllowed,
- bool CXX11AttributesAllowed,
+/// [ only if AttReqs & AR_CXX11AttributesParsed ]
+/// Note: vendor can be GNU, MS, etc and can be explicitly controlled via
+/// AttrRequirements bitmask values.
+void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs,
bool AtomicAllowed,
bool IdentifierRequired) {
- if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed &&
+ if (getLangOpts().CPlusPlus11 && (AttrReqs & AR_CXX11AttributesParsed) &&
isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
ParseCXX11Attributes(attrs);
@@ -4425,7 +4500,7 @@
case tok::kw___uptr:
// GNU libc headers in C mode use '__uptr' as an identifer which conflicts
// with the MS modifier keyword.
- if (VendorAttributesAllowed && !getLangOpts().CPlusPlus &&
+ if ((AttrReqs & AR_DeclspecAttributesParsed) && !getLangOpts().CPlusPlus &&
IdentifierRequired && DS.isEmpty() && NextToken().is(tok::semi)) {
if (TryKeywordIdentFallback(false))
continue;
@@ -4438,20 +4513,28 @@
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___unaligned:
- if (VendorAttributesAllowed) {
+ if (AttrReqs & AR_DeclspecAttributesParsed) {
ParseMicrosoftTypeAttributes(DS.getAttributes());
continue;
}
goto DoneWithTypeQuals;
case tok::kw___pascal:
- if (VendorAttributesAllowed) {
+ if (AttrReqs & AR_VendorAttributesParsed) {
ParseBorlandTypeAttributes(DS.getAttributes());
continue;
}
goto DoneWithTypeQuals;
case tok::kw___attribute:
- if (VendorAttributesAllowed) {
+ if (AttrReqs & AR_GNUAttributesParsedAndRejected)
+ // When GNU attributes are expressly forbidden, diagnose their usage.
+ Diag(Tok, diag::err_attributes_not_allowed);
+
+ // Parse the attributes even if they are rejected to ensure that error
+ // recovery is graceful.
+ if (AttrReqs & AR_GNUAttributesParsed ||
+ AttrReqs & AR_GNUAttributesParsedAndRejected) {
ParseGNUAttributes(DS.getAttributes());
continue; // do *not* consume the next token!
}
@@ -4484,15 +4567,27 @@
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
}
-static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang) {
+static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang,
+ unsigned TheContext) {
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;
+ if (Kind == tok::amp)
+ return true;
+
+ // We parse rvalue refs in C++03, because otherwise the errors are scary.
+ // But we must not parse them in conversion-type-ids and new-type-ids, since
+ // those can be legitimately followed by a && operator.
+ // (The same thing can in theory happen after a trailing-return-type, but
+ // since those are a C++11 feature, there is no rejects-valid issue there.)
+ if (Kind == tok::ampamp)
+ return Lang.CPlusPlus11 || (TheContext != Declarator::ConversionIdContext &&
+ TheContext != Declarator::CXXNewContext);
+
+ return false;
}
/// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator
@@ -4529,7 +4624,9 @@
// Member pointers get special handling, since there's no place for the
// scope spec in the generic path below.
if (getLangOpts().CPlusPlus &&
- (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
+ (Tok.is(tok::coloncolon) ||
+ (Tok.is(tok::identifier) &&
+ (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) ||
Tok.is(tok::annot_cxxscope))) {
bool EnteringContext = D.getContext() == Declarator::FileContext ||
D.getContext() == Declarator::MemberContext;
@@ -4570,7 +4667,7 @@
tok::TokenKind Kind = Tok.getKind();
// Not a pointer, C++ reference, or block.
- if (!isPtrOperatorToken(Kind, getLangOpts())) {
+ if (!isPtrOperatorToken(Kind, getLangOpts(), D.getContext())) {
if (DirectDeclParser)
(this->*DirectDeclParser)(D);
return;
@@ -4585,8 +4682,13 @@
// Is a pointer.
DeclSpec DS(AttrFactory);
- // FIXME: GNU attributes are not allowed here in a new-type-id.
- ParseTypeQualifierListOpt(DS, true, true, true, !D.mayOmitIdentifier());
+ // GNU attributes are not allowed here in a new-type-id, but Declspec and
+ // C++11 attributes are allowed.
+ unsigned Reqs = AR_CXX11AttributesParsed | AR_DeclspecAttributesParsed |
+ ((D.getContext() != Declarator::CXXNewContext)
+ ? AR_GNUAttributesParsed
+ : AR_GNUAttributesParsedAndRejected);
+ ParseTypeQualifierListOpt(DS, Reqs, true, !D.mayOmitIdentifier());
D.ExtendWithDeclSpec(DS);
// Recursively parse the declarator.
@@ -4722,6 +4824,14 @@
DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec());
if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) {
+ // Don't parse FOO:BAR as if it were a typo for FOO::BAR inside a class, in
+ // this context it is a bitfield. Also in range-based for statement colon
+ // may delimit for-range-declaration.
+ ColonProtectionRAIIObject X(*this,
+ D.getContext() == Declarator::MemberContext ||
+ (D.getContext() == Declarator::ForContext &&
+ getLangOpts().CPlusPlus11));
+
// ParseDeclaratorInternal might already have parsed the scope.
if (D.getCXXScopeSpec().isEmpty()) {
bool EnteringContext = D.getContext() == Declarator::FileContext ||
@@ -4752,7 +4862,7 @@
!D.hasGroupingParens() &&
!Actions.containsUnexpandedParameterPacks(D))) {
SourceLocation EllipsisLoc = ConsumeToken();
- if (isPtrOperatorToken(Tok.getKind(), getLangOpts())) {
+ if (isPtrOperatorToken(Tok.getKind(), getLangOpts(), D.getContext())) {
// The ellipsis was put in the wrong place. Recover, and explain to
// the user what they should have done.
ParseDeclarator(D);
@@ -5078,11 +5188,13 @@
SourceLocation RefQualifierLoc;
SourceLocation ConstQualifierLoc;
SourceLocation VolatileQualifierLoc;
+ SourceLocation RestrictQualifierLoc;
ExceptionSpecificationType ESpecType = EST_None;
SourceRange ESpecRange;
SmallVector<ParsedType, 2> DynamicExceptions;
SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
+ CachedTokens *ExceptionSpecTokens = 0;
ParsedAttributes FnAttrs(AttrFactory);
TypeResult TrailingReturnType;
@@ -5125,13 +5237,13 @@
// with the virt-specifier-seq and pure-specifier in the same way.
// Parse cv-qualifier-seq[opt].
- ParseTypeQualifierListOpt(DS, /*VendorAttributesAllowed*/ false,
- /*CXX11AttributesAllowed*/ false,
+ ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed,
/*AtomicAllowed*/ false);
if (!DS.getSourceRange().getEnd().isInvalid()) {
EndLoc = DS.getSourceRange().getEnd();
ConstQualifierLoc = DS.getConstSpecLoc();
VolatileQualifierLoc = DS.getVolatileSpecLoc();
+ RestrictQualifierLoc = DS.getRestrictSpecLoc();
}
// Parse ref-qualifier[opt].
@@ -5164,15 +5276,36 @@
dyn_cast<CXXRecordDecl>(Actions.CurContext),
DS.getTypeQualifiers() |
(D.getDeclSpec().isConstexprSpecified() &&
- !getLangOpts().CPlusPlus1y
+ !getLangOpts().CPlusPlus14
? Qualifiers::Const : 0),
IsCXX11MemberFunction);
// Parse exception-specification[opt].
- ESpecType = tryParseExceptionSpecification(ESpecRange,
+ bool Delayed = D.isFirstDeclarationOfMember() &&
+ D.isFunctionDeclaratorAFunctionDeclaration();
+ if (Delayed && Actions.isLibstdcxxEagerExceptionSpecHack(D) &&
+ GetLookAheadToken(0).is(tok::kw_noexcept) &&
+ GetLookAheadToken(1).is(tok::l_paren) &&
+ GetLookAheadToken(2).is(tok::kw_noexcept) &&
+ GetLookAheadToken(3).is(tok::l_paren) &&
+ GetLookAheadToken(4).is(tok::identifier) &&
+ GetLookAheadToken(4).getIdentifierInfo()->isStr("swap")) {
+ // HACK: We've got an exception-specification
+ // noexcept(noexcept(swap(...)))
+ // or
+ // noexcept(noexcept(swap(...)) && noexcept(swap(...)))
+ // on a 'swap' member function. This is a libstdc++ bug; the lookup
+ // for 'swap' will only find the function we're currently declaring,
+ // whereas it expects to find a non-member swap through ADL. Turn off
+ // delayed parsing to give it a chance to find what it expects.
+ Delayed = false;
+ }
+ ESpecType = tryParseExceptionSpecification(Delayed,
+ ESpecRange,
DynamicExceptions,
DynamicExceptionRanges,
- NoexceptExpr);
+ NoexceptExpr,
+ ExceptionSpecTokens);
if (ESpecType != EST_None)
EndLoc = ESpecRange.getEnd();
@@ -5204,6 +5337,7 @@
RefQualifierIsLValueRef,
RefQualifierLoc, ConstQualifierLoc,
VolatileQualifierLoc,
+ RestrictQualifierLoc,
/*MutableLoc=*/SourceLocation(),
ESpecType, ESpecRange.getBegin(),
DynamicExceptions.data(),
@@ -5211,6 +5345,7 @@
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : nullptr,
+ ExceptionSpecTokens,
StartLoc, LocalEndLoc, D,
TrailingReturnType),
FnAttrs, EndLoc);
@@ -5282,7 +5417,7 @@
Diag(Tok, diag::err_unexpected_typedef_ident) << ParmII;
// Verify that the argument identifier has not already been mentioned.
- if (!ParamsSoFar.insert(ParmII)) {
+ if (!ParamsSoFar.insert(ParmII).second) {
Diag(Tok, diag::err_param_redefinition) << ParmII;
} else {
// Remember this identifier in ParamInfo.
@@ -5390,10 +5525,18 @@
// Otherwise, we have something. Add it and let semantic analysis try
// to grok it and add the result to the ParamInfo we are building.
+ // Last chance to recover from a misplaced ellipsis in an attempted
+ // parameter pack declaration.
+ if (Tok.is(tok::ellipsis) &&
+ (NextToken().isNot(tok::r_paren) ||
+ (!ParmDeclarator.getEllipsisLoc().isValid() &&
+ !Actions.isUnexpandedParameterPackPermitted())) &&
+ Actions.containsUnexpandedParameterPacks(ParmDeclarator))
+ DiagnoseMisplacedEllipsisInDeclarator(ConsumeToken(), ParmDeclarator);
+
// Inform the actions module about the parameter declarator, so it gets
// added to the current scope.
- Decl *Param = Actions.ActOnParamDeclarator(getCurScope(),
- ParmDeclarator);
+ Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator);
// Parse the default argument, if any. We parse the default
// arguments in all dialects; the semantic analysis in
// ActOnParamDefaultArgument will reject the default argument in
@@ -5412,7 +5555,7 @@
if (!ConsumeAndStoreInitializer(*DefArgToks, CIK_DefaultArgument)) {
delete DefArgToks;
DefArgToks = nullptr;
- Actions.ActOnParamDefaultArgumentError(Param);
+ Actions.ActOnParamDefaultArgumentError(Param, EqualLoc);
} else {
// Mark the end of the default argument so that we know when to
// stop when we parse it later on.
@@ -5440,8 +5583,9 @@
DefArgResult = ParseBraceInitializer();
} else
DefArgResult = ParseAssignmentExpression();
+ DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult);
if (DefArgResult.isInvalid()) {
- Actions.ActOnParamDefaultArgumentError(Param);
+ Actions.ActOnParamDefaultArgumentError(Param, EqualLoc);
SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);
} else {
// Inform the actions module about the default argument
@@ -5456,12 +5600,34 @@
Param, DefArgToks));
}
- if (TryConsumeToken(tok::ellipsis, EllipsisLoc) &&
- !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)
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
+ 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)
+ << FixItHint::CreateInsertion(EllipsisLoc, ", ");
+ } else if (ParmDeclarator.getEllipsisLoc().isValid() ||
+ Actions.containsUnexpandedParameterPacks(ParmDeclarator)) {
+ // It looks like this was supposed to be a parameter pack. Warn and
+ // point out where the ellipsis should have gone.
+ SourceLocation ParmEllipsis = ParmDeclarator.getEllipsisLoc();
+ Diag(EllipsisLoc, diag::warn_misplaced_ellipsis_vararg)
+ << ParmEllipsis.isValid() << ParmEllipsis;
+ if (ParmEllipsis.isValid()) {
+ Diag(ParmEllipsis,
+ diag::note_misplaced_ellipsis_vararg_existing_ellipsis);
+ } else {
+ Diag(ParmDeclarator.getIdentifierLoc(),
+ diag::note_misplaced_ellipsis_vararg_add_ellipsis)
+ << FixItHint::CreateInsertion(ParmDeclarator.getIdentifierLoc(),
+ "...")
+ << !ParmDeclarator.hasName();
+ }
+ Diag(EllipsisLoc, diag::note_misplaced_ellipsis_vararg_add_comma)
<< FixItHint::CreateInsertion(EllipsisLoc, ", ");
+ }
+
+ // We can't have any more parameters after an ellipsis.
break;
}
@@ -5522,7 +5688,7 @@
// If there is a type-qualifier-list, read it now.
// Type qualifiers in an array subscript are a C99 feature.
DeclSpec DS(AttrFactory);
- ParseTypeQualifierListOpt(DS, false /*no attributes*/);
+ ParseTypeQualifierListOpt(DS, AR_CXX11AttributesParsed);
// If we haven't already read 'static', check to see if there is one after the
// type-qualifier-list.
@@ -5560,6 +5726,11 @@
Sema::ConstantEvaluated);
NumElements = ParseAssignmentExpression();
}
+ } else {
+ if (StaticLoc.isValid()) {
+ Diag(StaticLoc, diag::err_unspecified_size_with_static);
+ StaticLoc = SourceLocation(); // Drop the static.
+ }
}
// If there was an error parsing the assignment-expression, recover.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index cd2e397..79ae878 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -73,7 +73,15 @@
std::vector<IdentifierInfo*> ExtraIdent;
std::vector<SourceLocation> ExtraNamespaceLoc;
- Token attrTok;
+ ParsedAttributesWithRange attrs(AttrFactory);
+ SourceLocation attrLoc;
+ if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+ if (!getLangOpts().CPlusPlus1z)
+ Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute)
+ << 0 /*namespace*/;
+ attrLoc = Tok.getLocation();
+ ParseCXX11Attributes(attrs);
+ }
if (Tok.is(tok::identifier)) {
Ident = Tok.getIdentifierInfo();
@@ -85,10 +93,13 @@
}
}
+ // A nested namespace definition cannot have attributes.
+ if (!ExtraNamespaceLoc.empty() && attrLoc.isValid())
+ Diag(attrLoc, diag::err_unexpected_nested_namespace_attribute);
+
// Read label attributes, if present.
- ParsedAttributes attrs(AttrFactory);
if (Tok.is(tok::kw___attribute)) {
- attrTok = Tok;
+ attrLoc = Tok.getLocation();
ParseGNUAttributes(attrs);
}
@@ -99,8 +110,8 @@
SkipUntil(tok::semi);
return nullptr;
}
- if (!attrs.empty())
- Diag(attrTok, diag::err_unexpected_namespace_attributes_alias);
+ if (attrLoc.isValid())
+ Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias);
if (InlineLoc.isValid())
Diag(InlineLoc, diag::err_inline_namespace_alias)
<< FixItHint::CreateRemoval(InlineLoc);
@@ -110,39 +121,36 @@
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen()) {
- if (!ExtraIdent.empty()) {
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
- << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
- }
-
if (Ident)
Diag(Tok, diag::err_expected) << tok::l_brace;
else
Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
-
return nullptr;
}
if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() ||
getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() ||
getCurScope()->getFnParent()) {
- if (!ExtraIdent.empty()) {
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
- << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
- }
Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope);
SkipUntil(tok::r_brace);
return nullptr;
}
- if (!ExtraIdent.empty()) {
+ if (ExtraIdent.empty()) {
+ // Normal namespace definition, not a nested-namespace-definition.
+ } else if (InlineLoc.isValid()) {
+ Diag(InlineLoc, diag::err_inline_nested_namespace_definition);
+ } else if (getLangOpts().CPlusPlus1z) {
+ Diag(ExtraNamespaceLoc[0],
+ diag::warn_cxx14_compat_nested_namespace_definition);
+ } else {
TentativeParsingAction TPA(*this);
SkipUntil(tok::r_brace, StopBeforeMatch);
Token rBraceToken = Tok;
TPA.Revert();
if (!rBraceToken.is(tok::r_brace)) {
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)
<< SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
} else {
std::string NamespaceFix;
@@ -156,7 +164,7 @@
for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i)
RBraces += "} ";
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)
<< FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(),
ExtraIdentLoc.back()),
NamespaceFix)
@@ -195,11 +203,11 @@
}
/// ParseInnerNamespace - Parse the contents of a namespace.
-void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
- std::vector<IdentifierInfo*>& Ident,
- std::vector<SourceLocation>& NamespaceLoc,
- unsigned int index, SourceLocation& InlineLoc,
- ParsedAttributes& attrs,
+void Parser::ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc,
+ std::vector<IdentifierInfo *> &Ident,
+ std::vector<SourceLocation> &NamespaceLoc,
+ unsigned int index, SourceLocation &InlineLoc,
+ ParsedAttributes &attrs,
BalancedDelimiterTracker &Tracker) {
if (index == Ident.size()) {
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
@@ -216,7 +224,9 @@
return;
}
- // Parse improperly nested namespaces.
+ // Handle a nested namespace definition.
+ // FIXME: Preserve the source information through to the AST rather than
+ // desugaring it here.
ParseScope NamespaceScope(this, Scope::DeclScope);
Decl *NamespcDecl =
Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(),
@@ -493,6 +503,12 @@
if (TryConsumeToken(tok::kw_typename, TypenameLoc))
HasTypenameKeyword = true;
+ if (Tok.is(tok::kw___super)) {
+ Diag(Tok.getLocation(), diag::err_super_in_using_declaration);
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
+
// Parse nested-name-specifier.
IdentifierInfo *LastII = nullptr;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false,
@@ -692,7 +708,7 @@
ExprResult AssertMessage;
if (Tok.is(tok::r_paren)) {
Diag(Tok, getLangOpts().CPlusPlus1z
- ? diag::warn_cxx1y_compat_static_assert_no_message
+ ? diag::warn_cxx14_compat_static_assert_no_message
: diag::ext_static_assert_no_message)
<< (getLangOpts().CPlusPlus1z
? FixItHint()
@@ -769,7 +785,7 @@
// because the typename-specifier in a function-style cast operation can't
// be 'auto'.
Diag(Tok.getLocation(),
- getLangOpts().CPlusPlus1y
+ getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_decltype_auto_type_specifier
: diag::ext_decltype_auto_type_specifier);
ConsumeToken();
@@ -780,7 +796,7 @@
// The operand of the decltype specifier is an unevaluated operand.
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
nullptr,/*IsDecltype=*/true);
- Result = ParseExpression();
+ Result = Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (Result.isInvalid()) {
DS.SetTypeSpecError();
if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) {
@@ -903,8 +919,8 @@
/// In C++98, instead of base-type-specifier, we have:
///
/// ::[opt] nested-name-specifier[opt] class-name
-Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
- SourceLocation &EndLocation) {
+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)
@@ -1066,6 +1082,11 @@
case tok::comma: // __builtin_offsetof(struct foo{...} ,
case tok::kw_operator: // struct foo operator ++() {...}
case tok::kw___declspec: // struct foo {...} __declspec(...)
+ case tok::l_square: // void f(struct f [ 3])
+ case tok::ellipsis: // void f(struct f ... [Ns])
+ // FIXME: we should emit semantic diagnostic when declaration
+ // attribute is in type attribute position.
+ case tok::kw___attribute: // struct foo __attribute__((used)) x;
return true;
case tok::colon:
return CouldBeBitfield; // enum E { ... } : 2;
@@ -1073,6 +1094,7 @@
case tok::kw_const: // struct foo {...} const x;
case tok::kw_volatile: // struct foo {...} volatile x;
case tok::kw_restrict: // struct foo {...} restrict x;
+ case tok::kw__Atomic: // struct foo {...} _Atomic x;
// Function specifiers
// Note, no 'explicit'. An explicit function must be either a conversion
// operator or a constructor. Either way, it can't have a return type.
@@ -1111,10 +1133,6 @@
if (!getLangOpts().CPlusPlus)
return true;
break;
- // C++11 attributes
- case tok::l_square: // enum E [[]] x
- // Note, no tok::kw_alignas here; alignas cannot appertain to a type.
- return getLangOpts().CPlusPlus11 && NextToken().is(tok::l_square);
case tok::greater:
// template<class T = class X>
return getLangOpts().CPlusPlus;
@@ -1224,22 +1242,70 @@
// C++11 attributes
SourceLocation AttrFixitLoc = Tok.getLocation();
- // GNU libstdc++ and libc++ use certain intrinsic names as the
- // name of struct templates, but some are keywords in GCC >= 4.3
- // MSVC and Clang. For compatibility, convert the token to an identifier
- // and issue a warning diagnostic.
- if (TagType == DeclSpec::TST_struct && !Tok.is(tok::identifier) &&
- !Tok.isAnnotation()) {
- const IdentifierInfo *II = Tok.getIdentifierInfo();
- // We rarely end up here so the following check is efficient.
- if (II && II->getName().startswith("__is_"))
- TryKeywordIdentFallback(true);
- }
+ if (TagType == DeclSpec::TST_struct &&
+ !Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo() &&
+ (Tok.is(tok::kw___is_abstract) ||
+ Tok.is(tok::kw___is_arithmetic) ||
+ Tok.is(tok::kw___is_array) ||
+ Tok.is(tok::kw___is_base_of) ||
+ Tok.is(tok::kw___is_class) ||
+ Tok.is(tok::kw___is_complete_type) ||
+ Tok.is(tok::kw___is_compound) ||
+ Tok.is(tok::kw___is_const) ||
+ Tok.is(tok::kw___is_constructible) ||
+ Tok.is(tok::kw___is_convertible) ||
+ Tok.is(tok::kw___is_convertible_to) ||
+ Tok.is(tok::kw___is_destructible) ||
+ Tok.is(tok::kw___is_empty) ||
+ Tok.is(tok::kw___is_enum) ||
+ Tok.is(tok::kw___is_floating_point) ||
+ Tok.is(tok::kw___is_final) ||
+ Tok.is(tok::kw___is_function) ||
+ Tok.is(tok::kw___is_fundamental) ||
+ Tok.is(tok::kw___is_integral) ||
+ Tok.is(tok::kw___is_interface_class) ||
+ Tok.is(tok::kw___is_literal) ||
+ Tok.is(tok::kw___is_lvalue_expr) ||
+ Tok.is(tok::kw___is_lvalue_reference) ||
+ Tok.is(tok::kw___is_member_function_pointer) ||
+ Tok.is(tok::kw___is_member_object_pointer) ||
+ Tok.is(tok::kw___is_member_pointer) ||
+ Tok.is(tok::kw___is_nothrow_assignable) ||
+ Tok.is(tok::kw___is_nothrow_constructible) ||
+ Tok.is(tok::kw___is_nothrow_destructible) ||
+ Tok.is(tok::kw___is_object) ||
+ Tok.is(tok::kw___is_pod) ||
+ Tok.is(tok::kw___is_pointer) ||
+ Tok.is(tok::kw___is_polymorphic) ||
+ Tok.is(tok::kw___is_reference) ||
+ Tok.is(tok::kw___is_rvalue_expr) ||
+ Tok.is(tok::kw___is_rvalue_reference) ||
+ Tok.is(tok::kw___is_same) ||
+ Tok.is(tok::kw___is_scalar) ||
+ Tok.is(tok::kw___is_sealed) ||
+ Tok.is(tok::kw___is_signed) ||
+ Tok.is(tok::kw___is_standard_layout) ||
+ Tok.is(tok::kw___is_trivial) ||
+ Tok.is(tok::kw___is_trivially_assignable) ||
+ Tok.is(tok::kw___is_trivially_constructible) ||
+ Tok.is(tok::kw___is_trivially_copyable) ||
+ Tok.is(tok::kw___is_union) ||
+ Tok.is(tok::kw___is_unsigned) ||
+ Tok.is(tok::kw___is_void) ||
+ Tok.is(tok::kw___is_volatile)))
+ // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
+ // name of struct templates, but some are keywords in GCC >= 4.3
+ // and Clang. Therefore, when we see the token sequence "struct
+ // X", make X into a normal identifier rather than a keyword, to
+ // allow libstdc++ 4.2 and libc++ to work properly.
+ TryKeywordIdentFallback(true);
// Parse the (optional) nested-name-specifier.
CXXScopeSpec &SS = DS.getTypeSpecScope();
if (getLangOpts().CPlusPlus) {
- // "FOO : BAR" is not a potential typo for "FOO::BAR".
+ // "FOO : BAR" is not a potential typo for "FOO::BAR". In this context it
+ // is a base-specifier-list.
ColonProtectionRAIIObject X(*this);
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
@@ -1668,7 +1734,11 @@
// Also enforce C++ [temp]p3:
// In a template-declaration which defines a class, no declarator
// is permitted.
+ //
+ // After a type-specifier, we don't expect a semicolon. This only happens in
+ // C, since definitions are not permitted in this context in C++.
if (TUK == Sema::TUK_Definition &&
+ (getLangOpts().CPlusPlus || !isTypeSpecifier(DSC)) &&
(TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) {
if (Tok.isNot(tok::semi)) {
const PrintingPolicy &PPol = Actions.getASTContext().getPrintingPolicy();
@@ -1730,7 +1800,7 @@
/// base-type-specifier
/// attribute-specifier-seq[opt] access-specifier 'virtual'[opt]
/// base-type-specifier
-Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
+BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
bool IsVirtual = false;
SourceLocation StartLoc = Tok.getLocation();
@@ -1805,16 +1875,34 @@
}
/// \brief If the given declarator has any parts for which parsing has to be
-/// delayed, e.g., default arguments, create a late-parsed method declaration
-/// record to handle the parsing at the end of the class definition.
+/// delayed, e.g., default arguments or an exception-specification, create a
+/// late-parsed method declaration record to handle the parsing at the end of
+/// the class definition.
void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
Decl *ThisDecl) {
// We just declared a member function. If this member function
- // has any default arguments, we'll need to parse them later.
+ // has any default arguments or an exception-specification, we'll need to
+ // parse them later.
LateParsedMethodDeclaration *LateMethod = nullptr;
DeclaratorChunk::FunctionTypeInfo &FTI
= DeclaratorInfo.getFunctionTypeInfo();
+ // If there was a late-parsed exception-specification, hold onto its tokens.
+ if (FTI.getExceptionSpecType() == EST_Unparsed) {
+ // Push this method onto the stack of late-parsed method
+ // declarations.
+ LateMethod = new LateParsedMethodDeclaration(this, ThisDecl);
+ getCurrentClass().LateParsedDeclarations.push_back(LateMethod);
+ LateMethod->TemplateScope = getCurScope()->isTemplateParamScope();
+
+ // Stash the exception-specification tokens in the late-pased mthod.
+ LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens;
+ FTI.ExceptionSpecTokens = 0;
+
+ // Reserve space for the parameters.
+ LateMethod->DefaultArgs.reserve(FTI.NumParams);
+ }
+
for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) {
if (LateMethod || FTI.Params[ParamIdx].DefaultArgTokens) {
if (!LateMethod) {
@@ -1878,12 +1966,22 @@
/// virt-specifier
/// virt-specifier-seq virt-specifier
void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
- bool IsInterface) {
+ bool IsInterface,
+ SourceLocation FriendLoc) {
while (true) {
VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier();
if (Specifier == VirtSpecifiers::VS_None)
return;
+ if (FriendLoc.isValid()) {
+ Diag(Tok.getLocation(), diag::err_friend_decl_spec)
+ << VirtSpecifiers::getSpecifierName(Specifier)
+ << FixItHint::CreateRemoval(Tok.getLocation())
+ << SourceRange(FriendLoc, FriendLoc);
+ ConsumeToken();
+ continue;
+ }
+
// C++ [class.mem]p8:
// A virt-specifier-seq shall contain at most one of each virt-specifier.
const char *PrevSpec = nullptr;
@@ -1926,21 +2024,21 @@
// declarator pure-specifier[opt]
// declarator brace-or-equal-initializer[opt]
// identifier[opt] ':' constant-expression
- if (Tok.isNot(tok::colon)) {
- // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
- // is a bitfield.
- // FIXME: This should only apply when parsing the id-expression (see
- // PR18587).
- ColonProtectionRAIIObject X(*this);
+ if (Tok.isNot(tok::colon))
ParseDeclarator(DeclaratorInfo);
- }
+ else
+ DeclaratorInfo.SetIdentifier(nullptr, Tok.getLocation());
if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) {
+ assert(DeclaratorInfo.isPastIdentifier() &&
+ "don't know where identifier would go yet?");
BitfieldSize = ParseConstantExpression();
if (BitfieldSize.isInvalid())
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
} else
- ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ ParseOptionalCXX11VirtSpecifierSeq(
+ VS, getCurrentClass().IsInterface,
+ DeclaratorInfo.getDeclSpec().getFriendSpecLoc());
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
@@ -1958,10 +2056,21 @@
// For compatibility with code written to older Clang, also accept a
// virt-specifier *after* the GNU attributes.
- // FIXME: If we saw any attributes that are known to GCC followed by a
- // virt-specifier, issue a GCC-compat warning.
- if (BitfieldSize.isUnset() && VS.isUnset())
- ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ if (BitfieldSize.isUnset() && VS.isUnset()) {
+ ParseOptionalCXX11VirtSpecifierSeq(
+ VS, getCurrentClass().IsInterface,
+ DeclaratorInfo.getDeclSpec().getFriendSpecLoc());
+ if (!VS.isUnset()) {
+ // If we saw any GNU-style attributes that are known to GCC followed by a
+ // virt-specifier, issue a GCC-compat warning.
+ const AttributeList *Attr = DeclaratorInfo.getAttributes();
+ while (Attr) {
+ if (Attr->isKnownToGCC() && !Attr->isCXX11Attribute())
+ Diag(Attr->getLoc(), diag::warn_gcc_attribute_location);
+ Attr = Attr->getNext();
+ }
+ }
+ }
}
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
@@ -2015,10 +2124,19 @@
return;
}
+ // Turn on colon protection early, while parsing declspec, although there is
+ // nothing to protect there. It prevents from false errors if error recovery
+ // incorrectly determines where the declspec ends, as in the example:
+ // struct A { enum class B { C }; };
+ // const int C = 4;
+ // struct D { A::B : C; };
+ ColonProtectionRAIIObject X(*this);
+
// Access declarations.
bool MalformedTypeSpec = false;
if (!TemplateInfo.Kind &&
- (Tok.is(tok::identifier) || Tok.is(tok::coloncolon))) {
+ (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw___super))) {
if (TryAnnotateCXXScopeToken())
MalformedTypeSpec = true;
@@ -2036,6 +2154,11 @@
ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
/*EnteringContext=*/false);
+ if (SS.isInvalid()) {
+ SkipUntil(tok::semi);
+ return;
+ }
+
// Try to parse an unqualified-id.
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
@@ -2063,9 +2186,10 @@
}
}
- // static_assert-declaration
- if (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) {
- // FIXME: Check for templates
+ // static_assert-declaration. A templated static_assert declaration is
+ // diagnosed in Parser::ParseSingleDeclarationAfterTemplate.
+ if (!TemplateInfo.Kind &&
+ (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert))) {
SourceLocation DeclEnd;
ParseStaticAssertDeclaration(DeclEnd);
return;
@@ -2128,13 +2252,11 @@
if (MalformedTypeSpec)
DS.SetTypeSpecError();
- {
- // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
- // is a bitfield.
- ColonProtectionRAIIObject X(*this);
- ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
- &CommonLateParsedAttrs);
- }
+ ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
+ &CommonLateParsedAttrs);
+
+ // Turn off colon protection that was set for declspec.
+ X.restore();
// If we had a free-standing type definition with a missing semicolon, we
// may get this far before the problem becomes obvious.
@@ -2308,7 +2430,6 @@
E = Ranges.end(); I != E; ++I)
Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I;
- // TODO: handle initializers, VS, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
TemplateParams);
} else {
@@ -2584,13 +2705,43 @@
if (Tok.is(tok::colon)) {
ParseBaseClause(TagDecl);
-
if (!Tok.is(tok::l_brace)) {
- Diag(Tok, diag::err_expected_lbrace_after_base_specifiers);
-
- if (TagDecl)
- Actions.ActOnTagDefinitionError(getCurScope(), TagDecl);
- return;
+ bool SuggestFixIt = false;
+ SourceLocation BraceLoc = PP.getLocForEndOfToken(PrevTokLocation);
+ if (Tok.isAtStartOfLine()) {
+ switch (Tok.getKind()) {
+ case tok::kw_private:
+ case tok::kw_protected:
+ case tok::kw_public:
+ SuggestFixIt = NextToken().getKind() == tok::colon;
+ break;
+ case tok::kw_static_assert:
+ case tok::r_brace:
+ case tok::kw_using:
+ // base-clause can have simple-template-id; 'template' can't be there
+ case tok::kw_template:
+ SuggestFixIt = true;
+ break;
+ case tok::identifier:
+ SuggestFixIt = isConstructorDeclarator(true);
+ break;
+ default:
+ SuggestFixIt = isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
+ break;
+ }
+ }
+ DiagnosticBuilder LBraceDiag =
+ Diag(BraceLoc, diag::err_expected_lbrace_after_base_specifiers);
+ if (SuggestFixIt) {
+ LBraceDiag << FixItHint::CreateInsertion(BraceLoc, " {");
+ // Try recovering from missing { after base-clause.
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::l_brace);
+ } else {
+ if (TagDecl)
+ Actions.ActOnTagDefinitionError(getCurScope(), TagDecl);
+ return;
+ }
}
}
@@ -2724,7 +2875,7 @@
// C++11 [class.mem]p2:
// Within the class member-specification, the class is regarded as complete
- // within function bodies, default arguments, and
+ // within function bodies, default arguments, exception-specifications, and
// brace-or-equal-initializers for non-static data members (including such
// things in nested classes).
if (TagDecl && NonNestedClass) {
@@ -2853,7 +3004,7 @@
/// [C++] mem-initializer-id:
/// '::'[opt] nested-name-specifier[opt] class-name
/// identifier
-Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
+MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
@@ -2943,13 +3094,63 @@
/// 'noexcept'
/// 'noexcept' '(' constant-expression ')'
ExceptionSpecificationType
-Parser::tryParseExceptionSpecification(
+Parser::tryParseExceptionSpecification(bool Delayed,
SourceRange &SpecificationRange,
SmallVectorImpl<ParsedType> &DynamicExceptions,
SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
- ExprResult &NoexceptExpr) {
+ ExprResult &NoexceptExpr,
+ CachedTokens *&ExceptionSpecTokens) {
ExceptionSpecificationType Result = EST_None;
+ ExceptionSpecTokens = 0;
+
+ // Handle delayed parsing of exception-specifications.
+ if (Delayed) {
+ if (Tok.isNot(tok::kw_throw) && Tok.isNot(tok::kw_noexcept))
+ return EST_None;
+ // Consume and cache the starting token.
+ bool IsNoexcept = Tok.is(tok::kw_noexcept);
+ Token StartTok = Tok;
+ SpecificationRange = SourceRange(ConsumeToken());
+
+ // Check for a '('.
+ if (!Tok.is(tok::l_paren)) {
+ // If this is a bare 'noexcept', we're done.
+ if (IsNoexcept) {
+ Diag(Tok, diag::warn_cxx98_compat_noexcept_decl);
+ NoexceptExpr = 0;
+ return EST_BasicNoexcept;
+ }
+
+ Diag(Tok, diag::err_expected_lparen_after) << "throw";
+ return EST_DynamicNone;
+ }
+
+ // Cache the tokens for the exception-specification.
+ ExceptionSpecTokens = new CachedTokens;
+ ExceptionSpecTokens->push_back(StartTok); // 'throw' or 'noexcept'
+ ExceptionSpecTokens->push_back(Tok); // '('
+ SpecificationRange.setEnd(ConsumeParen()); // '('
+
+ if (!ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens,
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/true)) {
+ NoexceptExpr = 0;
+ delete ExceptionSpecTokens;
+ ExceptionSpecTokens = 0;
+ return IsNoexcept? EST_BasicNoexcept : EST_DynamicNone;
+ }
+ SpecificationRange.setEnd(Tok.getLocation());
+
+ // Add the 'stop' token.
+ Token End;
+ End.startToken();
+ End.setKind(tok::cxx_exceptspec_end);
+ End.setLocation(Tok.getLocation());
+ ExceptionSpecTokens->push_back(End);
+ return EST_Unparsed;
+ }
+
// See if there's a dynamic specification.
if (Tok.is(tok::kw_throw)) {
Result = ParseDynamicExceptionSpecification(SpecificationRange,
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 0c231d6..3d57ba9 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -216,6 +216,13 @@
return isKnownToBeDeclarationSpecifier();
}
+static bool isFoldOperator(prec::Level Level) {
+ return Level > prec::Unknown && Level != prec::Conditional;
+}
+static bool isFoldOperator(tok::TokenKind Kind) {
+ return isFoldOperator(getBinOpPrecedence(Kind, false, true));
+}
+
/// \brief Parse a binary expression that starts with \p LHS and has a
/// precedence of at least \p MinPrec.
ExprResult
@@ -247,6 +254,16 @@
return LHS;
}
+ // If the next token is an ellipsis, then this is a fold-expression. Leave
+ // it alone so we can handle it in the paren expression.
+ if (isFoldOperator(NextTokPrec) && Tok.is(tok::ellipsis)) {
+ // FIXME: We can't check this via lookahead before we consume the token
+ // because that tickles a lexer bug.
+ PP.EnterToken(Tok);
+ Tok = OpToken;
+ return LHS;
+ }
+
// Special case handling for the ternary operator.
ExprResult TernaryMiddle(true);
if (NextTokPrec == prec::Conditional) {
@@ -260,6 +277,7 @@
// 'logical-OR-expression' as we might expect.
TernaryMiddle = ParseExpression();
if (TernaryMiddle.isInvalid()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
TernaryMiddle = nullptr;
}
@@ -328,9 +346,11 @@
else
RHS = ParseCastExpression(false);
- if (RHS.isInvalid())
+ if (RHS.isInvalid()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
-
+ }
+
// Remember the precedence of this operator and get the precedence of the
// operator immediately to the right of the RHS.
prec::Level ThisPrec = NextTokPrec;
@@ -359,13 +379,14 @@
static_cast<prec::Level>(ThisPrec + !isRightAssoc));
RHSIsInitList = false;
- if (RHS.isInvalid())
+ if (RHS.isInvalid()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
+ }
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
getLangOpts().CPlusPlus11);
}
- assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
if (!RHS.isInvalid() && RHSIsInitList) {
if (ThisPrec == prec::Assignment) {
@@ -397,7 +418,9 @@
LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc,
LHS.get(), TernaryMiddle.get(),
RHS.get());
- }
+ } else
+ // Ensure potential typos in the RHS aren't left undiagnosed.
+ Actions.CorrectDelayedTyposInExpr(RHS);
}
}
@@ -425,7 +448,7 @@
public:
CastExpressionIdValidator(bool AllowTypes, bool AllowNonTypes)
: AllowNonTypes(AllowNonTypes) {
- WantTypeSpecifiers = AllowTypes;
+ WantTypeSpecifiers = WantFunctionLikeCasts = AllowTypes;
}
bool ValidateCandidate(const TypoCorrection &candidate) override {
@@ -688,11 +711,12 @@
ConsumeToken();
break;
+ case tok::kw___super:
case tok::kw_decltype:
// Annotate the token and tail recurse.
if (TryAnnotateTypeOrScopeToken())
return ExprError();
- assert(Tok.isNot(tok::kw_decltype));
+ assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super));
return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
case tok::identifier: { // primary-expression: identifier
@@ -708,11 +732,81 @@
// If this identifier was reverted from a token ID, and the next token
// is a parenthesis, this is likely to be a use of a type trait. Check
// those tokens.
- if (Next.is(tok::l_paren) && Tok.is(tok::identifier) &&
- Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier() &&
- TryIdentKeywordUpgrade())
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
+ if (Next.is(tok::l_paren) &&
+ Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ // Build up the mapping of revertible type traits, for future use.
+ if (RevertibleTypeTraits.empty()) {
+#define RTT_JOIN(X,Y) X##Y
+#define REVERTIBLE_TYPE_TRAIT(Name) \
+ RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] \
+ = RTT_JOIN(tok::kw_,Name)
+
+ REVERTIBLE_TYPE_TRAIT(__is_abstract);
+ REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
+ REVERTIBLE_TYPE_TRAIT(__is_array);
+ REVERTIBLE_TYPE_TRAIT(__is_base_of);
+ REVERTIBLE_TYPE_TRAIT(__is_class);
+ REVERTIBLE_TYPE_TRAIT(__is_complete_type);
+ REVERTIBLE_TYPE_TRAIT(__is_compound);
+ REVERTIBLE_TYPE_TRAIT(__is_const);
+ REVERTIBLE_TYPE_TRAIT(__is_constructible);
+ REVERTIBLE_TYPE_TRAIT(__is_convertible);
+ REVERTIBLE_TYPE_TRAIT(__is_convertible_to);
+ REVERTIBLE_TYPE_TRAIT(__is_destructible);
+ REVERTIBLE_TYPE_TRAIT(__is_empty);
+ REVERTIBLE_TYPE_TRAIT(__is_enum);
+ REVERTIBLE_TYPE_TRAIT(__is_floating_point);
+ REVERTIBLE_TYPE_TRAIT(__is_final);
+ REVERTIBLE_TYPE_TRAIT(__is_function);
+ REVERTIBLE_TYPE_TRAIT(__is_fundamental);
+ REVERTIBLE_TYPE_TRAIT(__is_integral);
+ REVERTIBLE_TYPE_TRAIT(__is_interface_class);
+ REVERTIBLE_TYPE_TRAIT(__is_literal);
+ REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
+ REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
+ REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
+ REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer);
+ REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
+ REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable);
+ REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible);
+ REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible);
+ REVERTIBLE_TYPE_TRAIT(__is_object);
+ REVERTIBLE_TYPE_TRAIT(__is_pod);
+ REVERTIBLE_TYPE_TRAIT(__is_pointer);
+ REVERTIBLE_TYPE_TRAIT(__is_polymorphic);
+ REVERTIBLE_TYPE_TRAIT(__is_reference);
+ REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr);
+ REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference);
+ REVERTIBLE_TYPE_TRAIT(__is_same);
+ REVERTIBLE_TYPE_TRAIT(__is_scalar);
+ REVERTIBLE_TYPE_TRAIT(__is_sealed);
+ REVERTIBLE_TYPE_TRAIT(__is_signed);
+ REVERTIBLE_TYPE_TRAIT(__is_standard_layout);
+ REVERTIBLE_TYPE_TRAIT(__is_trivial);
+ REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable);
+ REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible);
+ REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable);
+ REVERTIBLE_TYPE_TRAIT(__is_union);
+ REVERTIBLE_TYPE_TRAIT(__is_unsigned);
+ REVERTIBLE_TYPE_TRAIT(__is_void);
+ REVERTIBLE_TYPE_TRAIT(__is_volatile);
+#undef REVERTIBLE_TYPE_TRAIT
+#undef RTT_JOIN
+ }
+
+ // If we find that this is in fact the name of a type trait,
+ // update the token kind in place and parse again to treat it as
+ // the appropriate kind of type trait.
+ llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
+ = RevertibleTypeTraits.find(II);
+ if (Known != RevertibleTypeTraits.end()) {
+ Tok.setKind(Known->second);
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, isTypeCast);
+ }
+ }
if (Next.is(tok::coloncolon) ||
(!ColonIsSacred && Next.is(tok::colon)) ||
@@ -812,17 +906,25 @@
UnqualifiedId Name;
CXXScopeSpec ScopeSpec;
SourceLocation TemplateKWLoc;
- CastExpressionIdValidator Validator(isTypeCast != NotTypeCast,
- isTypeCast != IsTypeCast);
- Validator.IsAddressOfOperand = isAddressOfOperand;
+ Token Replacement;
+ auto Validator = llvm::make_unique<CastExpressionIdValidator>(
+ isTypeCast != NotTypeCast, isTypeCast != IsTypeCast);
+ Validator->IsAddressOfOperand = isAddressOfOperand;
Name.setIdentifier(&II, ILoc);
- Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
- Name, Tok.is(tok::l_paren),
- isAddressOfOperand, &Validator);
+ Res = Actions.ActOnIdExpression(
+ getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren),
+ isAddressOfOperand, std::move(Validator),
+ /*IsInlineAsmIdentifier=*/false, &Replacement);
+ if (!Res.isInvalid() && !Res.get()) {
+ UnconsumeToken(Replacement);
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, isTypeCast);
+ }
break;
}
case tok::char_constant: // constant: character-constant
case tok::wide_char_constant:
+ case tok::utf8_char_constant:
case tok::utf16_char_constant:
case tok::utf32_char_constant:
Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope());
@@ -863,7 +965,12 @@
// ++ cast-expression
// -- cast-expression
SourceLocation SavedLoc = ConsumeToken();
- Res = ParseCastExpression(!getLangOpts().CPlusPlus);
+ // One special case is implicitly handled here: if the preceding tokens are
+ // an ambiguous cast expression, such as "(T())++", then we recurse to
+ // determine whether the '++' is prefix or postfix.
+ Res = ParseCastExpression(!getLangOpts().CPlusPlus,
+ /*isAddressOfOperand*/false, NotCastExpr,
+ NotTypeCast);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
return Res;
@@ -1913,11 +2020,15 @@
/// cast-expression: [C99 6.5.4]
/// '(' type-name ')' cast-expression
/// [ARC] bridged-cast-expression
-///
/// [ARC] bridged-cast-expression:
/// (__bridge type-name) cast-expression
/// (__bridge_transfer type-name) cast-expression
/// (__bridge_retained type-name) cast-expression
+/// fold-expression: [C++1z]
+/// '(' cast-expression fold-operator '...' ')'
+/// '(' '...' fold-operator cast-expression ')'
+/// '(' cast-expression fold-operator '...'
+/// fold-operator cast-expression ')'
/// \endverbatim
ExprResult
Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
@@ -2106,24 +2217,36 @@
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
return ExprError();
}
+ } else if (Tok.is(tok::ellipsis) &&
+ isFoldOperator(NextToken().getKind())) {
+ return ParseFoldExpression(ExprResult(), T);
} else if (isTypeCast) {
// Parse the expression-list.
InMessageExpressionRAIIObject InMessage(*this, false);
-
+
ExprVector ArgExprs;
CommaLocsTy CommaLocs;
if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) {
+ // FIXME: If we ever support comma expressions as operands to
+ // fold-expressions, we'll need to allow multiple ArgExprs here.
+ if (ArgExprs.size() == 1 && isFoldOperator(Tok.getKind()) &&
+ NextToken().is(tok::ellipsis))
+ return ParseFoldExpression(Result, T);
+
ExprType = SimpleExpr;
Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
ArgExprs);
}
} else {
InMessageExpressionRAIIObject InMessage(*this, false);
-
+
Result = ParseExpression(MaybeTypeCast);
ExprType = SimpleExpr;
+ if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis))
+ return ParseFoldExpression(Result, T);
+
// Don't build a paren expression unless we actually match a ')'.
if (!Result.isInvalid() && Tok.is(tok::r_paren))
Result =
@@ -2281,6 +2404,59 @@
Types, Exprs);
}
+/// \brief Parse A C++1z fold-expression after the opening paren and optional
+/// left-hand-side expression.
+///
+/// \verbatim
+/// fold-expression:
+/// ( cast-expression fold-operator ... )
+/// ( ... fold-operator cast-expression )
+/// ( cast-expression fold-operator ... fold-operator cast-expression )
+ExprResult Parser::ParseFoldExpression(ExprResult LHS,
+ BalancedDelimiterTracker &T) {
+ if (LHS.isInvalid()) {
+ T.skipToEnd();
+ return true;
+ }
+
+ tok::TokenKind Kind = tok::unknown;
+ SourceLocation FirstOpLoc;
+ if (LHS.isUsable()) {
+ Kind = Tok.getKind();
+ assert(isFoldOperator(Kind) && "missing fold-operator");
+ FirstOpLoc = ConsumeToken();
+ }
+
+ assert(Tok.is(tok::ellipsis) && "not a fold-expression");
+ SourceLocation EllipsisLoc = ConsumeToken();
+
+ ExprResult RHS;
+ if (Tok.isNot(tok::r_paren)) {
+ if (!isFoldOperator(Tok.getKind()))
+ return Diag(Tok.getLocation(), diag::err_expected_fold_operator);
+
+ if (Kind != tok::unknown && Tok.getKind() != Kind)
+ Diag(Tok.getLocation(), diag::err_fold_operator_mismatch)
+ << SourceRange(FirstOpLoc);
+ Kind = Tok.getKind();
+ ConsumeToken();
+
+ RHS = ParseExpression();
+ if (RHS.isInvalid()) {
+ T.skipToEnd();
+ return true;
+ }
+ }
+
+ Diag(EllipsisLoc, getLangOpts().CPlusPlus1z
+ ? diag::warn_cxx14_compat_fold_expression
+ : diag::ext_fold_expression);
+
+ T.consumeClose();
+ return Actions.ActOnCXXFoldExpr(T.getOpenLocation(), LHS.get(), Kind,
+ EllipsisLoc, RHS.get(), T.getCloseLocation());
+}
+
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
///
/// \verbatim
@@ -2309,6 +2485,7 @@
Expr *Data,
ArrayRef<Expr *> Args),
Expr *Data) {
+ bool SawError = false;
while (1) {
if (Tok.is(tok::code_completion)) {
if (Completer)
@@ -2328,13 +2505,15 @@
if (Tok.is(tok::ellipsis))
Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
- if (Expr.isInvalid())
- return true;
-
- Exprs.push_back(Expr.get());
+ if (Expr.isInvalid()) {
+ SkipUntil(tok::comma, tok::r_paren, StopBeforeMatch);
+ SawError = true;
+ } else {
+ Exprs.push_back(Expr.get());
+ }
if (Tok.isNot(tok::comma))
- return false;
+ return SawError;
// Move to the next argument, remember where the comma was.
CommaLocs.push_back(ConsumeToken());
}
@@ -2469,6 +2648,7 @@
/*RefQualifierLoc=*/NoLoc,
/*ConstQualifierLoc=*/NoLoc,
/*VolatileQualifierLoc=*/NoLoc,
+ /*RestrictQualifierLoc=*/NoLoc,
/*MutableLoc=*/NoLoc,
EST_None,
/*ESpecLoc=*/NoLoc,
@@ -2476,6 +2656,7 @@
/*ExceptionRanges=*/nullptr,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
+ /*ExceptionSpecTokens=*/nullptr,
CaretLoc, CaretLoc,
ParamInfo),
attrs, CaretLoc);
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 3d1925c..613246e 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -218,7 +218,7 @@
return false;
// '::' - Global scope qualifier.
- if (Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), ConsumeToken(), SS))
+ if (Actions.ActOnCXXGlobalScopeSpecifier(ConsumeToken(), SS))
return true;
CheckForLParenAfterColonColon();
@@ -226,13 +226,24 @@
HasScopeSpecifier = true;
}
+ if (Tok.is(tok::kw___super)) {
+ SourceLocation SuperLoc = ConsumeToken();
+ if (!Tok.is(tok::coloncolon)) {
+ Diag(Tok.getLocation(), diag::err_expected_coloncolon_after_super);
+ return true;
+ }
+
+ return Actions.ActOnSuperScopeSpecifier(SuperLoc, ConsumeToken(), SS);
+ }
+
bool CheckForDestructor = false;
if (MayBePseudoDestructor && *MayBePseudoDestructor) {
CheckForDestructor = true;
*MayBePseudoDestructor = false;
}
- if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) {
+ if (!HasScopeSpecifier &&
+ (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype))) {
DeclSpec DS(AttrFactory);
SourceLocation DeclLoc = Tok.getLocation();
SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
@@ -426,8 +437,8 @@
if (Next.is(tok::coloncolon)) {
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) &&
- !Actions.isNonTypeNestedNameSpecifier(getCurScope(), SS, Tok.getLocation(),
- II, ObjectType)) {
+ !Actions.isNonTypeNestedNameSpecifier(
+ getCurScope(), SS, Tok.getLocation(), II, ObjectType)) {
*MayBePseudoDestructor = true;
return false;
}
@@ -556,6 +567,28 @@
return false;
}
+ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand,
+ Token &Replacement) {
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId Name;
+ if (ParseUnqualifiedId(SS,
+ /*EnteringContext=*/false,
+ /*AllowDestructorName=*/false,
+ /*AllowConstructorName=*/false,
+ /*ObjectType=*/ParsedType(), TemplateKWLoc, Name))
+ return ExprError();
+
+ // This is only the direct operand of an & operator if it is not
+ // followed by a postfix-expression suffix.
+ if (isAddressOfOperand && isPostfixExpressionSuffixStart())
+ isAddressOfOperand = false;
+
+ return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name,
+ Tok.is(tok::l_paren), isAddressOfOperand,
+ nullptr, /*IsInlineAsmIdentifier=*/false,
+ &Replacement);
+}
+
/// ParseCXXIdExpression - Handle id-expression.
///
/// id-expression:
@@ -606,24 +639,17 @@
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
- SourceLocation TemplateKWLoc;
- UnqualifiedId Name;
- if (ParseUnqualifiedId(SS,
- /*EnteringContext=*/false,
- /*AllowDestructorName=*/false,
- /*AllowConstructorName=*/false,
- /*ObjectType=*/ ParsedType(),
- TemplateKWLoc,
- Name))
- return ExprError();
-
- // This is only the direct operand of an & operator if it is not
- // followed by a postfix-expression suffix.
- if (isAddressOfOperand && isPostfixExpressionSuffixStart())
- isAddressOfOperand = false;
-
- return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name,
- Tok.is(tok::l_paren), isAddressOfOperand);
+ Token Replacement;
+ ExprResult Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
+ if (Result.isUnset()) {
+ // If the ExprResult is valid but null, then typo correction suggested a
+ // keyword replacement that needs to be reparsed.
+ UnconsumeToken(Replacement);
+ Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
+ }
+ assert(!Result.isUnset() && "Typo correction suggested a keyword replacement "
+ "for a previous keyword suggestion");
+ return Result;
}
/// ParseLambdaExpression - Parse a C++11 lambda expression.
@@ -1050,10 +1076,13 @@
SmallVector<ParsedType, 2> DynamicExceptions;
SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
- ESpecType = tryParseExceptionSpecification(ESpecRange,
+ CachedTokens *ExceptionSpecTokens;
+ ESpecType = tryParseExceptionSpecification(/*Delayed=*/false,
+ ESpecRange,
DynamicExceptions,
DynamicExceptionRanges,
- NoexceptExpr);
+ NoexceptExpr,
+ ExceptionSpecTokens);
if (ESpecType != EST_None)
DeclEndLoc = ESpecRange.getEnd();
@@ -1086,6 +1115,7 @@
/*RefQualifierLoc=*/NoLoc,
/*ConstQualifierLoc=*/NoLoc,
/*VolatileQualifierLoc=*/NoLoc,
+ /*RestrictQualifierLoc=*/NoLoc,
MutableLoc,
ESpecType, ESpecRange.getBegin(),
DynamicExceptions.data(),
@@ -1093,6 +1123,7 @@
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : nullptr,
+ /*ExceptionSpecTokens*/nullptr,
LParenLoc, FunLocalRangeEnd, D,
TrailingReturnType),
Attr, DeclEndLoc);
@@ -1153,6 +1184,7 @@
/*RefQualifierLoc=*/NoLoc,
/*ConstQualifierLoc=*/NoLoc,
/*VolatileQualifierLoc=*/NoLoc,
+ /*RestrictQualifierLoc=*/NoLoc,
MutableLoc,
EST_None,
/*ESpecLoc=*/NoLoc,
@@ -1160,6 +1192,7 @@
/*ExceptionRanges=*/nullptr,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
+ /*ExceptionSpecTokens=*/nullptr,
DeclLoc, DeclEndLoc, D,
TrailingReturnType),
Attr, DeclEndLoc);
@@ -1389,7 +1422,7 @@
/// ::[opt] nested-name-specifier[opt] ~type-name
///
ExprResult
-Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
+Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
tok::TokenKind OpKind,
CXXScopeSpec &SS,
ParsedType ObjectType) {
@@ -2452,10 +2485,29 @@
return true;
}
+ // If the user wrote ~T::T, correct it to T::~T.
+ if (!TemplateSpecified && NextToken().is(tok::coloncolon)) {
+ if (SS.isSet()) {
+ AnnotateScopeToken(SS, /*NewAnnotation*/true);
+ SS.clear();
+ }
+ if (ParseOptionalCXXScopeSpecifier(SS, ObjectType, EnteringContext))
+ return true;
+ if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon)) {
+ Diag(TildeLoc, diag::err_destructor_tilde_scope);
+ return true;
+ }
+
+ // Recover as if the tilde had been written before the identifier.
+ Diag(TildeLoc, diag::err_destructor_tilde_scope)
+ << FixItHint::CreateRemoval(TildeLoc)
+ << FixItHint::CreateInsertion(Tok.getLocation(), "~");
+ }
+
// Parse the class-name (or template-name in a simple-template-id).
IdentifierInfo *ClassName = Tok.getIdentifierInfo();
SourceLocation ClassNameLoc = ConsumeToken();
-
+
if (TemplateSpecified || Tok.is(tok::less)) {
Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc);
return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc,
@@ -2463,7 +2515,7 @@
EnteringContext, ObjectType,
Result, TemplateSpecified);
}
-
+
// Note that this is a destructor name.
ParsedType Ty = Actions.getDestructorName(TildeLoc, *ClassName,
ClassNameLoc, getCurScope(),
@@ -2952,7 +3004,6 @@
ParseAs = CompoundLiteral;
} else {
bool NotCastExpr;
- // FIXME: Special-case ++ and --: "(S())++;" is not a cast-expression
if (Tok.is(tok::l_paren) && NextToken().is(tok::r_paren)) {
NotCastExpr = true;
} else {
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 7fe72ec..0d0f110 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -307,72 +307,6 @@
return ClsType;
}
-/// 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), LParenLoc(LParenLoc),
- MethodImplKind(MethodImplKind) {
- }
-
- void invoke(ParsingFieldDeclarator &FD) override {
- if (FD.D.getIdentifier() == nullptr) {
- P.Diag(AtLoc, diag::err_objc_property_requires_field_name)
- << FD.D.getSourceRange();
- return;
- }
- if (FD.BitfieldSize) {
- P.Diag(AtLoc, diag::err_objc_property_bitfield)
- << FD.D.getSourceRange();
- return;
- }
-
- // Install the property declarator into interfaceDecl.
- IdentifierInfo *SelName =
- OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
-
- Selector GetterSel =
- P.PP.getSelectorTable().getNullarySelector(SelName);
- IdentifierInfo *SetterName = OCDS.getSetterName();
- Selector SetterSel;
- if (SetterName)
- SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName);
- else
- SetterSel =
- SelectorTable::constructSetterSelector(P.PP.getIdentifierTable(),
- P.PP.getSelectorTable(),
- FD.D.getIdentifier());
- bool isOverridingProperty = false;
- Decl *Property =
- P.Actions.ActOnProperty(P.getCurScope(), AtLoc, LParenLoc,
- FD, OCDS,
- GetterSel, SetterSel,
- &isOverridingProperty,
- MethodImplKind);
- if (!isOverridingProperty)
- Props.push_back(Property);
-
- FD.complete(Property);
- }
-};
-
-void Parser::ObjCPropertyCallback::anchor() {
-}
-
/// objc-interface-decl-list:
/// empty
/// objc-interface-decl-list objc-property-decl [OBJC2]
@@ -511,12 +445,44 @@
ParseObjCPropertyAttribute(OCDS);
}
- ObjCPropertyCallback Callback(*this, allProperties,
- OCDS, AtLoc, LParenLoc, MethodImplKind);
+ auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
+ if (FD.D.getIdentifier() == nullptr) {
+ Diag(AtLoc, diag::err_objc_property_requires_field_name)
+ << FD.D.getSourceRange();
+ return;
+ }
+ if (FD.BitfieldSize) {
+ Diag(AtLoc, diag::err_objc_property_bitfield)
+ << FD.D.getSourceRange();
+ return;
+ }
+
+ // Install the property declarator into interfaceDecl.
+ IdentifierInfo *SelName =
+ OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
+
+ Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName);
+ IdentifierInfo *SetterName = OCDS.getSetterName();
+ Selector SetterSel;
+ if (SetterName)
+ SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
+ else
+ SetterSel = SelectorTable::constructSetterSelector(
+ PP.getIdentifierTable(), PP.getSelectorTable(),
+ FD.D.getIdentifier());
+ bool isOverridingProperty = false;
+ Decl *Property = Actions.ActOnProperty(
+ getCurScope(), AtLoc, LParenLoc, FD, OCDS, GetterSel, SetterSel,
+ &isOverridingProperty, MethodImplKind);
+ if (!isOverridingProperty)
+ allProperties.push_back(Property);
+
+ FD.complete(Property);
+ };
// Parse all the comma separated declarators.
ParsingDeclSpec DS(*this);
- ParseStructDeclaration(DS, Callback);
+ ParseStructDeclaration(DS, ObjCPropertyCallback);
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
break;
@@ -1338,35 +1304,22 @@
Sema::PCC_ObjCInstanceVariableList);
return cutOffParsing();
}
-
- struct ObjCIvarCallback : FieldCallback {
- Parser &P;
- Decl *IDecl;
- tok::ObjCKeywordKind visibility;
- SmallVectorImpl<Decl *> &AllIvarDecls;
- ObjCIvarCallback(Parser &P, Decl *IDecl, tok::ObjCKeywordKind V,
- SmallVectorImpl<Decl *> &AllIvarDecls) :
- P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) {
- }
+ auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
+ Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
+ // Install the declarator into the interface decl.
+ Decl *Field = Actions.ActOnIvar(
+ getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,
+ FD.BitfieldSize, visibility);
+ Actions.ActOnObjCContainerFinishDefinition();
+ if (Field)
+ AllIvarDecls.push_back(Field);
+ FD.complete(Field);
+ };
- void invoke(ParsingFieldDeclarator &FD) override {
- P.Actions.ActOnObjCContainerStartDefinition(IDecl);
- // Install the declarator into the interface decl.
- Decl *Field
- = P.Actions.ActOnIvar(P.getCurScope(),
- FD.D.getDeclSpec().getSourceRange().getBegin(),
- FD.D, FD.BitfieldSize, visibility);
- P.Actions.ActOnObjCContainerFinishDefinition();
- if (Field)
- AllIvarDecls.push_back(Field);
- FD.complete(Field);
- }
- } Callback(*this, interfaceDecl, visibility, AllIvarDecls);
-
// Parse all the comma separated declarators.
ParsingDeclSpec DS(*this);
- ParseStructDeclaration(DS, Callback);
+ ParseStructDeclaration(DS, ObjCIvarCallback);
if (Tok.is(tok::semi)) {
ConsumeToken();
@@ -2217,7 +2170,10 @@
if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
// objc-receiver:
// expression
- ExprResult Receiver = ParseExpression();
+ // Make sure any typos in the receiver are corrected or diagnosed, so that
+ // proper recovery can happen. FIXME: Perhaps filter the corrected expr to
+ // only the things that are valid ObjC receivers?
+ ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (Receiver.isInvalid())
return true;
@@ -2446,7 +2402,7 @@
Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SourceLocation SuperLoc,
ParsedType ReceiverType,
- ExprArg ReceiverExpr) {
+ Expr *ReceiverExpr) {
InMessageExpressionRAIIObject InMessage(*this, true);
if (Tok.is(tok::code_completion)) {
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index b3a1063..7851c40 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -26,23 +26,31 @@
//===----------------------------------------------------------------------===//
static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
+ // Array of foldings: F[i][0] F[i][1] ===> F[i][2].
+ // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd
+ // TODO: add other combined directives in topological order.
+ const OpenMPDirectiveKind F[][3] = {
+ { OMPD_for, OMPD_simd, OMPD_for_simd },
+ { OMPD_parallel, OMPD_for, OMPD_parallel_for },
+ { OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd },
+ { OMPD_parallel, OMPD_sections, OMPD_parallel_sections }
+ };
auto Tok = P.getCurToken();
auto DKind =
Tok.isAnnotation()
? OMPD_unknown
: getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
- if (DKind == OMPD_parallel) {
- Tok = P.getPreprocessor().LookAhead(0);
- auto SDKind =
- Tok.isAnnotation()
- ? OMPD_unknown
- : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
- if (SDKind == OMPD_for) {
- P.ConsumeToken();
- DKind = OMPD_parallel_for;
- } else if (SDKind == OMPD_sections) {
- P.ConsumeToken();
- DKind = OMPD_parallel_sections;
+ for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) {
+ if (DKind == F[i][0]) {
+ Tok = P.getPreprocessor().LookAhead(0);
+ auto SDKind =
+ Tok.isAnnotation()
+ ? OMPD_unknown
+ : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
+ if (SDKind == F[i][1]) {
+ P.ConsumeToken();
+ DKind = F[i][2];
+ }
}
}
return DKind;
@@ -83,12 +91,24 @@
case OMPD_parallel:
case OMPD_simd:
case OMPD_task:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_flush:
case OMPD_for:
+ case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
+ case OMPD_master:
+ case OMPD_ordered:
+ case OMPD_critical:
case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
+ case OMPD_atomic:
+ case OMPD_target:
+ case OMPD_teams:
Diag(Tok, diag::err_omp_unexpected_directive)
<< getOpenMPDirectiveName(DKind);
break;
@@ -105,10 +125,14 @@
///
/// executable-directive:
/// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
-/// 'section' | 'single' | 'parallel for' | 'parallel sections' {clause}
+/// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
+/// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' |
+/// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' |
+/// 'for simd' | 'parallel for simd' | 'target' | 'teams' {clause}
/// annot_pragma_openmp_end
///
-StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
+StmtResult
+Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SmallVector<Expr *, 5> Identifiers;
@@ -122,6 +146,8 @@
// Name of critical directive.
DeclarationNameInfo DirName;
StmtResult Directive = StmtError();
+ bool HasAssociatedStatement = true;
+ bool FlushHasClause = false;
switch (DKind) {
case OMPD_threadprivate:
@@ -140,15 +166,55 @@
}
SkipUntil(tok::annot_pragma_openmp_end);
break;
+ case OMPD_flush:
+ if (PP.LookAhead(0).is(tok::l_paren)) {
+ FlushHasClause = true;
+ // Push copy of the current token back to stream to properly parse
+ // pseudo-clause OMPFlushClause.
+ PP.EnterToken(Tok);
+ }
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ if (!StandAloneAllowed) {
+ Diag(Tok, diag::err_omp_immediate_directive)
+ << getOpenMPDirectiveName(DKind);
+ }
+ HasAssociatedStatement = false;
+ // Fall through for further analysis.
case OMPD_parallel:
case OMPD_simd:
case OMPD_for:
+ case OMPD_for_simd:
case OMPD_sections:
case OMPD_single:
case OMPD_section:
+ case OMPD_master:
+ case OMPD_critical:
case OMPD_parallel_for:
- case OMPD_parallel_sections: {
+ case OMPD_parallel_for_simd:
+ case OMPD_parallel_sections:
+ case OMPD_task:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_target:
+ case OMPD_teams: {
ConsumeToken();
+ // Parse directive name of the 'critical' directive if any.
+ if (DKind == OMPD_critical) {
+ BalancedDelimiterTracker T(*this, tok::l_paren,
+ tok::annot_pragma_openmp_end);
+ if (!T.consumeOpen()) {
+ if (Tok.isAnyIdentifier()) {
+ DirName =
+ DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation());
+ ConsumeAnyToken();
+ } else {
+ Diag(Tok, diag::err_omp_expected_identifier_for_critical);
+ }
+ T.consumeClose();
+ }
+ }
if (isOpenMPLoopDirective(DKind))
ScopeFlags |= Scope::OpenMPLoopDirectiveScope;
@@ -158,9 +224,12 @@
Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc);
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
- OpenMPClauseKind CKind = Tok.isAnnotation()
- ? OMPC_unknown
- : getOpenMPClauseKind(PP.getSpelling(Tok));
+ OpenMPClauseKind CKind =
+ Tok.isAnnotation()
+ ? OMPC_unknown
+ : FlushHasClause ? OMPC_flush
+ : getOpenMPClauseKind(PP.getSpelling(Tok));
+ FlushHasClause = false;
OMPClause *Clause =
ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt());
FirstClauses[CKind].setInt(true);
@@ -180,7 +249,7 @@
StmtResult AssociatedStmt;
bool CreateDirective = true;
- {
+ if (HasAssociatedStatement) {
// The body is a block scope like in Lambdas and Blocks.
Sema::CompoundScopeRAII CompoundScope(Actions);
Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
@@ -198,7 +267,7 @@
}
if (CreateDirective)
Directive = Actions.ActOnOpenMPExecutableDirective(
- DKind, Clauses, AssociatedStmt.get(), Loc, EndLoc);
+ DKind, DirName, Clauses, AssociatedStmt.get(), Loc, EndLoc);
// Exit scope.
Actions.EndOpenMPDSABlock(Directive.get());
@@ -209,11 +278,6 @@
Diag(Tok, diag::err_omp_unknown_directive);
SkipUntil(tok::annot_pragma_openmp_end);
break;
- case OMPD_task:
- Diag(Tok, diag::err_omp_unexpected_directive)
- << getOpenMPDirectiveName(DKind);
- SkipUntil(tok::annot_pragma_openmp_end);
- break;
}
return Directive;
}
@@ -290,11 +354,13 @@
/// \brief Parsing of OpenMP clauses.
///
/// clause:
-/// if-clause | num_threads-clause | safelen-clause | default-clause |
-/// private-clause | firstprivate-clause | shared-clause | linear-clause |
-/// aligned-clause | collapse-clause | lastprivate-clause |
-/// reduction-clause | proc_bind-clause | schedule-clause |
-/// copyin-clause | copyprivate-clause
+/// if-clause | final-clause | num_threads-clause | safelen-clause |
+/// default-clause | private-clause | firstprivate-clause | shared-clause
+/// | linear-clause | aligned-clause | collapse-clause |
+/// lastprivate-clause | reduction-clause | proc_bind-clause |
+/// schedule-clause | copyin-clause | copyprivate-clause | untied-clause |
+/// mergeable-clause | flush-clause | read-clause | write-clause |
+/// update-clause | capture-clause | seq_cst-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -309,6 +375,7 @@
switch (CKind) {
case OMPC_if:
+ case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_collapse:
@@ -318,9 +385,13 @@
// OpenMP [2.8.1, simd construct, Restrictions]
// Only one safelen clause can appear on a simd directive.
// Only one collapse clause can appear on a simd directive.
+ // OpenMP [2.11.1, task Construct, Restrictions]
+ // At most one if clause can appear on the directive.
+ // At most one final clause can appear on the directive.
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(CKind);
+ ErrorFound = true;
}
Clause = ParseOpenMPSingleExprClause(CKind);
@@ -335,6 +406,7 @@
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(CKind);
+ ErrorFound = true;
}
Clause = ParseOpenMPSimpleClause(CKind);
@@ -345,12 +417,20 @@
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(CKind);
+ ErrorFound = true;
}
Clause = ParseOpenMPSingleExprWithArgClause(CKind);
break;
case OMPC_ordered:
case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
// OpenMP [2.7.1, Restrictions, p. 9]
// Only one ordered clause can appear on a loop directive.
// OpenMP [2.7.1, Restrictions, C/C++, p. 4]
@@ -358,6 +438,7 @@
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(CKind);
+ ErrorFound = true;
}
Clause = ParseOpenMPClause(CKind);
@@ -371,6 +452,7 @@
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
+ case OMPC_flush:
Clause = ParseOpenMPVarListClause(CKind);
break;
case OMPC_unknown:
@@ -388,12 +470,15 @@
}
/// \brief Parsing of OpenMP clauses with single expressions like 'if',
-/// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams' or
+/// 'final', 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams' or
/// 'thread_limit'.
///
/// if-clause:
/// 'if' '(' expression ')'
///
+/// final-clause:
+/// 'final' '(' expression ')'
+///
/// num_threads-clause:
/// 'num_threads' '(' expression ')'
///
@@ -463,6 +548,15 @@
/// nowait-clause:
/// 'nowait'
///
+/// untied-clause:
+/// 'untied'
+///
+/// mergeable-clause:
+/// 'mergeable'
+///
+/// read-clause:
+/// 'read'
+///
OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
ConsumeAnyToken();
@@ -560,7 +654,7 @@
}
/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
-/// 'shared', 'copyin', or 'reduction'.
+/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'.
///
/// private-clause:
/// 'private' '(' list ')'
@@ -576,6 +670,10 @@
/// 'aligned' '(' list [ ':' alignment ] ')'
/// reduction-clause:
/// 'reduction' '(' reduction-identifier ':' list ')'
+/// copyprivate-clause:
+/// 'copyprivate' '(' list ')'
+/// flush-clause:
+/// 'flush' '(' list ')'
///
OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
@@ -631,7 +729,10 @@
else if (Tok.isNot(tok::r_paren) &&
Tok.isNot(tok::annot_pragma_openmp_end) &&
(!MayHaveTail || Tok.isNot(tok::colon)))
- Diag(Tok, diag::err_omp_expected_punc) << getOpenMPClauseName(Kind);
+ Diag(Tok, diag::err_omp_expected_punc)
+ << ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush)
+ : getOpenMPClauseName(Kind))
+ << (Kind == OMPC_flush);
}
// Parse ':' linear-step (or ':' alignment).
@@ -640,7 +741,8 @@
if (MustHaveTail) {
ColonLoc = Tok.getLocation();
ConsumeToken();
- ExprResult Tail = ParseAssignmentExpression();
+ ExprResult Tail =
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (Tail.isUsable())
TailExpr = Tail.get();
else
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 2b248cc..473be54 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -12,6 +12,8 @@
//===----------------------------------------------------------------------===//
#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
@@ -148,6 +150,12 @@
Token &FirstToken) override;
};
+struct PragmaUnrollHintHandler : public PragmaHandler {
+ PragmaUnrollHintHandler(const char *name) : PragmaHandler(name) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
} // end namespace
void Parser::initializePragmaHandlers() {
@@ -218,6 +226,12 @@
LoopHintHandler.reset(new PragmaLoopHintHandler());
PP.AddPragmaHandler("clang", LoopHintHandler.get());
+
+ UnrollHintHandler.reset(new PragmaUnrollHintHandler("unroll"));
+ PP.AddPragmaHandler(UnrollHintHandler.get());
+
+ NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
+ PP.AddPragmaHandler(NoUnrollHintHandler.get());
}
void Parser::resetPragmaHandlers() {
@@ -278,6 +292,12 @@
PP.RemovePragmaHandler("clang", LoopHintHandler.get());
LoopHintHandler.reset();
+
+ PP.RemovePragmaHandler(UnrollHintHandler.get());
+ UnrollHintHandler.reset();
+
+ PP.RemovePragmaHandler(NoUnrollHintHandler.get());
+ NoUnrollHintHandler.reset();
}
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -467,11 +487,12 @@
PP.EnterTokenStream(TheTokens->first, TheTokens->second, true, true);
SourceLocation PragmaLocation = ConsumeToken(); // The annotation token.
assert(Tok.isAnyIdentifier());
- llvm::StringRef PragmaName = Tok.getIdentifierInfo()->getName();
+ StringRef PragmaName = Tok.getIdentifierInfo()->getName();
PP.Lex(Tok); // pragma kind
+
// Figure out which #pragma we're dealing with. The switch has no default
// because lex shouldn't emit the annotation token for unrecognized pragmas.
- typedef unsigned (Parser::*PragmaHandler)(llvm::StringRef, SourceLocation);
+ typedef bool (Parser::*PragmaHandler)(StringRef, SourceLocation);
PragmaHandler Handler = llvm::StringSwitch<PragmaHandler>(PragmaName)
.Case("data_seg", &Parser::HandlePragmaMSSegment)
.Case("bss_seg", &Parser::HandlePragmaMSSegment)
@@ -479,79 +500,118 @@
.Case("code_seg", &Parser::HandlePragmaMSSegment)
.Case("section", &Parser::HandlePragmaMSSection)
.Case("init_seg", &Parser::HandlePragmaMSInitSeg);
- if (auto DiagID = (this->*Handler)(PragmaName, PragmaLocation)) {
- PP.Diag(PragmaLocation, DiagID) << PragmaName;
+
+ if (!(this->*Handler)(PragmaName, PragmaLocation)) {
+ // Pragma handling failed, and has been diagnosed. Slurp up the tokens
+ // until eof (really end of line) to prevent follow-on errors.
while (Tok.isNot(tok::eof))
PP.Lex(Tok);
PP.Lex(Tok);
}
}
-unsigned Parser::HandlePragmaMSSection(llvm::StringRef PragmaName,
- SourceLocation PragmaLocation) {
- if (Tok.isNot(tok::l_paren))
- return diag::warn_pragma_expected_lparen;
+bool Parser::HandlePragmaMSSection(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // (
// Parsing code for pragma section
- if (Tok.isNot(tok::string_literal))
- return diag::warn_pragma_expected_section_name;
- StringLiteral *SegmentName =
- cast<StringLiteral>(ParseStringLiteralExpression().get());
- int SectionFlags = 0;
+ if (Tok.isNot(tok::string_literal)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_section_name)
+ << PragmaName;
+ return false;
+ }
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return false; // Already diagnosed.
+ StringLiteral *SegmentName = cast<StringLiteral>(StringResult.get());
+ if (SegmentName->getCharByteWidth() != 1) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
+ << PragmaName;
+ return false;
+ }
+ int SectionFlags = ASTContext::PSF_Read;
+ bool SectionFlagsAreDefault = true;
while (Tok.is(tok::comma)) {
PP.Lex(Tok); // ,
- if (!Tok.isAnyIdentifier())
- return diag::warn_pragma_expected_action_or_r_paren;
- Sema::PragmaSectionFlag Flag =
- llvm::StringSwitch<Sema::PragmaSectionFlag>(
+ // Ignore "long" and "short".
+ // They are undocumented, but widely used, section attributes which appear
+ // to do nothing.
+ if (Tok.is(tok::kw_long) || Tok.is(tok::kw_short)) {
+ PP.Lex(Tok); // long/short
+ continue;
+ }
+
+ if (!Tok.isAnyIdentifier()) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_action_or_r_paren)
+ << PragmaName;
+ return false;
+ }
+ ASTContext::PragmaSectionFlag Flag =
+ llvm::StringSwitch<ASTContext::PragmaSectionFlag>(
Tok.getIdentifierInfo()->getName())
- .Case("read", Sema::PSF_Read)
- .Case("write", Sema::PSF_Write)
- .Case("execute", Sema::PSF_Execute)
- .Case("shared", Sema::PSF_Invalid)
- .Case("nopage", Sema::PSF_Invalid)
- .Case("nocache", Sema::PSF_Invalid)
- .Case("discard", Sema::PSF_Invalid)
- .Case("remove", Sema::PSF_Invalid)
- .Default(Sema::PSF_None);
- if (Flag == Sema::PSF_None || Flag == Sema::PSF_Invalid) {
- PP.Diag(PragmaLocation, Flag == Sema::PSF_None ?
- diag::warn_pragma_invalid_specific_action :
- diag::warn_pragma_unsupported_action)
+ .Case("read", ASTContext::PSF_Read)
+ .Case("write", ASTContext::PSF_Write)
+ .Case("execute", ASTContext::PSF_Execute)
+ .Case("shared", ASTContext::PSF_Invalid)
+ .Case("nopage", ASTContext::PSF_Invalid)
+ .Case("nocache", ASTContext::PSF_Invalid)
+ .Case("discard", ASTContext::PSF_Invalid)
+ .Case("remove", ASTContext::PSF_Invalid)
+ .Default(ASTContext::PSF_None);
+ if (Flag == ASTContext::PSF_None || Flag == ASTContext::PSF_Invalid) {
+ PP.Diag(PragmaLocation, Flag == ASTContext::PSF_None
+ ? diag::warn_pragma_invalid_specific_action
+ : diag::warn_pragma_unsupported_action)
<< PragmaName << Tok.getIdentifierInfo()->getName();
- while (Tok.isNot(tok::eof))
- PP.Lex(Tok);
- PP.Lex(Tok);
- return 0;
+ return false;
}
SectionFlags |= Flag;
+ SectionFlagsAreDefault = false;
PP.Lex(Tok); // Identifier
}
- if (Tok.isNot(tok::r_paren))
- return diag::warn_pragma_expected_rparen;
+ // If no section attributes are specified, the section will be marked as
+ // read/write.
+ if (SectionFlagsAreDefault)
+ SectionFlags |= ASTContext::PSF_Write;
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // )
- if (Tok.isNot(tok::eof))
- return diag::warn_pragma_extra_tokens_at_eol;
+ if (Tok.isNot(tok::eof)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // eof
Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName);
- return 0;
+ return true;
}
-unsigned Parser::HandlePragmaMSSegment(llvm::StringRef PragmaName,
- SourceLocation PragmaLocation) {
- if (Tok.isNot(tok::l_paren))
- return diag::warn_pragma_expected_lparen;
+bool Parser::HandlePragmaMSSegment(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // (
Sema::PragmaMsStackAction Action = Sema::PSK_Reset;
- llvm::StringRef SlotLabel;
+ StringRef SlotLabel;
if (Tok.isAnyIdentifier()) {
- llvm::StringRef PushPop = Tok.getIdentifierInfo()->getName();
+ StringRef PushPop = Tok.getIdentifierInfo()->getName();
if (PushPop == "push")
Action = Sema::PSK_Push;
else if (PushPop == "pop")
Action = Sema::PSK_Pop;
- else
- return diag::warn_pragma_expected_section_push_pop_or_name;
+ else {
+ PP.Diag(PragmaLocation,
+ diag::warn_pragma_expected_section_push_pop_or_name)
+ << PragmaName;
+ return false;
+ }
if (Action != Sema::PSK_Reset) {
PP.Lex(Tok); // push | pop
if (Tok.is(tok::comma)) {
@@ -562,75 +622,241 @@
PP.Lex(Tok); // identifier
if (Tok.is(tok::comma))
PP.Lex(Tok);
- else if (Tok.isNot(tok::r_paren))
- return diag::warn_pragma_expected_punc;
+ else if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc)
+ << PragmaName;
+ return false;
+ }
}
- } else if (Tok.isNot(tok::r_paren))
- return diag::warn_pragma_expected_punc;
+ } else if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc) << PragmaName;
+ return false;
+ }
}
}
// Grab the string literal for our section name.
StringLiteral *SegmentName = nullptr;
if (Tok.isNot(tok::r_paren)) {
- if (Tok.isNot(tok::string_literal))
- return Action != Sema::PSK_Reset ? !SlotLabel.empty() ?
+ if (Tok.isNot(tok::string_literal)) {
+ unsigned DiagID = Action != Sema::PSK_Reset ? !SlotLabel.empty() ?
diag::warn_pragma_expected_section_name :
diag::warn_pragma_expected_section_label_or_name :
diag::warn_pragma_expected_section_push_pop_or_name;
- SegmentName = cast<StringLiteral>(ParseStringLiteralExpression().get());
+ PP.Diag(PragmaLocation, DiagID) << PragmaName;
+ return false;
+ }
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return false; // Already diagnosed.
+ SegmentName = cast<StringLiteral>(StringResult.get());
+ if (SegmentName->getCharByteWidth() != 1) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
+ << PragmaName;
+ return false;
+ }
// Setting section "" has no effect
if (SegmentName->getLength())
Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set);
}
- if (Tok.isNot(tok::r_paren))
- return diag::warn_pragma_expected_rparen;
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // )
- if (Tok.isNot(tok::eof))
- return diag::warn_pragma_extra_tokens_at_eol;
+ if (Tok.isNot(tok::eof)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // eof
Actions.ActOnPragmaMSSeg(PragmaLocation, Action, SlotLabel,
SegmentName, PragmaName);
- return 0;
+ return true;
}
-unsigned Parser::HandlePragmaMSInitSeg(llvm::StringRef PragmaName,
- SourceLocation PragmaLocation) {
- return PP.getDiagnostics().getCustomDiagID(
- DiagnosticsEngine::Error, "'#pragma %0' not implemented.");
+// #pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} )
+bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (getTargetInfo().getTriple().getEnvironment() != llvm::Triple::MSVC) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_init_seg_unsupported_target);
+ return false;
+ }
+
+ if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen,
+ PragmaName))
+ return false;
+
+ // Parse either the known section names or the string section name.
+ StringLiteral *SegmentName = nullptr;
+ if (Tok.isAnyIdentifier()) {
+ auto *II = Tok.getIdentifierInfo();
+ StringRef Section = llvm::StringSwitch<StringRef>(II->getName())
+ .Case("compiler", "\".CRT$XCC\"")
+ .Case("lib", "\".CRT$XCL\"")
+ .Case("user", "\".CRT$XCU\"")
+ .Default("");
+
+ if (!Section.empty()) {
+ // Pretend the user wrote the appropriate string literal here.
+ Token Toks[1];
+ Toks[0].startToken();
+ Toks[0].setKind(tok::string_literal);
+ Toks[0].setLocation(Tok.getLocation());
+ Toks[0].setLiteralData(Section.data());
+ Toks[0].setLength(Section.size());
+ SegmentName =
+ cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get());
+ PP.Lex(Tok);
+ }
+ } else if (Tok.is(tok::string_literal)) {
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return false;
+ SegmentName = cast<StringLiteral>(StringResult.get());
+ if (SegmentName->getCharByteWidth() != 1) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
+ << PragmaName;
+ return false;
+ }
+ // FIXME: Add support for the '[, func-name]' part of the pragma.
+ }
+
+ if (!SegmentName) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_init_seg) << PragmaName;
+ return false;
+ }
+
+ if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen,
+ PragmaName) ||
+ ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol,
+ PragmaName))
+ return false;
+
+ Actions.ActOnPragmaMSInitSeg(PragmaLocation, SegmentName);
+ return true;
}
struct PragmaLoopHintInfo {
- Token Loop;
- Token Value;
+ Token PragmaName;
Token Option;
+ Token *Toks;
+ size_t TokSize;
+ PragmaLoopHintInfo() : Toks(nullptr), TokSize(0) {}
};
-LoopHint Parser::HandlePragmaLoopHint() {
+static std::string PragmaLoopHintString(Token PragmaName, Token Option) {
+ std::string PragmaString;
+ if (PragmaName.getIdentifierInfo()->getName() == "loop") {
+ PragmaString = "clang loop ";
+ PragmaString += Option.getIdentifierInfo()->getName();
+ } else {
+ assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
+ "Unexpected pragma name");
+ PragmaString = "unroll";
+ }
+ return PragmaString;
+}
+
+bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
assert(Tok.is(tok::annot_pragma_loop_hint));
PragmaLoopHintInfo *Info =
static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
- LoopHint Hint;
- Hint.LoopLoc =
- IdentifierLoc::create(Actions.Context, Info->Loop.getLocation(),
- Info->Loop.getIdentifierInfo());
- Hint.OptionLoc =
- IdentifierLoc::create(Actions.Context, Info->Option.getLocation(),
- Info->Option.getIdentifierInfo());
- Hint.ValueLoc =
- IdentifierLoc::create(Actions.Context, Info->Value.getLocation(),
- Info->Value.getIdentifierInfo());
- Hint.Range =
- SourceRange(Info->Option.getLocation(), Info->Value.getLocation());
+ IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo();
+ Hint.PragmaNameLoc = IdentifierLoc::create(
+ Actions.Context, Info->PragmaName.getLocation(), PragmaNameInfo);
- // FIXME: We should allow non-type template parameters for the loop hint
- // value. See bug report #19610
- if (Info->Value.is(tok::numeric_constant))
- Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
- else
- Hint.ValueExpr = nullptr;
+ // It is possible that the loop hint has no option identifier, such as
+ // #pragma unroll(4).
+ IdentifierInfo *OptionInfo = Info->Option.is(tok::identifier)
+ ? Info->Option.getIdentifierInfo()
+ : nullptr;
+ Hint.OptionLoc = IdentifierLoc::create(
+ Actions.Context, Info->Option.getLocation(), OptionInfo);
- return Hint;
+ Token *Toks = Info->Toks;
+ size_t TokSize = Info->TokSize;
+
+ // Return a valid hint if pragma unroll or nounroll were specified
+ // without an argument.
+ bool PragmaUnroll = PragmaNameInfo->getName() == "unroll";
+ bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll";
+ if (TokSize == 0 && (PragmaUnroll || PragmaNoUnroll)) {
+ ConsumeToken(); // The annotation token.
+ Hint.Range = Info->PragmaName.getLocation();
+ return true;
+ }
+
+ // The constant expression is always followed by an eof token, which increases
+ // the TokSize by 1.
+ assert(TokSize > 0 &&
+ "PragmaLoopHintInfo::Toks must contain at least one token.");
+
+ // If no option is specified the argument is assumed to be a constant expr.
+ bool StateOption = false;
+ if (OptionInfo) { // Pragma unroll does not specify an option.
+ StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
+ .Case("vectorize", true)
+ .Case("interleave", true)
+ .Case("unroll", true)
+ .Default(false);
+ }
+
+ // Verify loop hint has an argument.
+ if (Toks[0].is(tok::eof)) {
+ ConsumeToken(); // The annotation token.
+ Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument)
+ << /*StateArgument=*/StateOption << /*FullKeyword=*/PragmaUnroll;
+ return false;
+ }
+
+ // Validate the argument.
+ if (StateOption) {
+ ConsumeToken(); // The annotation token.
+ bool OptionUnroll = OptionInfo->isStr("unroll");
+ SourceLocation StateLoc = Toks[0].getLocation();
+ IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
+ if (!StateInfo || ((OptionUnroll ? !StateInfo->isStr("full")
+ : !StateInfo->isStr("enable")) &&
+ !StateInfo->isStr("disable"))) {
+ Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword)
+ << /*FullKeyword=*/OptionUnroll;
+ return false;
+ }
+ if (TokSize > 2)
+ Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaLoopHintString(Info->PragmaName, Info->Option);
+ Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo);
+ } else {
+ // Enter constant expression including eof terminator into token stream.
+ PP.EnterTokenStream(Toks, TokSize, /*DisableMacroExpansion=*/false,
+ /*OwnsTokens=*/false);
+ ConsumeToken(); // The annotation token.
+
+ ExprResult R = ParseConstantExpression();
+
+ // Tokens following an error in an ill-formed constant expression will
+ // remain in the token stream and must be removed.
+ if (Tok.isNot(tok::eof)) {
+ Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaLoopHintString(Info->PragmaName, Info->Option);
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+ }
+
+ ConsumeToken(); // Consume the constant expression eof terminator.
+
+ if (R.isInvalid() ||
+ Actions.CheckLoopHintExpr(R.get(), Toks[0].getLocation()))
+ return false;
+
+ // Argument is a constant expression with an integer type.
+ Hint.ValueExpr = R.get();
+ }
+
+ Hint.Range = SourceRange(Info->PragmaName.getLocation(),
+ Info->Toks[TokSize - 1].getLocation());
+ return true;
}
// #pragma GCC visibility comes in two variants:
@@ -1601,7 +1827,8 @@
Token Tok;
PP.Lex(Tok);
if (Tok.is(tok::eod)) {
- PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_missing_argument);
+ PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
+ << "clang optimize" << /*Expected=*/true << "'on' or 'off'";
return;
}
if (Tok.isNot(tok::identifier)) {
@@ -1630,6 +1857,52 @@
Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
}
+/// \brief Parses loop or unroll pragma hint value and fills in Info.
+static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
+ Token Option, bool ValueInParens,
+ PragmaLoopHintInfo &Info) {
+ SmallVector<Token, 1> ValueList;
+ int OpenParens = ValueInParens ? 1 : 0;
+ // Read constant expression.
+ while (Tok.isNot(tok::eod)) {
+ if (Tok.is(tok::l_paren))
+ OpenParens++;
+ else if (Tok.is(tok::r_paren)) {
+ OpenParens--;
+ if (OpenParens == 0 && ValueInParens)
+ break;
+ }
+
+ ValueList.push_back(Tok);
+ PP.Lex(Tok);
+ }
+
+ if (ValueInParens) {
+ // Read ')'
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+ return true;
+ }
+ PP.Lex(Tok);
+ }
+
+ Token EOFTok;
+ EOFTok.startToken();
+ EOFTok.setKind(tok::eof);
+ EOFTok.setLocation(Tok.getLocation());
+ ValueList.push_back(EOFTok); // Terminates expression for parsing.
+
+ Token *TokenArray = (Token *)PP.getPreprocessorAllocator().Allocate(
+ ValueList.size() * sizeof(Token), llvm::alignOf<Token>());
+ std::copy(ValueList.begin(), ValueList.end(), TokenArray);
+ Info.Toks = TokenArray;
+ Info.TokSize = ValueList.size();
+
+ Info.PragmaName = PragmaName;
+ Info.Option = Option;
+ return false;
+}
+
/// \brief Handle the \#pragma clang loop directive.
/// #pragma clang 'loop' loop-hints
///
@@ -1639,7 +1912,7 @@
/// loop-hint:
/// 'vectorize' '(' loop-hint-keyword ')'
/// 'interleave' '(' loop-hint-keyword ')'
-/// 'unroll' '(' loop-hint-keyword ')'
+/// 'unroll' '(' unroll-hint-keyword ')'
/// 'vectorize_width' '(' loop-hint-value ')'
/// 'interleave_count' '(' loop-hint-value ')'
/// 'unroll_count' '(' loop-hint-value ')'
@@ -1648,6 +1921,10 @@
/// 'enable'
/// 'disable'
///
+/// unroll-hint-keyword:
+/// 'full'
+/// 'disable'
+///
/// loop-hint-value:
/// constant-expression
///
@@ -1662,16 +1939,15 @@
/// only works on inner loops.
///
/// The unroll and unroll_count directives control the concatenation
-/// unroller. Specifying unroll(enable) instructs llvm to try to
+/// unroller. Specifying unroll(full) instructs llvm to try to
/// unroll the loop completely, and unroll(disable) disables unrolling
/// for the loop. Specifying unroll_count(_value_) instructs llvm to
/// try to unroll the loop the number of times indicated by the value.
-/// If unroll(enable) and unroll_count are both specified only
-/// unroll_count takes effect.
void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
- Token Loop = Tok;
+ // Incoming token is "loop" from "#pragma clang loop".
+ Token PragmaName = Tok;
SmallVector<Token, 1> TokenList;
// Lex the optimization option and verify it is an identifier.
@@ -1687,57 +1963,37 @@
IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
bool OptionValid = llvm::StringSwitch<bool>(OptionInfo->getName())
- .Case("vectorize", true)
- .Case("interleave", true)
- .Case("unroll", true)
- .Case("vectorize_width", true)
- .Case("interleave_count", true)
- .Case("unroll_count", true)
- .Default(false);
+ .Case("vectorize", true)
+ .Case("interleave", true)
+ .Case("unroll", true)
+ .Case("vectorize_width", true)
+ .Case("interleave_count", true)
+ .Case("unroll_count", true)
+ .Default(false);
if (!OptionValid) {
PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)
<< /*MissingOption=*/false << OptionInfo;
return;
}
+ PP.Lex(Tok);
// Read '('
- PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
return;
}
-
- // FIXME: All tokens between '(' and ')' should be stored and parsed as a
- // constant expression.
- PP.Lex(Tok);
- if (Tok.is(tok::r_paren)) {
- // Nothing between the parentheses.
- PP.Diag(Tok.getLocation(), diag::err_pragma_loop_missing_argument)
- << OptionInfo;
- return;
- }
- Token Value = Tok;
-
- // Read ')'
- PP.Lex(Tok);
- if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
- return;
- }
-
- // Get next optimization option.
PP.Lex(Tok);
auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
- Info->Loop = Loop;
- Info->Option = Option;
- Info->Value = Value;
+ if (ParseLoopHintValue(PP, Tok, PragmaName, Option, /*ValueInParens=*/true,
+ *Info))
+ return;
- // Generate the vectorization hint token.
+ // Generate the loop hint token.
Token LoopHintTok;
LoopHintTok.startToken();
LoopHintTok.setKind(tok::annot_pragma_loop_hint);
- LoopHintTok.setLocation(Loop.getLocation());
+ LoopHintTok.setLocation(PragmaName.getLocation());
LoopHintTok.setAnnotationValue(static_cast<void *>(Info));
TokenList.push_back(LoopHintTok);
}
@@ -1755,3 +2011,72 @@
/*DisableMacroExpansion=*/false,
/*OwnsTokens=*/true);
}
+
+/// \brief Handle the loop unroll optimization pragmas.
+/// #pragma unroll
+/// #pragma unroll unroll-hint-value
+/// #pragma unroll '(' unroll-hint-value ')'
+/// #pragma nounroll
+///
+/// unroll-hint-value:
+/// constant-expression
+///
+/// Loop unrolling hints can be specified with '#pragma unroll' or
+/// '#pragma nounroll'. '#pragma unroll' can take a numeric argument optionally
+/// contained in parentheses. With no argument the directive instructs llvm to
+/// try to unroll the loop completely. A positive integer argument can be
+/// specified to indicate the number of times the loop should be unrolled. To
+/// maximize compatibility with other compilers the unroll count argument can be
+/// specified with or without parentheses. Specifying, '#pragma nounroll'
+/// disables unrolling of the loop.
+void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ // Incoming token is "unroll" for "#pragma unroll", or "nounroll" for
+ // "#pragma nounroll".
+ Token PragmaName = Tok;
+ PP.Lex(Tok);
+ auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
+ if (Tok.is(tok::eod)) {
+ // nounroll or unroll pragma without an argument.
+ Info->PragmaName = PragmaName;
+ Info->Option.startToken();
+ } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll") {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "nounroll";
+ return;
+ } else {
+ // Unroll pragma with an argument: "#pragma unroll N" or
+ // "#pragma unroll(N)".
+ // Read '(' if it exists.
+ bool ValueInParens = Tok.is(tok::l_paren);
+ if (ValueInParens)
+ PP.Lex(Tok);
+
+ Token Option;
+ Option.startToken();
+ if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info))
+ return;
+
+ // In CUDA, the argument to '#pragma unroll' should not be contained in
+ // parentheses.
+ if (PP.getLangOpts().CUDA && ValueInParens)
+ PP.Diag(Info->Toks[0].getLocation(),
+ diag::warn_pragma_unroll_cuda_value_in_parens);
+
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "unroll";
+ return;
+ }
+ }
+
+ // Generate the hint token.
+ Token *TokenArray = new Token[1];
+ TokenArray[0].startToken();
+ TokenArray[0].setKind(tok::annot_pragma_loop_hint);
+ TokenArray[0].setLocation(PragmaName.getLocation());
+ TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
+ PP.EnterTokenStream(TokenArray, 1, /*DisableMacroExpansion=*/false,
+ /*OwnsTokens=*/true);
+}
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index d29da83..1bfce60 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -185,9 +185,9 @@
if (Next.isNot(tok::coloncolon)) {
// Try to limit which sets of keywords should be included in typo
// correction based on what the next token is.
- StatementFilterCCC Validator(Next);
- if (TryAnnotateName(/*IsAddressOfOperand*/false, &Validator)
- == ANK_Error) {
+ if (TryAnnotateName(/*IsAddressOfOperand*/ false,
+ llvm::make_unique<StatementFilterCCC>(Next)) ==
+ ANK_Error) {
// Handle errors here by skipping up to the next semicolon or '}', and
// eat the semicolon if that's what stopped us.
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
@@ -207,7 +207,7 @@
default: {
if ((getLangOpts().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext,
+ DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext,
DeclEnd, Attrs);
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
}
@@ -345,7 +345,7 @@
case tok::annot_pragma_openmp:
ProhibitAttributes(Attrs);
- return ParseOpenMPDeclarativeOrExecutableDirective();
+ return ParseOpenMPDeclarativeOrExecutableDirective(!OnlyStatement);
case tok::annot_pragma_ms_pointers_to_members:
ProhibitAttributes(Attrs);
@@ -642,6 +642,11 @@
ExprResult LHS;
if (!MissingCase) {
LHS = ParseConstantExpression();
+ if (!getLangOpts().CPlusPlus11) {
+ LHS = Actions.CorrectDelayedTyposInExpr(LHS, [this](class Expr *E) {
+ return Actions.VerifyIntegerConstantExpression(E);
+ });
+ }
if (LHS.isInvalid()) {
// If constant-expression is parsed unsuccessfully, recover by skipping
// current case statement (moving to the colon that ends it).
@@ -804,7 +809,6 @@
/// declaration
/// [GNU] '__extension__' declaration
/// statement
-/// [OMP] openmp-directive [TODO]
///
/// [GNU] label-declarations:
/// [GNU] label-declaration
@@ -813,10 +817,6 @@
/// [GNU] label-declaration:
/// [GNU] '__label__' identifier-list ';'
///
-/// [OMP] openmp-directive: [TODO]
-/// [OMP] barrier-directive
-/// [OMP] flush-directive
-///
StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
unsigned ScopeFlags) {
assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
@@ -961,8 +961,7 @@
ExtensionRAIIObject O(Diags);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Res = ParseDeclaration(Stmts,
- Declarator::BlockContext, DeclEnd,
+ DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext, DeclEnd,
attrs);
R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
} else {
@@ -1522,7 +1521,7 @@
ForRangeInit.RangeExpr = ParseExpression();
Diag(Loc, getLangOpts().CPlusPlus1z
- ? diag::warn_cxx1y_compat_for_range_identifier
+ ? diag::warn_cxx14_compat_for_range_identifier
: diag::ext_for_range_identifier)
<< ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus1z)
? FixItHint::CreateInsertion(Loc, "auto &&")
@@ -1541,9 +1540,8 @@
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- StmtVector Stmts;
DeclGroupPtrTy DG = ParseSimpleDeclaration(
- Stmts, Declarator::ForContext, DeclEnd, attrs, false,
+ Declarator::ForContext, DeclEnd, attrs, false,
MightBeForRangeStmt ? &ForRangeInit : nullptr);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (ForRangeInit.ParsedForRangeDecl()) {
@@ -1569,7 +1567,7 @@
}
} else {
ProhibitAttributes(attrs);
- Value = ParseExpression();
+ Value = Actions.CorrectDelayedTyposInExpr(ParseExpression());
ForEach = isTokIdentifier_in();
@@ -1820,18 +1818,17 @@
// Create temporary attribute list.
ParsedAttributesWithRange TempAttrs(AttrFactory);
- // Get vectorize hints and consume annotated token.
+ // Get loop hints and consume annotated token.
while (Tok.is(tok::annot_pragma_loop_hint)) {
- LoopHint Hint = HandlePragmaLoopHint();
- ConsumeToken();
-
- if (!Hint.LoopLoc || !Hint.OptionLoc || !Hint.ValueLoc)
+ LoopHint Hint;
+ if (!HandlePragmaLoopHint(Hint))
continue;
- ArgsUnion ArgHints[] = {Hint.OptionLoc, Hint.ValueLoc,
+ ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.StateLoc,
ArgsUnion(Hint.ValueExpr)};
- TempAttrs.addNew(Hint.LoopLoc->Ident, Hint.Range, nullptr,
- Hint.LoopLoc->Loc, ArgHints, 3, AttributeList::AS_Pragma);
+ TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr,
+ Hint.PragmaNameLoc->Loc, ArgHints, 4,
+ AttributeList::AS_Pragma);
}
// Get the next statement.
diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp
index de299fd..6f89953 100644
--- a/lib/Parse/ParseStmtAsm.cpp
+++ b/lib/Parse/ParseStmtAsm.cpp
@@ -93,6 +93,15 @@
return Info.OpDecl;
}
+ StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM,
+ llvm::SMLoc Location,
+ bool Create) override {
+ SourceLocation Loc = translateLocation(LSM, Location);
+ LabelDecl *Label =
+ TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create);
+ return Label->getMSAsmLabel();
+ }
+
bool LookupInlineAsmField(StringRef Base, StringRef Member,
unsigned &Offset) override {
return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset,
@@ -133,14 +142,13 @@
}
}
- void handleDiagnostic(const llvm::SMDiagnostic &D) {
+ SourceLocation translateLocation(const llvm::SourceMgr &LSM, llvm::SMLoc SMLoc) {
// Compute an offset into the inline asm buffer.
// FIXME: This isn't right if .macro is involved (but hopefully, no
// real-world code does that).
- const llvm::SourceMgr &LSM = *D.getSourceMgr();
const llvm::MemoryBuffer *LBuf =
- LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
- unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
+ LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
+ unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();
// Figure out which token that offset points into.
const unsigned *TokOffsetPtr =
@@ -157,6 +165,12 @@
Loc = Tok.getLocation();
Loc = Loc.getLocWithOffset(Offset - TokOffset);
}
+ return Loc;
+ }
+
+ void handleDiagnostic(const llvm::SMDiagnostic &D) {
+ const llvm::SourceMgr &LSM = *D.getSourceMgr();
+ SourceLocation Loc = translateLocation(LSM, D.getLoc());
TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
}
};
@@ -322,8 +336,9 @@
SourceLocation EndLoc = AsmLoc;
SmallVector<Token, 4> AsmToks;
+ bool SingleLineMode = true;
unsigned BraceNesting = 0;
- unsigned short savedBraceCount = 0;
+ unsigned short savedBraceCount = BraceCount;
bool InAsmComment = false;
FileID FID;
unsigned LineNo = 0;
@@ -333,8 +348,8 @@
if (Tok.is(tok::l_brace)) {
// Braced inline asm: consume the opening brace.
+ SingleLineMode = false;
BraceNesting = 1;
- savedBraceCount = BraceCount;
EndLoc = ConsumeBrace();
LBraceLocs.push_back(EndLoc);
++NumTokensRead;
@@ -365,30 +380,39 @@
} else if (!InAsmComment && Tok.is(tok::semi)) {
// A semicolon in an asm is the start of a comment.
InAsmComment = true;
- if (BraceNesting) {
+ if (!SingleLineMode) {
// Compute which line the comment is on.
std::pair<FileID, unsigned> ExpSemiLoc =
SrcMgr.getDecomposedExpansionLoc(TokLoc);
FID = ExpSemiLoc.first;
LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
}
- } else if (!BraceNesting || InAsmComment) {
+ } else if (SingleLineMode || InAsmComment) {
// If end-of-line is significant, check whether this token is on a
// new line.
std::pair<FileID, unsigned> ExpLoc =
SrcMgr.getDecomposedExpansionLoc(TokLoc);
if (ExpLoc.first != FID ||
SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
- // If this is a single-line __asm, we're done.
- if (!BraceNesting)
+ // If this is a single-line __asm, we're done, except if the next
+ // line begins with an __asm too, in which case we finish a comment
+ // if needed and then keep processing the next line as a single
+ // line __asm.
+ bool isAsm = Tok.is(tok::kw_asm);
+ if (SingleLineMode && !isAsm)
break;
// We're no longer in a comment.
InAsmComment = false;
+ if (isAsm) {
+ LineNo = SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second);
+ SkippedStartOfLine = Tok.isAtStartOfLine();
+ }
} else if (!InAsmComment && Tok.is(tok::r_brace)) {
- // Single-line asm always ends when a closing brace is seen.
- // FIXME: This is compatible with Apple gcc's -fasm-blocks; what
- // does MSVC do here?
- break;
+ // In MSVC mode, braces only participate in brace matching and
+ // separating the asm statements. This is an intentional
+ // departure from the Apple gcc behavior.
+ if (!BraceNesting)
+ break;
}
}
if (!InAsmComment && BraceNesting && Tok.is(tok::r_brace) &&
@@ -397,8 +421,9 @@
SkippedStartOfLine = Tok.isAtStartOfLine();
EndLoc = ConsumeBrace();
BraceNesting--;
- // Finish if all of the opened braces in the inline asm section were consumed.
- if (BraceNesting == 0)
+ // Finish if all of the opened braces in the inline asm section were
+ // consumed.
+ if (BraceNesting == 0 && !SingleLineMode)
break;
else {
LBraceLocs.pop_back();
@@ -487,11 +512,13 @@
llvm::SourceMgr TempSrcMgr;
llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
- llvm::MemoryBuffer *Buffer =
+ MOFI->InitMCObjectFileInfo(TT, llvm::Reloc::Default, llvm::CodeModel::Default,
+ Ctx);
+ std::unique_ptr<llvm::MemoryBuffer> Buffer =
llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
// Tell SrcMgr about this buffer, which is what the parser will pick up.
- TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
+ TempSrcMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc());
std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
std::unique_ptr<llvm::MCAsmParser> Parser(
@@ -590,7 +617,7 @@
}
DeclSpec DS(AttrFactory);
SourceLocation Loc = Tok.getLocation();
- ParseTypeQualifierListOpt(DS, true, false);
+ ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed);
// GNU asms accept, but warn, about type-qualifiers other than volatile.
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index fa6401f..2f1c189 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -166,6 +166,14 @@
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
"Template information required");
+ if (Tok.is(tok::kw_static_assert)) {
+ // A static_assert declaration may not be templated.
+ Diag(Tok.getLocation(), diag::err_templated_invalid_declaration)
+ << TemplateInfo.getSourceRange();
+ // Parse the static_assert declaration to improve error recovery.
+ return ParseStaticAssertDeclaration(DeclEnd);
+ }
+
if (Context == Declarator::MemberContext) {
// We are parsing a member template.
ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
@@ -553,7 +561,7 @@
if (Tok.is(tok::kw_typename)) {
Diag(Tok.getLocation(),
getLangOpts().CPlusPlus1z
- ? diag::warn_cxx1y_compat_template_template_param_typename
+ ? diag::warn_cxx14_compat_template_template_param_typename
: diag::ext_template_template_param_typename)
<< (!getLangOpts().CPlusPlus1z
? FixItHint::CreateReplacement(Tok.getLocation(), "class")
@@ -1327,7 +1335,8 @@
ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
// Recreate the containing function DeclContext.
- Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FunD));
+ Sema::ContextRAII FunctionSavedContext(Actions,
+ Actions.getContainingDC(FunD));
Actions.ActOnStartOfFunctionDef(getCurScope(), FunD);
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 8514af2..1f39c25 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -837,6 +837,7 @@
Tok.is(tok::kw___stdcall) ||
Tok.is(tok::kw___fastcall) ||
Tok.is(tok::kw___thiscall) ||
+ Tok.is(tok::kw___vectorcall) ||
Tok.is(tok::kw___unaligned))
return TPResult::True; // attributes indicate declaration
TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
@@ -891,6 +892,7 @@
case tok::numeric_constant:
case tok::char_constant:
case tok::wide_char_constant:
+ case tok::utf8_char_constant:
case tok::utf16_char_constant:
case tok::utf32_char_constant:
case tok::string_literal:
@@ -984,6 +986,7 @@
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___unaligned:
case tok::kw___vector:
case tok::kw___pixel:
@@ -1004,6 +1007,28 @@
!= TentativelyDeclaredIdentifiers.end();
}
+namespace {
+class TentativeParseCCC : public CorrectionCandidateCallback {
+public:
+ TentativeParseCCC(const Token &Next) {
+ WantRemainingKeywords = false;
+ WantTypeSpecifiers = Next.is(tok::l_paren) || Next.is(tok::r_paren) ||
+ Next.is(tok::greater) || Next.is(tok::l_brace) ||
+ Next.is(tok::identifier);
+ }
+
+ bool ValidateCandidate(const TypoCorrection &Candidate) override {
+ // Reject any candidate that only resolves to instance members since they
+ // aren't viable as standalone identifiers instead of member references.
+ if (Candidate.isResolved() && !Candidate.isKeyword() &&
+ std::all_of(Candidate.begin(), Candidate.end(),
+ [](NamedDecl *ND) { return ND->isCXXInstanceMember(); }))
+ return false;
+
+ return CorrectionCandidateCallback::ValidateCandidate(Candidate);
+ }
+};
+}
/// isCXXDeclarationSpecifier - Returns TPResult::True if it is a declaration
/// specifier, TPResult::False if it is not, TPResult::Ambiguous if it could
/// be either a decl-specifier or a function-style cast, and TPResult::Error
@@ -1129,11 +1154,8 @@
// a parse error one way or another. In that case, tell the caller that
// this is ambiguous. Typo-correct to type and expression keywords and
// to types and identifiers, in order to try to recover from errors.
- CorrectionCandidateCallback TypoCorrection;
- TypoCorrection.WantRemainingKeywords = false;
- TypoCorrection.WantTypeSpecifiers = Next.isNot(tok::arrow);
switch (TryAnnotateName(false /* no nested name specifier */,
- &TypoCorrection)) {
+ llvm::make_unique<TentativeParseCCC>(Next))) {
case ANK_Error:
return TPResult::Error;
case ANK_TentativeDecl:
@@ -1181,6 +1203,7 @@
return TPResult::False;
}
// Fall through.
+ case tok::kw___super:
case tok::kw_decltype:
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
@@ -1250,6 +1273,7 @@
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___w64:
case tok::kw___sptr:
case tok::kw___uptr:
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index d28e046..2bac56c 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -109,7 +109,7 @@
}
bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
- const char *Msg) {
+ StringRef Msg) {
if (Tok.is(ExpectedTok) || Tok.is(tok::code_completion)) {
ConsumeAnyToken();
return false;
@@ -510,6 +510,13 @@
};
}
+void Parser::LateTemplateParserCleanupCallback(void *P) {
+ // While this RAII helper doesn't bracket any actual work, the destructor will
+ // clean up annotations that were created during ActOnEndOfTranslationUnit
+ // when incremental processing is enabled.
+ DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(((Parser *)P)->TemplateIds);
+}
+
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
/// action tells us to. This returns true if the EOF was encountered.
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
@@ -542,7 +549,10 @@
case tok::eof:
// Late template parsing can begin.
if (getLangOpts().DelayedTemplateParsing)
- Actions.SetLateTemplateParser(LateTemplateParserCallback, this);
+ Actions.SetLateTemplateParser(LateTemplateParserCallback,
+ PP.isIncrementalProcessingEnabled() ?
+ LateTemplateParserCleanupCallback : nullptr,
+ this);
if (!PP.isIncrementalProcessingEnabled())
Actions.ActOnEndOfTranslationUnit();
//else don't tell Sema that we ended parsing: more input might come.
@@ -624,8 +634,7 @@
HandlePragmaOpenCLExtension();
return DeclGroupPtrTy();
case tok::annot_pragma_openmp:
- ParseOpenMPDeclarativeDirective();
- return DeclGroupPtrTy();
+ return ParseOpenMPDeclarativeDirective();
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
return DeclGroupPtrTy();
@@ -697,8 +706,7 @@
// A function definition cannot start with any of these keywords.
{
SourceLocation DeclEnd;
- StmtVector Stmts;
- return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
+ return ParseDeclaration(Declarator::FileContext, DeclEnd, attrs);
}
case tok::kw_static:
@@ -708,8 +716,7 @@
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 0;
SourceLocation DeclEnd;
- StmtVector Stmts;
- return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
+ return ParseDeclaration(Declarator::FileContext, DeclEnd, attrs);
}
goto dont_know;
@@ -720,8 +727,7 @@
// Inline namespaces. Allowed as an extension even in C++03.
if (NextKind == tok::kw_namespace) {
SourceLocation DeclEnd;
- StmtVector Stmts;
- return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
+ return ParseDeclaration(Declarator::FileContext, DeclEnd, attrs);
}
// Parse (then ignore) 'inline' prior to a template instantiation. This is
@@ -730,8 +736,7 @@
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 1;
SourceLocation DeclEnd;
- StmtVector Stmts;
- return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
+ return ParseDeclaration(Declarator::FileContext, DeclEnd, attrs);
}
}
goto dont_know;
@@ -1218,7 +1223,7 @@
/// [GNU] asm-string-literal:
/// string-literal
///
-Parser::ExprResult Parser::ParseAsmStringLiteral() {
+ExprResult Parser::ParseAsmStringLiteral() {
switch (Tok.getKind()) {
case tok::string_literal:
break;
@@ -1246,7 +1251,7 @@
/// [GNU] simple-asm-expr:
/// 'asm' '(' asm-string-literal ')'
///
-Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
+ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
assert(Tok.is(tok::kw_asm) && "Not an asm!");
SourceLocation Loc = ConsumeToken();
@@ -1321,7 +1326,7 @@
/// no typo correction will be performed.
Parser::AnnotatedNameKind
Parser::TryAnnotateName(bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC) {
+ std::unique_ptr<CorrectionCandidateCallback> CCC) {
assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
const bool EnteringContext = false;
@@ -1359,9 +1364,9 @@
// after a scope specifier, because in general we can't recover from typos
// there (eg, after correcting 'A::tempalte B<X>::C' [sic], we would need to
// jump back into scope specifier parsing).
- Sema::NameClassification Classification
- = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next,
- IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);
+ Sema::NameClassification Classification = Actions.ClassifyName(
+ getCurScope(), SS, Name, NameLoc, Next, IsAddressOfOperand,
+ SS.isEmpty() ? std::move(CCC) : nullptr);
switch (Classification.getKind()) {
case Sema::NC_Error:
@@ -1431,34 +1436,16 @@
}
bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
- assert(!Tok.is(tok::identifier) && !Tok.isAnnotation());
+ assert(Tok.isNot(tok::identifier));
Diag(Tok, diag::ext_keyword_as_ident)
<< PP.getSpelling(Tok)
<< DisableKeyword;
- if (DisableKeyword) {
- IdentifierInfo *II = Tok.getIdentifierInfo();
- ContextualKeywords[II] = Tok.getKind();
- II->RevertTokenIDToIdentifier();
- }
+ if (DisableKeyword)
+ Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
Tok.setKind(tok::identifier);
return true;
}
-bool Parser::TryIdentKeywordUpgrade() {
- assert(Tok.is(tok::identifier));
- const IdentifierInfo *II = Tok.getIdentifierInfo();
- assert(II->hasRevertedTokenIDToIdentifier());
- // If we find that this is in fact the name of a type trait,
- // update the token kind in place and parse again to treat it as
- // the appropriate kind of type trait.
- llvm::SmallDenseMap<const IdentifierInfo *, tok::TokenKind>::iterator Known =
- ContextualKeywords.find(II);
- if (Known == ContextualKeywords.end())
- return false;
- Tok.setKind(Known->second);
- return true;
-}
-
/// TryAnnotateTypeOrScopeToken - If the current token position is on a
/// typename (possibly qualified in C++) or a C++ scope specifier not followed
/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
@@ -1482,10 +1469,11 @@
/// 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::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
- assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)
- || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)
- || Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id))
- && "Cannot be a type or scope token!");
+ assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) ||
+ Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) ||
+ Tok.is(tok::kw___super)) &&
+ "Cannot be a type or scope token!");
if (Tok.is(tok::kw_typename)) {
// MSVC lets you do stuff like:
@@ -1694,7 +1682,8 @@
"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)) ||
- Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!");
+ Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super)) &&
+ "Cannot be a type or scope token!");
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
@@ -1756,13 +1745,6 @@
return PrevTokLocation;
}
-// Anchor the Parser::FieldCallback vtable to this translation unit.
-// We use a spurious method instead of the destructor because
-// destroying FieldCallbacks can actually be slightly
-// performance-sensitive.
-void Parser::FieldCallback::_anchor() {
-}
-
// Code-completion pass-through functions
void Parser::CodeCompleteDirective(bool InConditional) {
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 4f5f3ab..a0c9c1f 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H
-#define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H
+#ifndef LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H
+#define LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"