in tools/clang/lib/Parse/ParseDecl.cpp [3303:4300]
void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS,
DeclSpecContext DSContext,
LateParsedAttrList *LateAttrs) {
if (DS.getSourceRange().isInvalid()) {
// Start the range at the current token but make the end of the range
// invalid. This will make the entire range invalid unless we successfully
// consume a token.
DS.SetRangeStart(Tok.getLocation());
DS.SetRangeEnd(SourceLocation());
}
bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
bool AttrsLastTime = false;
ParsedAttributesWithRange attrs(AttrFactory);
// We use Sema's policy to get bool macros right.
const PrintingPolicy &Policy = Actions.getPrintingPolicy();
while (1) {
bool isInvalid = false;
bool isStorageClass = false;
const char *PrevSpec = nullptr;
unsigned DiagID = 0;
SourceLocation Loc = Tok.getLocation();
switch (Tok.getKind()) {
default:
DoneWithDeclSpec:
if (!AttrsLastTime)
ProhibitAttributes(attrs);
else {
// Reject C++11 attributes that appertain to decl specifiers as
// we don't support any C++11 attributes that appertain to decl
// specifiers. This also conforms to what g++ 4.8 is doing.
ProhibitCXX11Attributes(attrs);
DS.takeAttributesFrom(attrs);
}
// If this is not a declaration specifier token, we're done reading decl
// specifiers. First verify that DeclSpec's are consistent.
DS.Finish(Diags, PP, Policy);
return;
case tok::l_square:
case tok::kw_alignas:
if (!getLangOpts().CPlusPlus11 || !isCXX11AttributeSpecifier())
goto DoneWithDeclSpec;
ProhibitAttributes(attrs);
// FIXME: It would be good to recover by accepting the attributes,
// but attempting to do that now would cause serious
// madness in terms of diagnostics.
attrs.clear();
attrs.Range = SourceRange();
ParseCXX11Attributes(attrs);
AttrsLastTime = true;
continue;
case tok::code_completion: {
Sema::ParserCompletionContext CCC = Sema::PCC_Namespace;
if (DS.hasTypeSpecifier()) {
bool AllowNonIdentifiers
= (getCurScope()->getFlags() & (Scope::ControlScope |
Scope::BlockScope |
Scope::TemplateParamScope |
Scope::FunctionPrototypeScope |
Scope::AtCatchScope)) == 0;
bool AllowNestedNameSpecifiers
= DSContext == DSC_top_level ||
(DSContext == DSC_class && DS.isFriendSpecified());
Actions.CodeCompleteDeclSpec(getCurScope(), DS,
AllowNonIdentifiers,
AllowNestedNameSpecifiers);
return cutOffParsing();
}
if (getCurScope()->getFnParent() || getCurScope()->getBlockParent())
CCC = Sema::PCC_LocalDeclarationSpecifiers;
else if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
CCC = DSContext == DSC_class? Sema::PCC_MemberTemplate
: Sema::PCC_Template;
else if (DSContext == DSC_class)
CCC = Sema::PCC_Class;
else if (CurParsedObjCImpl)
CCC = Sema::PCC_ObjCImplementation;
Actions.CodeCompleteOrdinaryName(getCurScope(), CCC);
return cutOffParsing();
}
case tok::coloncolon: // ::foo::bar
// C++ scope specifier. Annotate and loop, or bail out on error.
if (TryAnnotateCXXScopeToken(EnteringContext)) {
if (!DS.hasTypeSpecifier())
DS.SetTypeSpecError();
goto DoneWithDeclSpec;
}
if (Tok.is(tok::coloncolon)) // ::new or ::delete
goto DoneWithDeclSpec;
continue;
case tok::annot_cxxscope: {
if (DS.hasTypeSpecifier() || DS.isTypeAltiVecVector())
goto DoneWithDeclSpec;
CXXScopeSpec SS;
Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
Tok.getAnnotationRange(),
SS);
// 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) {
// We have a qualified template-id, e.g., N::A<int>
// C++ [class.qual]p2:
// In a lookup in which the constructor is an acceptable lookup
// result and the nested-name-specifier nominates a class C:
//
// - if the name specified after the
// nested-name-specifier, when looked up in C, is the
// injected-class-name of C (Clause 9), or
//
// - if the name specified after the nested-name-specifier
// is the same as the identifier or the
// simple-template-id's template-name in the last
// component of the nested-name-specifier,
//
// the name is instead considered to name the constructor of
// class C.
//
// Thus, if the template-name is actually the constructor
// name, then the code is ill-formed; this interpretation is
// reinforced by the NAD status of core issue 635.
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
if (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
// complain about it later.
goto DoneWithDeclSpec;
}
// The user meant this to name a type, but it actually names
// a constructor with some extraneous template
// arguments. Complain, then parse it as a type as the user
// intended.
Diag(TemplateId->TemplateNameLoc,
diag::err_out_of_line_template_id_names_constructor)
<< TemplateId->Name;
}
DS.getTypeSpecScope() = SS;
ConsumeToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
AnnotateTemplateIdTokenAsType();
continue;
}
if (Next.is(tok::annot_typename)) {
DS.getTypeSpecScope() = SS;
ConsumeToken(); // 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();
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeToken(); // The typename
}
if (Next.isNot(tok::identifier))
goto DoneWithDeclSpec;
// If we're in a context where the identifier could be a class name,
// check whether this is a constructor declaration.
if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
&SS)) {
if (isConstructorDeclarator(/*Unqualified*/false))
goto DoneWithDeclSpec;
// As noted in C++ [class.qual]p2 (cited above), when the name
// of the class is qualified in a context where it could name
// a constructor, its a constructor name. However, we've
// looked at the declarator, and the user probably meant this
// to be a type. Complain that it isn't supposed to be treated
// as a type, then proceed to parse it as a type.
Diag(Next.getLocation(), diag::err_out_of_line_type_names_constructor)
<< Next.getIdentifierInfo();
}
ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
Next.getLocation(),
getCurScope(), &SS,
false, false, ParsedType(),
/*IsCtorOrDtorName=*/false,
/*NonTrivialSourceInfo=*/true);
// If the referenced identifier is not a type, then this declspec is
// erroneous: We already checked about that it has no type specifier, and
// C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
// typename.
if (!TypeRep) {
ConsumeToken(); // Eat the scope spec so the identifier is current.
ParsedAttributesWithRange Attrs(AttrFactory);
if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) {
if (!Attrs.empty()) {
AttrsLastTime = true;
attrs.takeAllFrom(Attrs);
}
continue;
}
goto DoneWithDeclSpec;
}
DS.getTypeSpecScope() = SS;
ConsumeToken(); // The C++ scope.
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
DiagID, TypeRep, Policy);
if (isInvalid)
break;
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken(); // The typename.
continue;
}
case tok::annot_typename: {
// If we've previously seen a tag definition, we were almost surely
// missing a semicolon after it.
if (DS.hasTypeSpecifier() && DS.hasTagDefinition())
goto DoneWithDeclSpec;
// HLSL Change Starts
// Remember the current state of the default matrix orientation,
// since it can change between any two tokens with #pragma pack_matrix
if (Parser::Actions.HasDefaultMatrixPack)
DS.SetDefaultMatrixPackRowMajor(Parser::Actions.DefaultMatrixPackRowMajor);
// HLSL Change Ends
if (Tok.getAnnotationValue()) {
ParsedType T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
DiagID, T, Policy);
} else
DS.SetTypeSpecError();
if (isInvalid)
break;
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeToken(); // The typename
continue;
}
case tok::kw___is_signed:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - __is_signed is reserved for HLSL
// GNU libstdc++ 4.4 uses __is_signed as an identifier, but Clang
// typically treats it as a trait. If we see __is_signed as it appears
// in libstdc++, e.g.,
//
// static const bool __is_signed;
//
// then treat __is_signed as an identifier rather than as a keyword.
if (DS.getTypeSpecType() == TST_bool &&
DS.getTypeQualifiers() == DeclSpec::TQ_const &&
DS.getStorageClassSpec() == DeclSpec::SCS_static)
TryKeywordIdentFallback(true);
// We're done with the declaration-specifiers.
goto DoneWithDeclSpec;
// typedef-name
case tok::kw___super:
case tok::kw_decltype:
case tok::identifier: {
// This identifier can only be a typedef name if we haven't already seen
// a type-specifier. Without this check we misparse:
// typedef int X; struct Y { short X; }; as 'short int'.
if (DS.hasTypeSpecifier())
goto DoneWithDeclSpec;
// In C++, check to see if this is a scope specifier like foo::bar::, if
// so handle it as such. This is important for ctor parsing.
if (getLangOpts().CPlusPlus) {
if (TryAnnotateCXXScopeToken(EnteringContext)) {
DS.SetTypeSpecError();
goto DoneWithDeclSpec;
}
if (!Tok.is(tok::identifier))
continue;
}
// Check for need to substitute AltiVec keyword tokens.
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
break;
// [AltiVec] 2.2: [If the 'vector' specifier is used] The syntax does not
// allow the use of a typedef name as a type specifier.
if (DS.isTypeAltiVecVector())
goto DoneWithDeclSpec;
if (DSContext == DSC_objc_method_result && isObjCInstancetype()) {
ParsedType TypeRep = Actions.ActOnObjCInstanceType(Loc);
assert(TypeRep);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
DiagID, TypeRep, Policy);
if (isInvalid)
break;
DS.SetRangeEnd(Loc);
ConsumeToken();
continue;
}
ParsedType TypeRep =
Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), getCurScope());
// MSVC: If we weren't able to parse a default template argument, and it's
// just a simple identifier, create a DependentNameType. This will allow
// us to defer the name lookup to template instantiation time, as long we
// forge a NestedNameSpecifier for the current context.
if (!TypeRep && DSContext == DSC_template_type_arg &&
getLangOpts().MSVCCompat && getCurScope()->isTemplateParamScope()) {
TypeRep = Actions.ActOnDelayedDefaultTemplateArg(
*Tok.getIdentifierInfo(), Tok.getLocation());
}
// 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) {
ParsedAttributesWithRange Attrs(AttrFactory);
if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) {
if (!Attrs.empty()) {
AttrsLastTime = true;
attrs.takeAllFrom(Attrs);
}
continue;
}
goto DoneWithDeclSpec;
}
// If we're in a context where the identifier could be a class name,
// check whether this is a constructor declaration.
if (getLangOpts().CPlusPlus && DSContext == DSC_class &&
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
isConstructorDeclarator(/*Unqualified*/true))
goto DoneWithDeclSpec;
// HLSL Change Starts
// Modify TypeRep for unsigned vectors/matrix
QualType qt = TypeRep.get();
QualType newType = ApplyTypeSpecSignToParsedType(&Actions, qt, DS.getTypeSpecSign(), Loc);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
DiagID, ParsedType::make(newType), Policy);
// Remember the current state of the default matrix orientation,
// since it can change between any two tokens with #pragma pack_matrix
if (Parser::Actions.HasDefaultMatrixPack)
DS.SetDefaultMatrixPackRowMajor(Parser::Actions.DefaultMatrixPackRowMajor);
// HLSL Change Ends
if (isInvalid)
break;
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken(); // The identifier
// Objective-C supports type arguments and protocol references
// following an Objective-C object or object pointer
// type. Handle either one of them.
if (Tok.is(tok::less) && getLangOpts().ObjC1) {
SourceLocation NewEndLoc;
TypeResult NewTypeRep = parseObjCTypeArgsAndProtocolQualifiers(
Loc, TypeRep, /*consumeLastToken=*/true,
NewEndLoc);
if (NewTypeRep.isUsable()) {
DS.UpdateTypeRep(NewTypeRep.get());
DS.SetRangeEnd(NewEndLoc);
}
}
// Need to support trailing type qualifiers (e.g. "id<p> const").
// If a type specifier follows, it will be diagnosed elsewhere.
continue;
}
// type-name
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind != TNK_Type_template) {
// This template-id does not refer to a type name, so we're
// done with the type-specifiers.
goto DoneWithDeclSpec;
}
// If we're in a context where the template-id could be a
// constructor name or specialization, check whether this is a
// constructor declaration.
if (getLangOpts().CPlusPlus && DSContext == DSC_class &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) &&
isConstructorDeclarator(TemplateId->SS.isEmpty()))
goto DoneWithDeclSpec;
// Turn the template-id annotation token into a type annotation
// token, then try again to parse it as a type-specifier.
AnnotateTemplateIdTokenAsType();
continue;
}
// GNU attributes support.
case tok::kw___attribute:
ParseGNUAttributes(DS.getAttributes(), nullptr, LateAttrs);
continue;
// Microsoft declspec support.
case tok::kw___declspec:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - __declspec is reserved for HLSL
ParseMicrosoftDeclSpecs(DS.getAttributes());
continue;
// Microsoft single token adornments.
case tok::kw___forceinline: {
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - __forceinline is reserved for HLSL
isInvalid = DS.setFunctionSpecForceInline(Loc, PrevSpec, DiagID);
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = Tok.getLocation();
DS.getAttributes().addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc,
nullptr, 0, AttributeList::AS_Keyword);
break;
}
case tok::kw___sptr:
case tok::kw___uptr:
case tok::kw___ptr64:
case tok::kw___ptr32:
case tok::kw___w64:
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
case tok::kw___vectorcall:
case tok::kw___unaligned:
// HLSL Change Starts
HLSLReservedKeyword:
if (getLangOpts().HLSL) {
PrevSpec = ""; // unused by diagnostic.
DiagID = diag::err_hlsl_reserved_keyword;
isInvalid = true;
break;
}
else
// HLSL Change Ends
ParseMicrosoftTypeAttributes(DS.getAttributes());
continue;
// Borland single token adornments.
case tok::kw___pascal:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // HLSL Change - __pascal isn't a keyword for HLSL
ParseBorlandTypeAttributes(DS.getAttributes());
continue;
// OpenCL single token adornments.
case tok::kw___kernel:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // HLSL Change - __kernel isn't a keyword for HLSL
ParseOpenCLAttributes(DS.getAttributes());
continue;
// Nullability type specifiers.
case tok::kw__Nonnull:
case tok::kw__Nullable:
case tok::kw__Null_unspecified:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // HLSL Change - not a keyword for HLSL
ParseNullabilityTypeSpecifiers(DS.getAttributes());
continue;
// Objective-C 'kindof' types.
case tok::kw___kindof:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // HLSL Change - not a keyword for HLSL
DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc,
nullptr, 0, AttributeList::AS_Keyword);
(void)ConsumeToken();
continue;
// storage-class-specifier
case tok::kw_typedef:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw_extern:
if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "extern";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw___private_extern__:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // HLSL Change - not a keyword for HLSL
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_private_extern,
Loc, PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw_static:
if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "static";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
// HLSL Change Starts
case tok::kw_shared:
case tok::kw_groupshared:
case tok::kw_uniform:
case tok::kw_in:
case tok::kw_out:
case tok::kw_inout:
case tok::kw_linear:
case tok::kw_nointerpolation:
case tok::kw_noperspective:
case tok::kw_centroid:
case tok::kw_column_major:
case tok::kw_row_major:
case tok::kw_snorm:
case tok::kw_unorm:
case tok::kw_point:
case tok::kw_line:
case tok::kw_lineadj:
case tok::kw_triangle:
case tok::kw_triangleadj:
case tok::kw_export:
if (getLangOpts().HLSL) {
if (DS.getTypeSpecType() != DeclSpec::TST_unspecified) {
PrevSpec = "";
DiagID = diag::err_hlsl_modifier_after_type;
isInvalid = true;
} else {
DS.getAttributes().addNew(Tok.getIdentifierInfo(), Tok.getLocation(), 0, SourceLocation(), 0, 0, AttributeList::AS_CXX11);
}
}
break;
case tok::kw_precise:
case tok::kw_sample:
case tok::kw_globallycoherent:
case tok::kw_center:
case tok::kw_indices:
case tok::kw_vertices:
case tok::kw_primitives:
case tok::kw_payload:
// Back-compat: 'precise', 'globallycoherent', 'center' and 'sample' are keywords when used as an interpolation
// modifiers, but in FXC they can also be used an identifiers. If the decl type has already been specified
// we need to update the token to be handled as an identifier.
// Similarly 'indices', 'vertices', 'primitives' and 'payload' are keywords
// when used as a type qualifer in mesh shader, but may still be used as a variable name.
if (getLangOpts().HLSL) {
if (DS.getTypeSpecType() != DeclSpec::TST_unspecified) {
Tok.setKind(tok::identifier);
continue;
}
DS.getAttributes().addNew(Tok.getIdentifierInfo(), Tok.getLocation(), 0, SourceLocation(), 0, 0, AttributeList::AS_CXX11);
}
break;
// HLSL Change Ends
case tok::kw_auto:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - auto is reserved for HLSL
if (getLangOpts().CPlusPlus11) {
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
PrevSpec, DiagID, Policy);
if (!isInvalid)
Diag(Tok, diag::ext_auto_storage_class)
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
} else
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
DiagID, Policy);
} else
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw_register:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw_mutable:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_mutable, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw___thread:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS___thread, Loc,
PrevSpec, DiagID);
isStorageClass = true;
break;
case tok::kw_thread_local:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // HLSL Change - HLSL does not recognize these keywords
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc,
PrevSpec, DiagID);
break;
case tok::kw__Thread_local:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local,
Loc, PrevSpec, DiagID);
isStorageClass = true;
break;
// function-specifier
case tok::kw_inline:
isInvalid = DS.setFunctionSpecInline(Loc, PrevSpec, DiagID);
break;
case tok::kw_virtual:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - virtual is reserved for HLSL
isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
break;
case tok::kw_explicit:
isInvalid = DS.setFunctionSpecExplicit(Loc, PrevSpec, DiagID);
break;
case tok::kw__Noreturn:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - noreturn is reserved for HLSL
if (!getLangOpts().C11)
Diag(Loc, diag::ext_c11_noreturn);
isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID);
break;
// alignment-specifier
case tok::kw__Alignas:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - _Alignas is reserved for HLSL
if (!getLangOpts().C11)
Diag(Tok, diag::ext_c11_alignment) << Tok.getName();
ParseAlignmentSpecifier(DS.getAttributes());
continue;
// friend
case tok::kw_friend:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - friend is reserved for HLSL
if (DSContext == DSC_class)
isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID);
else {
PrevSpec = ""; // not actually used by the diagnostic
DiagID = diag::err_friend_invalid_in_context;
isInvalid = true;
}
break;
// Modules
case tok::kw___module_private__:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID);
break;
// constexpr
case tok::kw_constexpr:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID);
break;
// concept
case tok::kw_concept:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetConceptSpec(Loc, PrevSpec, DiagID);
break;
// type-specifier
case tok::kw_short:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw_long:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec,
DiagID, Policy);
else
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw___int64:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw_signed:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec,
DiagID);
break;
case tok::kw_unsigned:
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec,
DiagID);
break;
case tok::kw__Complex:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
DiagID);
break;
case tok::kw__Imaginary:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
DiagID);
break;
case tok::kw_void:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw_char:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - char is reserved for HLSL
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw_int:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw___int128:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec,
DiagID, Policy);
break;
// HLSL Change Starts
case tok::kw_half:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw_float:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw_double:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw_wchar_t:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw_char16_t:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw_char32_t:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw_bool:
case tok::kw__Bool:
if (Tok.is(tok::kw_bool) &&
DS.getTypeSpecType() != DeclSpec::TST_unspecified &&
DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
PrevSpec = ""; // Not used by the diagnostic.
DiagID = getLangOpts().HLSL ? diag::err_hlsl_bool_redeclaration : diag::err_bool_redeclaration; // HLSL Change
// For better error recovery.
Tok.setKind(tok::identifier);
isInvalid = true;
} else {
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec,
DiagID, Policy);
}
break;
case tok::kw__Decimal32:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw__Decimal64:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw__Decimal128:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
DiagID, Policy);
break;
case tok::kw___vector:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // MS Change - HLSL does not recognize this keyword
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___pixel:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // MS Change - HLSL does not recognize this keyword
isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___bool:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // MS Change - HLSL does not recognize this keyword
isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___unknown_anytype:
isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
PrevSpec, DiagID, Policy);
break;
// class-specifier:
case tok::kw_class:
case tok::kw_struct:
case tok::kw___interface:
case tok::kw_interface: // HLSL Change
case tok::kw_union: {
// HLSL Change Starts
if (getLangOpts().HLSL) {
if (Tok.is(tok::kw_union) || Tok.is(tok::kw___interface)) {
goto HLSLReservedKeyword;
}
}
// HLSL Change Ends
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
// These are attributes following class specifiers.
// To produce better diagnostic, we parse them when
// parsing class specifier.
ParsedAttributesWithRange Attributes(AttrFactory);
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS,
EnteringContext, DSContext, Attributes);
// If there are attributes following class specifier,
// take them over and handle them here.
if (!Attributes.empty()) {
AttrsLastTime = true;
attrs.takeAllFrom(Attributes);
}
continue;
}
// enum-specifier:
case tok::kw_enum:
ConsumeToken();
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext);
continue;
// cv-qualifier:
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID,
getLangOpts());
break;
case tok::kw_volatile:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
getLangOpts());
break;
case tok::kw_restrict:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // HLSL Change - HLSL does not recognize this keyword
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
getLangOpts());
break;
// C++ typename-specifier:
case tok::kw_typename:
if (getLangOpts().HLSL && !getLangOpts().EnableTemplates) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
if (TryAnnotateTypeOrScopeToken()) {
DS.SetTypeSpecError();
goto DoneWithDeclSpec;
}
if (!Tok.is(tok::kw_typename))
continue;
break;
// GNU typeof support.
case tok::kw_typeof:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
ParseTypeofSpecifier(DS);
continue;
case tok::annot_decltype:
ParseDecltypeSpecifier(DS);
continue;
case tok::kw___underlying_type:
ParseUnderlyingTypeSpecifier(DS);
continue;
case tok::kw__Atomic:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
// C11 6.7.2.4/4:
// 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 (NextToken().is(tok::l_paren)) {
ParseAtomicSpecifier(DS);
continue;
}
isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID,
getLangOpts());
break;
// OpenCL qualifiers:
case tok::kw___generic:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
// generic address space is introduced only in OpenCL v2.0
// see OpenCL C Spec v2.0 s6.5.5
if (Actions.getLangOpts().OpenCLVersion < 200) {
DiagID = diag::err_opencl_unknown_type_specifier;
PrevSpec = Tok.getIdentifierInfo()->getNameStart();
isInvalid = true;
break;
};
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
case tok::kw___constant:
case tok::kw___read_only:
case tok::kw___write_only:
case tok::kw___read_write:
if (getLangOpts().HLSL) { assert(false); goto DoneWithDeclSpec; } // MS Change - HLSL does not recognize these keywords
ParseOpenCLQualifiers(DS.getAttributes());
break;
case tok::less:
// GCC ObjC supports types like "<SomeProtocol>" as a synonym for
// "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
// but we support it.
if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1)
goto DoneWithDeclSpec;
SourceLocation StartLoc = Tok.getLocation();
SourceLocation EndLoc;
TypeResult Type = parseObjCProtocolQualifierType(EndLoc);
if (Type.isUsable()) {
if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, StartLoc,
PrevSpec, DiagID, Type.get(),
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
DS.SetRangeEnd(EndLoc);
} else {
DS.SetTypeSpecError();
}
// Need to support trailing type qualifiers (e.g. "id<p> const").
// If a type specifier follows, it will be diagnosed elsewhere.
continue;
}
bool consume = DiagID != diag::err_bool_redeclaration; // HLSL Change
// If the specifier wasn't legal, issue a diagnostic.
if (isInvalid) {
assert(PrevSpec && "Method did not return previous specifier!");
assert(DiagID);
if (DiagID == diag::ext_duplicate_declspec)
Diag(Tok, DiagID)
<< PrevSpec << FixItHint::CreateRemoval(Tok.getLocation());
else if (DiagID == diag::err_opencl_unknown_type_specifier)
Diag(Tok, DiagID) << PrevSpec << isStorageClass;
else if (DiagID == diag::err_hlsl_reserved_keyword) Diag(Tok, DiagID) << Tok.getName(); // HLSL Change
else if (DiagID == diag::err_hlsl_modifier_after_type) Diag(Tok, DiagID); // HLSL Change
else
Diag(Tok, DiagID) << PrevSpec;
// HLSL Change Starts
if (DiagID == diag::err_hlsl_reserved_keyword) {
if (Tok.is(tok::kw__Alignas) || Tok.is(tok::kw_alignas) || Tok.is(tok::kw_alignof) ||
Tok.is(tok::kw__Alignof) || Tok.is(tok::kw___declspec) || Tok.is(tok::kw__Atomic) ||
Tok.is(tok::kw_typeof)) {
// These are of the form keyword(stuff) decl;
// After issuing the diagnostic, consume the keyword and everything between the parens.
consume = false;
ConsumeToken();
if (Tok.is(tok::l_paren)) {
BalancedDelimiterTracker brackets(*this, tok::l_paren);
brackets.consumeOpen();
brackets.skipToEnd();
}
}
}
// HLSL Change Ends
}
DS.SetRangeEnd(Tok.getLocation());
if (consume) // HLSL Change
ConsumeToken();
AttrsLastTime = false;
}
}