Skip to content

release/23.x: [clang] Emit diagnostic for typedef+auto missed case in C++98/C23 (#210141) - #211391

Merged
tru merged 1 commit into
llvm:release/23.xfrom
llvmbot:issue210141
Jul 23, 2026
Merged

tru merged 1 commit into
llvm:release/23.xfrom
llvmbot:issue210141

Conversation

@llvmbot

@llvmbot llvmbot commented Jul 22, 2026

Copy link
Copy Markdown
Member

Backport 34436db

Requested by: @efriedma-quic

@llvmbot

llvmbot commented Jul 22, 2026

Copy link
Copy Markdown
Member Author

@AaronBallman What do you think about merging this PR to the release branch?

@llvmbot
llvmbot requested a review from AaronBallman July 22, 2026 22:12
@llvmorg-github-actions llvmorg-github-actions Bot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jul 22, 2026
@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-clang

Author: llvmbot

Changes

Backport 34436db

Requested by: @efriedma-quic


Full diff: https://github.com/llvm/llvm-project/pull/211391.diff

2 Files Affected:

  • (modified) clang/lib/Sema/DeclSpec.cpp (+26-10)
  • (modified) clang/test/SemaCXX/auto-cxx98.cpp (+9-1)
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();
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}}
+}

@tru tru moved this from Needs Triage to Needs Review in LLVM Release Status Jul 23, 2026

@cor3ntin cor3ntin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a release note, otherwise LGTM

@github-project-automation github-project-automation Bot moved this from Needs Review to Needs Merge in LLVM Release Status Jul 23, 2026

@AaronBallman AaronBallman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@AaronBallman

Copy link
Copy Markdown
Contributor

We need a release note, otherwise LGTM

I don't think we need a release note -- 22.x was in good shape, so this restores the good shape of things.

…vm#210141)

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 add the check for tydef in the code handling auto.

(cherry picked from commit 34436db)
@tru
tru merged commit 01e4c77 into llvm:release/23.x Jul 23, 2026
1 check was pending
@github-project-automation github-project-automation Bot moved this from Needs Merge to Done in LLVM Release Status Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

Development

Successfully merging this pull request may close these issues.

5 participants