summaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp397
1 files changed, 301 insertions, 96 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp
index 73b4f50fda46..cdc3506d5c68 100644
--- a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp
+++ b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp
@@ -86,8 +86,8 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) {
}
/// Check if the a start and end source location expand to the same macro.
-bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc,
- SourceLocation EndLoc) {
+static bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
if (!StartLoc.isMacroID() || !EndLoc.isMacroID())
return false;
@@ -335,6 +335,7 @@ unsigned Parser::ParseAttributeArgsCommon(
ConsumeParen();
bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(*AttrName);
+ bool AttributeIsTypeArgAttr = attributeIsTypeArgAttr(*AttrName);
// Interpret "kw_this" as an identifier if the attributed requests it.
if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
@@ -346,7 +347,7 @@ unsigned Parser::ParseAttributeArgsCommon(
bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName) ||
attributeHasVariadicIdentifierArg(*AttrName);
ParsedAttr::Kind AttrKind =
- ParsedAttr::getKind(AttrName, ScopeName, Syntax);
+ ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax);
// If we don't know how to parse this attribute, but this is the only
// token in this argument, assume it's meant to be an identifier.
@@ -360,6 +361,7 @@ unsigned Parser::ParseAttributeArgsCommon(
ArgExprs.push_back(ParseIdentifierLoc());
}
+ ParsedType TheParsedType;
if (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren)) {
// Eat the comma.
if (!ArgExprs.empty())
@@ -372,8 +374,17 @@ unsigned Parser::ParseAttributeArgsCommon(
Tok.setKind(tok::identifier);
ExprResult ArgExpr;
- if (Tok.is(tok::identifier) &&
- attributeHasVariadicIdentifierArg(*AttrName)) {
+ if (AttributeIsTypeArgAttr) {
+ TypeResult T = ParseTypeName();
+ if (T.isInvalid()) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return 0;
+ }
+ if (T.isUsable())
+ TheParsedType = T.get();
+ break; // FIXME: Multiple type arguments are not implemented.
+ } else if (Tok.is(tok::identifier) &&
+ attributeHasVariadicIdentifierArg(*AttrName)) {
ArgExprs.push_back(ParseIdentifierLoc());
} else {
bool Uneval = attributeParsedArgsUnevaluated(*AttrName);
@@ -397,14 +408,20 @@ unsigned Parser::ParseAttributeArgsCommon(
SourceLocation RParen = Tok.getLocation();
if (!ExpectAndConsume(tok::r_paren)) {
SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
- Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
- ArgExprs.data(), ArgExprs.size(), Syntax);
+
+ if (AttributeIsTypeArgAttr && !TheParsedType.get().isNull()) {
+ Attrs.addNewTypeAttr(AttrName, SourceRange(AttrNameLoc, RParen),
+ ScopeName, ScopeLoc, TheParsedType, Syntax);
+ } else {
+ Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
+ ArgExprs.data(), ArgExprs.size(), Syntax);
+ }
}
if (EndLoc)
*EndLoc = RParen;
- return static_cast<unsigned>(ArgExprs.size());
+ return static_cast<unsigned>(ArgExprs.size() + !TheParsedType.get().isNull());
}
/// Parse the arguments to a parameterized GNU attribute or
@@ -421,7 +438,7 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
ParsedAttr::Kind AttrKind =
- ParsedAttr::getKind(AttrName, ScopeName, Syntax);
+ ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax);
if (AttrKind == ParsedAttr::AT_Availability) {
ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
@@ -471,7 +488,7 @@ unsigned Parser::ParseClangAttributeArgs(
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
ParsedAttr::Kind AttrKind =
- ParsedAttr::getKind(AttrName, ScopeName, Syntax);
+ ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax);
switch (AttrKind) {
default:
@@ -1672,9 +1689,9 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
if (!AL.isCXX11Attribute() && !AL.isC2xAttribute())
continue;
if (AL.getKind() == ParsedAttr::UnknownAttribute)
- Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL.getName();
+ Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL;
else {
- Diag(AL.getLoc(), DiagID) << AL.getName();
+ Diag(AL.getLoc(), DiagID) << AL;
AL.setInvalid();
}
}
@@ -1724,9 +1741,10 @@ void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs,
/// [C++11/C11] static_assert-declaration
/// others... [FIXME]
///
-Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
- SourceLocation &DeclEnd,
- ParsedAttributesWithRange &attrs) {
+Parser::DeclGroupPtrTy
+Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd,
+ ParsedAttributesWithRange &attrs,
+ SourceLocation *DeclSpecStart) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
// Must temporarily exit the objective-c container scope for
// parsing c none objective-c decls.
@@ -1746,8 +1764,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
SourceLocation InlineLoc = ConsumeToken();
return ParseNamespace(Context, DeclEnd, InlineLoc);
}
- return ParseSimpleDeclaration(Context, DeclEnd, attrs,
- true);
+ return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr,
+ DeclSpecStart);
case tok::kw_namespace:
ProhibitAttributes(attrs);
return ParseNamespace(Context, DeclEnd);
@@ -1760,7 +1778,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
break;
default:
- return ParseSimpleDeclaration(Context, DeclEnd, attrs, true);
+ return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr,
+ DeclSpecStart);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -1785,11 +1804,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
/// If FRI is non-null, we might be parsing a for-range-declaration instead
/// 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(DeclaratorContext Context,
- SourceLocation &DeclEnd,
- ParsedAttributesWithRange &Attrs,
- bool RequireSemi, ForRangeInit *FRI) {
+///
+/// DeclSpecStart is used when decl-specifiers are parsed before parsing
+/// the Declaration. The SourceLocation for this Decl is set to
+/// DeclSpecStart if DeclSpecStart is non-null.
+Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
+ DeclaratorContext Context, SourceLocation &DeclEnd,
+ ParsedAttributesWithRange &Attrs, bool RequireSemi, ForRangeInit *FRI,
+ SourceLocation *DeclSpecStart) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
@@ -1819,6 +1841,9 @@ Parser::ParseSimpleDeclaration(DeclaratorContext Context,
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
+ if (DeclSpecStart)
+ DS.SetRangeStart(*DeclSpecStart);
+
DS.takeAttributesFrom(Attrs);
return ParseDeclGroup(DS, Context, &DeclEnd, FRI);
}
@@ -1989,6 +2014,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
return nullptr;
}
+ if (Tok.is(tok::kw_requires))
+ ParseTrailingRequiresClause(D);
+
// Save late-parsed attributes for now; they need to be parsed in the
// appropriate function scope after the function Decl has been constructed.
// These will be parsed in ParseFunctionDefinition or ParseLexedAttrList.
@@ -2075,6 +2103,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
bool IsForRangeLoop = false;
if (TryConsumeToken(tok::colon, FRI->ColonLoc)) {
IsForRangeLoop = true;
+ if (getLangOpts().OpenMP)
+ Actions.startOpenMPCXXRangeFor();
if (Tok.is(tok::l_brace))
FRI->RangeExpr = ParseBraceInitializer();
else
@@ -2138,6 +2168,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
ParseDeclarator(D);
if (!D.isInvalidType()) {
+ // C++2a [dcl.decl]p1
+ // init-declarator:
+ // declarator initializer[opt]
+ // declarator requires-clause
+ if (Tok.is(tok::kw_requires))
+ ParseTrailingRequiresClause(D);
Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
D.complete(ThisDecl);
if (ThisDecl)
@@ -2170,7 +2206,7 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) {
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
- ExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi, StopBeforeMatch);
return true;
@@ -2322,7 +2358,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
<< 0 /* default */;
else
- Diag(ConsumeToken(), diag::err_default_special_members);
+ Diag(ConsumeToken(), diag::err_default_special_members)
+ << getLangOpts().CPlusPlus2a;
} else {
InitializerScopeRAII InitScope(*this, D, ThisDecl);
@@ -2489,7 +2526,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
// Issue diagnostic and remove constexpr specifier if present.
if (DS.hasConstexprSpecifier() && DSC != DeclSpecContext::DSC_condition) {
Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr)
- << (DS.getConstexprSpecifier() == CSK_consteval);
+ << DS.getConstexprSpecifier();
DS.ClearConstexprSpec();
}
}
@@ -2902,28 +2939,30 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
IdentifierInfo *Name = AfterScope.getIdentifierInfo();
Sema::NameClassification Classification = Actions.ClassifyName(
getCurScope(), SS, Name, AfterScope.getLocation(), Next,
- /*IsAddressOfOperand=*/false, /*CCC=*/nullptr);
+ /*CCC=*/nullptr);
switch (Classification.getKind()) {
case Sema::NC_Error:
SkipMalformedDecl();
return true;
case Sema::NC_Keyword:
- case Sema::NC_NestedNameSpecifier:
- llvm_unreachable("typo correction and nested name specifiers not "
- "possible here");
+ llvm_unreachable("typo correction is not possible here");
case Sema::NC_Type:
case Sema::NC_TypeTemplate:
+ case Sema::NC_UndeclaredNonType:
+ case Sema::NC_UndeclaredTemplate:
// Not a previously-declared non-type entity.
MightBeDeclarator = false;
break;
case Sema::NC_Unknown:
- case Sema::NC_Expression:
+ case Sema::NC_NonType:
+ case Sema::NC_DependentNonType:
+ case Sema::NC_ContextIndependentExpr:
case Sema::NC_VarTemplate:
case Sema::NC_FunctionTemplate:
- case Sema::NC_UndeclaredTemplate:
+ case Sema::NC_Concept:
// Might be a redeclaration of a prior entity.
break;
}
@@ -3139,7 +3178,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
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
@@ -3151,7 +3190,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeAnnotationToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
- AnnotateTemplateIdTokenAsType();
+ AnnotateTemplateIdTokenAsType(SS);
+ continue;
+ }
+
+ if (Next.is(tok::annot_template_id) &&
+ static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
+ ->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;
}
@@ -3197,6 +3248,10 @@ 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 (isTypeConstraintAnnotation())
+ continue;
// Eat the scope spec so the identifier is current.
ConsumeAnnotationToken();
ParsedAttributesWithRange Attrs(AttrFactory);
@@ -3346,6 +3401,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 (isTypeConstraintAnnotation())
+ continue;
ParsedAttributesWithRange Attrs(AttrFactory);
if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) {
if (!Attrs.empty()) {
@@ -3395,9 +3454,51 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
}
- // type-name
+ // type-name or placeholder-specifier
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
+ if (TemplateId->Kind == TNK_Concept_template) {
+ 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
@@ -3410,12 +3511,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;
}
@@ -3549,6 +3651,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isStorageClass = true;
break;
case tok::kw__Thread_local:
+ if (!getLangOpts().C11)
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local,
Loc, PrevSpec, DiagID);
isStorageClass = true;
@@ -3577,7 +3681,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumedEnd = ExplicitLoc;
ConsumeToken(); // kw_explicit
if (Tok.is(tok::l_paren)) {
- if (getLangOpts().CPlusPlus2a) {
+ if (getLangOpts().CPlusPlus2a || isExplicitBool() == TPResult::True) {
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_explicit_bool
+ : diag::ext_explicit_bool);
+
ExprResult ExplicitExpr(static_cast<Expr *>(nullptr));
BalancedDelimiterTracker Tracker(*this, tok::l_paren);
Tracker.consumeOpen();
@@ -3590,8 +3698,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get());
} else
Tracker.skipToEnd();
- } else
+ } else {
Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool);
+ }
}
isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID,
ExplicitSpec, CloseParenLoc);
@@ -3599,14 +3708,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
case tok::kw__Noreturn:
if (!getLangOpts().C11)
- Diag(Loc, diag::ext_c11_noreturn);
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID);
break;
// alignment-specifier
case tok::kw__Alignas:
if (!getLangOpts().C11)
- Diag(Tok, diag::ext_c11_alignment) << Tok.getName();
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
ParseAlignmentSpecifier(DS.getAttributes());
continue;
@@ -3626,15 +3735,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID);
break;
- // constexpr
+ // constexpr, consteval, constinit specifiers
case tok::kw_constexpr:
isInvalid = DS.SetConstexprSpec(CSK_constexpr, Loc, PrevSpec, DiagID);
break;
-
- // consteval
case tok::kw_consteval:
isInvalid = DS.SetConstexprSpec(CSK_consteval, Loc, PrevSpec, DiagID);
break;
+ case tok::kw_constinit:
+ isInvalid = DS.SetConstexprSpec(CSK_constinit, Loc, PrevSpec, DiagID);
+ break;
// type-specifier
case tok::kw_short:
@@ -3662,10 +3772,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DiagID);
break;
case tok::kw__Complex:
+ if (!getLangOpts().C99)
+ Diag(Tok, diag::ext_c99_feature) << Tok.getName();
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
DiagID);
break;
case tok::kw__Imaginary:
+ if (!getLangOpts().C99)
+ Diag(Tok, diag::ext_c99_feature) << Tok.getName();
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
DiagID);
break;
@@ -3746,6 +3860,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
break;
case tok::kw_bool:
case tok::kw__Bool:
+ if (Tok.is(tok::kw__Bool) && !getLangOpts().C99)
+ Diag(Tok, diag::ext_c99_feature) << Tok.getName();
+
if (Tok.is(tok::kw_bool) &&
DS.getTypeSpecType() != DeclSpec::TST_unspecified &&
DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
@@ -3889,6 +4006,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If the _Atomic keyword is immediately followed by a left parenthesis,
// it is interpreted as a type specifier (with a type name), not as a
// type qualifier.
+ if (!getLangOpts().C11)
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
+
if (NextToken().is(tok::l_paren)) {
ParseAtomicSpecifier(DS);
continue;
@@ -3907,9 +4027,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
PrevSpec = Tok.getIdentifierInfo()->getNameStart();
isInvalid = true;
break;
- };
+ }
LLVM_FALLTHROUGH;
case tok::kw_private:
+ // It's fine (but redundant) to check this for __generic on the
+ // fallthrough path; we only form the __generic token in OpenCL mode.
+ if (!getLangOpts().OpenCL)
+ goto DoneWithDeclSpec;
+ LLVM_FALLTHROUGH;
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -4081,7 +4206,7 @@ void Parser::ParseStructDeclaration(
/// [OBC] '@' 'defs' '(' class-name ')'
///
void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
- unsigned TagType, Decl *TagDecl) {
+ DeclSpec::TST TagType, Decl *TagDecl) {
PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc,
"parsing struct/union body");
assert(!getLangOpts().CPlusPlus && "C++ declarations not supported");
@@ -4131,6 +4256,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
continue;
}
+ if (tok::isPragmaAnnotation(Tok.getKind())) {
+ Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
+ << DeclSpec::getSpecifierName(
+ TagType, Actions.getASTContext().getPrintingPolicy());
+ ConsumeAnnotationToken();
+ continue;
+ }
+
if (!Tok.is(tok::at)) {
auto CFieldCallback = [&](ParsingFieldDeclarator &FD) {
// Install the declarator into the current TagDecl.
@@ -4632,8 +4765,10 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
ExprResult AssignedVal;
EnumAvailabilityDiags.emplace_back(*this);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
if (TryConsumeToken(tok::equal, EqualLoc)) {
- AssignedVal = ParseConstantExpression();
+ AssignedVal = ParseConstantExpressionInExprEvalContext();
if (AssignedVal.isInvalid())
SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch);
}
@@ -4925,6 +5060,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;
@@ -5038,8 +5175,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::annot_decltype:
case tok::kw_constexpr:
- // C++20 consteval.
+ // C++20 consteval and constinit.
case tok::kw_consteval:
+ case tok::kw_constinit:
// C11 _Atomic
case tok::kw__Atomic:
@@ -5054,6 +5192,16 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
return !DisambiguatingWithExpression ||
!isStartOfObjCClassMessageMissingOpenBracket();
+ // placeholder-type-specifier
+ case tok::annot_template_id: {
+ return isTypeConstraintAnnotation() &&
+ (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype));
+ }
+ case tok::annot_cxxscope:
+ if (NextToken().is(tok::identifier) && TryAnnotateTypeConstraint())
+ return true;
+ return isTypeConstraintAnnotation() &&
+ GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype);
case tok::kw___declspec:
case tok::kw___cdecl:
case tok::kw___stdcall:
@@ -5286,6 +5434,8 @@ void Parser::ParseTypeQualifierListOpt(
case tok::kw__Atomic:
if (!AtomicAllowed)
goto DoneWithTypeQuals;
+ if (!getLangOpts().C11)
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID,
getLangOpts());
break;
@@ -5945,11 +6095,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);".
@@ -5968,10 +6119,31 @@ 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);
+ } else if (Tok.is(tok::kw_requires) && D.hasGroupingParens()) {
+ // This declarator is declaring a function, but the requires clause is
+ // in the wrong place:
+ // void (f() requires true);
+ // instead of
+ // void f() requires true;
+ // or
+ // void (f()) requires true;
+ Diag(Tok, diag::err_requires_clause_inside_parens);
+ ConsumeToken();
+ ExprResult TrailingRequiresClause = Actions.CorrectDelayedTyposInExpr(
+ ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true));
+ if (TrailingRequiresClause.isUsable() && D.isFunctionDeclarator() &&
+ !D.hasTrailingRequiresClause())
+ // We're already ill-formed if we got here but we'll accept it anyway.
+ D.setTrailingRequiresClause(TrailingRequiresClause.get());
} else {
break;
}
@@ -6152,6 +6324,47 @@ void Parser::ParseParenDeclarator(Declarator &D) {
PrototypeScope.Exit();
}
+void Parser::InitCXXThisScopeForDeclaratorIfRelevant(
+ const Declarator &D, const DeclSpec &DS,
+ llvm::Optional<Sema::CXXThisScopeRAII> &ThisScope) {
+ // 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.
+ // FIXME: currently, "static" case isn't handled correctly.
+ bool IsCXX11MemberFunction = getLangOpts().CPlusPlus11 &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ (D.getContext() == DeclaratorContext::MemberContext
+ ? !D.getDeclSpec().isFriendSpecified()
+ : D.getContext() == DeclaratorContext::FileContext &&
+ D.getCXXScopeSpec().isValid() &&
+ Actions.CurContext->isRecord());
+ if (!IsCXX11MemberFunction)
+ return;
+
+ Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers());
+ if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14)
+ Q.addConst();
+ // FIXME: Collect C++ address spaces.
+ // If there are multiple different address spaces, the source is invalid.
+ // Carry on using the first addr space for the qualifiers of 'this'.
+ // The diagnostic will be given later while creating the function
+ // prototype for the method.
+ if (getLangOpts().OpenCLCPlusPlus) {
+ for (ParsedAttr &attr : DS.getAttributes()) {
+ LangAS ASIdx = attr.asOpenCLLangAS();
+ if (ASIdx != LangAS::Default) {
+ Q.addAddressSpace(ASIdx);
+ break;
+ }
+ }
+ }
+ ThisScope.emplace(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q,
+ IsCXX11MemberFunction);
+}
+
/// ParseFunctionDeclarator - We are after the identifier and have parsed the
/// declarator D up to a paren, which indicates that we are parsing function
/// arguments.
@@ -6165,7 +6378,8 @@ void Parser::ParseParenDeclarator(Declarator &D) {
///
/// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt],
/// (C++11) ref-qualifier[opt], exception-specification[opt],
-/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt].
+/// (C++11) attribute-specifier-seq[opt], (C++11) trailing-return-type[opt] and
+/// (C++2a) the trailing requires-clause.
///
/// [C++11] exception-specification:
/// dynamic-exception-specification
@@ -6226,7 +6440,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);
@@ -6260,43 +6474,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc))
EndLoc = RefQualifierLoc;
- // 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.
- // FIXME: currently, "static" case isn't handled correctly.
- bool IsCXX11MemberFunction =
- getLangOpts().CPlusPlus11 &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
- (D.getContext() == DeclaratorContext::MemberContext
- ? !D.getDeclSpec().isFriendSpecified()
- : D.getContext() == DeclaratorContext::FileContext &&
- D.getCXXScopeSpec().isValid() &&
- Actions.CurContext->isRecord());
-
- Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers());
- if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14)
- Q.addConst();
- // FIXME: Collect C++ address spaces.
- // If there are multiple different address spaces, the source is invalid.
- // Carry on using the first addr space for the qualifiers of 'this'.
- // The diagnostic will be given later while creating the function
- // prototype for the method.
- if (getLangOpts().OpenCLCPlusPlus) {
- for (ParsedAttr &attr : DS.getAttributes()) {
- LangAS ASIdx = attr.asOpenCLLangAS();
- if (ASIdx != LangAS::Default) {
- Q.addAddressSpace(ASIdx);
- break;
- }
- }
- }
-
- Sema::CXXThisScopeRAII ThisScope(
- Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q,
- IsCXX11MemberFunction);
+ llvm::Optional<Sema::CXXThisScopeRAII> ThisScope;
+ InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope);
// Parse exception-specification[opt].
bool Delayed = D.isFirstDeclarationOfMember() &&
@@ -6479,9 +6658,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.
@@ -6507,10 +6686,23 @@ 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) {
+
+ // Avoid exceeding the maximum function scope depth.
+ // See https://bugs.llvm.org/show_bug.cgi?id=19607
+ // Note Sema::ActOnParamDeclarator calls ParmVarDecl::setScopeInfo with
+ // getFunctionPrototypeDepth() - 1.
+ if (getCurScope()->getFunctionPrototypeDepth() - 1 >
+ ParmVarDecl::getMaxFunctionScopeDepth()) {
+ Diag(Tok.getLocation(), diag::err_function_scope_depth_exceeded)
+ << ParmVarDecl::getMaxFunctionScopeDepth();
+ cutOffParsing();
+ return;
+ }
+
do {
// FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
// before deciding this was a parameter-declaration-clause.
@@ -6543,14 +6735,27 @@ 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.
MaybeParseGNUAttributes(ParmDeclarator);
+ if (Tok.is(tok::kw_requires)) {
+ // User tried to define a requires clause in a parameter declaration,
+ // which is surely not a function declaration.
+ // void f(int (*g)(int, int) requires true);
+ Diag(Tok,
+ diag::err_requires_clause_on_declarator_not_declaring_a_function);
+ ConsumeToken();
+ Actions.CorrectDelayedTyposInExpr(
+ ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true));
+ }
+
// Remember this parsed parameter in ParamInfo.
IdentifierInfo *ParmII = ParmDeclarator.getIdentifier();
@@ -6588,7 +6793,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.