summaryrefslogtreecommitdiff
path: root/clang/lib/Parse/ParseDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Parse/ParseDecl.cpp')
-rw-r--r--clang/lib/Parse/ParseDecl.cpp702
1 files changed, 380 insertions, 322 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 69a3ed9cbad77..c87d240a8206a 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -1409,154 +1409,6 @@ void Parser::ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
Syntax);
}
-// Late Parsed Attributes:
-// See other examples of late parsing in lib/Parse/ParseCXXInlineMethods
-
-void Parser::LateParsedDeclaration::ParseLexedAttributes() {}
-
-void Parser::LateParsedClass::ParseLexedAttributes() {
- Self->ParseLexedAttributes(*Class);
-}
-
-void Parser::LateParsedAttribute::ParseLexedAttributes() {
- Self->ParseLexedAttribute(*this, true, false);
-}
-
-/// Wrapper class which calls ParseLexedAttribute, after setting up the
-/// scope appropriately.
-void Parser::ParseLexedAttributes(ParsingClass &Class) {
- // Deal with templates
- // FIXME: Test cases to make sure this does the right thing for templates.
- bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
- ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
- HasTemplateScope);
- if (HasTemplateScope)
- Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
-
- // Set or update the scope flags.
- bool AlreadyHasClassScope = Class.TopLevelClass;
- unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope;
- ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
- ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
-
- // Enter the scope of nested classes
- if (!AlreadyHasClassScope)
- Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
- Class.TagOrTemplate);
- if (!Class.LateParsedDeclarations.empty()) {
- for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){
- Class.LateParsedDeclarations[i]->ParseLexedAttributes();
- }
- }
-
- if (!AlreadyHasClassScope)
- Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(),
- Class.TagOrTemplate);
-}
-
-/// Parse all attributes in LAs, and attach them to Decl D.
-void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
- bool EnterScope, bool OnDefinition) {
- assert(LAs.parseSoon() &&
- "Attribute list should be marked for immediate parsing.");
- for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) {
- if (D)
- LAs[i]->addDecl(D);
- ParseLexedAttribute(*LAs[i], EnterScope, OnDefinition);
- delete LAs[i];
- }
- LAs.clear();
-}
-
-/// Finish parsing an attribute for which parsing was delayed.
-/// This will be called at the end of parsing a class declaration
-/// for each LateParsedAttribute. We consume the saved tokens and
-/// create an attribute with the arguments filled in. We add this
-/// to the Attribute list for the decl.
-void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
- bool EnterScope, bool OnDefinition) {
- // Create a fake EOF so that attribute parsing won't go off the end of the
- // attribute.
- Token AttrEnd;
- AttrEnd.startToken();
- AttrEnd.setKind(tok::eof);
- AttrEnd.setLocation(Tok.getLocation());
- AttrEnd.setEofData(LA.Toks.data());
- LA.Toks.push_back(AttrEnd);
-
- // Append the current token at the end of the new token stream so that it
- // doesn't get lost.
- LA.Toks.push_back(Tok);
- PP.EnterTokenStream(LA.Toks, true, /*IsReinject=*/true);
- // Consume the previously pushed token.
- ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
-
- ParsedAttributes Attrs(AttrFactory);
- SourceLocation endLoc;
-
- if (LA.Decls.size() > 0) {
- Decl *D = LA.Decls[0];
- NamedDecl *ND = dyn_cast<NamedDecl>(D);
- RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
-
- // Allow 'this' within late-parsed attributes.
- Sema::CXXThisScopeRAII ThisScope(Actions, RD, Qualifiers(),
- ND && ND->isCXXInstanceMember());
-
- if (LA.Decls.size() == 1) {
- // If the Decl is templatized, add template parameters to scope.
- bool HasTemplateScope = EnterScope && D->isTemplateDecl();
- ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope);
- if (HasTemplateScope)
- Actions.ActOnReenterTemplateScope(Actions.CurScope, D);
-
- // If the Decl is on a function, add function parameters to the scope.
- bool HasFunScope = EnterScope && D->isFunctionOrFunctionTemplate();
- ParseScope FnScope(
- this, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope,
- HasFunScope);
- if (HasFunScope)
- Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
-
- ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc,
- nullptr, SourceLocation(), ParsedAttr::AS_GNU,
- nullptr);
-
- if (HasFunScope) {
- Actions.ActOnExitFunctionContext();
- FnScope.Exit(); // Pop scope, and remove Decls from IdResolver
- }
- if (HasTemplateScope) {
- TempScope.Exit();
- }
- } else {
- // If there are multiple decls, then the decl cannot be within the
- // function scope.
- ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc,
- nullptr, SourceLocation(), ParsedAttr::AS_GNU,
- nullptr);
- }
- } else {
- Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName();
- }
-
- if (OnDefinition && !Attrs.empty() && !Attrs.begin()->isCXX11Attribute() &&
- Attrs.begin()->isKnownToGCC())
- Diag(Tok, diag::warn_attribute_on_function_definition)
- << &LA.AttrName;
-
- for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i)
- Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.Decls[i], Attrs);
-
- // Due to a parsing error, we either went over the cached tokens or
- // there are still cached tokens left, so we skip the leftover tokens.
- while (Tok.isNot(tok::eof))
- ConsumeAnyToken();
-
- if (Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData())
- ConsumeAnyToken();
-}
-
void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
@@ -2046,46 +1898,52 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
}
// 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
- // declaration. We have to check this because __attribute__ might be the
- // start of a function definition in GCC-extended K&R C.
- !isDeclarationAfterDeclarator()) {
-
- // Function definitions are only allowed at file scope and in C++ classes.
- // The C++ inline method definition case is handled elsewhere, so we only
- // need to handle the file scope definition case.
- if (Context == DeclaratorContext::FileContext) {
- if (isStartOfFunctionDefinition(D)) {
- if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
- Diag(Tok, diag::err_function_declared_typedef);
-
- // Recover by treating the 'typedef' as spurious.
- DS.ClearStorageClassSpecs();
- }
+ if (D.isFunctionDeclarator()) {
+ if (Tok.is(tok::equal) && NextToken().is(tok::code_completion)) {
+ Actions.CodeCompleteAfterFunctionEquals(D);
+ cutOffParsing();
+ return nullptr;
+ }
+ // Look at the next token to make sure that this isn't a function
+ // declaration. We have to check this because __attribute__ might be the
+ // start of a function definition in GCC-extended K&R C.
+ if (!isDeclarationAfterDeclarator()) {
+
+ // Function definitions are only allowed at file scope and in C++ classes.
+ // The C++ inline method definition case is handled elsewhere, so we only
+ // need to handle the file scope definition case.
+ if (Context == DeclaratorContext::FileContext) {
+ if (isStartOfFunctionDefinition(D)) {
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ Diag(Tok, diag::err_function_declared_typedef);
+
+ // Recover by treating the 'typedef' as spurious.
+ DS.ClearStorageClassSpecs();
+ }
- Decl *TheDecl =
- ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs);
- return Actions.ConvertDeclToDeclGroup(TheDecl);
- }
+ Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(),
+ &LateParsedAttrs);
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ }
- if (isDeclarationSpecifier()) {
- // If there is an invalid declaration specifier right after the
- // function prototype, then we must be in a missing semicolon case
- // where this isn't actually a body. Just fall through into the code
- // that handles it as a prototype, and let the top-level code handle
- // the erroneous declspec where it would otherwise expect a comma or
- // semicolon.
+ if (isDeclarationSpecifier()) {
+ // If there is an invalid declaration specifier right after the
+ // function prototype, then we must be in a missing semicolon case
+ // where this isn't actually a body. Just fall through into the code
+ // that handles it as a prototype, and let the top-level code handle
+ // the erroneous declspec where it would otherwise expect a comma or
+ // semicolon.
+ } else {
+ Diag(Tok, diag::err_expected_fn_body);
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
} else {
- Diag(Tok, diag::err_expected_fn_body);
- SkipUntil(tok::semi);
- return nullptr;
- }
- } else {
- if (Tok.is(tok::l_brace)) {
- Diag(Tok, diag::err_function_definition_not_allowed);
- SkipMalformedDecl();
- return nullptr;
+ if (Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::err_function_definition_not_allowed);
+ SkipMalformedDecl();
+ return nullptr;
+ }
}
}
}
@@ -2359,7 +2217,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
<< 0 /* default */;
else
Diag(ConsumeToken(), diag::err_default_special_members)
- << getLangOpts().CPlusPlus2a;
+ << getLangOpts().CPlusPlus20;
} else {
InitializerScopeRAII InitScope(*this, D, ThisDecl);
@@ -2460,6 +2318,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
InitializerScopeRAII InitScope(*this, D, ThisDecl);
+ PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl);
ExprResult Init(ParseBraceInitializer());
InitScope.pop();
@@ -2741,7 +2600,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
default:
// This is probably supposed to be a type. This includes cases like:
// int f(itn);
- // struct S { unsinged : 4; };
+ // struct S { unsigned : 4; };
break;
}
}
@@ -2879,6 +2738,25 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
ParsedAttr::AS_Keyword, EllipsisLoc);
}
+ExprResult Parser::ParseExtIntegerArgument() {
+ assert(Tok.is(tok::kw__ExtInt) && "Not an extended int type");
+ ConsumeToken();
+
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume())
+ return ExprError();
+
+ ExprResult ER = ParseConstantExpression();
+ if (ER.isInvalid()) {
+ T.skipToEnd();
+ return ExprError();
+ }
+
+ if(T.consumeClose())
+ return ExprError();
+ return ER;
+}
+
/// Determine whether we're looking at something that might be a declarator
/// in a simple-declaration. If it can't possibly be a declarator, maybe
/// diagnose a missing semicolon after a prior tag definition in the decl
@@ -2962,6 +2840,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
case Sema::NC_ContextIndependentExpr:
case Sema::NC_VarTemplate:
case Sema::NC_FunctionTemplate:
+ case Sema::NC_Concept:
// Might be a redeclaration of a prior entity.
break;
}
@@ -3160,9 +3039,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// We are looking for a qualified typename.
Token Next = NextToken();
- if (Next.is(tok::annot_template_id) &&
- static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
- ->Kind == TNK_Type_template) {
+
+ TemplateIdAnnotation *TemplateId = Next.is(tok::annot_template_id)
+ ? takeTemplateIdAnnotation(Next)
+ : nullptr;
+ if (TemplateId && TemplateId->hasInvalidName()) {
+ // We found something like 'T::U<Args> x', but U is not a template.
+ // Assume it was supposed to be a type.
+ DS.SetTypeSpecError();
+ ConsumeAnnotationToken();
+ break;
+ }
+
+ if (TemplateId && TemplateId->Kind == TNK_Type_template) {
// We have a qualified template-id, e.g., N::A<int>
// If this would be a valid constructor declaration with template
@@ -3172,12 +3061,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
//
// To improve diagnostics for this case, parse the declaration as a
// constructor (and reject the extra template arguments later).
- TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
if ((DSContext == DeclSpecContext::DSC_top_level ||
DSContext == DeclSpecContext::DSC_class) &&
TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) &&
- isConstructorDeclarator(/*Unqualified*/ false)) {
+ isConstructorDeclarator(/*Unqualified=*/false)) {
// The user meant this to be an out-of-line constructor
// definition, but template arguments are not allowed
// there. Just allow this as a constructor; we'll
@@ -3189,23 +3077,29 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeAnnotationToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
- AnnotateTemplateIdTokenAsType();
+ AnnotateTemplateIdTokenAsType(SS);
+ continue;
+ }
+
+ if (TemplateId && TemplateId->Kind == TNK_Concept_template &&
+ GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype)) {
+ DS.getTypeSpecScope() = SS;
+ // This is a qualified placeholder-specifier, e.g., ::C<int> auto ...
+ // Consume the scope annotation and continue to consume the template-id
+ // as a placeholder-specifier.
+ ConsumeAnnotationToken();
continue;
}
if (Next.is(tok::annot_typename)) {
DS.getTypeSpecScope() = SS;
ConsumeAnnotationToken(); // The C++ scope.
- if (Tok.getAnnotationValue()) {
- ParsedType T = getTypeAnnotation(Tok);
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
- Tok.getAnnotationEndLoc(),
- PrevSpec, DiagID, T, Policy);
- if (isInvalid)
- break;
- }
- else
- DS.SetTypeSpecError();
+ TypeResult T = getTypeAnnotation(Tok);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
+ Tok.getAnnotationEndLoc(),
+ PrevSpec, DiagID, T, Policy);
+ if (isInvalid)
+ break;
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeAnnotationToken(); // The typename
}
@@ -3235,6 +3129,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
// typename.
if (!TypeRep) {
+ if (TryAnnotateTypeConstraint())
+ goto DoneWithDeclSpec;
+ if (Tok.isNot(tok::annot_cxxscope) ||
+ NextToken().isNot(tok::identifier))
+ continue;
// Eat the scope spec so the identifier is current.
ConsumeAnnotationToken();
ParsedAttributesWithRange Attrs(AttrFactory);
@@ -3268,13 +3167,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (DS.hasTypeSpecifier() && DS.hasTagDefinition())
goto DoneWithDeclSpec;
- if (Tok.getAnnotationValue()) {
- ParsedType T = getTypeAnnotation(Tok);
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
- DiagID, T, Policy);
- } else
- DS.SetTypeSpecError();
-
+ TypeResult T = getTypeAnnotation(Tok);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ DiagID, T, Policy);
if (isInvalid)
break;
@@ -3384,6 +3279,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If this is not a typedef name, don't parse it as part of the declspec,
// it must be an implicit int or an error.
if (!TypeRep) {
+ if (TryAnnotateTypeConstraint())
+ goto DoneWithDeclSpec;
+ if (Tok.isNot(tok::identifier))
+ continue;
ParsedAttributesWithRange Attrs(AttrFactory);
if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) {
if (!Attrs.empty()) {
@@ -3433,9 +3332,62 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
}
- // type-name
+ // type-name or placeholder-specifier
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
+
+ if (TemplateId->hasInvalidName()) {
+ DS.SetTypeSpecError();
+ break;
+ }
+
+ if (TemplateId->Kind == TNK_Concept_template) {
+ // If we've already diagnosed that this type-constraint has invalid
+ // arguemnts, drop it and just form 'auto' or 'decltype(auto)'.
+ if (TemplateId->hasInvalidArgs())
+ TemplateId = nullptr;
+
+ if (NextToken().is(tok::identifier)) {
+ Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto)
+ << FixItHint::CreateInsertion(NextToken().getLocation(), "auto");
+ // Attempt to continue as if 'auto' was placed here.
+ isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID,
+ TemplateId, Policy);
+ break;
+ }
+ if (!NextToken().isOneOf(tok::kw_auto, tok::kw_decltype))
+ goto DoneWithDeclSpec;
+ ConsumeAnnotationToken();
+ SourceLocation AutoLoc = Tok.getLocation();
+ if (TryConsumeToken(tok::kw_decltype)) {
+ BalancedDelimiterTracker Tracker(*this, tok::l_paren);
+ if (Tracker.consumeOpen()) {
+ // Something like `void foo(Iterator decltype i)`
+ Diag(Tok, diag::err_expected) << tok::l_paren;
+ } else {
+ if (!TryConsumeToken(tok::kw_auto)) {
+ // Something like `void foo(Iterator decltype(int) i)`
+ Tracker.skipToEnd();
+ Diag(Tok, diag::err_placeholder_expected_auto_or_decltype_auto)
+ << FixItHint::CreateReplacement(SourceRange(AutoLoc,
+ Tok.getLocation()),
+ "auto");
+ } else {
+ Tracker.consumeClose();
+ }
+ }
+ ConsumedEnd = Tok.getLocation();
+ // Even if something went wrong above, continue as if we've seen
+ // `decltype(auto)`.
+ isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec,
+ DiagID, TemplateId, Policy);
+ } else {
+ isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID,
+ TemplateId, Policy);
+ }
+ break;
+ }
+
if (TemplateId->Kind != TNK_Type_template &&
TemplateId->Kind != TNK_Undeclared_template) {
// This template-id does not refer to a type name, so we're
@@ -3448,12 +3400,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// constructor declaration.
if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) &&
- isConstructorDeclarator(TemplateId->SS.isEmpty()))
+ isConstructorDeclarator(/*Unqualified=*/true))
goto DoneWithDeclSpec;
// Turn the template-id annotation token into a type annotation
// token, then try again to parse it as a type-specifier.
- AnnotateTemplateIdTokenAsType();
+ CXXScopeSpec SS;
+ AnnotateTemplateIdTokenAsType(SS);
continue;
}
@@ -3617,7 +3570,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumedEnd = ExplicitLoc;
ConsumeToken(); // kw_explicit
if (Tok.is(tok::l_paren)) {
- if (getLangOpts().CPlusPlus2a) {
+ if (getLangOpts().CPlusPlus20 || isExplicitBool() == TPResult::True) {
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus20
+ ? diag::warn_cxx17_compat_explicit_bool
+ : diag::ext_explicit_bool);
+
ExprResult ExplicitExpr(static_cast<Expr *>(nullptr));
BalancedDelimiterTracker Tracker(*this, tok::l_paren);
Tracker.consumeOpen();
@@ -3630,8 +3587,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get());
} else
Tracker.skipToEnd();
- } else
- Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool);
+ } else {
+ Diag(Tok.getLocation(), diag::warn_cxx20_compat_explicit_bool);
+ }
}
isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID,
ExplicitSpec, CloseParenLoc);
@@ -3726,6 +3684,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec,
DiagID, Policy);
break;
+ case tok::kw__ExtInt: {
+ ExprResult ER = ParseExtIntegerArgument();
+ if (ER.isInvalid())
+ continue;
+ isInvalid = DS.SetExtIntType(Loc, ER.get(), PrevSpec, DiagID, Policy);
+ ConsumedEnd = PrevTokLocation;
+ break;
+ }
case tok::kw___int128:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec,
DiagID, Policy);
@@ -3734,6 +3700,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec,
DiagID, Policy);
break;
+ case tok::kw___bf16:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_BFloat16, Loc, PrevSpec,
+ DiagID, Policy);
+ break;
case tok::kw_float:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec,
DiagID, Policy);
@@ -4137,7 +4107,7 @@ void Parser::ParseStructDeclaration(
/// [OBC] '@' 'defs' '(' class-name ')'
///
void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
- DeclSpec::TST TagType, Decl *TagDecl) {
+ DeclSpec::TST TagType, RecordDecl *TagDecl) {
PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc,
"parsing struct/union body");
assert(!getLangOpts().CPlusPlus && "C++ declarations not supported");
@@ -4149,8 +4119,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
- SmallVector<Decl *, 32> FieldDecls;
-
// While we still have something to read, read the declarations in the struct.
while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
Tok.isNot(tok::eof)) {
@@ -4202,7 +4170,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
Actions.ActOnField(getCurScope(), TagDecl,
FD.D.getDeclSpec().getSourceRange().getBegin(),
FD.D, FD.BitfieldSize);
- FieldDecls.push_back(Field);
FD.complete(Field);
};
@@ -4226,7 +4193,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
SmallVector<Decl *, 16> Fields;
Actions.ActOnDefs(getCurScope(), TagDecl, Tok.getLocation(),
Tok.getIdentifierInfo(), Fields);
- FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end());
ConsumeToken();
ExpectAndConsume(tok::r_paren);
}
@@ -4252,6 +4218,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
// If attributes exist after struct contents, parse them.
MaybeParseGNUAttributes(attrs);
+ SmallVector<Decl *, 32> FieldDecls(TagDecl->field_begin(),
+ TagDecl->field_end());
+
Actions.ActOnFields(getCurScope(), RecordLoc, TagDecl, FieldDecls,
T.getOpenLocation(), T.getCloseLocation(), attrs);
StructScope.Exit();
@@ -4286,7 +4255,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
/// ':' type-specifier-seq
///
/// [C++] elaborated-type-specifier:
-/// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier
+/// [C++] 'enum' nested-name-specifier[opt] identifier
///
void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
@@ -4335,17 +4304,24 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag);
- // Enum definitions should not be parsed in a trailing-return-type.
- bool AllowDeclaration = DSC != DeclSpecContext::DSC_trailing;
+ // Determine whether this declaration is permitted to have an enum-base.
+ AllowDefiningTypeSpec AllowEnumSpecifier =
+ isDefiningTypeSpecifierContext(DSC);
+ bool CanBeOpaqueEnumDeclaration =
+ DS.isEmpty() && isOpaqueEnumDeclarationContext(DSC);
+ bool CanHaveEnumBase = (getLangOpts().CPlusPlus11 || getLangOpts().ObjC ||
+ getLangOpts().MicrosoftExt) &&
+ (AllowEnumSpecifier == AllowDefiningTypeSpec::Yes ||
+ CanBeOpaqueEnumDeclaration);
CXXScopeSpec &SS = DS.getTypeSpecScope();
if (getLangOpts().CPlusPlus) {
- // "enum foo : bar;" is not a potential typo for "enum foo::bar;"
- // if a fixed underlying type is allowed.
- ColonProtectionRAIIObject X(*this, AllowDeclaration);
+ // "enum foo : bar;" is not a potential typo for "enum foo::bar;".
+ ColonProtectionRAIIObject X(*this);
CXXScopeSpec Spec;
- if (ParseOptionalCXXScopeSpecifier(Spec, nullptr,
+ if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr,
+ /*ObjectHadErrors=*/false,
/*EnteringContext=*/true))
return;
@@ -4362,9 +4338,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
SS = Spec;
}
- // Must have either 'enum name' or 'enum {...}'.
+ // Must have either 'enum name' or 'enum {...}' or (rarely) 'enum : T { ... }'.
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
- !(AllowDeclaration && Tok.is(tok::colon))) {
+ Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
// Skip the rest of this declarator, up until the comma or semicolon.
@@ -4394,78 +4370,69 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
diagsFromTag.done();
TypeResult BaseType;
+ SourceRange BaseRange;
- // Parse the fixed underlying type.
- bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope;
- if (AllowDeclaration && Tok.is(tok::colon)) {
- bool PossibleBitfield = false;
- if (CanBeBitfield) {
- // If we're in class scope, this can either be an enum declaration with
- // an underlying type, or a declaration of a bitfield member. We try to
- // use a simple disambiguation scheme first to catch the common cases
- // (integer literal, sizeof); if it's still ambiguous, we then consider
- // anything that's a simple-type-specifier followed by '(' as an
- // expression. This suffices because function types are not valid
- // underlying types anyway.
- EnterExpressionEvaluationContext Unevaluated(
- Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
- TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind());
- // If the next token starts an expression, we know we're parsing a
- // bit-field. This is the common case.
- if (TPR == TPResult::True)
- PossibleBitfield = true;
- // If the next token starts a type-specifier-seq, it may be either a
- // a fixed underlying type or the start of a function-style cast in C++;
- // lookahead one more token to see if it's obvious that we have a
- // fixed underlying type.
- else if (TPR == TPResult::False &&
- GetLookAheadToken(2).getKind() == tok::semi) {
- // Consume the ':'.
- ConsumeToken();
- } else {
- // We have the start of a type-specifier-seq, so we have to perform
- // tentative parsing to determine whether we have an expression or a
- // type.
- TentativeParsingAction TPA(*this);
-
- // Consume the ':'.
- ConsumeToken();
+ bool CanBeBitfield = (getCurScope()->getFlags() & Scope::ClassScope) &&
+ ScopedEnumKWLoc.isInvalid() && Name;
- // If we see a type specifier followed by an open-brace, we have an
- // ambiguity between an underlying type and a C++11 braced
- // function-style cast. Resolve this by always treating it as an
- // underlying type.
- // FIXME: The standard is not entirely clear on how to disambiguate in
- // this case.
- if ((getLangOpts().CPlusPlus &&
- isCXXDeclarationSpecifier(TPResult::True) != TPResult::True) ||
- (!getLangOpts().CPlusPlus && !isDeclarationSpecifier(true))) {
- // We'll parse this as a bitfield later.
- PossibleBitfield = true;
- TPA.Revert();
- } else {
- // We have a type-specifier-seq.
- TPA.Commit();
- }
- }
- } else {
- // Consume the ':'.
- ConsumeToken();
- }
+ // Parse the fixed underlying type.
+ if (Tok.is(tok::colon)) {
+ // This might be an enum-base or part of some unrelated enclosing context.
+ //
+ // 'enum E : base' is permitted in two circumstances:
+ //
+ // 1) As a defining-type-specifier, when followed by '{'.
+ // 2) As the sole constituent of a complete declaration -- when DS is empty
+ // and the next token is ';'.
+ //
+ // The restriction to defining-type-specifiers is important to allow parsing
+ // a ? new enum E : int{}
+ // _Generic(a, enum E : int{})
+ // properly.
+ //
+ // One additional consideration applies:
+ //
+ // C++ [dcl.enum]p1:
+ // A ':' following "enum nested-name-specifier[opt] identifier" within
+ // the decl-specifier-seq of a member-declaration is parsed as part of
+ // an enum-base.
+ //
+ // Other language modes supporting enumerations with fixed underlying types
+ // do not have clear rules on this, so we disambiguate to determine whether
+ // the tokens form a bit-field width or an enum-base.
+
+ if (CanBeBitfield && !isEnumBase(CanBeOpaqueEnumDeclaration)) {
+ // Outside C++11, do not interpret the tokens as an enum-base if they do
+ // not make sense as one. In C++11, it's an error if this happens.
+ if (getLangOpts().CPlusPlus11)
+ Diag(Tok.getLocation(), diag::err_anonymous_enum_bitfield);
+ } else if (CanHaveEnumBase || !ColonIsSacred) {
+ SourceLocation ColonLoc = ConsumeToken();
+
+ // Parse a type-specifier-seq as a type. We can't just ParseTypeName here,
+ // because under -fms-extensions,
+ // enum E : int *p;
+ // declares 'enum E : int; E *p;' not 'enum E : int*; E p;'.
+ DeclSpec DS(AttrFactory);
+ ParseSpecifierQualifierList(DS, AS, DeclSpecContext::DSC_type_specifier);
+ Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext);
+ BaseType = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
- if (!PossibleBitfield) {
- SourceRange Range;
- BaseType = ParseTypeName(&Range);
+ BaseRange = SourceRange(ColonLoc, DeclaratorInfo.getSourceRange().getEnd());
if (!getLangOpts().ObjC) {
if (getLangOpts().CPlusPlus11)
- Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type);
+ Diag(ColonLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type)
+ << BaseRange;
else if (getLangOpts().CPlusPlus)
- Diag(StartLoc, diag::ext_cxx11_enum_fixed_underlying_type);
+ Diag(ColonLoc, diag::ext_cxx11_enum_fixed_underlying_type)
+ << BaseRange;
else if (getLangOpts().MicrosoftExt)
- Diag(StartLoc, diag::ext_ms_c_enum_fixed_underlying_type);
+ Diag(ColonLoc, diag::ext_ms_c_enum_fixed_underlying_type)
+ << BaseRange;
else
- Diag(StartLoc, diag::ext_clang_c_enum_fixed_underlying_type);
+ Diag(ColonLoc, diag::ext_clang_c_enum_fixed_underlying_type)
+ << BaseRange;
}
}
}
@@ -4481,14 +4448,19 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// enum foo {..}; void bar() { enum foo x; } <- use of old foo.
//
Sema::TagUseKind TUK;
- if (!AllowDeclaration) {
+ if (AllowEnumSpecifier == AllowDefiningTypeSpec::No)
TUK = Sema::TUK_Reference;
- } else if (Tok.is(tok::l_brace)) {
+ else if (Tok.is(tok::l_brace)) {
if (DS.isFriendSpecified()) {
Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
<< SourceRange(DS.getFriendSpecLoc());
ConsumeBrace();
SkipUntil(tok::r_brace, StopAtSemi);
+ // Discard any other definition-only pieces.
+ attrs.clear();
+ ScopedEnumKWLoc = SourceLocation();
+ IsScopedUsingClassTag = false;
+ BaseType = TypeResult();
TUK = Sema::TUK_Friend;
} else {
TUK = Sema::TUK_Definition;
@@ -4497,6 +4469,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
(Tok.is(tok::semi) ||
(Tok.isAtStartOfLine() &&
!isValidAfterTypeSpecifier(CanBeBitfield)))) {
+ // An opaque-enum-declaration is required to be standalone (no preceding or
+ // following tokens in the declaration). Sema enforces this separately by
+ // diagnosing anything else in the DeclSpec.
TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration;
if (Tok.isNot(tok::semi)) {
// A semicolon was missing after this declaration. Diagnose and recover.
@@ -4508,8 +4483,11 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
TUK = Sema::TUK_Reference;
}
- // If this is an elaborated type specifier, and we delayed
- // diagnostics before, just merge them into the current pool.
+ bool IsElaboratedTypeSpecifier =
+ TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend;
+
+ // If this is an elaborated type specifier nested in a larger declaration,
+ // and we delayed diagnostics before, just merge them into the current pool.
if (TUK == Sema::TUK_Reference && shouldDelayDiagsInTag) {
diagsFromTag.redelay();
}
@@ -4536,9 +4514,6 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
TemplateInfo.TemplateParams->size());
}
- if (TUK == Sema::TUK_Reference)
- ProhibitAttributes(attrs);
-
if (!Name && TUK != Sema::TUK_Definition) {
Diag(Tok, diag::err_enumerator_unnamed_no_def);
@@ -4547,6 +4522,25 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return;
}
+ // An elaborated-type-specifier has a much more constrained grammar:
+ //
+ // 'enum' nested-name-specifier[opt] identifier
+ //
+ // If we parsed any other bits, reject them now.
+ //
+ // MSVC and (for now at least) Objective-C permit a full enum-specifier
+ // or opaque-enum-declaration anywhere.
+ if (IsElaboratedTypeSpecifier && !getLangOpts().MicrosoftExt &&
+ !getLangOpts().ObjC) {
+ ProhibitAttributes(attrs);
+ if (BaseType.isUsable())
+ Diag(BaseRange.getBegin(), diag::ext_enum_base_in_type_specifier)
+ << (AllowEnumSpecifier == AllowDefiningTypeSpec::Yes) << BaseRange;
+ else if (ScopedEnumKWLoc.isValid())
+ Diag(ScopedEnumKWLoc, diag::ext_elaborated_enum_class)
+ << FixItHint::CreateRemoval(ScopedEnumKWLoc) << IsScopedUsingClassTag;
+ }
+
stripTypeAttributesOffDeclSpec(attrs, DS, TUK);
Sema::SkipBodyInfo SkipBody;
@@ -4621,7 +4615,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return;
}
- if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
+ if (Tok.is(tok::l_brace) && TUK == Sema::TUK_Definition) {
Decl *D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagDecl;
ParseEnumBody(StartLoc, D);
if (SkipBody.CheckSameAsPrevious &&
@@ -4808,6 +4802,8 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_int:
+ case tok::kw__ExtInt:
+ case tok::kw___bf16:
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
@@ -4887,7 +4883,9 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_int:
+ case tok::kw__ExtInt:
case tok::kw_half:
+ case tok::kw___bf16:
case tok::kw_float:
case tok::kw_double:
case tok::kw__Accum:
@@ -4991,6 +4989,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return true;
+ if (TryAnnotateTypeConstraint())
+ return true;
if (Tok.is(tok::identifier))
return false;
@@ -5051,7 +5051,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_char32_t:
case tok::kw_int:
+ case tok::kw__ExtInt:
case tok::kw_half:
+ case tok::kw___bf16:
case tok::kw_float:
case tok::kw_double:
case tok::kw__Accum:
@@ -5124,8 +5126,27 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
// placeholder-type-specifier
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
- return TemplateId->Kind == TNK_Concept_template &&
- (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype));
+ if (TemplateId->hasInvalidName())
+ return true;
+ // FIXME: What about type templates that have only been annotated as
+ // annot_template_id, not as annot_typename?
+ return isTypeConstraintAnnotation() &&
+ (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype));
+ }
+
+ case tok::annot_cxxscope: {
+ TemplateIdAnnotation *TemplateId =
+ NextToken().is(tok::annot_template_id)
+ ? takeTemplateIdAnnotation(NextToken())
+ : nullptr;
+ if (TemplateId && TemplateId->hasInvalidName())
+ return true;
+ // FIXME: What about type templates that have only been annotated as
+ // annot_template_id, not as annot_typename?
+ if (NextToken().is(tok::identifier) && TryAnnotateTypeConstraint())
+ return true;
+ return isTypeConstraintAnnotation() &&
+ GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype);
}
case tok::kw___declspec:
@@ -5173,7 +5194,8 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
// Parse the C++ scope specifier.
CXXScopeSpec SS;
- if (ParseOptionalCXXScopeSpecifier(SS, nullptr,
+ if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
+ /*ObjectHadErrors=*/false,
/*EnteringContext=*/true)) {
TPA.Revert();
return false;
@@ -5553,7 +5575,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
D.getContext() == DeclaratorContext::FileContext ||
D.getContext() == DeclaratorContext::MemberContext;
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
+ /*ObjectHadErrors=*/false, EnteringContext);
if (SS.isNotEmpty()) {
if (Tok.isNot(tok::star)) {
@@ -5568,8 +5591,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
return;
}
- SourceLocation Loc = ConsumeToken();
- D.SetRangeEnd(Loc);
+ SourceLocation StarLoc = ConsumeToken();
+ D.SetRangeEnd(StarLoc);
DeclSpec DS(AttrFactory);
ParseTypeQualifierListOpt(DS);
D.ExtendWithDeclSpec(DS);
@@ -5580,7 +5603,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// Sema will have to catch (syntactically invalid) pointers into global
// scope. It has to catch pointers into namespace scope anyway.
D.AddTypeInfo(DeclaratorChunk::getMemberPointer(
- SS, DS.getTypeQualifiers(), DS.getEndLoc()),
+ SS, DS.getTypeQualifiers(), StarLoc, DS.getEndLoc()),
std::move(DS.getAttributes()),
/* Don't replace range end. */ SourceLocation());
return;
@@ -5776,8 +5799,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
bool EnteringContext =
D.getContext() == DeclaratorContext::FileContext ||
D.getContext() == DeclaratorContext::MemberContext;
- ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), nullptr,
- EnteringContext);
+ ParseOptionalCXXScopeSpecifier(
+ D.getCXXScopeSpec(), /*ObjectType=*/nullptr,
+ /*ObjectHadErrors=*/false, EnteringContext);
}
if (D.getCXXScopeSpec().isValid()) {
@@ -5851,10 +5875,11 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
bool HadScope = D.getCXXScopeSpec().isValid();
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
+ /*ObjectType=*/nullptr,
+ /*ObjectHadErrors=*/false,
/*EnteringContext=*/true,
/*AllowDestructorName=*/true, AllowConstructorName,
- AllowDeductionGuide, nullptr, nullptr,
- D.getName()) ||
+ AllowDeductionGuide, nullptr, D.getName()) ||
// Once we're past the identifier, if the scope was bad, mark the
// whole declarator bad.
D.getCXXScopeSpec().isInvalid()) {
@@ -6021,11 +6046,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
while (1) {
if (Tok.is(tok::l_paren)) {
+ bool IsFunctionDeclaration = D.isFunctionDeclaratorAFunctionDeclaration();
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
ParseScope PrototypeScope(this,
Scope::FunctionPrototypeScope|Scope::DeclScope|
- (D.isFunctionDeclaratorAFunctionDeclaration()
+ (IsFunctionDeclaration
? Scope::FunctionDeclarationScope : 0));
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
@@ -6044,7 +6070,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
ParsedAttributes attrs(AttrFactory);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
+ if (IsFunctionDeclaration)
+ Actions.ActOnStartFunctionDeclarationDeclarator(D,
+ TemplateParameterDepth);
ParseFunctionDeclarator(D, attrs, T, IsAmbiguous);
+ if (IsFunctionDeclaration)
+ Actions.ActOnFinishFunctionDeclarationDeclarator(D);
PrototypeScope.Exit();
} else if (Tok.is(tok::l_square)) {
ParseBracketDeclarator(D);
@@ -6360,7 +6391,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
ProhibitAttributes(FnAttrs);
} else {
if (Tok.isNot(tok::r_paren))
- ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo,
+ ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo,
EllipsisLoc);
else if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
@@ -6578,9 +6609,9 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
/// after the opening parenthesis. This function will not parse a K&R-style
/// identifier list.
///
-/// D is the declarator being parsed. If FirstArgAttrs is non-null, then the
-/// caller parsed those arguments immediately after the open paren - they should
-/// be considered to be part of the first parameter.
+/// DeclContext is the context of the declarator being parsed. If FirstArgAttrs
+/// is non-null, then the caller parsed those attributes immediately after the
+/// open paren - they should be considered to be part of the first parameter.
///
/// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will
/// be the location of the ellipsis, if any was parsed.
@@ -6606,7 +6637,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
/// [C++11] attribute-specifier-seq parameter-declaration
///
void Parser::ParseParameterDeclarationClause(
- Declarator &D,
+ DeclaratorContext DeclaratorCtx,
ParsedAttributes &FirstArgAttrs,
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
SourceLocation &EllipsisLoc) {
@@ -6655,9 +6686,11 @@ void Parser::ParseParameterDeclarationClause(
// "LambdaExprParameterContext", because we must accept either
// 'declarator' or 'abstract-declarator' here.
Declarator ParmDeclarator(
- DS, D.getContext() == DeclaratorContext::LambdaExprContext
- ? DeclaratorContext::LambdaExprParameterContext
- : DeclaratorContext::PrototypeContext);
+ DS, DeclaratorCtx == DeclaratorContext::RequiresExprContext
+ ? DeclaratorContext::RequiresExprContext
+ : DeclaratorCtx == DeclaratorContext::LambdaExprContext
+ ? DeclaratorContext::LambdaExprParameterContext
+ : DeclaratorContext::PrototypeContext);
ParseDeclarator(ParmDeclarator);
// Parse GNU attributes, if present.
@@ -6700,6 +6733,31 @@ void Parser::ParseParameterDeclarationClause(
Actions.containsUnexpandedParameterPacks(ParmDeclarator))
DiagnoseMisplacedEllipsisInDeclarator(ConsumeToken(), ParmDeclarator);
+ // Now we are at the point where declarator parsing is finished.
+ //
+ // Try to catch keywords in place of the identifier in a declarator, and
+ // in particular the common case where:
+ // 1 identifier comes at the end of the declarator
+ // 2 if the identifier is dropped, the declarator is valid but anonymous
+ // (no identifier)
+ // 3 declarator parsing succeeds, and then we have a trailing keyword,
+ // which is never valid in a param list (e.g. missing a ',')
+ // And we can't handle this in ParseDeclarator because in general keywords
+ // may be allowed to follow the declarator. (And in some cases there'd be
+ // better recovery like inserting punctuation). ParseDeclarator is just
+ // treating this as an anonymous parameter, and fortunately at this point
+ // we've already almost done that.
+ //
+ // We care about case 1) where the declarator type should be known, and
+ // the identifier should be null.
+ if (!ParmDeclarator.isInvalidType() && !ParmDeclarator.hasName()) {
+ if (Tok.getIdentifierInfo() &&
+ Tok.getIdentifierInfo()->isKeyword(getLangOpts())) {
+ Diag(Tok, diag::err_keyword_as_parameter) << PP.getSpelling(Tok);
+ // Consume the keyword.
+ ConsumeToken();
+ }
+ }
// Inform the actions module about the parameter declarator, so it gets
// added to the current scope.
Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator);
@@ -6711,7 +6769,7 @@ void Parser::ParseParameterDeclarationClause(
SourceLocation EqualLoc = Tok.getLocation();
// Parse the default argument
- if (D.getContext() == DeclaratorContext::MemberContext) {
+ if (DeclaratorCtx == DeclaratorContext::MemberContext) {
// If we're inside a class definition, cache the tokens
// corresponding to the default argument. We'll actually parse
// them when we see the end of the class definition.