[clang] 34436db - [clang] Emit diagnostic for typedef+auto missed case in C++98/C23 (#210141)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 22 07:41:03 PDT 2026
Author: Rahul
Date: 2026-07-22T10:40:58-04:00
New Revision: 34436db53d3e4ad36e86019109fb5ceee9bb4d8c
URL: https://github.com/llvm/llvm-project/commit/34436db53d3e4ad36e86019109fb5ceee9bb4d8c
DIFF: https://github.com/llvm/llvm-project/commit/34436db53d3e4ad36e86019109fb5ceee9bb4d8c.diff
LOG: [clang] Emit diagnostic for typedef+auto missed case in C++98/C23 (#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.
Added:
Modified:
clang/lib/Sema/DeclSpec.cpp
clang/test/SemaCXX/auto-cxx98.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index ef74cd5e8c8b0..75b9b06a6392e 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}}
+}
More information about the cfe-commits
mailing list