Author: Osama Abdelkader Date: 2026-07-09T11:00:08+02:00 New Revision: d7ccd02c9c78b6576ca2caa3f4d2435ebda50744
URL: https://github.com/llvm/llvm-project/commit/d7ccd02c9c78b6576ca2caa3f4d2435ebda50744 DIFF: https://github.com/llvm/llvm-project/commit/d7ccd02c9c78b6576ca2caa3f4d2435ebda50744.diff LOG: [clang] Reject 'auto' storage class with type specifier in C++ (#166004) Fixes #164273 --------- Signed-off-by: Osama Abdelkader <[email protected]> Added: Modified: clang/docs/ReleaseNotes.md 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/class.cpp clang/test/SemaCXX/static-data-member.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index a573599d76f7d..61caf2d9ec99e 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -116,6 +116,8 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the as being of type `std::size_t` instead of `int`, matching the deduction of array sizes from `int(&)[N]`. This is a breaking change for code that depended on the previously deduced type. (#GH195033) +- Clang now rejects C++ declarations that combine the `auto` type specifier + with another type specifier, such as `auto int`. - Clang now rejects nested local classes defined in a diff erent block scope than their parent class. (#GH193472) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 15867f69a6718..45f909fc5452c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2759,6 +2759,8 @@ 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 6e7f9cd6e3d38..d1abc0e3c21fb 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -363,6 +363,10 @@ 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) @@ -427,10 +431,50 @@ class DeclSpec { SourceLocation FS_explicitCloseParenLoc; SourceLocation FS_forceinlineLoc; SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; - SourceLocation TQ_pipeLoc; + SourceLocation TQ_pipeLoc, ConflictingTypeSpecifierLoc; 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; @@ -474,13 +518,15 @@ 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), writtenBS(), ObjCQualifiers(nullptr) {} + Attrs(attrFactory), ConflictingTypeSpecifierLoc(), writtenBS(), + ObjCQualifiers(nullptr) {} // storage-class-specifier SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } @@ -520,6 +566,9 @@ 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 3f41e7c5c6f0d..1b865195f23e5 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3775,7 +3775,9 @@ 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'. - if (DS.hasTypeSpecifier()) + // 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) goto DoneWithDeclSpec; // If the token is an identifier named "__declspec" and Microsoft @@ -3860,6 +3862,14 @@ 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; + } + ParsedType TypeRep = Actions.getTypeName( *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr, false, false, nullptr, false, false, @@ -3867,11 +3877,16 @@ 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()) { @@ -3883,6 +3898,25 @@ void Parser::ParseDeclarationSpecifiers( goto DoneWithDeclSpec; } + // If 'auto' is set and this identifier is a type name, stop parsing + // declaration specifiers when the next token indicates this is the + // declarator-id rather than another type specifier. + if (DS.getTypeSpecType() == DeclSpec::TST_auto && TypeRep) { + Token Next = NextToken(); + if (Next.isOneOf(tok::equal, tok::l_paren, tok::l_square, tok::amp, + tok::ampamp, tok::star, tok::coloncolon, tok::comma, + tok::semi, tok::colon, tok::greater, tok::r_paren, + tok::arrow)) { + // This identifier is likely the variable/parameter name, stop parsing + // decl specifiers. Note: ':' is for range-based for loops: + // for (auto Arg: x). + // Note: '>' is for template parameters: template<auto V> + // Note: ')' is for function/lambda parameters: [](auto c) + // Note: '->' is for lambda return types: [](auto c) -> int + goto DoneWithDeclSpec; + } + } + // Likewise, if this is a context where the identifier could be a template // name, check whether this is a deduction guide declaration. CXXScopeSpec SS; @@ -4137,12 +4171,9 @@ void Parser::ParseDeclarationSpecifiers( } }; - if (MayBeTypeSpecifier()) { + if (!getLangOpts().CPlusPlus && MayBeTypeSpecifier()) { 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()); } else isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID, Policy); @@ -4700,7 +4731,8 @@ void Parser::ParseDeclarationSpecifiers( DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : Tok.getLocation()); // If the specifier wasn't legal, issue a diagnostic. - if (isInvalid) { + // Skip diagnostic if 'auto' conflict will be handled in Finish() + if (isInvalid && !DS.hasConflictingTypeSpecifier()) { 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 2add7c6aa3080..3c882bc3a1003 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -759,6 +759,7 @@ 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; @@ -790,6 +791,7 @@ 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; @@ -822,6 +824,7 @@ 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; @@ -852,6 +855,7 @@ 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; @@ -1212,6 +1216,164 @@ 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 + 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. No type conflict error - auto is treated as storage class, + // not type specifier. + StorageClassSpec = SCS_auto; + StorageClassSpecLoc = ConflictingTypeSpecifierLoc; + // TypeSpecType already has the correct type (e.g., TST_int) + // 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; + } 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). @@ -1440,6 +1602,7 @@ 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 723a79628116c..3a3f752a9e93b 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,66 +1,75 @@ -// 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 +// 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 // 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}} -#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}} -#endif +auto int ao; +// cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} +// cxx17-error@-2 {{'auto' cannot be combined with a type specifier}} +// cxx98-error@-3 {{illegal storage class on file-scoped variable}} -auto void af(); // expected-error {{illegal storage class on function}} -#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}} -#endif +auto void af(); +// cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} +// cxx17-error@-2 {{'auto' cannot be combined with a type specifier}} +// cxx98-error@-3 {{illegal storage class on function}} -register int ro; // expected-error {{illegal storage class on file-scoped variable}} -#if __cplusplus >= 201703L -// expected-error@-2 {{ISO C++17 does not allow 'register' storage class specifier}} -#elif __cplusplus >= 201103L -// expected-warning@-4 {{'register' storage class specifier is deprecated}} -#endif +register int ro; +// cxx98-error@-1 {{illegal storage class on file-scoped variable}} +// cxx11-error@-2 {{illegal storage class on file-scoped variable}} +// cxx11-warning@-3 {{'register' storage class specifier is deprecated and incompatible with C++17}} +// cxx17-error@-4 {{illegal storage class on file-scoped variable}} +// cxx17-error@-5 {{ISO C++17 does not allow 'register' storage class specifier}} -register void rf(); // expected-error {{illegal storage class on function}} +register void rf(); +// cxx98-error@-1 {{illegal storage class on function}} +// cxx11-error@-2 {{illegal storage class on function}} +// cxx17-error@-3 {{illegal storage class on function}} struct S { - auto int ao; // expected-error {{storage class specified for a member declaration}} -#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}} -#endif - auto void af(); // expected-error {{storage class specified for a member declaration}} -#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}} -#endif + auto int ao; + // cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} + // cxx17-error@-2 {{'auto' cannot be combined with a type specifier}} + // cxx98-error@-3 {{storage class specified for a member declaration}} + auto void af(); + // cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} + // cxx17-error@-2 {{'auto' cannot be combined with a type specifier}} + // cxx98-error@-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}} + register int ro; + // cxx98-error@-1 {{storage class specified for a member declaration}} + // cxx11-error@-2 {{storage class specified for a member declaration}} + // cxx17-error@-3 {{storage class specified for a member declaration}} + register void rf(); + // cxx98-error@-1 {{storage class specified for a member declaration}} + // cxx11-error@-2 {{storage class specified for a member declaration}} + // cxx17-error@-3 {{storage class specified for a member declaration}} }; 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@-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-warning@-6 {{'register' storage class specifier is deprecated}} -#endif + // cxx17-error@-1 {{'auto' cannot be combined with a type specifier}} + // cxx17-error@-2 {{ISO C++17 does not allow 'register' storage class specifier}} + // cxx11-error@-3 {{'auto' cannot be combined with a type specifier}} + // cxx11-warning@-4 {{'register' storage class specifier is deprecated and incompatible with C++17}} 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}} -#endif - auto void abf(); // expected-error {{illegal storage class on function}} -#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}} -#endif + // cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} + // cxx17-error@-2 {{'auto' cannot be combined with a type specifier}} + auto void abf(); + // cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} + // cxx11-warning@-2 {{empty parentheses interpreted as a function declaration}} + // cxx11-note@-3 {{replace parentheses with an initializer to declare a variable}} + // cxx17-error@-4 {{'auto' cannot be combined with a type specifier}} + // cxx17-warning@-5 {{empty parentheses interpreted as a function declaration}} + // cxx17-note@-6 {{replace parentheses with an initializer to declare a variable}} + // cxx98-error@-7 {{illegal storage class on function}} register int rbo; -#if __cplusplus >= 201703L -// expected-error@-2 {{ISO C++17 does not allow 'register' storage class specifier}} -#elif __cplusplus >= 201103L -// expected-warning@-4 {{'register' storage class specifier is deprecated}} -#endif + // cxx17-error@-1 {{ISO C++17 does not allow 'register' storage class specifier}} + // cxx11-warning@-2 {{'register' storage class specifier is deprecated and incompatible with C++17}} - register void rbf(); // expected-error {{illegal storage class on function}} + register void rbf(); + // cxx98-error@-1 {{illegal storage class on function}} + // cxx11-error@-2 {{illegal storage class on function}} + // cxx17-error@-3 {{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 e8f12156a4242..880014d591706 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,13 @@ 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; +#if __cplusplus >= 201103L + // expected-error@-2 {{'auto' cannot be combined with a type specifier}} +#else + // expected-warning@-4 {{storage class}} + // expected-error@-5 {{file-scope}} +#endif 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 a590f8eb77005..7577a789eb1c0 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 {{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}} + 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}} } } 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..8d7765523461c 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}} +#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/dcl/dcl.fct/p17.cpp b/clang/test/CXX/dcl/dcl.fct/p17.cpp index d837d0900d5b9..971edc7bf26eb 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 {{cannot combine with previous 'type-name' declaration specifier}} +void a_struct(AStruct auto); // expected-error {{'auto' cannot be combined with a type specifier}} } #if __cplusplus >= 202002L diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp index 10bf57e422f33..05db04255780b 100644 --- a/clang/test/CXX/drs/cwg3xx.cpp +++ b/clang/test/CXX/drs/cwg3xx.cpp @@ -1704,14 +1704,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}} + 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}} 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}} - // expected-error@-2 {{redefinition of 'i'}} - // expected-note@#cwg396-i {{previous definition is here}} + 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}} } } // namespace cwg396 diff --git a/clang/test/Parser/c2x-auto.c b/clang/test/Parser/c2x-auto.c index dc0e1f34dabdc..145e6f8b08b09 100644 --- a/clang/test/Parser/c2x-auto.c +++ b/clang/test/Parser/c2x-auto.c @@ -167,6 +167,13 @@ 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 f429bebb9941a..00ede3358b6b4 100644 --- a/clang/test/SemaCXX/auto-cxx0x.cpp +++ b/clang/test/SemaCXX/auto-cxx0x.cpp @@ -1,8 +1,14 @@ // 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}} - int auto b; // expected-error {{cannot combine with previous 'int' declaration specifier}} + 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}} } typedef auto PR25449(); // expected-error {{'auto' not allowed in typedef}} diff --git a/clang/test/SemaCXX/class.cpp b/clang/test/SemaCXX/class.cpp index f1e02d5158aac..71c71a1acc807 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}} -#if __cplusplus <= 199711L - // expected-warning@-2 {{'auto' storage class specifier is redundant}} + auto int errx; +#if __cplusplus >= 201103L + // expected-error@-2 {{'auto' cannot be combined with a type specifier}} #else - // expected-warning@-4 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} + // expected-error@-4 {{storage class specified for a member declaration}} + // expected-warning@-5 {{'auto' storage class specifier is redundant}} #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..2dbcae1745e5b 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}} +#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
