Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2775,8 +2775,6 @@ def err_decltype_auto_invalid : Error<
"'decltype(auto)' not allowed here">;
def err_decltype_auto_cannot_be_combined : Error<
"'decltype(auto)' cannot be combined with other type specifiers">;
def err_auto_type_specifier : Error<
"'auto' cannot be combined with a type specifier">;
def err_decltype_auto_function_declarator_not_declaration : Error<
"'decltype(auto)' can only be used as a return type "
"in a function declaration">;
Expand Down
53 changes: 2 additions & 51 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,6 @@ class DeclSpec {
unsigned TypeSpecSat : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned ConstrainedAuto : 1;
// Track conflicting type specifier when 'auto' is set (for Finish()
// detection)
LLVM_PREFERRED_TYPE(TST)
unsigned ConflictingTypeSpecifier : 7;

// type-qualifiers
LLVM_PREFERRED_TYPE(TQ)
Expand Down Expand Up @@ -431,50 +427,10 @@ class DeclSpec {
SourceLocation FS_explicitCloseParenLoc;
SourceLocation FS_forceinlineLoc;
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
SourceLocation TQ_pipeLoc, ConflictingTypeSpecifierLoc;
SourceLocation TQ_pipeLoc;

WrittenBuiltinSpecs writtenBS;
void SaveWrittenBuiltinSpecs();
void setConflictingTypeSpecifier(TST T, SourceLocation Loc) {
// Store conflicting type specifier for Finish() to detect:
// - If 'auto' is already set, store the conflicting type (e.g., "auto int")
// - If 'auto' is being set after another type, store TST_auto
// (e.g., "int auto").
if (TypeSpecType == TST_auto) {
ConflictingTypeSpecifier = T;
ConflictingTypeSpecifierLoc = Loc;
} else if (T == TST_auto) {
ConflictingTypeSpecifier = TST_auto;
ConflictingTypeSpecifierLoc = Loc;
}
}
void setConflictingTypeSpecifier(TST T, SourceLocation Loc,
SourceLocation NameLoc, ParsedType Rep) {
setConflictingTypeSpecifier(T, Loc);
if (TypeSpecType == TST_auto) {
TypeRep = Rep;
TSTNameLoc = NameLoc;
TypeSpecOwned = false;
}
}
void setConflictingTypeSpecifier(TST T, SourceLocation Loc, Expr *Rep) {
setConflictingTypeSpecifier(T, Loc);
if (TypeSpecType == TST_auto) {
ExprRep = Rep;
TSTNameLoc = Loc;
TypeSpecOwned = false;
}
}
void setConflictingTypeSpecifier(TST T, SourceLocation Loc,
SourceLocation NameLoc, Decl *Rep,
bool Owned) {
setConflictingTypeSpecifier(T, Loc);
if (TypeSpecType == TST_auto) {
DeclRep = Rep;
TSTNameLoc = NameLoc;
TypeSpecOwned = Owned && Rep != nullptr;
}
}

ObjCDeclSpec *ObjCQualifiers;

Expand Down Expand Up @@ -518,15 +474,13 @@ class DeclSpec {
TypeSpecType(TST_unspecified), TypeAltiVecVector(false),
TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false),
TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false),
ConflictingTypeSpecifier(TST_unspecified),
TypeQualifiers(TQ_unspecified),
OB_state(static_cast<unsigned>(OverflowBehaviorState::Unspecified)),
FS_inline_specified(false), FS_forceinline_specified(false),
FS_virtual_specified(false), FS_noreturn_specified(false),
FriendSpecifiedFirst(false), ConstexprSpecifier(static_cast<unsigned>(
ConstexprSpecKind::Unspecified)),
Attrs(attrFactory), ConflictingTypeSpecifierLoc(), writtenBS(),
ObjCQualifiers(nullptr) {}
Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {}

// storage-class-specifier
SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
Expand Down Expand Up @@ -566,9 +520,6 @@ class DeclSpec {
return static_cast<TypeSpecifierSign>(TypeSpecSign);
}
TST getTypeSpecType() const { return (TST)TypeSpecType; }
bool hasConflictingTypeSpecifier() const {
return ConflictingTypeSpecifier != TST_unspecified;
}
bool isTypeAltiVecVector() const { return TypeAltiVecVector; }
bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; }
bool isTypeAltiVecBool() const { return TypeAltiVecBool; }
Expand Down
46 changes: 7 additions & 39 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3778,9 +3778,7 @@ void Parser::ParseDeclarationSpecifiers(
// 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'.
// However, if 'auto' is set, we need to check if this identifier is a
// type name to detect conflicts (e.g., "auto MyInt").
if (DS.hasTypeSpecifier() && DS.getTypeSpecType() != DeclSpec::TST_auto)
if (DS.hasTypeSpecifier())
goto DoneWithDeclSpec;

// If the token is an identifier named "__declspec" and Microsoft
Expand Down Expand Up @@ -3865,44 +3863,18 @@ void Parser::ParseDeclarationSpecifiers(
DS.isFriendSpecified()))
goto DoneWithDeclSpec;

// If 'auto' is set and we're in a template parameter context, the
// identifier is always the parameter name, not a type specifier, so skip
// type name lookup to avoid false ambiguity errors.
if (DS.getTypeSpecType() == DeclSpec::TST_auto &&
DSContext == DeclSpecContext::DSC_template_param) {
goto DoneWithDeclSpec;
}

// If 'auto' is set and the next token indicates this identifier is the
// declarator-id, stop parsing declaration specifiers before doing type
// lookup. Looking up the declarator-id can produce bogus ambiguity errors
// when a variable name matches a type brought in by a using-directive.
if (DS.getTypeSpecType() == DeclSpec::TST_auto) {
Token Next = NextToken();
if (Next.isOneOf(tok::equal, tok::l_paren, tok::l_square, tok::l_brace,
tok::amp, tok::ampamp, tok::star, tok::coloncolon,
tok::comma, tok::semi, tok::colon, tok::greater,
tok::r_paren, tok::arrow))
goto DoneWithDeclSpec;
}

ParsedType TypeRep = Actions.getTypeName(
*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr,
false, false, nullptr, false, false,
isClassTemplateDeductionContext(DSContext));

// 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.
// However, if 'auto' is already set, we can't have an implicit int.
if (!TypeRep) {
if (TryAnnotateTypeConstraint())
goto DoneWithDeclSpec;
if (Tok.isNot(tok::identifier))
continue;
// If 'auto' is set, the identifier must be a type name or it's an
// error. Don't try to parse it as implicit int.
if (DS.getTypeSpecType() == DeclSpec::TST_auto)
goto DoneWithDeclSpec;
ParsedAttributes Attrs(AttrFactory);
if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) {
if (!Attrs.empty()) {
Expand Down Expand Up @@ -4168,18 +4140,15 @@ void Parser::ParseDeclarationSpecifiers(
}
};

if (!getLangOpts().CPlusPlus && MayBeTypeSpecifier()) {
if (MayBeTypeSpecifier()) {
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
PrevSpec, DiagID, Policy);
} else {
if (getLangOpts().CPlusPlus11 &&
NextToken().isOneOf(tok::kw_class, tok::kw_struct,
tok::kw___interface, tok::kw_union,
tok::kw_enum))
Diag(Loc, diag::ext_auto_storage_class);
if (!isInvalid && !getLangOpts().C23)
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);
Expand Down Expand Up @@ -4734,8 +4703,7 @@ void Parser::ParseDeclarationSpecifiers(
DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : Tok.getLocation());

// If the specifier wasn't legal, issue a diagnostic.
// Skip diagnostic if 'auto' conflict will be handled in Finish()
if (isInvalid && !DS.hasConflictingTypeSpecifier()) {
if (isInvalid) {
assert(PrevSpec && "Method did not return previous specifier!");
assert(DiagID);

Expand Down
Loading
Loading