https://github.com/rahulana-quic updated 
https://github.com/llvm/llvm-project/pull/210141

>From 62c7c85e99e7551ade93e3b6173e00b47d5019a6 Mon Sep 17 00:00:00 2001
From: Rahul Anand Radhakrishnan <[email protected]>
Date: Thu, 16 Jul 2026 11:43:59 -0700
Subject: [PATCH 1/2] [clang] Add test for typedef+auto diagnostic in
 C++98/pre-C23 C

---
 clang/test/SemaCXX/auto-cxx98.cpp | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/clang/test/SemaCXX/auto-cxx98.cpp 
b/clang/test/SemaCXX/auto-cxx98.cpp
index 1e28d0635a48d..db2036d462532 100644
--- a/clang/test/SemaCXX/auto-cxx98.cpp
+++ b/clang/test/SemaCXX/auto-cxx98.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wc++11-compat 
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wc++11-compat
 void f() {
   auto int a; // expected-warning {{'auto' storage class specifier is 
redundant and incompatible with C++11}}
   int auto b; // expected-warning {{'auto' storage class specifier is 
redundant and incompatible with C++11}}
@@ -6,3 +6,11 @@ void f() {
   static auto d = 0; // expected-warning {{C++11 extension}}
   auto static e = 0; // expected-warning {{C++11 extension}}
 }
+
+// typedef and auto storage-class-specifier cannot appear in the same
+// decl-specifier-seq ([dcl.stc] p1). This must be diagnosed in C++98 even
+// though 'auto int' (without typedef) is valid there.
+void g() {
+  typedef auto int t1;    // expected-error {{cannot combine with previous 
'typedef' declaration specifier}}
+  auto typedef int t2;    // expected-error {{cannot combine with previous 
'typedef' declaration specifier}}
+}

>From f27d290caa8bd53e6fdf77000faf113fb02b4199 Mon Sep 17 00:00:00 2001
From: Rahul Anand Radhakrishnan <[email protected]>
Date: Thu, 16 Jul 2026 11:43:59 -0700
Subject: [PATCH 2/2] [clang] Emit diagnostic for typedef+auto missed case in
 C++98/C23

CheckTypeSpec() converted 'auto' to a storage-class specifier without
checking whether 'typedef' was already set. [dcl.stc]p1 unconditionally
forbids typedef alongside any storage-class specifier regardless of C++
version.

This change adds the check for tydef in the code handling auto in the
C++98/C23 paths.
---
 clang/lib/Sema/DeclSpec.cpp | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 4d20657d5e517..8751aab1c9b8d 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -1244,11 +1244,19 @@ void DeclSpec::CheckTypeSpec(Sema &S, const 
PrintingPolicy &Policy) {
                (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)) {
       // In C23 or C++98, convert 'auto' to storage class specifier
       if (TypeSpecType == TST_auto) {
-        // "auto int" case: Convert 'auto' to storage class specifier
-        StorageClassSpec = SCS_auto;
-        StorageClassSpecLoc = TSTLoc;
-        TypeSpecType = ConflictingTypeSpecifier;
-        TSTLoc = ConflictingTypeSpecifierLoc;
+        // "auto int" case: Convert 'auto' to storage class specifier.
+        // But typedef + any storage-class-specifier is unconditionally invalid
+        // per [dcl.stc]p1, regardless of C++ version.
+        if (StorageClassSpec == SCS_typedef) {
+          S.Diag(TSTLoc, diag::err_invalid_decl_spec_combination)
+              << "typedef" << FixItHint::CreateRemoval(TSTLoc);
+          TypeSpecType = TST_error;
+        } else {
+          StorageClassSpec = SCS_auto;
+          StorageClassSpecLoc = TSTLoc;
+          TypeSpecType = ConflictingTypeSpecifier;
+          TSTLoc = ConflictingTypeSpecifierLoc;
+        }
         // Clear the conflict tracking
         ConflictingTypeSpecifier = TST_unspecified;
         ConflictingTypeSpecifierLoc = SourceLocation();
@@ -1273,11 +1281,19 @@ void DeclSpec::CheckTypeSpec(Sema &S, const 
PrintingPolicy &Policy) {
           return;
         }
         // int auto (without constexpr): Convert 'auto' to storage class
-        // specifier. No type conflict error - auto is treated as storage 
class,
-        // not type specifier.
-        StorageClassSpec = SCS_auto;
-        StorageClassSpecLoc = ConflictingTypeSpecifierLoc;
-        // TypeSpecType already has the correct type (e.g., TST_int)
+        // specifier. But typedef + any storage-class-specifier is
+        // unconditionally invalid per [dcl.stc]p1.
+        if (StorageClassSpec == SCS_typedef) {
+          S.Diag(ConflictingTypeSpecifierLoc,
+                 diag::err_invalid_decl_spec_combination)
+              << "typedef"
+              << FixItHint::CreateRemoval(ConflictingTypeSpecifierLoc);
+          TypeSpecType = TST_error;
+        } else {
+          StorageClassSpec = SCS_auto;
+          StorageClassSpecLoc = ConflictingTypeSpecifierLoc;
+          // TypeSpecType already has the correct type (e.g., TST_int)
+        }
         // Clear the conflict tracking
         ConflictingTypeSpecifier = TST_unspecified;
         ConflictingTypeSpecifierLoc = SourceLocation();

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

Reply via email to