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
36 changes: 26 additions & 10 deletions clang/lib/Sema/DeclSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1244,11 +1244,19 @@ void DeclSpec::CheckTypeSpec(Sema &S, const PrintingPolicy &Policy) {
(S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)) {
// In C23 or C++98, convert 'auto' to storage class specifier
if (TypeSpecType == TST_auto) {
// "auto int" case: Convert 'auto' to storage class specifier
StorageClassSpec = SCS_auto;
StorageClassSpecLoc = TSTLoc;
TypeSpecType = ConflictingTypeSpecifier;
TSTLoc = ConflictingTypeSpecifierLoc;
// "auto int" case: Convert 'auto' to storage class specifier.
// But typedef + any storage-class-specifier is unconditionally invalid
// per [dcl.stc]p1, regardless of C++ version.
if (StorageClassSpec == SCS_typedef) {
S.Diag(TSTLoc, diag::err_invalid_decl_spec_combination)
<< "typedef" << FixItHint::CreateRemoval(TSTLoc);
TypeSpecType = TST_error;
} else {
StorageClassSpec = SCS_auto;
StorageClassSpecLoc = TSTLoc;
TypeSpecType = ConflictingTypeSpecifier;
TSTLoc = ConflictingTypeSpecifierLoc;
}
// Clear the conflict tracking
ConflictingTypeSpecifier = TST_unspecified;
ConflictingTypeSpecifierLoc = SourceLocation();
Expand All @@ -1273,11 +1281,19 @@ void DeclSpec::CheckTypeSpec(Sema &S, const PrintingPolicy &Policy) {
return;
}
// int auto (without constexpr): Convert 'auto' to storage class
// specifier. No type conflict error - auto is treated as storage class,
// not type specifier.
StorageClassSpec = SCS_auto;
StorageClassSpecLoc = ConflictingTypeSpecifierLoc;
// TypeSpecType already has the correct type (e.g., TST_int)
// specifier. But typedef + any storage-class-specifier is
// unconditionally invalid per [dcl.stc]p1.
if (StorageClassSpec == SCS_typedef) {
S.Diag(ConflictingTypeSpecifierLoc,
diag::err_invalid_decl_spec_combination)
<< "typedef"
<< FixItHint::CreateRemoval(ConflictingTypeSpecifierLoc);
TypeSpecType = TST_error;
} else {
StorageClassSpec = SCS_auto;
StorageClassSpecLoc = ConflictingTypeSpecifierLoc;
// TypeSpecType already has the correct type (e.g., TST_int)
}
// Clear the conflict tracking
ConflictingTypeSpecifier = TST_unspecified;
ConflictingTypeSpecifierLoc = SourceLocation();
Expand Down
10 changes: 9 additions & 1 deletion clang/test/SemaCXX/auto-cxx98.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wc++11-compat
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wc++11-compat
void f() {
auto int a; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++11}}
int auto b; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++11}}
auto c; // expected-warning {{C++11 extension}} expected-error {{requires an initializer}}
static auto d = 0; // expected-warning {{C++11 extension}}
auto static e = 0; // expected-warning {{C++11 extension}}
}

// typedef and auto storage-class-specifier cannot appear in the same
// decl-specifier-seq ([dcl.stc] p1). This must be diagnosed in C++98 even
// though 'auto int' (without typedef) is valid there.
void g() {
typedef auto int t1; // expected-error {{cannot combine with previous 'typedef' declaration specifier}}
auto typedef int t2; // expected-error {{cannot combine with previous 'typedef' declaration specifier}}
}
Loading