Skip to content

Commit 9bc6045

Browse files
committed
[clang] Reject 'auto' storage class with type specifier in C++
Previously, clang allowed 'auto int x = 1;' in C++ as an extension (for C compatibility), emitting only a warning. This was confusing since 'auto' in C++11+ is a type specifier, not a storage class. This patch: - Adds a new error diagnostic 'err_auto_type_specifier' - Updates the parser to emit an error (instead of warning) when 'auto' is used as a storage class with a type specifier in C++ mode - Preserves C23 behavior where 'auto int' is valid - Adds comprehensive tests Fixes #164273 Signed-off-by: Osama Abdelkader <[email protected]>
1 parent 269f264 commit 9bc6045

File tree

7 files changed

+76
-18
lines changed

7 files changed

+76
-18
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ def err_requires_clause_on_declarator_not_declaring_a_function : Error<
399399
"trailing requires clause can only be used when declaring a function">;
400400
def err_requires_clause_inside_parens : Error<
401401
"trailing requires clause should be placed outside parentheses">;
402+
def err_auto_type_specifier : Error<
403+
"'auto' cannot be combined with a type specifier in C++">;
402404
def ext_auto_storage_class : ExtWarn<
403405
"'auto' storage class specifier is not permitted in C++11, and will not "
404406
"be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>;

clang/lib/Parse/ParseDecl.cpp

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4095,11 +4095,46 @@ void Parser::ParseDeclarationSpecifiers(
40954095
case tok::kw_auto:
40964096
if (getLangOpts().CPlusPlus11 || getLangOpts().C23) {
40974097
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
4098-
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
4099-
PrevSpec, DiagID, Policy);
4100-
if (!isInvalid && !getLangOpts().C23)
4101-
Diag(Tok, diag::ext_auto_storage_class)
4102-
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
4098+
// In C++ (not C23), 'auto' cannot be combined with a type specifier.
4099+
// However, OpenCL has its own error handling for this case.
4100+
// Also, static data member definitions are handled by Sema.
4101+
if (getLangOpts().CPlusPlus && !getLangOpts().C23 &&
4102+
!getLangOpts().OpenCLCPlusPlus) {
4103+
// Check if this might be a static data member definition (has :: in the name).
4104+
// If so, let Sema handle it with its more specific error message.
4105+
// Pattern: auto TYPE CLASS::member
4106+
// We need to look past the type specifier to find ::
4107+
bool MightBeStaticDataMember = false;
4108+
unsigned LookAhead = 2; // Skip 'auto' and the type specifier
4109+
while (LookAhead <= 15) { // Safety limit
4110+
Token Next = GetLookAheadToken(LookAhead);
4111+
if (Next.is(tok::coloncolon)) {
4112+
MightBeStaticDataMember = true;
4113+
break;
4114+
}
4115+
// Stop if we hit something that's not part of a qualified name
4116+
if (Next.is(tok::semi) || Next.is(tok::equal) ||
4117+
Next.is(tok::l_brace) || Next.is(tok::l_paren)) {
4118+
break;
4119+
}
4120+
LookAhead++;
4121+
}
4122+
4123+
if (!MightBeStaticDataMember) {
4124+
isInvalid = true;
4125+
if (!PrevSpec)
4126+
PrevSpec = "";
4127+
DiagID = diag::err_auto_type_specifier;
4128+
} else {
4129+
// Let it through so Sema can emit the static data member error.
4130+
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
4131+
PrevSpec, DiagID, Policy);
4132+
}
4133+
} else {
4134+
// C23 allows 'auto' as storage class with type specifier.
4135+
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
4136+
PrevSpec, DiagID, Policy);
4137+
}
41034138
} else
41044139
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
41054140
DiagID, Policy);

clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77

88
auto int ao; // expected-error {{illegal storage class on file-scoped variable}}
99
#if __cplusplus >= 201103L // C++11 or later
10-
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
10+
// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}}
1111
#endif
1212

1313
auto void af(); // expected-error {{illegal storage class on function}}
1414
#if __cplusplus >= 201103L // C++11 or later
15-
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
15+
// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}}
1616
#endif
1717

1818
register int ro; // expected-error {{illegal storage class on file-scoped variable}}
@@ -27,11 +27,11 @@ register void rf(); // expected-error {{illegal storage class on function}}
2727
struct S {
2828
auto int ao; // expected-error {{storage class specified for a member declaration}}
2929
#if __cplusplus >= 201103L // C++11 or later
30-
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
30+
// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}}
3131
#endif
3232
auto void af(); // expected-error {{storage class specified for a member declaration}}
3333
#if __cplusplus >= 201103L // C++11 or later
34-
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
34+
// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}}
3535
#endif
3636

3737
register int ro; // expected-error {{storage class specified for a member declaration}}
@@ -40,19 +40,19 @@ struct S {
4040

4141
void foo(auto int ap, register int rp) {
4242
#if __cplusplus >= 201703L
43-
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
43+
// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}}
4444
// expected-error@-3 {{ISO C++17 does not allow 'register' storage class specifier}}
4545
#elif __cplusplus >= 201103L
46-
// expected-warning@-5 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
46+
// expected-error@-5 {{'auto' cannot be combined with a type specifier in C++}}
4747
// expected-warning@-6 {{'register' storage class specifier is deprecated}}
4848
#endif
4949
auto int abo;
5050
#if __cplusplus >= 201103L // C++11 or later
51-
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
51+
// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}}
5252
#endif
5353
auto void abf(); // expected-error {{illegal storage class on function}}
5454
#if __cplusplus >= 201103L // C++11 or later
55-
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
55+
// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}}
5656
#endif
5757

5858
register int rbo;

clang/test/CXX/drs/cwg3xx.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,11 +1732,10 @@ namespace cwg395 { // cwg395: 3.0
17321732
namespace cwg396 { // cwg396: 3.0
17331733
void f() {
17341734
auto int a();
1735-
// since-cxx11-error@-1 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
1736-
// expected-error@-2 {{illegal storage class on function}}
1735+
// since-cxx11-error@-1 {{'auto' cannot be combined with a type specifier in C++}}
17371736
int (i); // #cwg396-i
17381737
auto int (i);
1739-
// since-cxx11-error@-1 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
1738+
// since-cxx11-error@-1 {{'auto' cannot be combined with a type specifier in C++}}
17401739
// expected-error@-2 {{redefinition of 'i'}}
17411740
// expected-note@#cwg396-i {{previous definition is here}}
17421741
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
2+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
3+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
4+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
5+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++23 %s
6+
7+
// Test that 'auto' cannot be combined with a type specifier in C++.
8+
void f() {
9+
auto int x = 1; // expected-error {{'auto' cannot be combined with a type specifier in C++}}
10+
auto char c = 'a'; // expected-error {{'auto' cannot be combined with a type specifier in C++}}
11+
auto float f = 1.0f; // expected-error {{'auto' cannot be combined with a type specifier in C++}}
12+
auto double d = 1.0; // expected-error {{'auto' cannot be combined with a type specifier in C++}}
13+
auto long l = 1L; // expected-error {{'auto' cannot be combined with a type specifier in C++}}
14+
}
15+
16+
// Test that regular 'auto' (type deduction) still works in C++.
17+
void h() {
18+
auto x = 1;
19+
auto y = 2.0;
20+
auto z = 'c';
21+
}
22+

clang/test/SemaCXX/auto-cxx0x.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
22
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y
33
void f() {
4-
auto int a; // expected-warning {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
4+
auto int a; // expected-error {{'auto' cannot be combined with a type specifier in C++}}
55
int auto b; // expected-error{{cannot combine with previous 'int' declaration specifier}}
66
}
77

clang/test/SemaCXX/class.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class C {
66
#if __cplusplus <= 199711L
77
// expected-warning@-2 {{'auto' storage class specifier is redundant}}
88
#else
9-
// expected-warning@-4 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
9+
// cxx11-error@-4 {{'auto' cannot be combined with a type specifier in C++}}
1010
#endif
1111
register int erry; // expected-error {{storage class specified for a member declaration}}
1212
extern int errz; // expected-error {{storage class specified for a member declaration}}

0 commit comments

Comments
 (0)