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

>From b0d5dd5d4d76714dd359ceeec5d50e049a729dd0 Mon Sep 17 00:00:00 2001
From: Osama Abdelkader <[email protected]>
Date: Sat, 1 Nov 2025 19:53:55 +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       |   2 +
 clang/lib/Parse/ParseDecl.cpp                 | 492 +++++++++---------
 .../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                 |  11 +-
 clang/test/Parser/cxx-auto-type-specifier.cpp |  22 +
 clang/test/SemaCXX/auto-cxx0x.cpp             |   2 +-
 clang/test/SemaCXX/class.cpp                  |   7 +-
 clang/test/SemaCXX/static-data-member.cpp     |   7 +-
 10 files changed, 329 insertions(+), 259 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..baf91b107b8c4 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -399,6 +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 err_auto_type_specifier : Error<
+  "'auto' cannot be combined with a type specifier in C++">;
 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">>;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 7e4a164e34eda..47b17ba7510ec 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -674,9 +674,9 @@ void Parser::ParseGNUAttributeArgs(
   // These may refer to the function arguments, but need to be parsed early to
   // participate in determining whether it's a redeclaration.
   std::optional<ParseScope> PrototypeScope;
-  if (normalizeAttrName(AttrName->getName()) == "enable_if" &&
-      D && D->isFunctionDeclarator()) {
-    const DeclaratorChunk::FunctionTypeInfo& FTI = D->getFunctionTypeInfo();
+  if (normalizeAttrName(AttrName->getName()) == "enable_if" && D &&
+      D->isFunctionDeclarator()) {
+    const DeclaratorChunk::FunctionTypeInfo &FTI = D->getFunctionTypeInfo();
     PrototypeScope.emplace(this, Scope::FunctionPrototypeScope |
                                      Scope::FunctionDeclarationScope |
                                      Scope::DeclScope);
@@ -1090,8 +1090,7 @@ void 
Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) {
       IdentifierInfo *AttrName = Tok.getIdentifierInfo();
       SourceLocation AttrNameLoc = ConsumeToken();
       if (!getLangOpts().ObjC)
-        Diag(AttrNameLoc, diag::ext_nullability)
-          << AttrName;
+        Diag(AttrNameLoc, diag::ext_nullability) << AttrName;
       attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0,
                    Kind);
       break;
@@ -1121,7 +1120,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange 
&Range) {
   // lexer, which is that it handles something like 1.2.3 as a single
   // numeric constant, rather than two separate tokens.
   SmallString<512> Buffer;
-  Buffer.resize(Tok.getLength()+1);
+  Buffer.resize(Tok.getLength() + 1);
   const char *ThisTokBegin = &Buffer[0];
 
   // Get the spelling of the token, which eliminates trigraphs, etc.
@@ -1158,8 +1157,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange 
&Range) {
   }
 
   const char AfterMajorSeparator = ThisTokBegin[AfterMajor];
-  if (!VersionNumberSeparator(AfterMajorSeparator)
-      || (AfterMajor + 1 == ActualLength)) {
+  if (!VersionNumberSeparator(AfterMajorSeparator) ||
+      (AfterMajor + 1 == ActualLength)) {
     Diag(Tok, diag::err_expected_version);
     SkipUntil(tok::comma, tok::r_paren,
               StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
@@ -1291,7 +1290,7 @@ void Parser::ParseAvailabilityAttribute(
     if (Keyword == Ident_strict) {
       if (StrictLoc.isValid()) {
         Diag(KeywordLoc, diag::err_availability_redundant)
-          << Keyword << SourceRange(StrictLoc);
+            << Keyword << SourceRange(StrictLoc);
       }
       StrictLoc = KeywordLoc;
       continue;
@@ -1300,7 +1299,7 @@ void Parser::ParseAvailabilityAttribute(
     if (Keyword == Ident_unavailable) {
       if (UnavailableLoc.isValid()) {
         Diag(KeywordLoc, diag::err_availability_redundant)
-          << Keyword << SourceRange(UnavailableLoc);
+            << Keyword << SourceRange(UnavailableLoc);
       }
       UnavailableLoc = KeywordLoc;
       continue;
@@ -1311,8 +1310,7 @@ void Parser::ParseAvailabilityAttribute(
       // For swift, we deprecate for all versions.
       if (Changes[Deprecated].KeywordLoc.isValid()) {
         Diag(KeywordLoc, diag::err_availability_redundant)
-          << Keyword
-          << SourceRange(Changes[Deprecated].KeywordLoc);
+            << Keyword << SourceRange(Changes[Deprecated].KeywordLoc);
       }
 
       Changes[Deprecated].KeywordLoc = KeywordLoc;
@@ -1337,7 +1335,7 @@ void Parser::ParseAvailabilityAttribute(
     if (Keyword == Ident_message || Keyword == Ident_replacement) {
       if (!isTokenStringLiteral()) {
         Diag(Tok, diag::err_expected_string_literal)
-          << /*Source='availability attribute'*/2;
+            << /*Source='availability attribute'*/ 2;
         SkipUntil(tok::r_paren, StopAtSemi);
         return;
       }
@@ -1393,9 +1391,9 @@ void Parser::ParseAvailabilityAttribute(
     if (Index < Unknown) {
       if (!Changes[Index].KeywordLoc.isInvalid()) {
         Diag(KeywordLoc, diag::err_availability_redundant)
-          << Keyword
-          << SourceRange(Changes[Index].KeywordLoc,
-                         Changes[Index].VersionRange.getEnd());
+            << Keyword
+            << SourceRange(Changes[Index].KeywordLoc,
+                           Changes[Index].VersionRange.getEnd());
       }
 
       Changes[Index].KeywordLoc = KeywordLoc;
@@ -1403,7 +1401,7 @@ void Parser::ParseAvailabilityAttribute(
       Changes[Index].VersionRange = VersionRange;
     } else {
       Diag(KeywordLoc, diag::err_availability_unknown_change)
-        << Keyword << VersionRange;
+          << Keyword << VersionRange;
     }
 
   } while (TryConsumeToken(tok::comma));
@@ -1423,8 +1421,8 @@ void Parser::ParseAvailabilityAttribute(
       if (Changes[Index].KeywordLoc.isValid()) {
         if (!Complained) {
           Diag(UnavailableLoc, diag::warn_availability_and_unavailable)
-            << SourceRange(Changes[Index].KeywordLoc,
-                           Changes[Index].VersionRange.getEnd());
+              << SourceRange(Changes[Index].KeywordLoc,
+                             Changes[Index].VersionRange.getEnd());
           Complained = true;
         }
 
@@ -1735,7 +1733,7 @@ void Parser::ParseTypeTagForDatatypeAttribute(
 bool Parser::DiagnoseProhibitedCXX11Attribute() {
   assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square));
 
-  switch (isCXX11AttributeSpecifier(/*Disambiguate*/true)) {
+  switch (isCXX11AttributeSpecifier(/*Disambiguate*/ true)) {
   case CXX11AttributeKind::NotAttributeSpecifier:
     // No diagnostic: we're in Obj-C++11 and this is not actually an attribute.
     return false;
@@ -1752,7 +1750,7 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() {
     assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied");
     SourceLocation EndLoc = ConsumeBracket();
     Diag(BeginLoc, diag::err_attributes_not_allowed)
-      << SourceRange(BeginLoc, EndLoc);
+        << SourceRange(BeginLoc, EndLoc);
     return true;
   }
   llvm_unreachable("All cases handled above.");
@@ -1859,8 +1857,7 @@ void 
Parser::stripTypeAttributesOffDeclSpec(ParsedAttributes &Attrs,
   llvm::SmallVector<ParsedAttr *, 1> ToBeMoved;
 
   for (ParsedAttr &AL : DS.getAttributes()) {
-    if ((AL.getKind() == ParsedAttr::AT_Aligned &&
-         AL.isDeclspecAttribute()) ||
+    if ((AL.getKind() == ParsedAttr::AT_Aligned && AL.isDeclspecAttribute()) ||
         AL.isMicrosoftAttribute())
       ToBeMoved.push_back(&AL);
   }
@@ -1956,14 +1953,15 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
   if (Tok.is(tok::semi)) {
     ProhibitAttributes(DeclAttrs);
     DeclEnd = Tok.getLocation();
-    if (RequireSemi) ConsumeToken();
+    if (RequireSemi)
+      ConsumeToken();
     RecordDecl *AnonRecord = nullptr;
     Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(
         getCurScope(), AS_none, DS, ParsedAttributesView::none(), AnonRecord);
     Actions.ActOnDefinedDeclarationSpecifier(TheDecl);
     DS.complete(TheDecl);
     if (AnonRecord) {
-      Decl* decls[] = {AnonRecord, TheDecl};
+      Decl *decls[] = {AnonRecord, TheDecl};
       return Actions.BuildDeclaratorGroup(decls);
     }
     return Actions.ConvertDeclToDeclGroup(TheDecl);
@@ -2097,8 +2095,7 @@ void Parser::SkipMalformedDecl() {
 
     case tok::at:
       // @end is very much like } in Objective-C contexts.
-      if (NextToken().isObjCAtKeyword(tok::objc_end) &&
-          ParsingInObjCContainer)
+      if (NextToken().isObjCAtKeyword(tok::objc_end) && ParsingInObjCContainer)
         return;
       break;
 
@@ -2371,7 +2368,7 @@ Parser::DeclGroupPtrTy 
Parser::ParseDeclGroup(ParsingDeclSpec &DS,
       // the start of a declarator. The comma was probably a typo for a
       // semicolon.
       Diag(CommaLoc, diag::err_expected_semi_declaration)
-        << FixItHint::CreateReplacement(CommaLoc, ";");
+          << FixItHint::CreateReplacement(CommaLoc, ";");
       ExpectSemi = false;
       break;
     }
@@ -2529,8 +2526,7 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
   case ParsedTemplateKind::Template:
   case ParsedTemplateKind::ExplicitSpecialization: {
     ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(),
-                                               *TemplateInfo.TemplateParams,
-                                               D);
+                                               *TemplateInfo.TemplateParams, 
D);
     if (VarTemplateDecl *VT = dyn_cast_or_null<VarTemplateDecl>(ThisDecl)) {
       // Re-direct this decl to refer to the templated decl so that we can
       // initialize it.
@@ -2577,7 +2573,7 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
       }
     }
     break;
-    }
+  }
   }
 
   SemaCUDA::CUDATargetContextRAII X(Actions.CUDA(),
@@ -2590,14 +2586,14 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
     if (Tok.is(tok::kw_delete)) {
       if (D.isFunctionDeclarator())
         Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
-          << 1 /* delete */;
+            << 1 /* delete */;
       else
         Diag(ConsumeToken(), diag::err_deleted_non_function);
       SkipDeletedFunctionBody();
     } else if (Tok.is(tok::kw_default)) {
       if (D.isFunctionDeclarator())
         Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
-          << 0 /* default */;
+            << 0 /* default */;
       else
         Diag(ConsumeToken(), diag::err_default_special_members)
             << getLangOpts().CPlusPlus20;
@@ -2689,9 +2685,8 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
       // Match the ')'.
       T.consumeClose();
 
-      ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(),
-                                                          T.getCloseLocation(),
-                                                          Exprs);
+      ExprResult Initializer = Actions.ActOnParenListExpr(
+          T.getOpenLocation(), T.getCloseLocation(), Exprs);
       Actions.AddInitializerToDecl(ThisDecl, Initializer.get(),
                                    /*DirectInit=*/true);
     }
@@ -2747,7 +2742,8 @@ void Parser::ParseSpecifierQualifierList(
   // Issue diagnostic and remove storage class if present.
   if (Specs & DeclSpec::PQ_StorageClassSpecifier) {
     if (DS.getStorageClassSpecLoc().isValid())
-      
Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass);
+      Diag(DS.getStorageClassSpecLoc(),
+           diag::err_typename_invalid_storageclass);
     else
       Diag(DS.getThreadStorageClassSpecLoc(),
            diag::err_typename_invalid_storageclass);
@@ -2843,7 +2839,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec 
*SS,
     // Don't require a type specifier if we have the 'auto' storage class
     // specifier in C++98 -- we'll promote it to a type specifier.
     if (SS)
-      AnnotateScopeToken(*SS, /*IsNewAnnotation*/false);
+      AnnotateScopeToken(*SS, /*IsNewAnnotation*/ false);
     return false;
   }
 
@@ -2876,18 +2872,33 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, 
CXXScopeSpec *SS,
     tok::TokenKind TagKind = tok::unknown;
 
     switch (Actions.isTagName(*Tok.getIdentifierInfo(), getCurScope())) {
-      default: break;
-      case DeclSpec::TST_enum:
-        TagName="enum"  ; FixitTagName = "enum "  ; TagKind=tok::kw_enum 
;break;
-      case DeclSpec::TST_union:
-        TagName="union" ; FixitTagName = "union " ;TagKind=tok::kw_union 
;break;
-      case DeclSpec::TST_struct:
-        TagName="struct"; FixitTagName = "struct 
";TagKind=tok::kw_struct;break;
-      case DeclSpec::TST_interface:
-        TagName="__interface"; FixitTagName = "__interface ";
-        TagKind=tok::kw___interface;break;
-      case DeclSpec::TST_class:
-        TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class 
;break;
+    default:
+      break;
+    case DeclSpec::TST_enum:
+      TagName = "enum";
+      FixitTagName = "enum ";
+      TagKind = tok::kw_enum;
+      break;
+    case DeclSpec::TST_union:
+      TagName = "union";
+      FixitTagName = "union ";
+      TagKind = tok::kw_union;
+      break;
+    case DeclSpec::TST_struct:
+      TagName = "struct";
+      FixitTagName = "struct ";
+      TagKind = tok::kw_struct;
+      break;
+    case DeclSpec::TST_interface:
+      TagName = "__interface";
+      FixitTagName = "__interface ";
+      TagKind = tok::kw___interface;
+      break;
+    case DeclSpec::TST_class:
+      TagName = "class";
+      FixitTagName = "class ";
+      TagKind = tok::kw_class;
+      break;
     }
 
     if (TagName) {
@@ -2896,14 +2907,14 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, 
CXXScopeSpec *SS,
                      Sema::LookupOrdinaryName);
 
       Diag(Loc, diag::err_use_of_tag_name_without_tag)
-        << TokenName << TagName << getLangOpts().CPlusPlus
-        << FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);
+          << TokenName << TagName << getLangOpts().CPlusPlus
+          << FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);
 
       if (Actions.LookupName(R, getCurScope())) {
-        for (LookupResult::iterator I = R.begin(), IEnd = R.end();
-             I != IEnd; ++I)
+        for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd;
+             ++I)
           Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
-            << TokenName << TagName;
+              << TokenName << TagName;
       }
 
       // Parse this as a tag as if the missing tag were present.
@@ -2934,7 +2945,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec 
*SS,
       // parse to determine which case we're in.
       TentativeParsingAction PA(*this);
       ConsumeToken();
-      TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false);
+      TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/ false);
       PA.Revert();
 
       if (TPR != TPResult::False) {
@@ -2950,8 +2961,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec 
*SS,
         IdentifierInfo *II = Tok.getIdentifierInfo();
         if (Actions.isCurrentClassNameTypo(II, SS)) {
           Diag(Loc, diag::err_constructor_bad_name)
-            << Tok.getIdentifierInfo() << II
-            << FixItHint::CreateReplacement(Tok.getLocation(), II->getName());
+              << Tok.getIdentifierInfo() << II
+              << FixItHint::CreateReplacement(Tok.getLocation(), 
II->getName());
           Tok.setIdentifierInfo(II);
         }
       }
@@ -2970,7 +2981,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec 
*SS,
       if (getCurScope()->isFunctionPrototypeScope())
         break;
       if (SS)
-        AnnotateScopeToken(*SS, /*IsNewAnnotation*/false);
+        AnnotateScopeToken(*SS, /*IsNewAnnotation*/ false);
       return false;
 
     default:
@@ -3242,15 +3253,14 @@ ExprResult Parser::ParseExtIntegerArgument() {
     return ExprError();
   }
 
-  if(T.consumeClose())
+  if (T.consumeClose())
     return ExprError();
   return ER;
 }
 
-bool
-Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
-                                              DeclSpecContext DSContext,
-                                              LateParsedAttrList *LateAttrs) {
+bool Parser::DiagnoseMissingSemiAfterTagDefinition(
+    DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext,
+    LateParsedAttrList *LateAttrs) {
   assert(DS.hasTagDefinition() && "shouldn't call this");
 
   bool EnteringContext = (DSContext == DeclSpecContext::DSC_class ||
@@ -3402,15 +3412,19 @@ void Parser::ParseDeclarationSpecifiers(
     SourceLocation Loc = Tok.getLocation();
 
     // Helper for image types in OpenCL.
-    auto handleOpenCLImageKW = [&] (StringRef Ext, TypeSpecifierType 
ImageTypeSpec) {
-      // Check if the image type is supported and otherwise turn the keyword 
into an identifier
-      // because image types from extensions are not reserved identifiers.
-      if (!StringRef(Ext).empty() && 
!getActions().getOpenCLOptions().isSupported(Ext, getLangOpts())) {
+    auto handleOpenCLImageKW = [&](StringRef Ext,
+                                   TypeSpecifierType ImageTypeSpec) {
+      // Check if the image type is supported and otherwise turn the keyword
+      // into an identifier because image types from extensions are not 
reserved
+      // identifiers.
+      if (!StringRef(Ext).empty() &&
+          !getActions().getOpenCLOptions().isSupported(Ext, getLangOpts())) {
         Tok.getIdentifierInfo()->revertTokenIDToIdentifier();
         Tok.setKind(tok::identifier);
         return false;
       }
-      isInvalid = DS.SetTypeSpecType(ImageTypeSpec, Loc, PrevSpec, DiagID, 
Policy);
+      isInvalid =
+          DS.SetTypeSpecType(ImageTypeSpec, Loc, PrevSpec, DiagID, Policy);
       return true;
     };
 
@@ -3506,14 +3520,13 @@ void Parser::ParseDeclarationSpecifiers(
       SemaCodeCompletion::ParserCompletionContext CCC =
           SemaCodeCompletion::PCC_Namespace;
       if (DS.hasTypeSpecifier()) {
-        bool AllowNonIdentifiers
-          = (getCurScope()->getFlags() & (Scope::ControlScope |
-                                          Scope::BlockScope |
-                                          Scope::TemplateParamScope |
-                                          Scope::FunctionPrototypeScope |
-                                          Scope::AtCatchScope)) == 0;
-        bool AllowNestedNameSpecifiers
-          = DSContext == DeclSpecContext::DSC_top_level ||
+        bool AllowNonIdentifiers =
+            (getCurScope()->getFlags() &
+             (Scope::ControlScope | Scope::BlockScope |
+              Scope::TemplateParamScope | Scope::FunctionPrototypeScope |
+              Scope::AtCatchScope)) == 0;
+        bool AllowNestedNameSpecifiers =
+            DSContext == DeclSpecContext::DSC_top_level ||
             (DSContext == DeclSpecContext::DSC_class && 
DS.isFriendSpecified());
 
         cutOffParsing();
@@ -3558,9 +3571,8 @@ void Parser::ParseDeclarationSpecifiers(
       CXXScopeSpec SS;
       if (TemplateInfo.TemplateParams)
         SS.setTemplateParamLists(*TemplateInfo.TemplateParams);
-      Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
-                                                   Tok.getAnnotationRange(),
-                                                   SS);
+      Actions.RestoreNestedNameSpecifierAnnotation(
+          Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS);
 
       // We are looking for a qualified typename.
       Token Next = NextToken();
@@ -3623,8 +3635,8 @@ void Parser::ParseDeclarationSpecifiers(
         ConsumeAnnotationToken(); // The C++ scope.
         TypeResult T = getTypeAnnotation(Tok);
         isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
-                                       Tok.getAnnotationEndLoc(),
-                                       PrevSpec, DiagID, T, Policy);
+                                       Tok.getAnnotationEndLoc(), PrevSpec,
+                                       DiagID, T, Policy);
         if (isInvalid)
           break;
         DS.SetRangeEnd(Tok.getAnnotationEndLoc());
@@ -3653,8 +3665,7 @@ void Parser::ParseDeclarationSpecifiers(
                                      &SS) &&
           isConstructorDeclarator(/*Unqualified=*/false,
                                   /*DeductionGuide=*/false,
-                                  DS.isFriendSpecified(),
-                                  &TemplateInfo))
+                                  DS.isFriendSpecified(), &TemplateInfo))
         goto DoneWithDeclSpec;
 
       // C++20 [temp.spec] 13.9/6.
@@ -3887,8 +3898,7 @@ void Parser::ParseDeclarationSpecifiers(
       if (Tok.is(tok::less) && getLangOpts().ObjC) {
         SourceLocation NewEndLoc;
         TypeResult NewTypeRep = parseObjCTypeArgsAndProtocolQualifiers(
-                                  Loc, TypeRep, /*consumeLastToken=*/true,
-                                  NewEndLoc);
+            Loc, TypeRep, /*consumeLastToken=*/true, NewEndLoc);
         if (NewTypeRep.isUsable()) {
           DS.UpdateTypeRep(NewTypeRep.get());
           DS.SetRangeEnd(NewEndLoc);
@@ -3931,10 +3941,10 @@ void Parser::ParseDeclarationSpecifiers(
           break;
         }
         if (!NextToken().isOneOf(tok::kw_auto, tok::kw_decltype))
-            goto DoneWithDeclSpec;
+          goto DoneWithDeclSpec;
 
         if (TemplateId && !isInvalid && 
Actions.CheckTypeConstraint(TemplateId))
-            TemplateId = nullptr;
+          TemplateId = nullptr;
 
         ConsumeAnnotationToken();
         SourceLocation AutoLoc = Tok.getLocation();
@@ -3948,9 +3958,8 @@ void Parser::ParseDeclarationSpecifiers(
               // Something like `void foo(Iterator decltype(int) i)`
               Tracker.skipToEnd();
               Diag(Tok, diag::err_placeholder_expected_auto_or_decltype_auto)
-                << FixItHint::CreateReplacement(SourceRange(AutoLoc,
-                                                            Tok.getLocation()),
-                                                "auto");
+                  << FixItHint::CreateReplacement(
+                         SourceRange(AutoLoc, Tok.getLocation()), "auto");
             } else {
               Tracker.consumeClose();
             }
@@ -4095,11 +4104,22 @@ void Parser::ParseDeclarationSpecifiers(
     case tok::kw_auto:
       if (getLangOpts().CPlusPlus11 || getLangOpts().C23) {
         if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
-          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());
+          // In C++ (not C23), 'auto' cannot be combined with a type specifier.
+          // However, OpenCL has its own error handling for this case.
+          if (getLangOpts().CPlusPlus && !getLangOpts().C23 &&
+              !getLangOpts().OpenCLCPlusPlus) {
+            // In C++11+, 'auto' cannot be combined with a type specifier.
+            // Don't set the storage class specifier to avoid Sema emitting a
+            // redundant error (GCC only emits one error for this case: "two or
+            // more data types in declaration").
+            isInvalid = true;
+            PrevSpec = "auto";
+            DiagID = diag::err_auto_type_specifier;
+          } else {
+            // C23 allows 'auto' as storage class with type specifier.
+            isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, 
Loc,
+                                               PrevSpec, DiagID, Policy);
+          }
         } else
           isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
                                          DiagID, Policy);
@@ -4281,26 +4301,26 @@ void Parser::ParseDeclarationSpecifiers(
     case tok::kw__Complex:
       if (!getLangOpts().C99)
         Diag(Tok, diag::ext_c99_feature) << Tok.getName();
-      isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
-                                        DiagID);
+      isInvalid =
+          DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec, DiagID);
       break;
     case tok::kw__Imaginary:
       if (!getLangOpts().C99)
         Diag(Tok, diag::ext_c99_feature) << Tok.getName();
-      isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
-                                        DiagID);
+      isInvalid =
+          DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec, 
DiagID);
       break;
     case tok::kw_void:
-      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec,
-                                     DiagID, Policy);
+      isInvalid =
+          DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID, 
Policy);
       break;
     case tok::kw_char:
-      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec,
-                                     DiagID, Policy);
+      isInvalid =
+          DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID, 
Policy);
       break;
     case tok::kw_int:
-      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec,
-                                     DiagID, Policy);
+      isInvalid =
+          DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID, Policy);
       break;
     case tok::kw__ExtInt:
     case tok::kw__BitInt: {
@@ -4317,16 +4337,16 @@ void Parser::ParseDeclarationSpecifiers(
                                      DiagID, Policy);
       break;
     case tok::kw_half:
-      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec,
-                                     DiagID, Policy);
+      isInvalid =
+          DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID, 
Policy);
       break;
     case tok::kw___bf16:
       isInvalid = DS.SetTypeSpecType(DeclSpec::TST_BFloat16, Loc, PrevSpec,
                                      DiagID, Policy);
       break;
     case tok::kw_float:
-      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec,
-                                     DiagID, Policy);
+      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, 
DiagID,
+                                     Policy);
       break;
     case tok::kw_double:
       isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec,
@@ -4365,12 +4385,12 @@ void Parser::ParseDeclarationSpecifiers(
                                      DiagID, Policy);
       break;
     case tok::kw_wchar_t:
-      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec,
-                                     DiagID, Policy);
+      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, 
DiagID,
+                                     Policy);
       break;
     case tok::kw_char8_t:
-      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char8, Loc, PrevSpec,
-                                     DiagID, Policy);
+      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char8, Loc, PrevSpec, 
DiagID,
+                                     Policy);
       break;
     case tok::kw_char16_t:
       isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec,
@@ -4440,15 +4460,15 @@ void Parser::ParseDeclarationSpecifiers(
 // We only need to enumerate each image type once.
 #define IMAGE_READ_WRITE_TYPE(Type, Id, Ext)
 #define IMAGE_WRITE_TYPE(Type, Id, Ext)
-#define IMAGE_READ_TYPE(ImgType, Id, Ext) \
-    case tok::kw_##ImgType##_t: \
-      if (!handleOpenCLImageKW(Ext, DeclSpec::TST_##ImgType##_t)) \
-        goto DoneWithDeclSpec; \
-      break;
+#define IMAGE_READ_TYPE(ImgType, Id, Ext)                                      
\
+  case tok::kw_##ImgType##_t:                                                  
\
+    if (!handleOpenCLImageKW(Ext, DeclSpec::TST_##ImgType##_t))                
\
+      goto DoneWithDeclSpec;                                                   
\
+    break;
 #include "clang/Basic/OpenCLImageTypes.def"
     case tok::kw___unknown_anytype:
-      isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
-                                     PrevSpec, DiagID, Policy);
+      isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, PrevSpec, 
DiagID,
+                                     Policy);
       break;
 
     // class-specifier:
@@ -4463,8 +4483,8 @@ void Parser::ParseDeclarationSpecifiers(
       // To produce better diagnostic, we parse them when
       // parsing class specifier.
       ParsedAttributes Attributes(AttrFactory);
-      ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS,
-                          EnteringContext, DSContext, Attributes);
+      ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS, EnteringContext,
+                          DSContext, Attributes);
 
       // If there are attributes following class specifier,
       // take them over and handle them here.
@@ -4696,7 +4716,7 @@ void Parser::ParseStructDeclaration(
 
   if (Tok.is(tok::kw___extension__)) {
     // __extension__ silences extension warnings in the subexpression.
-    ExtensionRAIIObject O(Diags);  // Use RAII to do this.
+    ExtensionRAIIObject O(Diags); // Use RAII to do this.
     ConsumeToken();
     return ParseStructDeclaration(DS, FieldsCallback, LateFieldAttrs);
   }
@@ -4851,7 +4871,7 @@ void Parser::ParseStructUnionBody(SourceLocation 
RecordLoc,
   if (T.consumeOpen())
     return;
 
-  ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
+  ParseScope StructScope(this, Scope::ClassScope | Scope::DeclScope);
   Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
 
   // `LateAttrParseExperimentalExtOnly=true` requests that only attributes
@@ -5018,8 +5038,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, 
DeclSpec &DS,
   // we don't suppress if this turns out to be an elaborated type
   // specifier.
   bool shouldDelayDiagsInTag =
-    (TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation ||
-     TemplateInfo.Kind == ParsedTemplateKind::ExplicitSpecialization);
+      (TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation ||
+       TemplateInfo.Kind == ParsedTemplateKind::ExplicitSpecialization);
   SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag);
 
   // Determine whether this declaration is permitted to have an enum-base.
@@ -5057,7 +5077,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, 
DeclSpec &DS,
     SS = Spec;
   }
 
-  // Must have either 'enum name' or 'enum {...}' or (rarely) 'enum : T { ... 
}'.
+  // Must have either 'enum name' or 'enum {...}' or (rarely) 'enum : T { ...
+  // }'.
   if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
       Tok.isNot(tok::colon)) {
     Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
@@ -5142,7 +5163,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, 
DeclSpec &DS,
                                 DeclaratorContext::TypeName);
       BaseType = Actions.ActOnTypeName(DeclaratorInfo);
 
-      BaseRange = SourceRange(ColonLoc, 
DeclaratorInfo.getSourceRange().getEnd());
+      BaseRange =
+          SourceRange(ColonLoc, DeclaratorInfo.getSourceRange().getEnd());
 
       if (!getLangOpts().ObjC) {
         if (getLangOpts().CPlusPlus)
@@ -5176,7 +5198,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, 
DeclSpec &DS,
   else if (Tok.is(tok::l_brace)) {
     if (DS.isFriendSpecified()) {
       Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
-        << SourceRange(DS.getFriendSpecLoc());
+          << SourceRange(DS.getFriendSpecLoc());
       ConsumeBrace();
       SkipUntil(tok::r_brace, StopAtSemi);
       // Discard any other definition-only pieces.
@@ -5265,7 +5287,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, 
DeclSpec &DS,
           << (AllowEnumSpecifier == AllowDefiningTypeSpec::Yes) << BaseRange;
     else if (ScopedEnumKWLoc.isValid())
       Diag(ScopedEnumKWLoc, diag::ext_elaborated_enum_class)
-        << FixItHint::CreateRemoval(ScopedEnumKWLoc) << IsScopedUsingClassTag;
+          << FixItHint::CreateRemoval(ScopedEnumKWLoc) << 
IsScopedUsingClassTag;
   }
 
   stripTypeAttributesOffDeclSpec(attrs, DS, TUK);
@@ -5282,14 +5304,15 @@ void Parser::ParseEnumSpecifier(SourceLocation 
StartLoc, DeclSpec &DS,
   const char *PrevSpec = nullptr;
   unsigned DiagID;
   Decl *TagDecl =
-      Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS,
-                    Name, NameLoc, attrs, AS, DS.getModulePrivateSpecLoc(),
-                    TParams, Owned, IsDependent, ScopedEnumKWLoc,
-                    IsScopedUsingClassTag,
+      Actions
+          .ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, Name,
+                    NameLoc, attrs, AS, DS.getModulePrivateSpecLoc(), TParams,
+                    Owned, IsDependent, ScopedEnumKWLoc, IsScopedUsingClassTag,
                     BaseType, DSC == DeclSpecContext::DSC_type_specifier,
                     DSC == DeclSpecContext::DSC_template_param ||
                         DSC == DeclSpecContext::DSC_template_type_arg,
-                    OffsetOfState, &SkipBody).get();
+                    OffsetOfState, &SkipBody)
+          .get();
 
   if (SkipBody.ShouldSkip) {
     assert(TUK == TagUseKind::Definition && "can only skip a definition");
@@ -5299,8 +5322,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, 
DeclSpec &DS,
     T.skipToEnd();
 
     if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
-                           NameLoc.isValid() ? NameLoc : StartLoc,
-                           PrevSpec, DiagID, TagDecl, Owned,
+                           NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
+                           DiagID, TagDecl, Owned,
                            Actions.getASTContext().getPrintingPolicy()))
       Diag(StartLoc, DiagID) << PrevSpec;
     return;
@@ -5323,8 +5346,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, 
DeclSpec &DS,
     }
 
     if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc,
-                           NameLoc.isValid() ? NameLoc : StartLoc,
-                           PrevSpec, DiagID, Type.get(),
+                           NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
+                           DiagID, Type.get(),
                            Actions.getASTContext().getPrintingPolicy()))
       Diag(StartLoc, DiagID) << PrevSpec;
 
@@ -5354,8 +5377,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, 
DeclSpec &DS,
   }
 
   if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
-                         NameLoc.isValid() ? NameLoc : StartLoc,
-                         PrevSpec, DiagID, TagDecl, Owned,
+                         NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
+                         DiagID, TagDecl, Owned,
                          Actions.getASTContext().getPrintingPolicy()))
     Diag(StartLoc, DiagID) << PrevSpec;
 }
@@ -5429,7 +5452,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl 
*EnumDecl,
       // We're missing a comma between enumerators.
       SourceLocation Loc = getEndOfPreviousToken();
       Diag(Loc, diag::err_enumerator_list_missing_comma)
-        << FixItHint::CreateInsertion(Loc, ", ");
+          << FixItHint::CreateInsertion(Loc, ", ");
       continue;
     }
 
@@ -5438,8 +5461,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl 
*EnumDecl,
     SourceLocation CommaLoc;
     if (Tok.isNot(tok::r_brace) && !TryConsumeToken(tok::comma, CommaLoc)) {
       if (EqualLoc.isValid())
-        Diag(Tok.getLocation(), diag::err_expected_either) << tok::r_brace
-                                                           << tok::comma;
+        Diag(Tok.getLocation(), diag::err_expected_either)
+            << tok::r_brace << tok::comma;
       else
         Diag(Tok.getLocation(), diag::err_expected_end_of_enumerator);
       if (SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch)) {
@@ -5453,13 +5476,13 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, 
Decl *EnumDecl,
     // If comma is followed by r_brace, emit appropriate warning.
     if (Tok.is(tok::r_brace) && CommaLoc.isValid()) {
       if (!getLangOpts().C99 && !getLangOpts().CPlusPlus11)
-        Diag(CommaLoc, getLangOpts().CPlusPlus ?
-               diag::ext_enumerator_list_comma_cxx :
-               diag::ext_enumerator_list_comma_c)
-          << FixItHint::CreateRemoval(CommaLoc);
+        Diag(CommaLoc, getLangOpts().CPlusPlus
+                           ? diag::ext_enumerator_list_comma_cxx
+                           : diag::ext_enumerator_list_comma_c)
+            << FixItHint::CreateRemoval(CommaLoc);
       else if (getLangOpts().CPlusPlus11)
         Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma)
-          << FixItHint::CreateRemoval(CommaLoc);
+            << FixItHint::CreateRemoval(CommaLoc);
       break;
     }
   }
@@ -5500,7 +5523,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl 
*EnumDecl,
 
 bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
   switch (Tok.getKind()) {
-  default: return false;
+  default:
+    return false;
     // type-specifiers
   case tok::kw_short:
   case tok::kw_long:
@@ -5555,13 +5579,14 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) 
const {
 
 bool Parser::isTypeSpecifierQualifier() {
   switch (Tok.getKind()) {
-  default: return false;
+  default:
+    return false;
 
-  case tok::identifier:   // foo::bar
+  case tok::identifier: // foo::bar
     if (TryAltiVecVectorToken())
       return true;
     [[fallthrough]];
-  case tok::kw_typename:  // typename T::type
+  case tok::kw_typename: // typename T::type
     // Annotate typenames and C++ scope specifiers.  If we get one, just
     // recurse to handle whatever we get.
     if (TryAnnotateTypeOrScopeToken())
@@ -5570,9 +5595,9 @@ bool Parser::isTypeSpecifierQualifier() {
       return false;
     return isTypeSpecifierQualifier();
 
-  case tok::coloncolon:   // ::foo::bar
-    if (NextToken().is(tok::kw_new) ||    // ::new
-        NextToken().is(tok::kw_delete))   // ::delete
+  case tok::coloncolon:                 // ::foo::bar
+    if (NextToken().is(tok::kw_new) ||  // ::new
+        NextToken().is(tok::kw_delete)) // ::delete
       return false;
 
     if (TryAnnotateTypeOrScopeToken())
@@ -5734,14 +5759,15 @@ bool Parser::isDeclarationSpecifier(
     ImplicitTypenameContext AllowImplicitTypename,
     bool DisambiguatingWithExpression) {
   switch (Tok.getKind()) {
-  default: return false;
+  default:
+    return false;
 
   // OpenCL 2.0 and later define this keyword.
   case tok::kw_pipe:
     return getLangOpts().OpenCL &&
            getLangOpts().getOpenCLCompatibleVersion() >= 200;
 
-  case tok::identifier:   // foo::bar
+  case tok::identifier: // foo::bar
     // Unfortunate hack to support "Class.factoryMethod" notation.
     if (getLangOpts().ObjC && NextToken().is(tok::period))
       return false;
@@ -5770,11 +5796,11 @@ bool Parser::isDeclarationSpecifier(
 
     return isDeclarationSpecifier(AllowImplicitTypename);
 
-  case tok::coloncolon:   // ::foo::bar
+  case tok::coloncolon: // ::foo::bar
     if (!getLangOpts().CPlusPlus)
       return false;
-    if (NextToken().is(tok::kw_new) ||    // ::new
-        NextToken().is(tok::kw_delete))   // ::delete
+    if (NextToken().is(tok::kw_new) ||  // ::new
+        NextToken().is(tok::kw_delete)) // ::delete
       return false;
 
     // Annotate typenames and C++ scope specifiers.  If we get one, just
@@ -5923,7 +5949,7 @@ bool Parser::isDeclarationSpecifier(
     if (NextToken().is(tok::identifier) && TryAnnotateTypeConstraint())
       return true;
     return isTypeConstraintAnnotation() &&
-        GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype);
+           GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype);
   }
 
   case tok::kw___declspec:
@@ -6150,7 +6176,7 @@ void Parser::ParseTypeQualifierListOpt(
       return;
 
     case tok::kw_const:
-      isInvalid = DS.SetTypeQual(DeclSpec::TQ_const   , Loc, PrevSpec, DiagID,
+      isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID,
                                  getLangOpts());
       break;
     case tok::kw_volatile:
@@ -6206,10 +6232,11 @@ void Parser::ParseTypeQualifierListOpt(
                                  getLangOpts());
       break;
     case tok::kw___uptr:
-      // GNU libc headers in C mode use '__uptr' as an identifier which 
conflicts
-      // with the MS modifier keyword.
-      if ((AttrReqs & AR_DeclspecAttributesParsed) && !getLangOpts().CPlusPlus 
&&
-          IdentifierRequired && DS.isEmpty() && NextToken().is(tok::semi)) {
+      // GNU libc headers in C mode use '__uptr' as an identifier which
+      // conflicts with the MS modifier keyword.
+      if ((AttrReqs & AR_DeclspecAttributesParsed) &&
+          !getLangOpts().CPlusPlus && IdentifierRequired && DS.isEmpty() &&
+          NextToken().is(tok::semi)) {
         if (TryKeywordIdentFallback(false))
           continue;
       }
@@ -6272,7 +6299,7 @@ void Parser::ParseTypeQualifierListOpt(
       // otherwise, FALL THROUGH!
       [[fallthrough]];
     default:
-      DoneWithTypeQuals:
+    DoneWithTypeQuals:
       // If this is not a type-qualifier token, we're done reading type
       // qualifiers.  First verify that DeclSpec's are consistent.
       DS.Finish(Actions, Actions.getASTContext().getPrintingPolicy());
@@ -6434,7 +6461,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
 
   // Otherwise, '*' -> pointer, '^' -> block, '&' -> lvalue reference,
   // '&&' -> rvalue reference
-  SourceLocation Loc = ConsumeToken();  // Eat the *, ^, & or &&.
+  SourceLocation Loc = ConsumeToken(); // Eat the *, ^, & or &&.
   D.SetRangeEnd(Loc);
 
   if (Kind == tok::star || Kind == tok::caret) {
@@ -6473,9 +6500,9 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
     // Complain about rvalue references in C++03, but then go on and build
     // the declarator.
     if (Kind == tok::ampamp)
-      Diag(Loc, getLangOpts().CPlusPlus11 ?
-           diag::warn_cxx98_compat_rvalue_reference :
-           diag::ext_rvalue_reference);
+      Diag(Loc, getLangOpts().CPlusPlus11
+                    ? diag::warn_cxx98_compat_rvalue_reference
+                    : diag::ext_rvalue_reference);
 
     // GNU-style and C++11 attributes are allowed here, as is restrict.
     ParseTypeQualifierListOpt(DS);
@@ -6487,14 +6514,17 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
     if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
       if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
         Diag(DS.getConstSpecLoc(),
-             diag::err_invalid_reference_qualifier_application) << "const";
+             diag::err_invalid_reference_qualifier_application)
+            << "const";
       if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
         Diag(DS.getVolatileSpecLoc(),
-             diag::err_invalid_reference_qualifier_application) << "volatile";
+             diag::err_invalid_reference_qualifier_application)
+            << "volatile";
       // 'restrict' is permitted as an extension.
       if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
         Diag(DS.getAtomicSpecLoc(),
-             diag::err_invalid_reference_qualifier_application) << "_Atomic";
+             diag::err_invalid_reference_qualifier_application)
+            << "_Atomic";
     }
 
     // Recursively parse the declarator.
@@ -6503,14 +6533,14 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
 
     if (D.getNumTypeObjects() > 0) {
       // C++ [dcl.ref]p4: There shall be no references to references.
-      DeclaratorChunk& InnerChunk = D.getTypeObject(D.getNumTypeObjects() - 1);
+      DeclaratorChunk &InnerChunk = D.getTypeObject(D.getNumTypeObjects() - 1);
       if (InnerChunk.Kind == DeclaratorChunk::Reference) {
         if (const IdentifierInfo *II = D.getIdentifier())
           Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference)
-           << II;
+              << II;
         else
           Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference)
-            << "type name";
+              << "type name";
 
         // Once we've complained about the reference-to-reference, we
         // can go ahead and build the (technically ill-formed)
@@ -6674,7 +6704,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
       // We have a scope specifier but no following unqualified-id.
       Diag(PP.getLocForEndOfToken(D.getCXXScopeSpec().getEndLoc()),
            diag::err_expected_unqualified_id)
-          << /*C++*/1;
+          << /*C++*/ 1;
       D.SetIdentifier(nullptr, Tok.getLocation());
       goto PastIdentifier;
     }
@@ -6710,7 +6740,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
           tok::comma, tok::semi, tok::equal, tok::l_brace, tok::kw_try);
     if (DiagnoseIdentifier) {
       Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id)
-        << FixItHint::CreateRemoval(Tok.getLocation());
+          << FixItHint::CreateRemoval(Tok.getLocation());
       D.SetIdentifier(nullptr, Tok.getLocation());
       ConsumeToken();
       goto PastIdentifier;
@@ -6742,9 +6772,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
     if (D.getCXXScopeSpec().isSet()) {
       // If there was an error parsing parenthesized declarator, declarator
       // scope may have been entered before. Don't do it again.
-      if (!D.isInvalidType() &&
-          Actions.ShouldEnterDeclaratorScope(getCurScope(),
-                                             D.getCXXScopeSpec()))
+      if (!D.isInvalidType() && Actions.ShouldEnterDeclaratorScope(
+                                    getCurScope(), D.getCXXScopeSpec()))
         // Change the declaration context for name lookup, until this function
         // is exited (and the declarator has been parsed).
         DeclScopeObj.EnterDeclaratorScope();
@@ -6810,7 +6839,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
     D.setInvalidType(true);
   }
 
- PastIdentifier:
+PastIdentifier:
   assert(D.isPastIdentifier() &&
          "Haven't past the location of the identifier yet?");
 
@@ -7042,7 +7071,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
   ParseMicrosoftTypeAttributes(attrs);
 
   // Eat any Borland extensions.
-  if  (Tok.is(tok::kw___pascal))
+  if (Tok.is(tok::kw___pascal))
     ParseBorlandTypeAttributes(attrs);
 
   // If we haven't past the identifier yet (or where the identifier would be
@@ -7159,8 +7188,7 @@ void Parser::InitCXXThisScopeForDeclaratorIfRelevant(
 void Parser::ParseFunctionDeclarator(Declarator &D,
                                      ParsedAttributes &FirstArgAttrs,
                                      BalancedDelimiterTracker &Tracker,
-                                     bool IsAmbiguous,
-                                     bool RequiresArg) {
+                                     bool IsAmbiguous, bool RequiresArg) {
   assert(getCurScope()->isFunctionPrototypeScope() &&
          "Should call from a Function scope");
   // lparen is already consumed!
@@ -7283,12 +7311,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
         // delayed parsing to give it a chance to find what it expects.
         Delayed = false;
       }
-      ESpecType = tryParseExceptionSpecification(Delayed,
-                                                 ESpecRange,
-                                                 DynamicExceptions,
-                                                 DynamicExceptionRanges,
-                                                 NoexceptExpr,
-                                                 ExceptionSpecTokens);
+      ESpecType = tryParseExceptionSpecification(
+          Delayed, ESpecRange, DynamicExceptions, DynamicExceptionRanges,
+          NoexceptExpr, ExceptionSpecTokens);
       if (ESpecType != EST_None)
         EndLoc = ESpecRange.getEnd();
 
@@ -7338,26 +7363,24 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
   }
 
   // Remember that we parsed a function type, and remember the attributes.
-  D.AddTypeInfo(DeclaratorChunk::getFunction(
-                    HasProto, IsAmbiguous, LParenLoc, ParamInfo.data(),
-                    ParamInfo.size(), EllipsisLoc, RParenLoc,
-                    RefQualifierIsLValueRef, RefQualifierLoc,
-                    /*MutableLoc=*/SourceLocation(),
-                    ESpecType, ESpecRange, DynamicExceptions.data(),
-                    DynamicExceptionRanges.data(), DynamicExceptions.size(),
-                    NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
-                    ExceptionSpecTokens, DeclsInPrototype, StartLoc,
-                    LocalEndLoc, D, TrailingReturnType, TrailingReturnTypeLoc,
-                    &DS),
-                std::move(FnAttrs), EndLoc);
+  D.AddTypeInfo(
+      DeclaratorChunk::getFunction(
+          HasProto, IsAmbiguous, LParenLoc, ParamInfo.data(), ParamInfo.size(),
+          EllipsisLoc, RParenLoc, RefQualifierIsLValueRef, RefQualifierLoc,
+          /*MutableLoc=*/SourceLocation(), ESpecType, ESpecRange,
+          DynamicExceptions.data(), DynamicExceptionRanges.data(),
+          DynamicExceptions.size(),
+          NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
+          ExceptionSpecTokens, DeclsInPrototype, StartLoc, LocalEndLoc, D,
+          TrailingReturnType, TrailingReturnTypeLoc, &DS),
+      std::move(FnAttrs), EndLoc);
 }
 
 bool Parser::ParseRefQualifier(bool &RefQualifierIsLValueRef,
                                SourceLocation &RefQualifierLoc) {
   if (Tok.isOneOf(tok::amp, tok::ampamp)) {
-    Diag(Tok, getLangOpts().CPlusPlus11 ?
-         diag::warn_cxx98_compat_ref_qualifier :
-         diag::ext_ref_qualifier);
+    Diag(Tok, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_ref_qualifier
+                                        : diag::ext_ref_qualifier);
 
     RefQualifierIsLValueRef = Tok.is(tok::amp);
     RefQualifierLoc = ConsumeToken();
@@ -7367,9 +7390,8 @@ bool Parser::ParseRefQualifier(bool 
&RefQualifierIsLValueRef,
 }
 
 bool Parser::isFunctionDeclaratorIdentifierList() {
-  return !getLangOpts().requiresStrictPrototypes()
-         && Tok.is(tok::identifier)
-         && !TryAltiVecVectorToken()
+  return !getLangOpts().requiresStrictPrototypes() && Tok.is(tok::identifier) 
&&
+         !TryAltiVecVectorToken()
          // K&R identifier lists can't have typedefs as identifiers, per C99
          // 6.7.5.3p11.
          && (TryAnnotateTypeOrScopeToken() || !Tok.is(tok::annot_typename))
@@ -7390,8 +7412,7 @@ bool Parser::isFunctionDeclaratorIdentifierList() {
 }
 
 void Parser::ParseFunctionDeclaratorIdentifierList(
-       Declarator &D,
-       SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo) {
+    Declarator &D, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo) {
   // We should never reach this point in C23 or C++.
   assert(!getLangOpts().requiresStrictPrototypes() &&
          "Cannot parse an identifier list in C23 or C++");
@@ -7427,9 +7448,8 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
       Diag(Tok, diag::err_param_redefinition) << ParmII;
     } else {
       // Remember this identifier in ParamInfo.
-      ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
-                                                     Tok.getLocation(),
-                                                     nullptr));
+      ParamInfo.push_back(
+          DeclaratorChunk::ParamInfo(ParmII, Tok.getLocation(), nullptr));
     }
 
     // Eat the identifier.
@@ -7666,9 +7686,9 @@ void Parser::ParseParameterDeclarationClause(
         }
       }
 
-      ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
-                                          ParmDeclarator.getIdentifierLoc(),
-                                          Param, std::move(DefArgToks)));
+      ParamInfo.push_back(
+          DeclaratorChunk::ParamInfo(ParmII, ParmDeclarator.getIdentifierLoc(),
+                                     Param, std::move(DefArgToks)));
     }
 
     if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
@@ -7691,19 +7711,19 @@ void Parser::ParseParameterDeclarationClause(
         // point out where the ellipsis should have gone.
         SourceLocation ParmEllipsis = ParmDeclarator.getEllipsisLoc();
         Diag(EllipsisLoc, diag::warn_misplaced_ellipsis_vararg)
-          << ParmEllipsis.isValid() << ParmEllipsis;
+            << ParmEllipsis.isValid() << ParmEllipsis;
         if (ParmEllipsis.isValid()) {
           Diag(ParmEllipsis,
                diag::note_misplaced_ellipsis_vararg_existing_ellipsis);
         } else {
           Diag(ParmDeclarator.getIdentifierLoc(),
                diag::note_misplaced_ellipsis_vararg_add_ellipsis)
-            << FixItHint::CreateInsertion(ParmDeclarator.getIdentifierLoc(),
-                                          "...")
-            << !ParmDeclarator.hasName();
+              << FixItHint::CreateInsertion(ParmDeclarator.getIdentifierLoc(),
+                                            "...")
+              << !ParmDeclarator.hasName();
         }
         Diag(EllipsisLoc, diag::note_misplaced_ellipsis_vararg_add_comma)
-          << FixItHint::CreateInsertion(EllipsisLoc, ", ");
+            << FixItHint::CreateInsertion(EllipsisLoc, ", ");
       }
 
       // We can't have any more parameters after an ellipsis.
@@ -7779,11 +7799,11 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
   // the token after the star is a ']'.  Since stars in arrays are
   // infrequent, use of lookahead is not costly here.
   if (Tok.is(tok::star) && GetLookAheadToken(1).is(tok::r_square)) {
-    ConsumeToken();  // Eat the '*'.
+    ConsumeToken(); // Eat the '*'.
 
     if (StaticLoc.isValid()) {
       Diag(StaticLoc, diag::err_unspecified_vla_size_with_static);
-      StaticLoc = SourceLocation();  // Drop the static.
+      StaticLoc = SourceLocation(); // Drop the static.
     }
     isStar = true;
   } else if (Tok.isNot(tok::r_square)) {
@@ -7804,7 +7824,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
   } else {
     if (StaticLoc.isValid()) {
       Diag(StaticLoc, diag::err_unspecified_size_with_static);
-      StaticLoc = SourceLocation();  // Drop the static.
+      StaticLoc = SourceLocation(); // Drop the static.
     }
   }
 
@@ -7958,8 +7978,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
     // Check for duplicate type specifiers (e.g. "int typeof(int)").
     if (DS.SetTypeSpecType(IsUnqual ? DeclSpec::TST_typeof_unqualType
                                     : DeclSpec::TST_typeofType,
-                           StartLoc, PrevSpec,
-                           DiagID, CastTy,
+                           StartLoc, PrevSpec, DiagID, CastTy,
                            Actions.getASTContext().getPrintingPolicy()))
       Diag(StartLoc, DiagID) << PrevSpec;
     return;
@@ -7983,8 +8002,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
   // Check for duplicate type specifiers (e.g. "int typeof(int)").
   if (DS.SetTypeSpecType(IsUnqual ? DeclSpec::TST_typeof_unqualExpr
                                   : DeclSpec::TST_typeofExpr,
-                         StartLoc, PrevSpec,
-                         DiagID, Operand.get(),
+                         StartLoc, PrevSpec, DiagID, Operand.get(),
                          Actions.getASTContext().getPrintingPolicy()))
     Diag(StartLoc, DiagID) << PrevSpec;
 }
@@ -8015,8 +8033,8 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
 
   const char *PrevSpec = nullptr;
   unsigned DiagID;
-  if (DS.SetTypeSpecType(DeclSpec::TST_atomic, StartLoc, PrevSpec,
-                         DiagID, Result.get(),
+  if (DS.SetTypeSpecType(DeclSpec::TST_atomic, StartLoc, PrevSpec, DiagID,
+                         Result.get(),
                          Actions.getASTContext().getPrintingPolicy()))
     Diag(StartLoc, DiagID) << PrevSpec;
 }
@@ -8024,7 +8042,8 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
 bool Parser::TryAltiVecVectorTokenOutOfLine() {
   Token Next = NextToken();
   switch (Next.getKind()) {
-  default: return false;
+  default:
+    return false;
   case tok::kw_short:
   case tok::kw_long:
   case tok::kw_signed:
@@ -8078,7 +8097,8 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, 
SourceLocation Loc,
       return true;
     case tok::identifier:
       if (Next.getIdentifierInfo() == Ident_pixel) {
-        isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, 
DiagID,Policy);
+        isInvalid =
+            DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy);
         return true;
       }
       if (Next.getIdentifierInfo() == Ident_bool ||
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..da8732dc6e62c 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 in C++}}
+#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 in C++}}
+#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 in C++}}
+#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 in C++}}
+#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 in C++}}
 // 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 in C++}}
 // 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 in C++}}
 #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 in C++}}
+#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..983119d6af8d0 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 in C++}}
 
   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..0a2688ee288ae 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 in 
C++}}
+#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..905591d9518a8 100644
--- a/clang/test/CXX/drs/cwg3xx.cpp
+++ b/clang/test/CXX/drs/cwg3xx.cpp
@@ -1732,11 +1732,16 @@ 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}}
+    // since-cxx11-error@-1 {{'auto' cannot be combined with a type specifier 
in C++}}
+#if __cplusplus < 201103L
+    // expected-error@-3 {{illegal storage class on function}}
+#else
+    // expected-warning@-3 {{empty parentheses interpreted as a function 
declaration}}
+    // expected-note@-3 {{replace parentheses with an initializer to declare a 
variable}}
+#endif
     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 
in C++}}
     // 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..f34195934cc85
--- /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 in C++}}
+  auto char c = 'a';    // expected-error {{'auto' cannot be combined with a 
type specifier in C++}}
+  auto float f = 1.0f;  // expected-error {{'auto' cannot be combined with a 
type specifier in C++}}
+  auto double d = 1.0;   // expected-error {{'auto' cannot be combined with a 
type specifier in C++}}
+  auto long l = 1L;     // expected-error {{'auto' cannot be combined with a 
type specifier in C++}}
+}
+
+// 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/SemaCXX/auto-cxx0x.cpp 
b/clang/test/SemaCXX/auto-cxx0x.cpp
index 07687b6066790..2662319b900cd 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 in C++}}
   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..e0aa09dca82e4 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 in 
C++}}
 #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..49c016dee892b 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 in C++}}
+#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

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

Reply via email to