aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Parse/ParseDecl.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:11 +0000
commite3b557809604d036af6e00c60f012c2025b59a5e (patch)
tree8a11ba2269a3b669601e2fd41145b174008f4da8 /clang/lib/Parse/ParseDecl.cpp
parent08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff)
Diffstat (limited to 'clang/lib/Parse/ParseDecl.cpp')
-rw-r--r--clang/lib/Parse/ParseDecl.cpp414
1 files changed, 303 insertions, 111 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index aef9909a7c97..c7fd1156928c 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -25,10 +25,10 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaDiagnostic.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
+#include <optional>
using namespace clang;
@@ -449,10 +449,8 @@ unsigned Parser::ParseAttributeArgsCommon(
? Sema::ExpressionEvaluationContext::Unevaluated
: Sema::ExpressionEvaluationContext::ConstantEvaluated);
- CommaLocsTy CommaLocs;
ExprVector ParsedExprs;
- if (ParseExpressionList(ParsedExprs, CommaLocs,
- llvm::function_ref<void()>(),
+ if (ParseExpressionList(ParsedExprs, llvm::function_ref<void()>(),
/*FailImmediatelyOnInvalidExpr=*/true,
/*EarlyTypoCorrection=*/true)) {
SkipUntil(tok::r_paren, StopAtSemi);
@@ -536,7 +534,7 @@ void Parser::ParseGNUAttributeArgs(
// These may refer to the function arguments, but need to be parsed early to
// participate in determining whether it's a redeclaration.
- llvm::Optional<ParseScope> PrototypeScope;
+ std::optional<ParseScope> PrototypeScope;
if (normalizeAttrName(AttrName->getName()) == "enable_if" &&
D && D->isFunctionDeclarator()) {
DeclaratorChunk::FunctionTypeInfo FTI = D->getFunctionTypeInfo();
@@ -914,6 +912,17 @@ void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) {
ParsedAttr::AS_Keyword);
}
+bool Parser::isHLSLQualifier(const Token &Tok) const {
+ return Tok.is(tok::kw_groupshared);
+}
+
+void Parser::ParseHLSLQualifiers(ParsedAttributes &Attrs) {
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+ Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ ParsedAttr::AS_Keyword);
+}
+
void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) {
// Treat these like attributes, even though they're type specifiers.
while (true) {
@@ -1417,7 +1426,7 @@ void Parser::ParseExternalSourceSymbolAttribute(
ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(),
GeneratedDeclaration};
Attrs.addNew(&ExternalSourceSymbol, SourceRange(Loc, T.getCloseLocation()),
- ScopeName, ScopeLoc, Args, llvm::array_lengthof(Args), Syntax);
+ ScopeName, ScopeLoc, Args, std::size(Args), Syntax);
}
/// Parse the contents of the "objc_bridge_related" attribute.
@@ -1538,7 +1547,7 @@ void Parser::ParseSwiftNewTypeAttribute(
ArgsUnion Args[] = {SwiftType};
Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, T.getCloseLocation()),
- ScopeName, ScopeLoc, Args, llvm::array_lengthof(Args), Syntax);
+ ScopeName, ScopeLoc, Args, std::size(Args), Syntax);
}
void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
@@ -1680,7 +1689,7 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID,
Lexer::getRawToken(Attrs.Range.getBegin(), FirstLSquare, SM, LangOpts);
if (FirstLSquare.is(tok::l_square)) {
- llvm::Optional<Token> SecondLSquare =
+ std::optional<Token> SecondLSquare =
Lexer::findNextToken(FirstLSquare.getLocation(), SM, LangOpts);
if (SecondLSquare && SecondLSquare->is(tok::l_square)) {
@@ -1787,6 +1796,11 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
}
return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs,
true, nullptr, DeclSpecStart);
+
+ case tok::kw_cbuffer:
+ case tok::kw_tbuffer:
+ SingleDecl = ParseHLSLBuffer(DeclEnd);
+ break;
case tok::kw_namespace:
ProhibitAttributes(DeclAttrs);
ProhibitAttributes(DeclSpecAttrs);
@@ -2049,6 +2063,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
return nullptr;
}
+ if (getLangOpts().HLSL)
+ MaybeParseHLSLSemantics(D);
+
if (Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);
@@ -2078,10 +2095,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
<< (Fixit ? FixItHint::CreateInsertion(D.getBeginLoc(), "_Noreturn ")
: FixItHint());
}
- }
- // Check to see if we have a function *definition* which must have a body.
- if (D.isFunctionDeclarator()) {
+ // Check to see if we have a function *definition* which must have a body.
if (Tok.is(tok::equal) && NextToken().is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteAfterFunctionEquals(D);
@@ -2121,7 +2136,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- if (isDeclarationSpecifier()) {
+ if (isDeclarationSpecifier(ImplicitTypenameContext::No)) {
// 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
@@ -2220,6 +2235,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
DiagnoseAndSkipExtendedMicrosoftTypeAttributes();
ParseDeclarator(D);
+
+ if (getLangOpts().HLSL)
+ MaybeParseHLSLSemantics(D);
+
if (!D.isInvalidType()) {
// C++2a [dcl.decl]p1
// init-declarator:
@@ -2244,7 +2263,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Okay, there was no semicolon and one was expected. If we see a
// declaration specifier, just assume it was missing and continue parsing.
// Otherwise things are very confused and we skip to recover.
- if (!isDeclarationSpecifier()) {
+ if (!isDeclarationSpecifier(ImplicitTypenameContext::No)) {
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
TryConsumeToken(tok::semi);
}
@@ -2402,8 +2421,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
// Recover as if it were an explicit specialization.
TemplateParameterLists FakedParamLists;
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None,
- LAngleLoc, nullptr));
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
+ std::nullopt, LAngleLoc, nullptr));
ThisDecl =
Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D);
@@ -2478,7 +2497,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
T.consumeOpen();
ExprVector Exprs;
- CommaLocsTy CommaLocs;
InitializerScopeRAII InitScope(*this, D, ThisDecl);
@@ -2503,7 +2521,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
// ProduceConstructorSignatureHelp only on VarDecls.
ExpressionStarts = SetPreferredType;
}
- if (ParseExpressionList(Exprs, CommaLocs, ExpressionStarts)) {
+ if (ParseExpressionList(Exprs, ExpressionStarts)) {
if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) {
Actions.ProduceConstructorSignatureHelp(
ThisVarDecl->getType()->getCanonicalTypeInternal(),
@@ -2516,10 +2534,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
} else {
// Match the ')'.
T.consumeClose();
-
- assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
- "Unexpected number of commas!");
-
InitScope.pop();
ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(),
@@ -2563,12 +2577,14 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
/// type-qualifier specifier-qualifier-list[opt]
/// [GNU] attributes specifier-qualifier-list[opt]
///
-void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
- DeclSpecContext DSC) {
+void Parser::ParseSpecifierQualifierList(
+ DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename,
+ AccessSpecifier AS, DeclSpecContext DSC) {
/// specifier-qualifier-list is a subset of declaration-specifiers. Just
/// parse declaration-specifiers and complain about extra stuff.
/// TODO: diagnose attribute-specifiers and alignment-specifiers.
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC, nullptr,
+ AllowImplicitTypename);
// Validate declspec for type-name.
unsigned Specs = DS.getParsedSpecifiers();
@@ -2599,6 +2615,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
if (DS.hasExplicitSpecifier())
Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
+ if (DS.isNoreturnSpecified())
+ Diag(DS.getNoreturnSpecLoc(), diag::err_typename_invalid_functionspec);
DS.ClearFunctionSpecs();
}
@@ -2800,7 +2818,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
}
}
// Fall through.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case tok::comma:
case tok::equal:
@@ -2876,24 +2894,50 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
/// DeclaratorContext enumerator values.
Parser::DeclSpecContext
Parser::getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context) {
- if (Context == DeclaratorContext::Member)
+ switch (Context) {
+ case DeclaratorContext::Member:
return DeclSpecContext::DSC_class;
- if (Context == DeclaratorContext::File)
+ case DeclaratorContext::File:
return DeclSpecContext::DSC_top_level;
- if (Context == DeclaratorContext::TemplateParam)
+ case DeclaratorContext::TemplateParam:
return DeclSpecContext::DSC_template_param;
- if (Context == DeclaratorContext::TemplateArg ||
- Context == DeclaratorContext::TemplateTypeArg)
+ case DeclaratorContext::TemplateArg:
+ return DeclSpecContext::DSC_template_arg;
+ case DeclaratorContext::TemplateTypeArg:
return DeclSpecContext::DSC_template_type_arg;
- if (Context == DeclaratorContext::TrailingReturn ||
- Context == DeclaratorContext::TrailingReturnVar)
+ case DeclaratorContext::TrailingReturn:
+ case DeclaratorContext::TrailingReturnVar:
return DeclSpecContext::DSC_trailing;
- if (Context == DeclaratorContext::AliasDecl ||
- Context == DeclaratorContext::AliasTemplate)
+ case DeclaratorContext::AliasDecl:
+ case DeclaratorContext::AliasTemplate:
return DeclSpecContext::DSC_alias_declaration;
- if (Context == DeclaratorContext::Association)
+ case DeclaratorContext::Association:
return DeclSpecContext::DSC_association;
- return DeclSpecContext::DSC_normal;
+ case DeclaratorContext::TypeName:
+ return DeclSpecContext::DSC_type_specifier;
+ case DeclaratorContext::Condition:
+ return DeclSpecContext::DSC_condition;
+ case DeclaratorContext::ConversionId:
+ return DeclSpecContext::DSC_conv_operator;
+ case DeclaratorContext::Prototype:
+ case DeclaratorContext::ObjCResult:
+ case DeclaratorContext::ObjCParameter:
+ case DeclaratorContext::KNRTypeList:
+ case DeclaratorContext::FunctionalCast:
+ case DeclaratorContext::Block:
+ case DeclaratorContext::ForInit:
+ case DeclaratorContext::SelectionInit:
+ case DeclaratorContext::CXXNew:
+ case DeclaratorContext::CXXCatch:
+ case DeclaratorContext::ObjCCatch:
+ case DeclaratorContext::BlockLiteral:
+ case DeclaratorContext::LambdaExpr:
+ case DeclaratorContext::LambdaExprParameter:
+ case DeclaratorContext::RequiresExpr:
+ return DeclSpecContext::DSC_normal;
+ }
+
+ llvm_unreachable("Missing DeclaratorContext case");
}
/// ParseAlignArgument - Parse the argument to an alignment-specifier.
@@ -3129,11 +3173,10 @@ static void SetupFixedPointError(const LangOptions &LangOpts,
/// [OpenCL] '__kernel'
/// 'friend': [C++ dcl.friend]
/// 'constexpr': [C++0x dcl.constexpr]
-void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
- const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS,
- DeclSpecContext DSContext,
- LateParsedAttrList *LateAttrs) {
+void Parser::ParseDeclarationSpecifiers(
+ DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS,
+ DeclSpecContext DSContext, LateParsedAttrList *LateAttrs,
+ ImplicitTypenameContext AllowImplicitTypename) {
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
@@ -3142,6 +3185,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DS.SetRangeEnd(SourceLocation());
}
+ // If we are in a operator context, convert it back into a type specifier
+ // context for better error handling later on.
+ if (DSContext == DeclSpecContext::DSC_conv_operator) {
+ // No implicit typename here.
+ AllowImplicitTypename = ImplicitTypenameContext::No;
+ DSContext = DeclSpecContext::DSC_type_specifier;
+ }
+
bool EnteringContext = (DSContext == DeclSpecContext::DSC_class ||
DSContext == DeclSpecContext::DSC_top_level);
bool AttrsLastTime = false;
@@ -3266,13 +3317,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
return;
}
- if (getCurScope()->getFnParent() || getCurScope()->getBlockParent())
- CCC = Sema::PCC_LocalDeclarationSpecifiers;
- else if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
+ // Class context can appear inside a function/block, so prioritise that.
+ if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
CCC = DSContext == DeclSpecContext::DSC_class ? Sema::PCC_MemberTemplate
: Sema::PCC_Template;
else if (DSContext == DeclSpecContext::DSC_class)
CCC = Sema::PCC_Class;
+ else if (getCurScope()->getFnParent() || getCurScope()->getBlockParent())
+ CCC = Sema::PCC_LocalDeclarationSpecifiers;
else if (CurParsedObjCImpl)
CCC = Sema::PCC_ObjCImplementation;
@@ -3329,7 +3381,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DSContext == DeclSpecContext::DSC_class) &&
TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) &&
- isConstructorDeclarator(/*Unqualified=*/false)) {
+ isConstructorDeclarator(/*Unqualified=*/false,
+ /*DeductionGuide=*/false,
+ DS.isFriendSpecified())) {
// 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
@@ -3341,7 +3395,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeAnnotationToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename);
continue;
}
@@ -3368,6 +3422,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeAnnotationToken(); // The typename
}
+ if (AllowImplicitTypename == ImplicitTypenameContext::Yes &&
+ Next.is(tok::annot_template_id) &&
+ static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
+ ->Kind == TNK_Dependent_template_name) {
+ DS.getTypeSpecScope() = SS;
+ ConsumeAnnotationToken(); // The C++ scope.
+ AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename);
+ continue;
+ }
+
if (Next.isNot(tok::identifier))
goto DoneWithDeclSpec;
@@ -3378,7 +3442,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DSContext == DeclSpecContext::DSC_class) &&
Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
&SS) &&
- isConstructorDeclarator(/*Unqualified*/ false))
+ isConstructorDeclarator(/*Unqualified=*/false,
+ /*DeductionGuide=*/false,
+ DS.isFriendSpecified()))
goto DoneWithDeclSpec;
// C++20 [temp.spec] 13.9/6.
@@ -3387,12 +3453,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// - `return type`.
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
- ParsedType TypeRep =
- Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(),
- getCurScope(), &SS, false, false, nullptr,
- /*IsCtorOrDtorName=*/false,
- /*WantNontrivialTypeSourceInfo=*/true,
- isClassTemplateDeductionContext(DSContext));
+ ParsedType TypeRep = Actions.getTypeName(
+ *Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS,
+ false, false, nullptr,
+ /*IsCtorOrDtorName=*/false,
+ /*WantNontrivialTypeSourceInfo=*/true,
+ isClassTemplateDeductionContext(DSContext), AllowImplicitTypename);
if (IsTemplateSpecOrInst)
SAC.done();
@@ -3471,7 +3537,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// typedef-name
case tok::kw___super:
case tok::kw_decltype:
- case tok::identifier: {
+ case tok::identifier:
+ ParseIdentifier: {
// 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'.
@@ -3555,7 +3622,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// check whether this is a constructor declaration.
if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class &&
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
- isConstructorDeclarator(/*Unqualified*/true))
+ isConstructorDeclarator(/*Unqualified=*/true,
+ /*DeductionGuide=*/false,
+ DS.isFriendSpecified()))
goto DoneWithDeclSpec;
ParsedType TypeRep = Actions.getTypeName(
@@ -3630,11 +3699,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
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)'.
+ // arguments, drop it and just form 'auto' or 'decltype(auto)'.
if (TemplateId->hasInvalidArgs())
TemplateId = nullptr;
- if (NextToken().is(tok::identifier)) {
+ // Any of the following tokens are likely the start of the user
+ // forgetting 'auto' or 'decltype(auto)', so diagnose.
+ // Note: if updating this list, please make sure we update
+ // isCXXDeclarationSpecifier's check for IsPlaceholderSpecifier to have
+ // a matching list.
+ if (NextToken().isOneOf(tok::identifier, tok::kw_const,
+ tok::kw_volatile, tok::kw_restrict, tok::amp,
+ tok::ampamp)) {
Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto)
<< FixItHint::CreateInsertion(NextToken().getLocation(), "auto");
// Attempt to continue as if 'auto' was placed here.
@@ -3664,7 +3740,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
}
ConsumedEnd = Tok.getLocation();
- DS.setTypeofParensRange(Tracker.getRange());
+ DS.setTypeArgumentRange(Tracker.getRange());
// Even if something went wrong above, continue as if we've seen
// `decltype(auto)`.
isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec,
@@ -3688,13 +3764,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// constructor declaration.
if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) &&
- isConstructorDeclarator(/*Unqualified=*/true))
+ isConstructorDeclarator(/*Unqualified=*/true,
+ /*DeductionGuide=*/false,
+ DS.isFriendSpecified()))
goto DoneWithDeclSpec;
// Turn the template-id annotation token into a type annotation
// token, then try again to parse it as a type-specifier.
CXXScopeSpec SS;
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename);
continue;
}
@@ -4181,8 +4259,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
break;
- // GNU typeof support.
+ // C2x/GNU typeof support.
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
ParseTypeofSpecifier(DS);
continue;
@@ -4206,8 +4285,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
HandlePragmaMSPointersToMembers();
continue;
- case tok::kw___underlying_type:
- ParseUnderlyingTypeSpecifier(DS);
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+ // HACK: libstdc++ already uses '__remove_cv' as an alias template so we
+ // work around this by expecting all transform type traits to be suffixed
+ // with '('. They're an identifier otherwise.
+ if (!MaybeParseTypeTransformTypeSpecifier(DS))
+ goto ParseIdentifier;
continue;
case tok::kw__Atomic:
@@ -4238,13 +4322,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = true;
break;
}
- LLVM_FALLTHROUGH;
+ [[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;
+ [[fallthrough]];
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -4256,6 +4340,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ParseOpenCLQualifiers(DS.getAttributes());
break;
+ case tok::kw_groupshared:
+ // NOTE: ParseHLSLQualifiers will consume the qualifier token.
+ ParseHLSLQualifiers(DS.getAttributes());
+ continue;
+
case tok::less:
// GCC ObjC supports types like "<SomeProtocol>" as a synonym for
// "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
@@ -4581,6 +4670,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// Code completion for an enum name.
cutOffParsing();
Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum);
+ DS.SetTypeSpecError(); // Needed by ActOnUsingDeclaration.
return;
}
@@ -4640,6 +4730,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Spec.isSet() && Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected) << tok::identifier;
+ DS.SetTypeSpecError();
if (Tok.isNot(tok::l_brace)) {
// Has no name and is not a definition.
// Skip the rest of this declarator, up until the comma or semicolon.
@@ -4656,6 +4747,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
+ DS.SetTypeSpecError();
// Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, StopAtSemi);
return;
@@ -4727,7 +4819,10 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// 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);
+ // enum-base is not assumed to be a type and therefore requires the
+ // typename keyword [p0634r3].
+ ParseSpecifierQualifierList(DS, ImplicitTypenameContext::No, AS,
+ DeclSpecContext::DSC_type_specifier);
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
DeclaratorContext::TypeName);
BaseType = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
@@ -4831,6 +4926,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (!Name && TUK != Sema::TUK_Definition) {
Diag(Tok, diag::err_enumerator_unnamed_no_def);
+ DS.SetTypeSpecError();
// Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, StopAtSemi);
return;
@@ -4869,14 +4965,16 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool IsDependent = false;
const char *PrevSpec = nullptr;
unsigned DiagID;
- Decl *TagDecl = Actions.ActOnTag(
- getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc,
- attrs, AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent,
- ScopedEnumKWLoc, IsScopedUsingClassTag, BaseType,
- DSC == DeclSpecContext::DSC_type_specifier,
- DSC == DeclSpecContext::DSC_template_param ||
- DSC == DeclSpecContext::DSC_template_type_arg,
- &SkipBody);
+ UsingShadowDecl* FoundUsing = nullptr;
+ Decl *TagDecl =
+ Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS,
+ Name, NameLoc, attrs, AS, DS.getModulePrivateSpecLoc(),
+ TParams, Owned, IsDependent, ScopedEnumKWLoc,
+ IsScopedUsingClassTag,
+ BaseType, DSC == DeclSpecContext::DSC_type_specifier,
+ DSC == DeclSpecContext::DSC_template_param ||
+ DSC == DeclSpecContext::DSC_template_type_arg,
+ OffsetOfState, FoundUsing, &SkipBody).get();
if (SkipBody.ShouldSkip) {
assert(TUK == Sema::TUK_Definition && "can only skip a definition");
@@ -4886,8 +4984,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
T.skipToEnd();
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
- NameLoc.isValid() ? NameLoc : StartLoc,
- PrevSpec, DiagID, TagDecl, Owned,
+ NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
+ DiagID, FoundUsing ? FoundUsing : TagDecl, Owned,
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
return;
@@ -4941,8 +5039,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
}
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
- NameLoc.isValid() ? NameLoc : StartLoc,
- PrevSpec, DiagID, TagDecl, Owned,
+ NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
+ DiagID, FoundUsing ? FoundUsing : TagDecl, Owned,
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
}
@@ -5159,7 +5257,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::identifier: // foo::bar
if (TryAltiVecVectorToken())
return true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
@@ -5180,8 +5278,9 @@ bool Parser::isTypeSpecifierQualifier() {
// GNU attributes support.
case tok::kw___attribute:
- // GNU typeof support.
+ // C2x/GNU typeof support.
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
// type-specifiers
case tok::kw_short:
@@ -5271,6 +5370,8 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw___read_only:
case tok::kw___read_write:
case tok::kw___write_only:
+
+ case tok::kw_groupshared:
return true;
case tok::kw_private:
@@ -5282,12 +5383,35 @@ bool Parser::isTypeSpecifierQualifier() {
}
}
+Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() {
+ assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode");
+
+ // Parse a top-level-stmt.
+ Parser::StmtVector Stmts;
+ ParsedStmtContext SubStmtCtx = ParsedStmtContext();
+ StmtResult R = ParseStatementOrDeclaration(Stmts, SubStmtCtx);
+ if (!R.isUsable())
+ return nullptr;
+
+ SmallVector<Decl *, 2> DeclsInGroup;
+ DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(R.get()));
+ // Currently happens for things like -fms-extensions and use `__if_exists`.
+ for (Stmt *S : Stmts)
+ DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(S));
+
+ return Actions.BuildDeclaratorGroup(DeclsInGroup);
+}
+
/// isDeclarationSpecifier() - Return true if the current token is part of a
/// declaration specifier.
///
+/// \param AllowImplicitTypename whether this is a context where T::type [T
+/// dependent] can appear.
/// \param DisambiguatingWithExpression True to indicate that the purpose of
/// this check is to disambiguate between an expression and a declaration.
-bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
+bool Parser::isDeclarationSpecifier(
+ ImplicitTypenameContext AllowImplicitTypename,
+ bool DisambiguatingWithExpression) {
switch (Tok.getKind()) {
default: return false;
@@ -5302,12 +5426,12 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
return false;
if (TryAltiVecVectorToken())
return true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_decltype: // decltype(T())::type
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
- if (TryAnnotateTypeOrScopeToken())
+ if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
return true;
if (TryAnnotateTypeConstraint())
return true;
@@ -5323,9 +5447,11 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
isStartOfObjCClassMessageMissingOpenBracket())
return false;
- return isDeclarationSpecifier();
+ return isDeclarationSpecifier(AllowImplicitTypename);
case tok::coloncolon: // ::foo::bar
+ if (!getLangOpts().CPlusPlus)
+ return false;
if (NextToken().is(tok::kw_new) || // ::new
NextToken().is(tok::kw_delete)) // ::delete
return false;
@@ -5334,7 +5460,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return true;
- return isDeclarationSpecifier();
+ return isDeclarationSpecifier(ImplicitTypenameContext::No);
// storage-class-specifier
case tok::kw_typedef:
@@ -5419,8 +5545,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_static_assert:
case tok::kw__Static_assert:
- // GNU typeof support.
+ // C2x/GNU typeof support.
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
// GNU attributes.
case tok::kw___attribute:
@@ -5506,6 +5633,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
#include "clang/Basic/OpenCLImageTypes.def"
+ case tok::kw_groupshared:
return true;
case tok::kw_private:
@@ -5513,7 +5641,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
}
}
-bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
+bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide,
+ DeclSpec::FriendSpecified IsFriend) {
TentativeParsingAction TPA(*this);
// Parse the C++ scope specifier.
@@ -5577,8 +5706,11 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
// Check whether the next token(s) are part of a declaration
// specifier, in which case we have the start of a parameter and,
// therefore, we know that this is a constructor.
+ // Due to an ambiguity with implicit typename, the above is not enough.
+ // Additionally, check to see if we are a friend.
bool IsConstructor = false;
- if (isDeclarationSpecifier())
+ if (isDeclarationSpecifier(IsFriend ? ImplicitTypenameContext::No
+ : ImplicitTypenameContext::Yes))
IsConstructor = true;
else if (Tok.is(tok::identifier) ||
(Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) {
@@ -5667,7 +5799,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
void Parser::ParseTypeQualifierListOpt(
DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed,
bool IdentifierRequired,
- Optional<llvm::function_ref<void()>> CodeCompletionHandler) {
+ std::optional<llvm::function_ref<void()>> CodeCompletionHandler) {
if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) &&
isCXX11AttributeSpecifier()) {
ParsedAttributes Attrs(AttrFactory);
@@ -5717,7 +5849,7 @@ void Parser::ParseTypeQualifierListOpt(
case tok::kw_private:
if (!getLangOpts().OpenCL)
goto DoneWithTypeQuals;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -5729,6 +5861,11 @@ void Parser::ParseTypeQualifierListOpt(
ParseOpenCLQualifiers(DS.getAttributes());
break;
+ case tok::kw_groupshared:
+ // NOTE: ParseHLSLQualifiers will consume the qualifier token.
+ ParseHLSLQualifiers(DS.getAttributes());
+ continue;
+
case tok::kw___unaligned:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_unaligned, Loc, PrevSpec, DiagID,
getLangOpts());
@@ -5741,7 +5878,7 @@ void Parser::ParseTypeQualifierListOpt(
if (TryKeywordIdentFallback(false))
continue;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw___sptr:
case tok::kw___w64:
case tok::kw___ptr64:
@@ -5792,7 +5929,7 @@ void Parser::ParseTypeQualifierListOpt(
continue; // do *not* consume the next token!
}
// otherwise, FALL THROUGH!
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
DoneWithTypeQuals:
// If this is not a type-qualifier token, we're done reading type
@@ -6393,10 +6530,27 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// is not, the declarator has been fully parsed.
bool IsAmbiguous = false;
if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
+ // C++2a [temp.res]p5
+ // A qualified-id is assumed to name a type if
+ // - [...]
+ // - it is a decl-specifier of the decl-specifier-seq of a
+ // - [...]
+ // - parameter-declaration in a member-declaration [...]
+ // - parameter-declaration in a declarator of a function or function
+ // template declaration whose declarator-id is qualified [...]
+ auto AllowImplicitTypename = ImplicitTypenameContext::No;
+ if (D.getCXXScopeSpec().isSet())
+ AllowImplicitTypename =
+ (ImplicitTypenameContext)Actions.isDeclaratorFunctionLike(D);
+ else if (D.getContext() == DeclaratorContext::Member) {
+ AllowImplicitTypename = ImplicitTypenameContext::Yes;
+ }
+
// The name of the declarator, if any, is tentatively declared within
// a possible direct initializer.
TentativelyDeclaredIdentifiers.push_back(D.getIdentifier());
- bool IsFunctionDecl = isCXXFunctionDeclarator(&IsAmbiguous);
+ bool IsFunctionDecl =
+ isCXXFunctionDeclarator(&IsAmbiguous, AllowImplicitTypename);
TentativelyDeclaredIdentifiers.pop_back();
if (!IsFunctionDecl)
break;
@@ -6555,11 +6709,12 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// If this can't be an abstract-declarator, this *must* be a grouping
// paren, because we haven't seen the identifier yet.
isGrouping = true;
- } else if (Tok.is(tok::r_paren) || // 'int()' is a function.
+ } else if (Tok.is(tok::r_paren) || // 'int()' is a function.
(getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) &&
NextToken().is(tok::r_paren)) || // C++ int(...)
- isDeclarationSpecifier() || // 'int(int)' is a function.
- isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function.
+ isDeclarationSpecifier(
+ ImplicitTypenameContext::No) || // 'int(int)' is a function.
+ isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function.
// This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is
// considered to be a type, not a K&R identifier-list.
isGrouping = false;
@@ -6611,7 +6766,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
void Parser::InitCXXThisScopeForDeclaratorIfRelevant(
const Declarator &D, const DeclSpec &DS,
- llvm::Optional<Sema::CXXThisScopeRAII> &ThisScope) {
+ std::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
@@ -6727,8 +6882,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
ProhibitAttributes(FnAttrs);
} else {
if (Tok.isNot(tok::r_paren))
- ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo,
- EllipsisLoc);
+ ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
else if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
@@ -6764,7 +6918,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc))
EndLoc = RefQualifierLoc;
- llvm::Optional<Sema::CXXThisScopeRAII> ThisScope;
+ std::optional<Sema::CXXThisScopeRAII> ThisScope;
InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope);
// Parse exception-specification[opt].
@@ -6987,7 +7141,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
void Parser::ParseParameterDeclarationClause(
DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs,
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
- SourceLocation &EllipsisLoc) {
+ SourceLocation &EllipsisLoc, bool IsACXXFunctionDeclaration) {
// Avoid exceeding the maximum function scope depth.
// See https://bugs.llvm.org/show_bug.cgi?id=19607
@@ -7001,6 +7155,23 @@ void Parser::ParseParameterDeclarationClause(
return;
}
+ // C++2a [temp.res]p5
+ // A qualified-id is assumed to name a type if
+ // - [...]
+ // - it is a decl-specifier of the decl-specifier-seq of a
+ // - [...]
+ // - parameter-declaration in a member-declaration [...]
+ // - parameter-declaration in a declarator of a function or function
+ // template declaration whose declarator-id is qualified [...]
+ // - parameter-declaration in a lambda-declarator [...]
+ auto AllowImplicitTypename = ImplicitTypenameContext::No;
+ if (DeclaratorCtx == DeclaratorContext::Member ||
+ DeclaratorCtx == DeclaratorContext::LambdaExpr ||
+ DeclaratorCtx == DeclaratorContext::RequiresExpr ||
+ IsACXXFunctionDeclaration) {
+ AllowImplicitTypename = ImplicitTypenameContext::Yes;
+ }
+
do {
// FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
// before deciding this was a parameter-declaration-clause.
@@ -7030,7 +7201,9 @@ void Parser::ParseParameterDeclarationClause(
SourceLocation DSStart = Tok.getLocation();
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiers(DS, /*TemplateInfo=*/ParsedTemplateInfo(),
+ AS_none, DeclSpecContext::DSC_normal,
+ /*LateAttrs=*/nullptr, AllowImplicitTypename);
DS.takeAttributesFrom(ArgDeclSpecAttrs);
// Parse the declarator. This is "PrototypeContext" or
@@ -7046,7 +7219,8 @@ void Parser::ParseParameterDeclarationClause(
// Parse GNU attributes, if present.
MaybeParseGNUAttributes(ParmDeclarator);
- MaybeParseHLSLSemantics(DS.getAttributes());
+ if (getLangOpts().HLSL)
+ MaybeParseHLSLSemantics(DS.getAttributes());
if (Tok.is(tok::kw_requires)) {
// User tried to define a requires clause in a parameter declaration,
@@ -7427,13 +7601,27 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) {
/// typeof ( expressions )
/// typeof ( type-name )
/// [GNU/C++] typeof unary-expression
+/// [C2x] typeof-specifier:
+/// typeof '(' typeof-specifier-argument ')'
+/// typeof_unqual '(' typeof-specifier-argument ')'
+///
+/// typeof-specifier-argument:
+/// expression
+/// type-name
///
void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
- assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier");
+ assert(Tok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual) &&
+ "Not a typeof specifier");
+
+ bool IsUnqual = Tok.is(tok::kw_typeof_unqual);
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (getLangOpts().C2x && !II->getName().startswith("__"))
+ Diag(Tok.getLocation(), diag::warn_c2x_compat_typeof_type_specifier)
+ << IsUnqual;
+
Token OpTok = Tok;
SourceLocation StartLoc = ConsumeToken();
-
- const bool hasParens = Tok.is(tok::l_paren);
+ bool HasParens = Tok.is(tok::l_paren);
EnterExpressionEvaluationContext Unevaluated(
Actions, Sema::ExpressionEvaluationContext::Unevaluated,
@@ -7444,8 +7632,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
SourceRange CastRange;
ExprResult Operand = Actions.CorrectDelayedTyposInExpr(
ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange));
- if (hasParens)
- DS.setTypeofParensRange(CastRange);
+ if (HasParens)
+ DS.setTypeArgumentRange(CastRange);
if (CastRange.getEnd().isInvalid())
// FIXME: Not accurate, the range gets one token more than it should.
@@ -7462,7 +7650,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const char *PrevSpec = nullptr;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int typeof(int)").
- if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec,
+ if (DS.SetTypeSpecType(IsUnqual ? DeclSpec::TST_typeof_unqualType
+ : DeclSpec::TST_typeofType,
+ StartLoc, PrevSpec,
DiagID, CastTy,
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
@@ -7485,7 +7675,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const char *PrevSpec = nullptr;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int typeof(int)").
- if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
+ if (DS.SetTypeSpecType(IsUnqual ? DeclSpec::TST_typeof_unqualExpr
+ : DeclSpec::TST_typeofExpr,
+ StartLoc, PrevSpec,
DiagID, Operand.get(),
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
@@ -7515,7 +7707,7 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
if (T.getCloseLocation().isInvalid())
return;
- DS.setTypeofParensRange(T.getRange());
+ DS.setTypeArgumentRange(T.getRange());
DS.SetRangeEnd(T.getCloseLocation());
const char *PrevSpec = nullptr;