https://github.com/osamakader updated 
https://github.com/llvm/llvm-project/pull/166004

>From 67a90c46228aecc1692f5a46b2533ac37aef8e8c Mon Sep 17 00:00:00 2001
From: Osama Abdelkader <[email protected]>
Date: Sun, 2 Nov 2025 17:03:02 +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       |  5 ++-
 clang/lib/Parse/ParseDecl.cpp                 | 33 ++++++++++++-----
 .../test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp  | 36 ++++++++++++-------
 .../dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp |  2 +-
 .../dcl.spec/dcl.type/dcl.spec.auto/p3.cpp    |  7 +++-
 clang/test/CXX/drs/cwg3xx.cpp                 |  8 +++--
 clang/test/Parser/cxx-auto-type-specifier.cpp | 22 ++++++++++++
 clang/test/Parser/opencl-storage-class.cl     |  4 +--
 clang/test/SemaCXX/auto-cxx0x.cpp             |  2 +-
 clang/test/SemaCXX/class.cpp                  |  7 ++--
 clang/test/SemaCXX/static-data-member.cpp     |  7 +++-
 clang/test/SemaOpenCL/storageclass.cl         |  6 +---
 12 files changed, 97 insertions(+), 42 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..170616afff9b9 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -399,9 +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 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">>;
+def err_auto_type_specifier : Error<
+  "'auto' cannot be combined with a type specifier">;
 def ext_decltype_auto_type_specifier : ExtWarn<
   "'decltype(auto)' type specifier is a C++14 extension">, InGroup<CXX14>;
 def warn_cxx11_compat_decltype_auto_type_specifier : Warning<
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 7e4a164e34eda..45f696e9c474d 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4093,19 +4093,34 @@ void Parser::ParseDeclarationSpecifiers(
       isStorageClass = true;
       break;
     case tok::kw_auto:
-      if (getLangOpts().CPlusPlus11 || getLangOpts().C23) {
-        if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
+      if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
+        // 'auto' cannot be combined with a type specifier, except in C23 and 
C++98.
+        if (getLangOpts().C23) {
+          // C23 allows 'auto' as storage class with type specifier.
           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());
-        } else
+        } else if (getLangOpts().CPlusPlus11 || getLangOpts().OpenCL) {
+          // In C++11+ or OpenCL, 'auto' cannot be combined with a type 
specifier.
+          isInvalid = true;
+          PrevSpec = Tok.getIdentifierInfo()->getNameStart();
+          DiagID = diag::err_auto_type_specifier;
+        } else {
+          // In C++98 or C, 'auto' can be a storage class specifier with a 
type.
+          isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
+                                             PrevSpec, DiagID, Policy);
+        }
+      } else {
+        // 'auto' is not followed by a type specifier.
+        if (getLangOpts().CPlusPlus11 || getLangOpts().C23) {
+          // In C++11+ or C23, 'auto' is a type specifier (type deduction).
           isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
                                          DiagID, Policy);
-      } else
-        isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
-                                           PrevSpec, DiagID, Policy);
+        } else {
+          // In C (not C++11+ and not C23), 'auto' is a storage class 
specifier.
+          isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
+                                             PrevSpec, DiagID, Policy);
+        }
+      }
       isStorageClass = true;
       break;
     case tok::kw___auto_type:
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..da252d11175ab 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
@@ -5,14 +5,18 @@
 // The auto or register specifiers can be applied only to names of objects
 // declared in a block (6.3) or to function parameters (8.4).
 
-auto int ao; // expected-error {{illegal storage class on file-scoped 
variable}}
+auto int ao;
 #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}}
+#else
+// expected-error@-4 {{illegal storage class on file-scoped variable}}
 #endif
 
-auto void af(); // expected-error {{illegal storage class on function}}
+auto void af();
 #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}}
+#else
+// expected-error@-4 {{illegal storage class on function}}
 #endif
 
 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
 register void rf(); // expected-error {{illegal storage class on function}}
 
 struct S {
-  auto int ao; // expected-error {{storage class specified for a member 
declaration}}
+  auto int ao;
 #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}}
+#else
+// expected-error@-4 {{storage class specified for a member declaration}}
 #endif
-  auto void af(); // expected-error {{storage class specified for a member 
declaration}}
+  auto void af();
 #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}}
+#else
+// expected-error@-4 {{storage class specified for a member declaration}}
 #endif
 
   register int ro; // expected-error {{storage class specified for a member 
declaration}}
@@ -40,19 +48,21 @@ 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}}
 // 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}}
 // 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}}
 #endif
-  auto void abf(); // expected-error {{illegal storage class on function}}
+  auto void abf();
 #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}}
+#else
+// expected-error@-4 {{illegal storage class on function}}
 #endif
 
   register int rbo;
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp 
b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
index e8f12156a4242..907765780d069 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
@@ -56,7 +56,7 @@ namespace p3_example {
   auto x = 5;
   const auto *v = &x, u = 6;
   static auto y = 0.0;
-  auto int r;  // expected-warning {{storage class}} expected-error 
{{file-scope}}
+  auto int r;  // expected-error {{'auto' cannot be combined with a type 
specifier}}
 
   static_assert(is_same<decltype(x), int>(), "");
   static_assert(is_same<decltype(v), const int*>(), "");
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp 
b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
index 440c78201293b..8d7765523461c 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
@@ -42,7 +42,12 @@ void p3example() {
   static auto y = 0.0;
   // In C++98: 'auto' storage class specifier is redundant and incompatible 
with C++0x
   // In C++0x: 'auto' storage class specifier is not permitted in C++0x, and 
will not be supported in future releases
-  auto int r; // expected-warning {{'auto' storage class specifier}}
+  auto int r;
+#if __cplusplus >= 201103L
+  // expected-error@-2 {{'auto' cannot be combined with a type specifier}}
+#else
+  // expected-warning@-4 {{'auto' storage class specifier}}
+#endif
 
   same<__typeof(x), int> xHasTypeInt;
   same<__typeof(v), const int*> vHasTypeConstIntPtr;
diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp
index bbd87c060801a..2e735df3d8d78 100644
--- a/clang/test/CXX/drs/cwg3xx.cpp
+++ b/clang/test/CXX/drs/cwg3xx.cpp
@@ -1732,11 +1732,13 @@ 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}}
+    // cxx98-error@-1 {{illegal storage class on function}}
+    // since-cxx11-error@-2 {{'auto' cannot be combined with a type specifier}}
+    // since-cxx11-warning@-3 {{empty parentheses interpreted as a function 
declaration}}
+    // since-cxx11-note@-4 {{replace parentheses with an initializer to 
declare a variable}}
     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}}
     // 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..689e25abdea05
--- /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}}
+  auto char c = 'a';    // expected-error {{'auto' cannot be combined with a 
type specifier}}
+  auto float f = 1.0f;  // expected-error {{'auto' cannot be combined with a 
type specifier}}
+  auto double d = 1.0;   // expected-error {{'auto' cannot be combined with a 
type specifier}}
+  auto long l = 1L;     // expected-error {{'auto' cannot be combined with a 
type specifier}}
+}
+
+// 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/Parser/opencl-storage-class.cl 
b/clang/test/Parser/opencl-storage-class.cl
index 7d3e202e8127a..af4e0340ec795 100644
--- a/clang/test/Parser/opencl-storage-class.cl
+++ b/clang/test/Parser/opencl-storage-class.cl
@@ -5,11 +5,11 @@ void test_storage_class_specs()
   static int a;   // expected-error {{OpenCL C version 1.0 does not support 
the 'static' storage class specifier}}
   register int b; // expected-error {{OpenCL C version 1.0 does not support 
the 'register' storage class specifier}}
   extern int c;   // expected-error {{OpenCL C version 1.0 does not support 
the 'extern' storage class specifier}}
-  auto int d;     // expected-error {{OpenCL C version 1.0 does not support 
the 'auto' storage class specifier}}
+  auto int d;     // expected-error {{'auto' cannot be combined with a type 
specifier}}
 
 #pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
   static int e; // expected-error {{static local variable must reside in 
constant address space}}
   register int f;
   extern int g; // expected-error {{extern variable must reside in constant 
address space}}
-  auto int h;
+  auto int h; // expected-error {{'auto' cannot be combined with a type 
specifier}}
 }
diff --git a/clang/test/SemaCXX/auto-cxx0x.cpp 
b/clang/test/SemaCXX/auto-cxx0x.cpp
index 07687b6066790..8282444b1e96e 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}}
   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..fae85db68ddc4 100644
--- a/clang/test/SemaCXX/class.cpp
+++ b/clang/test/SemaCXX/class.cpp
@@ -2,11 +2,12 @@
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98 -Wc++11-compat %s 
-std=c++98
 class C {
 public:
-  auto int errx; // expected-error {{storage class specified for a member 
declaration}}
+  auto int errx;
 #if __cplusplus <= 199711L
-  // expected-warning@-2 {{'auto' storage class specifier is redundant}}
+  // expected-error@-2 {{storage class specified for a member declaration}}
+  // expected-warning@-3 {{'auto' storage class specifier is redundant and 
incompatible with C++11}}
 #else
-  // expected-warning@-4 {{'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}}
 #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}}
diff --git a/clang/test/SemaCXX/static-data-member.cpp 
b/clang/test/SemaCXX/static-data-member.cpp
index fb63da9b40099..2dbcae1745e5b 100644
--- a/clang/test/SemaCXX/static-data-member.cpp
+++ b/clang/test/SemaCXX/static-data-member.cpp
@@ -13,7 +13,12 @@ double ABC::a = 1.0;
 extern double ABC::b = 1.0; // expected-error {{static data member definition 
cannot specify a storage class}}
 static double ABC::c = 1.0;  // expected-error {{'static' can only be 
specified inside the class definition}}
 __private_extern__ double ABC::d = 1.0; // expected-error {{static data member 
definition cannot specify a storage class}}
-auto double ABC::e = 1.0; // expected-error {{static data member definition 
cannot specify a storage class}}
+auto double ABC::e = 1.0;
+#if __cplusplus >= 201103L
+// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
+#else
+// expected-error@-4 {{static data member definition cannot specify a storage 
class}}
+#endif
 #if __cplusplus < 201703L
 register double ABC::f = 1.0; // expected-error {{static data member 
definition cannot specify a storage class}}
 #endif
diff --git a/clang/test/SemaOpenCL/storageclass.cl 
b/clang/test/SemaOpenCL/storageclass.cl
index 4b9d6e9dd4f2d..53d0012d67fda 100644
--- a/clang/test/SemaOpenCL/storageclass.cl
+++ b/clang/test/SemaOpenCL/storageclass.cl
@@ -135,11 +135,7 @@ void kernel foo(int x) {
   }
 
   auto int L3 = 7;
-#if (__OPENCL_CPP_VERSION__ == 202100)
-// expected-error@-2{{C++ for OpenCL version 2021 does not support the 'auto' 
storage class specifier}}
-#else
-// expected-error-re@-4{{OpenCL C version {{1.2|3.0}} does not support the 
'auto' storage class specifier}}
-#endif
+// expected-error@-1{{'auto' cannot be combined with a type specifier}}
   global int L4;                              // expected-error{{function 
scope variable cannot be declared in global address space}}
   __attribute__((address_space(100))) int L5; // expected-error{{automatic 
variable qualified with an invalid address space}}
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to