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

Reply via email to