Skip to content

Commit 88511de

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 88511de

File tree

12 files changed

+99
-42
lines changed

12 files changed

+99
-42
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,9 +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 ext_auto_storage_class : ExtWarn<
403-
"'auto' storage class specifier is not permitted in C++11, and will not "
404-
"be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>;
402+
def err_auto_type_specifier : Error<
403+
"'auto' cannot be combined with a type specifier">;
405404
def ext_decltype_auto_type_specifier : ExtWarn<
406405
"'decltype(auto)' type specifier is a C++14 extension">, InGroup<CXX14>;
407406
def warn_cxx11_compat_decltype_auto_type_specifier : Warning<

clang/lib/Parse/ParseDecl.cpp

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4093,19 +4093,36 @@ void Parser::ParseDeclarationSpecifiers(
40934093
isStorageClass = true;
40944094
break;
40954095
case tok::kw_auto:
4096-
if (getLangOpts().CPlusPlus11 || getLangOpts().C23) {
4097-
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
4096+
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
4097+
// 'auto' cannot be combined with a type specifier, except in C23 and
4098+
// C++98.
4099+
if (getLangOpts().C23) {
4100+
// C23 allows 'auto' as storage class with type specifier.
40984101
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
40994102
PrevSpec, DiagID, Policy);
4100-
if (!isInvalid && !getLangOpts().C23)
4101-
Diag(Tok, diag::ext_auto_storage_class)
4102-
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
4103-
} else
4103+
} else if (getLangOpts().CPlusPlus11 || getLangOpts().OpenCL) {
4104+
// In C++11+ or OpenCL, 'auto' cannot be combined with a type
4105+
// specifier.
4106+
isInvalid = true;
4107+
PrevSpec = Tok.getIdentifierInfo()->getNameStart();
4108+
DiagID = diag::err_auto_type_specifier;
4109+
} else {
4110+
// In C++98 or C, 'auto' can be a storage class specifier with a type.
4111+
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
4112+
PrevSpec, DiagID, Policy);
4113+
}
4114+
} else {
4115+
// 'auto' is not followed by a type specifier.
4116+
if (getLangOpts().CPlusPlus11 || getLangOpts().C23) {
4117+
// In C++11+ or C23, 'auto' is a type specifier (type deduction).
41044118
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
41054119
DiagID, Policy);
4106-
} else
4107-
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
4108-
PrevSpec, DiagID, Policy);
4120+
} else {
4121+
// In C (not C++11+ and not C23), 'auto' is a storage class specifier.
4122+
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
4123+
PrevSpec, DiagID, Policy);
4124+
}
4125+
}
41094126
isStorageClass = true;
41104127
break;
41114128
case tok::kw___auto_type:

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

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@
55
// The auto or register specifiers can be applied only to names of objects
66
// declared in a block (6.3) or to function parameters (8.4).
77

8-
auto int ao; // expected-error {{illegal storage class on file-scoped variable}}
8+
auto int ao;
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}}
11+
#else
12+
// expected-error@-4 {{illegal storage class on file-scoped variable}}
1113
#endif
1214

13-
auto void af(); // expected-error {{illegal storage class on function}}
15+
auto void af();
1416
#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}}
17+
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
18+
#else
19+
// expected-error@-4 {{illegal storage class on function}}
1620
#endif
1721

1822
register int ro; // expected-error {{illegal storage class on file-scoped variable}}
@@ -25,13 +29,17 @@ register int ro; // expected-error {{illegal storage class on file-scoped variab
2529
register void rf(); // expected-error {{illegal storage class on function}}
2630

2731
struct S {
28-
auto int ao; // expected-error {{storage class specified for a member declaration}}
32+
auto int ao;
2933
#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}}
34+
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
35+
#else
36+
// expected-error@-4 {{storage class specified for a member declaration}}
3137
#endif
32-
auto void af(); // expected-error {{storage class specified for a member declaration}}
38+
auto void af();
3339
#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}}
40+
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
41+
#else
42+
// expected-error@-4 {{storage class specified for a member declaration}}
3543
#endif
3644

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

4149
void foo(auto int ap, register int rp) {
4250
#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}}
51+
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
4452
// expected-error@-3 {{ISO C++17 does not allow 'register' storage class specifier}}
4553
#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}}
54+
// expected-error@-5 {{'auto' cannot be combined with a type specifier}}
4755
// expected-warning@-6 {{'register' storage class specifier is deprecated}}
4856
#endif
4957
auto int abo;
5058
#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}}
59+
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
5260
#endif
53-
auto void abf(); // expected-error {{illegal storage class on function}}
61+
auto void abf();
5462
#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}}
63+
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
64+
#else
65+
// expected-error@-4 {{illegal storage class on function}}
5666
#endif
5767

5868
register int rbo;

clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ namespace p3_example {
5656
auto x = 5;
5757
const auto *v = &x, u = 6;
5858
static auto y = 0.0;
59-
auto int r; // expected-warning {{storage class}} expected-error {{file-scope}}
59+
auto int r; // expected-error {{'auto' cannot be combined with a type specifier}}
6060

6161
static_assert(is_same<decltype(x), int>(), "");
6262
static_assert(is_same<decltype(v), const int*>(), "");

clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ void p3example() {
4242
static auto y = 0.0;
4343
// In C++98: 'auto' storage class specifier is redundant and incompatible with C++0x
4444
// In C++0x: 'auto' storage class specifier is not permitted in C++0x, and will not be supported in future releases
45-
auto int r; // expected-warning {{'auto' storage class specifier}}
45+
auto int r;
46+
#if __cplusplus >= 201103L
47+
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
48+
#else
49+
// expected-warning@-4 {{'auto' storage class specifier}}
50+
#endif
4651

4752
same<__typeof(x), int> xHasTypeInt;
4853
same<__typeof(v), const int*> vHasTypeConstIntPtr;

clang/test/CXX/drs/cwg3xx.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,11 +1732,13 @@ 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+
// cxx98-error@-1 {{illegal storage class on function}}
1736+
// since-cxx11-error@-2 {{'auto' cannot be combined with a type specifier}}
1737+
// since-cxx11-warning@-3 {{empty parentheses interpreted as a function declaration}}
1738+
// since-cxx11-note@-4 {{replace parentheses with an initializer to declare a variable}}
17371739
int (i); // #cwg396-i
17381740
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}}
1741+
// since-cxx11-error@-1 {{'auto' cannot be combined with a type specifier}}
17401742
// expected-error@-2 {{redefinition of 'i'}}
17411743
// expected-note@#cwg396-i {{previous definition is here}}
17421744
}
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}}
10+
auto char c = 'a'; // expected-error {{'auto' cannot be combined with a type specifier}}
11+
auto float f = 1.0f; // expected-error {{'auto' cannot be combined with a type specifier}}
12+
auto double d = 1.0; // expected-error {{'auto' cannot be combined with a type specifier}}
13+
auto long l = 1L; // expected-error {{'auto' cannot be combined with a type specifier}}
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/Parser/opencl-storage-class.cl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ void test_storage_class_specs()
55
static int a; // expected-error {{OpenCL C version 1.0 does not support the 'static' storage class specifier}}
66
register int b; // expected-error {{OpenCL C version 1.0 does not support the 'register' storage class specifier}}
77
extern int c; // expected-error {{OpenCL C version 1.0 does not support the 'extern' storage class specifier}}
8-
auto int d; // expected-error {{OpenCL C version 1.0 does not support the 'auto' storage class specifier}}
8+
auto int d; // expected-error {{'auto' cannot be combined with a type specifier}}
99

1010
#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
1111
static int e; // expected-error {{static local variable must reside in constant address space}}
1212
register int f;
1313
extern int g; // expected-error {{extern variable must reside in constant address space}}
14-
auto int h;
14+
auto int h; // expected-error {{'auto' cannot be combined with a type specifier}}
1515
}

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}}
55
int auto b; // expected-error{{cannot combine with previous 'int' declaration specifier}}
66
}
77

clang/test/SemaCXX/class.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98 -Wc++11-compat %s -std=c++98
33
class C {
44
public:
5-
auto int errx; // expected-error {{storage class specified for a member declaration}}
5+
auto int errx;
66
#if __cplusplus <= 199711L
7-
// expected-warning@-2 {{'auto' storage class specifier is redundant}}
7+
// expected-error@-2 {{storage class specified for a member declaration}}
8+
// expected-warning@-3 {{'auto' storage class specifier is redundant and incompatible with C++11}}
89
#else
9-
// expected-warning@-4 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
10+
// expected-error@-5 {{'auto' cannot be combined with a type specifier}}
1011
#endif
1112
register int erry; // expected-error {{storage class specified for a member declaration}}
1213
extern int errz; // expected-error {{storage class specified for a member declaration}}

0 commit comments

Comments
 (0)