[clang] 6d1b926 - [Clang] Revert "Reject auto combined with type specifiers in C++ (#208552)" and follow-ups commits (#215320)

via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 11 02:00:51 PDT 2026


Author: Tony Guillot
Date: 2026-08-11T11:00:46+02:00
New Revision: 6d1b926b6a9428e5b561bcda0432b39e07cb7cc6

URL: https://github.com/llvm/llvm-project/commit/6d1b926b6a9428e5b561bcda0432b39e07cb7cc6
DIFF: https://github.com/llvm/llvm-project/commit/6d1b926b6a9428e5b561bcda0432b39e07cb7cc6.diff

LOG: [Clang] Revert "Reject auto combined with type specifiers in C++ (#208552)" and follow-ups commits (#215320)

The initial fix for #164273 had several follow up commits to fix the
initial implementation. This fix induces a lot of regressions and a
refactoring of the area is required in order to fix the issue in a later
release.

This reverts the following commits (from oldest to latest):
72af746a3e19627fc1d1c40bf6eabb2887850ac5
226acaf7aeeda64a6e4e55d21f586ffe97a72fc8
d592aa5a10f44164cd403257270802eb2a4b123a
34436db53d3e4ad36e86019109fb5ceee9bb4d8c
de4b1f5572f8ff5a38a17655584ae200774551c6

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/DeclSpec.h
    clang/lib/Parse/ParseDecl.cpp
    clang/lib/Sema/DeclSpec.cpp
    clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp
    clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
    clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp
    clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
    clang/test/CXX/dcl/dcl.fct/p17.cpp
    clang/test/CXX/drs/cwg3xx.cpp
    clang/test/Parser/c2x-auto.c
    clang/test/SemaCXX/auto-cxx0x.cpp
    clang/test/SemaCXX/auto-cxx98.cpp
    clang/test/SemaCXX/class.cpp
    clang/test/SemaCXX/static-data-member.cpp

Removed: 
    clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.type.general/p2.cpp


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4e9c6fd8cbf0e..5e1d1d546bb3e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2775,8 +2775,6 @@ def err_decltype_auto_invalid : Error<
   "'decltype(auto)' not allowed here">;
 def err_decltype_auto_cannot_be_combined : Error<
   "'decltype(auto)' cannot be combined with other type specifiers">;
-def err_auto_type_specifier : Error<
-  "'auto' cannot be combined with a type specifier">;
 def err_decltype_auto_function_declarator_not_declaration : Error<
   "'decltype(auto)' can only be used as a return type "
   "in a function declaration">;

diff  --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 659bc06a257b5..e6dc6831d893f 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -363,10 +363,6 @@ class DeclSpec {
   unsigned TypeSpecSat : 1;
   LLVM_PREFERRED_TYPE(bool)
   unsigned ConstrainedAuto : 1;
-  // Track conflicting type specifier when 'auto' is set (for Finish()
-  // detection)
-  LLVM_PREFERRED_TYPE(TST)
-  unsigned ConflictingTypeSpecifier : 7;
 
   // type-qualifiers
   LLVM_PREFERRED_TYPE(TQ)
@@ -431,50 +427,10 @@ class DeclSpec {
   SourceLocation FS_explicitCloseParenLoc;
   SourceLocation FS_forceinlineLoc;
   SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
-  SourceLocation TQ_pipeLoc, ConflictingTypeSpecifierLoc;
+  SourceLocation TQ_pipeLoc;
 
   WrittenBuiltinSpecs writtenBS;
   void SaveWrittenBuiltinSpecs();
-  void setConflictingTypeSpecifier(TST T, SourceLocation Loc) {
-    // Store conflicting type specifier for Finish() to detect:
-    // - If 'auto' is already set, store the conflicting type (e.g., "auto int")
-    // - If 'auto' is being set after another type, store TST_auto
-    //   (e.g., "int auto").
-    if (TypeSpecType == TST_auto) {
-      ConflictingTypeSpecifier = T;
-      ConflictingTypeSpecifierLoc = Loc;
-    } else if (T == TST_auto) {
-      ConflictingTypeSpecifier = TST_auto;
-      ConflictingTypeSpecifierLoc = Loc;
-    }
-  }
-  void setConflictingTypeSpecifier(TST T, SourceLocation Loc,
-                                   SourceLocation NameLoc, ParsedType Rep) {
-    setConflictingTypeSpecifier(T, Loc);
-    if (TypeSpecType == TST_auto) {
-      TypeRep = Rep;
-      TSTNameLoc = NameLoc;
-      TypeSpecOwned = false;
-    }
-  }
-  void setConflictingTypeSpecifier(TST T, SourceLocation Loc, Expr *Rep) {
-    setConflictingTypeSpecifier(T, Loc);
-    if (TypeSpecType == TST_auto) {
-      ExprRep = Rep;
-      TSTNameLoc = Loc;
-      TypeSpecOwned = false;
-    }
-  }
-  void setConflictingTypeSpecifier(TST T, SourceLocation Loc,
-                                   SourceLocation NameLoc, Decl *Rep,
-                                   bool Owned) {
-    setConflictingTypeSpecifier(T, Loc);
-    if (TypeSpecType == TST_auto) {
-      DeclRep = Rep;
-      TSTNameLoc = NameLoc;
-      TypeSpecOwned = Owned && Rep != nullptr;
-    }
-  }
 
   ObjCDeclSpec *ObjCQualifiers;
 
@@ -518,15 +474,13 @@ class DeclSpec {
         TypeSpecType(TST_unspecified), TypeAltiVecVector(false),
         TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false),
         TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false),
-        ConflictingTypeSpecifier(TST_unspecified),
         TypeQualifiers(TQ_unspecified),
         OB_state(static_cast<unsigned>(OverflowBehaviorState::Unspecified)),
         FS_inline_specified(false), FS_forceinline_specified(false),
         FS_virtual_specified(false), FS_noreturn_specified(false),
         FriendSpecifiedFirst(false), ConstexprSpecifier(static_cast<unsigned>(
                                          ConstexprSpecKind::Unspecified)),
-        Attrs(attrFactory), ConflictingTypeSpecifierLoc(), writtenBS(),
-        ObjCQualifiers(nullptr) {}
+        Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {}
 
   // storage-class-specifier
   SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
@@ -566,9 +520,6 @@ class DeclSpec {
     return static_cast<TypeSpecifierSign>(TypeSpecSign);
   }
   TST getTypeSpecType() const { return (TST)TypeSpecType; }
-  bool hasConflictingTypeSpecifier() const {
-    return ConflictingTypeSpecifier != TST_unspecified;
-  }
   bool isTypeAltiVecVector() const { return TypeAltiVecVector; }
   bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; }
   bool isTypeAltiVecBool() const { return TypeAltiVecBool; }

diff  --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 2aaeba9225c38..2bbc76fc7c4df 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3778,9 +3778,7 @@ void Parser::ParseDeclarationSpecifiers(
       // This identifier can only be a typedef name if we haven't already seen
       // a type-specifier.  Without this check we misparse:
       //  typedef int X; struct Y { short X; };  as 'short int'.
-      // However, if 'auto' is set, we need to check if this identifier is a
-      // type name to detect conflicts (e.g., "auto MyInt").
-      if (DS.hasTypeSpecifier() && DS.getTypeSpecType() != DeclSpec::TST_auto)
+      if (DS.hasTypeSpecifier())
         goto DoneWithDeclSpec;
 
       // If the token is an identifier named "__declspec" and Microsoft
@@ -3865,27 +3863,6 @@ void Parser::ParseDeclarationSpecifiers(
                                   DS.isFriendSpecified()))
         goto DoneWithDeclSpec;
 
-      // If 'auto' is set and we're in a template parameter context, the
-      // identifier is always the parameter name, not a type specifier, so skip
-      // type name lookup to avoid false ambiguity errors.
-      if (DS.getTypeSpecType() == DeclSpec::TST_auto &&
-          DSContext == DeclSpecContext::DSC_template_param) {
-        goto DoneWithDeclSpec;
-      }
-
-      // If 'auto' is set and the next token indicates this identifier is the
-      // declarator-id, stop parsing declaration specifiers before doing type
-      // lookup. Looking up the declarator-id can produce bogus ambiguity errors
-      // when a variable name matches a type brought in by a using-directive.
-      if (DS.getTypeSpecType() == DeclSpec::TST_auto) {
-        Token Next = NextToken();
-        if (Next.isOneOf(tok::equal, tok::l_paren, tok::l_square, tok::l_brace,
-                         tok::amp, tok::ampamp, tok::star, tok::coloncolon,
-                         tok::comma, tok::semi, tok::colon, tok::greater,
-                         tok::r_paren, tok::arrow))
-          goto DoneWithDeclSpec;
-      }
-
       ParsedType TypeRep = Actions.getTypeName(
           *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr,
           false, false, nullptr, false, false,
@@ -3893,16 +3870,11 @@ void Parser::ParseDeclarationSpecifiers(
 
       // If this is not a typedef name, don't parse it as part of the declspec,
       // it must be an implicit int or an error.
-      // However, if 'auto' is already set, we can't have an implicit int.
       if (!TypeRep) {
         if (TryAnnotateTypeConstraint())
           goto DoneWithDeclSpec;
         if (Tok.isNot(tok::identifier))
           continue;
-        // If 'auto' is set, the identifier must be a type name or it's an
-        // error. Don't try to parse it as implicit int.
-        if (DS.getTypeSpecType() == DeclSpec::TST_auto)
-          goto DoneWithDeclSpec;
         ParsedAttributes Attrs(AttrFactory);
         if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) {
           if (!Attrs.empty()) {
@@ -4168,18 +4140,15 @@ void Parser::ParseDeclarationSpecifiers(
           }
         };
 
-        if (!getLangOpts().CPlusPlus && MayBeTypeSpecifier()) {
+        if (MayBeTypeSpecifier()) {
           isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
                                              PrevSpec, DiagID, Policy);
-        } else {
-          if (getLangOpts().CPlusPlus11 &&
-              NextToken().isOneOf(tok::kw_class, tok::kw_struct,
-                                  tok::kw___interface, tok::kw_union,
-                                  tok::kw_enum))
-            Diag(Loc, diag::ext_auto_storage_class);
+          if (!isInvalid && !getLangOpts().C23)
+            Diag(Tok, diag::ext_auto_storage_class)
+              << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+        } else
           isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
                                          DiagID, Policy);
-        }
       } else
         isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
                                            PrevSpec, DiagID, Policy);
@@ -4734,8 +4703,7 @@ void Parser::ParseDeclarationSpecifiers(
     DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : Tok.getLocation());
 
     // If the specifier wasn't legal, issue a diagnostic.
-    // Skip diagnostic if 'auto' conflict will be handled in Finish()
-    if (isInvalid && !DS.hasConflictingTypeSpecifier()) {
+    if (isInvalid) {
       assert(PrevSpec && "Method did not return previous specifier!");
       assert(DiagID);
 

diff  --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 1492bbf60a373..c13d5c8345604 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -431,7 +431,7 @@ void DeclSpec::forEachQualifier(
 }
 
 bool DeclSpec::hasTagDefinition() const {
-  if (!TypeSpecOwned || !isDeclRep((TST)TypeSpecType))
+  if (!TypeSpecOwned)
     return false;
   return cast<TagDecl>(getRepAsDecl())->isCompleteDefinition();
 }
@@ -759,7 +759,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
   if (TypeSpecType == TST_error)
     return false;
   if (TypeSpecType != TST_unspecified) {
-    setConflictingTypeSpecifier(T, TagKwLoc, TagNameLoc, Rep);
     PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
     DiagID = diag::err_invalid_decl_spec_combination;
     return true;
@@ -791,7 +790,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
   if (TypeSpecType == TST_error)
     return false;
   if (TypeSpecType != TST_unspecified) {
-    setConflictingTypeSpecifier(T, Loc, Rep);
     PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
     DiagID = diag::err_invalid_decl_spec_combination;
     return true;
@@ -824,7 +822,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
   if (TypeSpecType == TST_error)
     return false;
   if (TypeSpecType != TST_unspecified) {
-    setConflictingTypeSpecifier(T, TagKwLoc, TagNameLoc, Rep, Owned);
     PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
     DiagID = diag::err_invalid_decl_spec_combination;
     return true;
@@ -855,7 +852,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
   if (TypeSpecType == TST_error)
     return false;
   if (TypeSpecType != TST_unspecified) {
-    setConflictingTypeSpecifier(T, Loc);
     PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
     DiagID = diag::err_invalid_decl_spec_combination;
     return true;
@@ -1216,181 +1212,6 @@ void DeclSpec::CheckTypeSpec(Sema &S, const PrintingPolicy &Policy) {
       << Hints[4] << Hints[5] << Hints[6] << Hints[7];
   }
 
-  // If 'auto' type specifier is combined with another type specifier, we need
-  // to handle it based on the language:
-  // - In C++11+: Emit error (cannot combine type specifiers)
-  // - In C23: Convert 'auto' to storage class (valid)
-  // - In OpenCL: Convert 'auto' to storage class, then OpenCL will reject it
-  // Handle both cases:
-  // - "auto int" (TypeSpecType == TST_auto, ConflictingTypeSpecifier ==
-  // TST_int)
-  // - "int auto" (TypeSpecType == TST_int, ConflictingTypeSpecifier ==
-  // TST_auto)
-  if (ConflictingTypeSpecifier != TST_unspecified) {
-    // Special case: "auto auto" - duplicate 'auto', emit error
-    if (TypeSpecType == TST_auto && ConflictingTypeSpecifier == TST_auto) {
-      // Both are 'auto', emit "cannot combine with previous 'auto' declaration
-      // specifier" error This matches GCC's "duplicate 'auto'" behavior Note:
-      // We keep TypeSpecType = TST_auto (don't set to TST_error) so that later
-      // checks in SemaType.cpp can emit "not allowed in function prototype" and
-      // "not allowed in function return type" errors as needed.
-      const char *PrevSpec = "auto";
-      unsigned DiagID = diag::err_invalid_decl_spec_combination;
-      S.Diag(ConflictingTypeSpecifierLoc, DiagID) << PrevSpec << PrevSpec;
-      // Clear the conflict tracking but keep TypeSpecType = TST_auto
-      ConflictingTypeSpecifier = TST_unspecified;
-      ConflictingTypeSpecifierLoc = SourceLocation();
-    } else if ((S.getLangOpts().C23 && !S.getLangOpts().CPlusPlus) ||
-               (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.
-        // 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();
-      } else if (ConflictingTypeSpecifier == TST_auto) {
-        // "int auto" case: Convert 'auto' to storage class specifier
-        // In C23, if 'constexpr' is present, treat 'auto' as a type specifier
-        // conflict with 'int' rather than converting it to storage class, so we
-        // emit the "cannot combine with previous 'int' declaration specifier"
-        // error and mark the type as error to prevent further processing.
-        // Otherwise, convert 'auto' to storage class specifier (no type
-        // conflict error).
-        if (S.getLangOpts().C23 && !S.getLangOpts().CPlusPlus &&
-            getConstexprSpecifier() != ConstexprSpecKind::Unspecified) {
-          // constexpr int auto: treat as type specifier conflict
-          const char *PrevSpec =
-              getSpecifierName((TST)TypeSpecType, S.getPrintingPolicy());
-          unsigned DiagID = diag::err_invalid_decl_spec_combination;
-          S.Diag(ConflictingTypeSpecifierLoc, DiagID) << PrevSpec << "auto";
-          TypeSpecType = TST_error;
-          ConflictingTypeSpecifier = TST_unspecified;
-          ConflictingTypeSpecifierLoc = SourceLocation();
-          return;
-        }
-        // int auto (without constexpr): Convert 'auto' to storage class
-        // 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();
-      }
-    } else if (S.getLangOpts().OpenCL) {
-      // For OpenCL (C or C++), convert 'auto' to storage class specifier first
-      // (OpenCL will then reject it via SetStorageClassSpec checks)
-      // This must come before the C++11+ check to handle OpenCL C++
-      if (TypeSpecType == TST_auto) {
-        // "auto int" case: Convert 'auto' to storage class specifier
-        // Use SetStorageClassSpec to trigger OpenCL-specific error checking
-        const char *PrevSpec = nullptr;
-        unsigned DiagID = 0;
-        if (SetStorageClassSpec(
-                S, SCS_auto, TSTLoc, PrevSpec, DiagID,
-                S.getPrintingPolicy())) { // OpenCL rejected it, emit the error
-                                          // with version string
-          if (S.getLangOpts().OpenCL && S.getLangOpts().CPlusPlus) {
-            S.Diag(TSTLoc, DiagID)
-                << S.getLangOpts().getOpenCLVersionString() << PrevSpec << 1;
-          } else {
-            S.Diag(TSTLoc, DiagID) << PrevSpec;
-          }
-          TypeSpecType = TST_error;
-        } else {
-          StorageClassSpec = SCS_auto;
-          StorageClassSpecLoc = TSTLoc;
-          TypeSpecType = ConflictingTypeSpecifier;
-          TSTLoc = ConflictingTypeSpecifierLoc;
-        }
-        // Clear the conflict tracking
-        ConflictingTypeSpecifier = TST_unspecified;
-        ConflictingTypeSpecifierLoc = SourceLocation();
-      } else if (ConflictingTypeSpecifier == TST_auto) {
-        // "int auto" case: Convert 'auto' to storage class specifier
-        // Use SetStorageClassSpec to trigger OpenCL-specific error checking
-        const char *PrevSpec = nullptr;
-        unsigned DiagID = 0;
-        if (SetStorageClassSpec(S, SCS_auto, ConflictingTypeSpecifierLoc,
-                                PrevSpec, DiagID, S.getPrintingPolicy())) {
-          // OpenCL rejected it, emit the error with version string
-          if (S.getLangOpts().OpenCL && S.getLangOpts().CPlusPlus) {
-            S.Diag(ConflictingTypeSpecifierLoc, DiagID)
-                << S.getLangOpts().getOpenCLVersionString() << PrevSpec << 1;
-          } else {
-            S.Diag(ConflictingTypeSpecifierLoc, DiagID) << PrevSpec;
-          }
-          TypeSpecType = TST_error;
-        } else {
-          StorageClassSpec = SCS_auto;
-          StorageClassSpecLoc = ConflictingTypeSpecifierLoc;
-        }
-        // Clear the conflict tracking
-        ConflictingTypeSpecifier = TST_unspecified;
-        ConflictingTypeSpecifierLoc = SourceLocation();
-      }
-    } else if (S.getLangOpts().CPlusPlus && S.getLangOpts().CPlusPlus11 &&
-               !S.getLangOpts().C23) {
-      // In C++11+ (but not C23 or OpenCL), emit error (cannot combine type
-      // specifiers)
-      if (TypeSpecType == TST_auto) {
-        // "auto int" case
-        S.Diag(ConflictingTypeSpecifierLoc, diag::err_auto_type_specifier)
-            << FixItHint::CreateRemoval(ConflictingTypeSpecifierLoc);
-      } else if (ConflictingTypeSpecifier == TST_auto) {
-        // "int auto" case
-        S.Diag(ConflictingTypeSpecifierLoc, diag::err_auto_type_specifier)
-            << FixItHint::CreateRemoval(ConflictingTypeSpecifierLoc);
-      }
-      // Mark as error to prevent further processing
-      TypeSpecType = TST_error;
-      TypeSpecOwned = false;
-    } else if (!S.getLangOpts().CPlusPlus) {
-      // For C, C23, etc., convert 'auto' to storage class specifier
-      // (This is already handled above for C23, but keep for other C dialects)
-      // In C, C23, OpenCL, etc., 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;
-        // Clear the conflict tracking
-        ConflictingTypeSpecifier = TST_unspecified;
-        ConflictingTypeSpecifierLoc = SourceLocation();
-      } else if (ConflictingTypeSpecifier == TST_auto) {
-        // "int auto" case: Convert 'auto' to storage class specifier
-        StorageClassSpec = SCS_auto;
-        StorageClassSpecLoc = ConflictingTypeSpecifierLoc;
-        // TypeSpecType already has the correct type (e.g., TST_int)
-        // Clear the conflict tracking
-        ConflictingTypeSpecifier = TST_unspecified;
-        ConflictingTypeSpecifierLoc = SourceLocation();
-      }
-    }
-  }
-
   // Validate and finalize AltiVec vector declspec.
   if (TypeAltiVecVector) {
     // No vector long long without VSX (or ZVector).
@@ -1619,7 +1440,6 @@ void DeclSpec::CheckTypeSpec(Sema &S, const PrintingPolicy &Policy) {
       S.getLangOpts().getHLSLVersion() < LangOptions::HLSL_202y &&
       TypeSpecType == TST_auto)
     S.Diag(TSTLoc, diag::ext_hlsl_auto_type_specifier) << /*HLSL*/ 1;
-  // Emit warning for 'auto' storage class in pre-C++11 dialects
   if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11 &&
       StorageClassSpec == SCS_auto)
     S.Diag(StorageClassSpecLoc, diag::warn_auto_storage_class)

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 3a3f752a9e93b..723a79628116c 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
@@ -1,75 +1,66 @@
-// RUN: %clang_cc1 -fsyntax-only -verify=cxx98 -std=c++98 %s
-// RUN: %clang_cc1 -fsyntax-only -verify=cxx11 -std=c++11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify=cxx17 -std=c++17 %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 
 // 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;
-// cxx11-error at -1 {{'auto' cannot be combined with a type specifier}}
-// cxx17-error at -2 {{'auto' cannot be combined with a type specifier}}
-// cxx98-error at -3 {{illegal storage class on file-scoped variable}}
+auto int ao; // expected-error {{illegal storage class on file-scoped variable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning at -2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
 
-auto void af();
-// cxx11-error at -1 {{'auto' cannot be combined with a type specifier}}
-// cxx17-error at -2 {{'auto' cannot be combined with a type specifier}}
-// cxx98-error at -3 {{illegal storage class on function}}
+auto void af(); // expected-error {{illegal storage class on function}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning at -2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
 
-register int ro;
-// cxx98-error at -1 {{illegal storage class on file-scoped variable}}
-// cxx11-error at -2 {{illegal storage class on file-scoped variable}}
-// cxx11-warning at -3 {{'register' storage class specifier is deprecated and incompatible with C++17}}
-// cxx17-error at -4 {{illegal storage class on file-scoped variable}}
-// cxx17-error at -5 {{ISO C++17 does not allow 'register' storage class specifier}}
+register int ro; // expected-error {{illegal storage class on file-scoped variable}}
+#if __cplusplus >= 201703L
+// expected-error at -2 {{ISO C++17 does not allow 'register' storage class specifier}}
+#elif __cplusplus >= 201103L
+// expected-warning at -4 {{'register' storage class specifier is deprecated}}
+#endif
 
-register void rf();
-// cxx98-error at -1 {{illegal storage class on function}}
-// cxx11-error at -2 {{illegal storage class on function}}
-// cxx17-error at -3 {{illegal storage class on function}}
+register void rf(); // expected-error {{illegal storage class on function}}
 
 struct S {
-  auto int ao;
-  // cxx11-error at -1 {{'auto' cannot be combined with a type specifier}}
-  // cxx17-error at -2 {{'auto' cannot be combined with a type specifier}}
-  // cxx98-error at -3 {{storage class specified for a member declaration}}
-  auto void af();
-  // cxx11-error at -1 {{'auto' cannot be combined with a type specifier}}
-  // cxx17-error at -2 {{'auto' cannot be combined with a type specifier}}
-  // cxx98-error at -3 {{storage class specified for a member declaration}}
+  auto int ao; // expected-error {{storage class specified for a member declaration}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning at -2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
+  auto void af(); // expected-error {{storage class specified for a member declaration}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning at -2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
 
-  register int ro;
-  // cxx98-error at -1 {{storage class specified for a member declaration}}
-  // cxx11-error at -2 {{storage class specified for a member declaration}}
-  // cxx17-error at -3 {{storage class specified for a member declaration}}
-  register void rf();
-  // cxx98-error at -1 {{storage class specified for a member declaration}}
-  // cxx11-error at -2 {{storage class specified for a member declaration}}
-  // cxx17-error at -3 {{storage class specified for a member declaration}}
+  register int ro; // expected-error {{storage class specified for a member declaration}}
+  register void rf(); // expected-error {{storage class specified for a member declaration}}
 };
 
 void foo(auto int ap, register int rp) {
-  // cxx17-error at -1 {{'auto' cannot be combined with a type specifier}}
-  // cxx17-error at -2 {{ISO C++17 does not allow 'register' storage class specifier}}
-  // cxx11-error at -3 {{'auto' cannot be combined with a type specifier}}
-  // cxx11-warning at -4 {{'register' storage class specifier is deprecated and incompatible with C++17}}
+#if __cplusplus >= 201703L
+// expected-warning at -2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+// expected-error at -3 {{ISO C++17 does not allow 'register' storage class specifier}}
+#elif __cplusplus >= 201103L
+// expected-warning at -5 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+// expected-warning at -6 {{'register' storage class specifier is deprecated}}
+#endif
   auto int abo;
-  // cxx11-error at -1 {{'auto' cannot be combined with a type specifier}}
-  // cxx17-error at -2 {{'auto' cannot be combined with a type specifier}}
-  auto void abf();
-  // cxx11-error at -1 {{'auto' cannot be combined with a type specifier}}
-  // cxx11-warning at -2 {{empty parentheses interpreted as a function declaration}}
-  // cxx11-note at -3 {{replace parentheses with an initializer to declare a variable}}
-  // cxx17-error at -4 {{'auto' cannot be combined with a type specifier}}
-  // cxx17-warning at -5 {{empty parentheses interpreted as a function declaration}}
-  // cxx17-note at -6 {{replace parentheses with an initializer to declare a variable}}
-  // cxx98-error at -7 {{illegal storage class on function}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning at -2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
+  auto void abf(); // expected-error {{illegal storage class on function}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning at -2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
 
   register int rbo;
-  // cxx17-error at -1 {{ISO C++17 does not allow 'register' storage class specifier}}
-  // cxx11-warning at -2 {{'register' storage class specifier is deprecated and incompatible with C++17}}
+#if __cplusplus >= 201703L
+// expected-error at -2 {{ISO C++17 does not allow 'register' storage class specifier}}
+#elif __cplusplus >= 201103L
+// expected-warning at -4 {{'register' storage class specifier is deprecated}}
+#endif
 
-  register void rbf();
-  // cxx98-error at -1 {{illegal storage class on function}}
-  // cxx11-error at -2 {{illegal storage class on function}}
-  // cxx17-error at -3 {{illegal storage class on function}}
+  register void rbf(); // expected-error {{illegal storage class on function}}
 }

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 880014d591706..e8f12156a4242 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,13 +56,7 @@ namespace p3_example {
   auto x = 5;
   const auto *v = &x, u = 6;
   static auto y = 0.0;
-  auto int r;
-#if __cplusplus >= 201103L
-  // expected-error at -2 {{'auto' cannot be combined with a type specifier}}
-#else
-  // expected-warning at -4 {{storage class}}
-  // expected-error at -5 {{file-scope}}
-#endif
+  auto int r;  // expected-warning {{storage class}} expected-error {{file-scope}}
 
   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-generic-lambda-1y.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp
index 7577a789eb1c0..a590f8eb77005 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp
@@ -62,11 +62,11 @@ int main()
   {
     auto l = [](auto (*)(auto)) { }; //expected-error{{'auto' not allowed}} expected-warning {{'auto' parameters are a C++20 extension}}
     //FIXME: These diagnostics might need some work.
-    auto l2 = [](char auto::*pm) { };  //expected-error{{'auto' cannot be combined with a type specifier}}\
-                                         expected-error{{'pm' does not point into a class}}
-    auto l3 = [](char (auto::*pmf)()) { };  //expected-error{{'auto' not allowed}}\
-                                              expected-error{{'pmf' does not point into a class}}\
-                                              expected-error{{function cannot return function type 'char ()'}} \
-                                              expected-warning {{'auto' parameters are a C++20 extension}}
+    auto l2 = [](char auto::*pm) { };       // expected-error {{cannot combine with previous 'char' declaration specifier}} \
+                                               expected-error{{'pm' does not point into a class}}
+    auto l3 = [](char (auto::*pmf)()) { };  // expected-error{{'auto' not allowed}}\
+                                               expected-error{{'pmf' does not point into a class}}\
+                                               expected-error{{function cannot return function type 'char ()'}} \
+                                               expected-warning {{'auto' parameters are a C++20 extension}}
   }
 }

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 8d7765523461c..440c78201293b 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,12 +42,7 @@ 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;
-#if __cplusplus >= 201103L
-  // expected-error at -2 {{'auto' cannot be combined with a type specifier}}
-#else
-  // expected-warning at -4 {{'auto' storage class specifier}}
-#endif
+  auto int r; // expected-warning {{'auto' storage class specifier}}
 
   same<__typeof(x), int> xHasTypeInt;
   same<__typeof(v), const int*> vHasTypeConstIntPtr;

diff  --git a/clang/test/CXX/dcl/dcl.fct/p17.cpp b/clang/test/CXX/dcl/dcl.fct/p17.cpp
index 971edc7bf26eb..d837d0900d5b9 100644
--- a/clang/test/CXX/dcl/dcl.fct/p17.cpp
+++ b/clang/test/CXX/dcl/dcl.fct/p17.cpp
@@ -135,7 +135,7 @@ void undefined(Foo auto); // expected-error {{unknown type name 'Foo'}}
 
 struct AStruct {};
 
-void a_struct(AStruct auto); // expected-error {{'auto' cannot be combined with a type specifier}}
+void a_struct(AStruct auto); // expected-error {{cannot combine with previous 'type-name' declaration specifier}}
 }
 
 #if __cplusplus >= 202002L

diff  --git a/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.type.general/p2.cpp b/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.type.general/p2.cpp
deleted file mode 100644
index 2255cdf11309c..0000000000000
--- a/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.type.general/p2.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN:  %clang_cc1 -std=c++2c -verify %s
-
-void func1() {
-  typedef float foo; // expected-note {{previous definition is here}}
-  auto foo{16};      // expected-error {{redefinition of 'foo' as 
diff erent kind of symbol}}
-}
-
-typedef float bar;
-void func2() {
-  auto bar{16};
-}

diff  --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp
index daa6e82a1f57a..10bf57e422f33 100644
--- a/clang/test/CXX/drs/cwg3xx.cpp
+++ b/clang/test/CXX/drs/cwg3xx.cpp
@@ -1704,16 +1704,14 @@ namespace cwg395 { // cwg395: 3.0
 
 namespace cwg396 { // cwg396: 3.0
   void f() {
-    auto int a(); // #cwg396-a
-    // cxx98-error@#cwg396-a {{illegal storage class on function}}
-    // since-cxx11-error@#cwg396-a {{'auto' cannot be combined with a type specifier}}
-    // since-cxx11-warning@#cwg396-a {{empty parentheses interpreted as a function declaration}}
-    //   since-cxx11-note@#cwg396-a {{replace parentheses with an initializer to declare a variable}}
+    auto int a();
+    // since-cxx11-error at -1 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+    // expected-error at -2 {{illegal storage class on function}}
     int (i); // #cwg396-i
-    auto int (i); // #cwg396-auto-i
-    // cxx98-error@#cwg396-auto-i {{redefinition of 'i'}}
-    //   cxx98-note@#cwg396-i {{previous definition is here}}
-    // since-cxx11-error@#cwg396-auto-i {{'auto' cannot be combined with a type specifier}}
+    auto int (i);
+    // since-cxx11-error at -1 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+    // expected-error at -2 {{redefinition of 'i'}}
+    //   expected-note@#cwg396-i {{previous definition is here}}
   }
 } // namespace cwg396
 

diff  --git a/clang/test/Parser/c2x-auto.c b/clang/test/Parser/c2x-auto.c
index 145e6f8b08b09..dc0e1f34dabdc 100644
--- a/clang/test/Parser/c2x-auto.c
+++ b/clang/test/Parser/c2x-auto.c
@@ -167,13 +167,6 @@ void t1() {
   int auto d2 = 0;
 }
 
-void typedef_type_specifiers(void) {
-  typedef int MyInt;
-
-  auto MyInt a = 0;
-  MyInt auto b = 0;
-}
-
 void t2() {
   auto long long a1 = 0;
   long auto long a2 = 0;

diff  --git a/clang/test/SemaCXX/auto-cxx0x.cpp b/clang/test/SemaCXX/auto-cxx0x.cpp
index eccc2ddb26eec..f429bebb9941a 100644
--- a/clang/test/SemaCXX/auto-cxx0x.cpp
+++ b/clang/test/SemaCXX/auto-cxx0x.cpp
@@ -1,24 +1,10 @@
 // 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-error {{'auto' cannot be combined with a type specifier}}
-  int auto b; // expected-error {{'auto' cannot be combined with a type specifier}}
-  unsigned auto int x; // expected-error {{'auto' cannot be combined with a type specifier}} expected-error-re {{'{{.*}}' cannot be signed or unsigned}}
-  signed auto int s; // expected-error {{'auto' cannot be combined with a type specifier}} expected-error-re {{'{{.*}}' cannot be signed or unsigned}}
-  auto double y; // expected-error {{'auto' cannot be combined with a type specifier}}
-  auto float z; // expected-error {{'auto' cannot be combined with a type specifier}}
-  long auto int l; // expected-error {{'auto' cannot be combined with a type specifier}} expected-error-re {{'long {{.*}}' is invalid}}
-  auto int arr[10]; // expected-error {{'auto' cannot be combined with a type specifier}}
+  auto int a; // expected-warning {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+  int auto b; // expected-error {{cannot combine with previous 'int' declaration specifier}}
 }
 
-struct PR209000 {
-} auto; // expected-error {{'auto' cannot be combined with a type specifier}}
-
-auto union { // expected-warning {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} \
-             // expected-error {{cannot combine with previous 'auto' declaration specifier}}
-} foo<>(); // expected-error {{no template named 'foo'}} \
-           // expected-error {{expected unqualified-id}}
-
 typedef auto PR25449(); // expected-error {{'auto' not allowed in typedef}}
 
 thread_local auto x; // expected-error {{requires an initializer}}
@@ -37,23 +23,3 @@ void rdar47689465() {
   // expected-error at -2 {{'auto' not allowed in lambda parameter before C++14}}
 #endif
 }
-
-namespace auto_declarator_name_lookup {
-namespace llvm {
-  class Use;
-namespace rdf {
-  template <class T> struct NodeAddr {};
-  class UseNode;
-  using Use = NodeAddr<UseNode *>;
-} // namespace rdf
-} // namespace llvm
-
-using namespace llvm;
-
-namespace {
-void f() {
-  using namespace rdf;
-  auto Use = 0;
-}
-} // namespace
-} // namespace auto_declarator_name_lookup

diff  --git a/clang/test/SemaCXX/auto-cxx98.cpp b/clang/test/SemaCXX/auto-cxx98.cpp
index db2036d462532..1e28d0635a48d 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,11 +6,3 @@ 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}}
-}

diff  --git a/clang/test/SemaCXX/class.cpp b/clang/test/SemaCXX/class.cpp
index 71c71a1acc807..f1e02d5158aac 100644
--- a/clang/test/SemaCXX/class.cpp
+++ b/clang/test/SemaCXX/class.cpp
@@ -2,12 +2,11 @@
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98 -Wc++11-compat %s -std=c++98
 class C {
 public:
-  auto int errx;
-#if __cplusplus >= 201103L
-  // expected-error at -2 {{'auto' cannot be combined with a type specifier}}
+  auto int errx; // expected-error {{storage class specified for a member declaration}}
+#if __cplusplus <= 199711L
+  // expected-warning at -2 {{'auto' storage class specifier is redundant}}
 #else
-  // expected-error at -4 {{storage class specified for a member declaration}}
-  // expected-warning at -5 {{'auto' storage class specifier is redundant}}
+  // expected-warning at -4 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
 #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 2dbcae1745e5b..fb63da9b40099 100644
--- a/clang/test/SemaCXX/static-data-member.cpp
+++ b/clang/test/SemaCXX/static-data-member.cpp
@@ -13,12 +13,7 @@ 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;
-#if __cplusplus >= 201103L
-// expected-error at -2 {{'auto' cannot be combined with a type specifier}}
-#else
-// expected-error at -4 {{static data member definition cannot specify a storage class}}
-#endif
+auto double ABC::e = 1.0; // expected-error {{static data member definition cannot specify a storage class}}
 #if __cplusplus < 201703L
 register double ABC::f = 1.0; // expected-error {{static data member definition cannot specify a storage class}}
 #endif


        


More information about the cfe-commits mailing list