https://github.com/osamakader updated https://github.com/llvm/llvm-project/pull/166004
>From 9bc604524425641cdf7072a080d4e7ef160c51a1 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Sat, 1 Nov 2025 19:53:55 +0200 Subject: [PATCH] [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]> --- .../clang/Basic/DiagnosticParseKinds.td | 2 + clang/lib/Parse/ParseDecl.cpp | 45 ++++++++++++++++--- .../test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp | 16 +++---- clang/test/CXX/drs/cwg3xx.cpp | 5 +-- clang/test/Parser/cxx-auto-type-specifier.cpp | 22 +++++++++ clang/test/SemaCXX/auto-cxx0x.cpp | 2 +- clang/test/SemaCXX/class.cpp | 2 +- 7 files changed, 76 insertions(+), 18 deletions(-) create mode 100644 clang/test/Parser/cxx-auto-type-specifier.cpp diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index e5e071f43fa75..baf91b107b8c4 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -399,6 +399,8 @@ def err_requires_clause_on_declarator_not_declaring_a_function : Error< "trailing requires clause can only be used when declaring a function">; def err_requires_clause_inside_parens : Error< "trailing requires clause should be placed outside parentheses">; +def err_auto_type_specifier : Error< + "'auto' cannot be combined with a type specifier in C++">; def ext_auto_storage_class : ExtWarn< "'auto' storage class specifier is not permitted in C++11, and will not " "be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7e4a164e34eda..51ae397836b0f 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4095,11 +4095,46 @@ void Parser::ParseDeclarationSpecifiers( case tok::kw_auto: if (getLangOpts().CPlusPlus11 || getLangOpts().C23) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { - isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, - PrevSpec, DiagID, Policy); - if (!isInvalid && !getLangOpts().C23) - Diag(Tok, diag::ext_auto_storage_class) - << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); + // In C++ (not C23), 'auto' cannot be combined with a type specifier. + // However, OpenCL has its own error handling for this case. + // Also, static data member definitions are handled by Sema. + if (getLangOpts().CPlusPlus && !getLangOpts().C23 && + !getLangOpts().OpenCLCPlusPlus) { + // Check if this might be a static data member definition (has :: in the name). + // If so, let Sema handle it with its more specific error message. + // Pattern: auto TYPE CLASS::member + // We need to look past the type specifier to find :: + bool MightBeStaticDataMember = false; + unsigned LookAhead = 2; // Skip 'auto' and the type specifier + while (LookAhead <= 15) { // Safety limit + Token Next = GetLookAheadToken(LookAhead); + if (Next.is(tok::coloncolon)) { + MightBeStaticDataMember = true; + break; + } + // Stop if we hit something that's not part of a qualified name + if (Next.is(tok::semi) || Next.is(tok::equal) || + Next.is(tok::l_brace) || Next.is(tok::l_paren)) { + break; + } + LookAhead++; + } + + if (!MightBeStaticDataMember) { + isInvalid = true; + if (!PrevSpec) + PrevSpec = ""; + DiagID = diag::err_auto_type_specifier; + } else { + // Let it through so Sema can emit the static data member error. + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, + PrevSpec, DiagID, Policy); + } + } else { + // C23 allows 'auto' as storage class with type specifier. + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, + PrevSpec, DiagID, Policy); + } } else isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID, Policy); diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp index 723a79628116c..6625c95a35310 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp @@ -7,12 +7,12 @@ auto int ao; // expected-error {{illegal storage class on file-scoped variable}} #if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} +// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}} #endif auto void af(); // expected-error {{illegal storage class on function}} #if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} +// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}} #endif 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}} struct S { auto int ao; // expected-error {{storage class specified for a member declaration}} #if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} +// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}} #endif auto void af(); // expected-error {{storage class specified for a member declaration}} #if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} +// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}} #endif register int ro; // expected-error {{storage class specified for a member declaration}} @@ -40,19 +40,19 @@ struct S { void foo(auto int ap, register int rp) { #if __cplusplus >= 201703L -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} +// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}} // expected-error@-3 {{ISO C++17 does not allow 'register' storage class specifier}} #elif __cplusplus >= 201103L -// expected-warning@-5 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} +// expected-error@-5 {{'auto' cannot be combined with a type specifier in C++}} // expected-warning@-6 {{'register' storage class specifier is deprecated}} #endif auto int abo; #if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} +// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}} #endif auto void abf(); // expected-error {{illegal storage class on function}} #if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} +// expected-error@-2 {{'auto' cannot be combined with a type specifier in C++}} #endif register int rbo; diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp index bbd87c060801a..27cd036627dc0 100644 --- a/clang/test/CXX/drs/cwg3xx.cpp +++ b/clang/test/CXX/drs/cwg3xx.cpp @@ -1732,11 +1732,10 @@ namespace cwg395 { // cwg395: 3.0 namespace cwg396 { // cwg396: 3.0 void f() { auto int a(); - // since-cxx11-error@-1 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} - // expected-error@-2 {{illegal storage class on function}} + // since-cxx11-error@-1 {{'auto' cannot be combined with a type specifier in C++}} int (i); // #cwg396-i auto int (i); - // since-cxx11-error@-1 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} + // since-cxx11-error@-1 {{'auto' cannot be combined with a type specifier in C++}} // expected-error@-2 {{redefinition of 'i'}} // expected-note@#cwg396-i {{previous definition is here}} } diff --git a/clang/test/Parser/cxx-auto-type-specifier.cpp b/clang/test/Parser/cxx-auto-type-specifier.cpp new file mode 100644 index 0000000000000..f34195934cc85 --- /dev/null +++ b/clang/test/Parser/cxx-auto-type-specifier.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++23 %s + +// Test that 'auto' cannot be combined with a type specifier in C++. +void f() { + auto int x = 1; // expected-error {{'auto' cannot be combined with a type specifier in C++}} + auto char c = 'a'; // expected-error {{'auto' cannot be combined with a type specifier in C++}} + auto float f = 1.0f; // expected-error {{'auto' cannot be combined with a type specifier in C++}} + auto double d = 1.0; // expected-error {{'auto' cannot be combined with a type specifier in C++}} + auto long l = 1L; // expected-error {{'auto' cannot be combined with a type specifier in C++}} +} + +// Test that regular 'auto' (type deduction) still works in C++. +void h() { + auto x = 1; + auto y = 2.0; + auto z = 'c'; +} + diff --git a/clang/test/SemaCXX/auto-cxx0x.cpp b/clang/test/SemaCXX/auto-cxx0x.cpp index 07687b6066790..2662319b900cd 100644 --- a/clang/test/SemaCXX/auto-cxx0x.cpp +++ b/clang/test/SemaCXX/auto-cxx0x.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y void f() { - auto int a; // expected-warning {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} + auto int a; // expected-error {{'auto' cannot be combined with a type specifier in C++}} int auto b; // expected-error{{cannot combine with previous 'int' declaration specifier}} } diff --git a/clang/test/SemaCXX/class.cpp b/clang/test/SemaCXX/class.cpp index f1e02d5158aac..3f65919655c52 100644 --- a/clang/test/SemaCXX/class.cpp +++ b/clang/test/SemaCXX/class.cpp @@ -6,7 +6,7 @@ class C { #if __cplusplus <= 199711L // expected-warning@-2 {{'auto' storage class specifier is redundant}} #else - // expected-warning@-4 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} + // cxx11-error@-4 {{'auto' cannot be combined with a type specifier in C++}} #endif register int erry; // expected-error {{storage class specified for a member declaration}} extern int errz; // expected-error {{storage class specified for a member declaration}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
