llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Nikita Popov (nikic) <details> <summary>Changes</summary> Reverts llvm/llvm-project#<!-- -->166004. Breaks stage 2 build, see comments on PR. --- Patch is 37.17 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/208436.diff 15 Files Affected: - (modified) clang/docs/ReleaseNotes.md (-2) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (-2) - (modified) clang/include/clang/Sema/DeclSpec.h (+2-51) - (modified) clang/lib/Parse/ParseDecl.cpp (+6-38) - (modified) clang/lib/Sema/DeclSpec.cpp (-163) - (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp (+48-57) - (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp (+1-7) - (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp (+6-6) - (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp (+1-6) - (modified) clang/test/CXX/dcl/dcl.fct/p17.cpp (+1-1) - (modified) clang/test/CXX/drs/cwg3xx.cpp (+7-9) - (modified) clang/test/Parser/c2x-auto.c (-7) - (modified) clang/test/SemaCXX/auto-cxx0x.cpp (+2-8) - (modified) clang/test/SemaCXX/class.cpp (+4-5) - (modified) clang/test/SemaCXX/static-data-member.cpp (+1-6) ``````````diff diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 61caf2d9ec99e..a573599d76f7d 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -116,8 +116,6 @@ 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 different block scope than their parent class. (#GH193472) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 45f909fc5452c..15867f69a6718 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2759,8 +2759,6 @@ def err_decltype_auto_invalid : Error< "'decltype(auto)' not allowed here">; def err_decltype_auto_cannot_be_combined : Error< "'decltype(auto)' cannot be combined with other type specifiers">; -def err_auto_type_specifier : Error< - "'auto' cannot be combined with a type specifier">; def err_decltype_auto_function_declarator_not_declaration : Error< "'decltype(auto)' can only be used as a return type " "in a function declaration">; diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index d1abc0e3c21fb..6e7f9cd6e3d38 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -363,10 +363,6 @@ class DeclSpec { unsigned TypeSpecSat : 1; LLVM_PREFERRED_TYPE(bool) unsigned ConstrainedAuto : 1; - // Track conflicting type specifier when 'auto' is set (for Finish() - // detection) - LLVM_PREFERRED_TYPE(TST) - unsigned ConflictingTypeSpecifier : 7; // type-qualifiers LLVM_PREFERRED_TYPE(TQ) @@ -431,50 +427,10 @@ class DeclSpec { SourceLocation FS_explicitCloseParenLoc; SourceLocation FS_forceinlineLoc; SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; - SourceLocation TQ_pipeLoc, ConflictingTypeSpecifierLoc; + SourceLocation TQ_pipeLoc; WrittenBuiltinSpecs writtenBS; void SaveWrittenBuiltinSpecs(); - void setConflictingTypeSpecifier(TST T, SourceLocation Loc) { - // Store conflicting type specifier for Finish() to detect: - // - If 'auto' is already set, store the conflicting type (e.g., "auto int") - // - If 'auto' is being set after another type, store TST_auto - // (e.g., "int auto"). - if (TypeSpecType == TST_auto) { - ConflictingTypeSpecifier = T; - ConflictingTypeSpecifierLoc = Loc; - } else if (T == TST_auto) { - ConflictingTypeSpecifier = TST_auto; - ConflictingTypeSpecifierLoc = Loc; - } - } - void setConflictingTypeSpecifier(TST T, SourceLocation Loc, - SourceLocation NameLoc, ParsedType Rep) { - setConflictingTypeSpecifier(T, Loc); - if (TypeSpecType == TST_auto) { - TypeRep = Rep; - TSTNameLoc = NameLoc; - TypeSpecOwned = false; - } - } - void setConflictingTypeSpecifier(TST T, SourceLocation Loc, Expr *Rep) { - setConflictingTypeSpecifier(T, Loc); - if (TypeSpecType == TST_auto) { - ExprRep = Rep; - TSTNameLoc = Loc; - TypeSpecOwned = false; - } - } - void setConflictingTypeSpecifier(TST T, SourceLocation Loc, - SourceLocation NameLoc, Decl *Rep, - bool Owned) { - setConflictingTypeSpecifier(T, Loc); - if (TypeSpecType == TST_auto) { - DeclRep = Rep; - TSTNameLoc = NameLoc; - TypeSpecOwned = Owned && Rep != nullptr; - } - } ObjCDeclSpec *ObjCQualifiers; @@ -518,15 +474,13 @@ class DeclSpec { TypeSpecType(TST_unspecified), TypeAltiVecVector(false), TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false), TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false), - ConflictingTypeSpecifier(TST_unspecified), TypeQualifiers(TQ_unspecified), OB_state(static_cast<unsigned>(OverflowBehaviorState::Unspecified)), FS_inline_specified(false), FS_forceinline_specified(false), FS_virtual_specified(false), FS_noreturn_specified(false), FriendSpecifiedFirst(false), ConstexprSpecifier(static_cast<unsigned>( ConstexprSpecKind::Unspecified)), - Attrs(attrFactory), ConflictingTypeSpecifierLoc(), writtenBS(), - ObjCQualifiers(nullptr) {} + Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {} // storage-class-specifier SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } @@ -566,9 +520,6 @@ class DeclSpec { return static_cast<TypeSpecifierSign>(TypeSpecSign); } TST getTypeSpecType() const { return (TST)TypeSpecType; } - bool hasConflictingTypeSpecifier() const { - return ConflictingTypeSpecifier != TST_unspecified; - } bool isTypeAltiVecVector() const { return TypeAltiVecVector; } bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; } bool isTypeAltiVecBool() const { return TypeAltiVecBool; } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 1b865195f23e5..3f41e7c5c6f0d 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3775,9 +3775,7 @@ void Parser::ParseDeclarationSpecifiers( // This identifier can only be a typedef name if we haven't already seen // a type-specifier. Without this check we misparse: // typedef int X; struct Y { short X; }; as 'short int'. - // However, if 'auto' is set, we need to check if this identifier is a - // type name to detect conflicts (e.g., "auto MyInt"). - if (DS.hasTypeSpecifier() && DS.getTypeSpecType() != DeclSpec::TST_auto) + if (DS.hasTypeSpecifier()) goto DoneWithDeclSpec; // If the token is an identifier named "__declspec" and Microsoft @@ -3862,14 +3860,6 @@ void Parser::ParseDeclarationSpecifiers( DS.isFriendSpecified())) goto DoneWithDeclSpec; - // If 'auto' is set and we're in a template parameter context, the - // identifier is always the parameter name, not a type specifier, so skip - // type name lookup to avoid false ambiguity errors. - if (DS.getTypeSpecType() == DeclSpec::TST_auto && - DSContext == DeclSpecContext::DSC_template_param) { - goto DoneWithDeclSpec; - } - ParsedType TypeRep = Actions.getTypeName( *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr, false, false, nullptr, false, false, @@ -3877,16 +3867,11 @@ void Parser::ParseDeclarationSpecifiers( // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. - // However, if 'auto' is already set, we can't have an implicit int. if (!TypeRep) { if (TryAnnotateTypeConstraint()) goto DoneWithDeclSpec; if (Tok.isNot(tok::identifier)) continue; - // If 'auto' is set, the identifier must be a type name or it's an - // error. Don't try to parse it as implicit int. - if (DS.getTypeSpecType() == DeclSpec::TST_auto) - goto DoneWithDeclSpec; ParsedAttributes Attrs(AttrFactory); if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { if (!Attrs.empty()) { @@ -3898,25 +3883,6 @@ 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; @@ -4171,9 +4137,12 @@ void Parser::ParseDeclarationSpecifiers( } }; - if (!getLangOpts().CPlusPlus && MayBeTypeSpecifier()) { + if (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); @@ -4731,8 +4700,7 @@ void Parser::ParseDeclarationSpecifiers( DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : Tok.getLocation()); // If the specifier wasn't legal, issue a diagnostic. - // Skip diagnostic if 'auto' conflict will be handled in Finish() - if (isInvalid && !DS.hasConflictingTypeSpecifier()) { + if (isInvalid) { assert(PrevSpec && "Method did not return previous specifier!"); assert(DiagID); diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 3c882bc3a1003..2add7c6aa3080 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -759,7 +759,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { - setConflictingTypeSpecifier(T, TagKwLoc, TagNameLoc, Rep); PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -791,7 +790,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { - setConflictingTypeSpecifier(T, Loc, Rep); PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -824,7 +822,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { - setConflictingTypeSpecifier(T, TagKwLoc, TagNameLoc, Rep, Owned); PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -855,7 +852,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { - setConflictingTypeSpecifier(T, Loc); PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -1216,164 +1212,6 @@ void DeclSpec::CheckTypeSpec(Sema &S, const PrintingPolicy &Policy) { << Hints[4] << Hints[5] << Hints[6] << Hints[7]; } - // If 'auto' type specifier is combined with another type specifier, we need - // to handle it based on the language: - // - In C++11+: Emit error (cannot combine type specifiers) - // - In C23: Convert 'auto' to storage class (valid) - // - In OpenCL: Convert 'auto' to storage class, then OpenCL will reject it - // Handle both cases: - // - "auto int" (TypeSpecType == TST_auto, ConflictingTypeSpecifier == - // TST_int) - // - "int auto" (TypeSpecType == TST_int, ConflictingTypeSpecifier == - // TST_auto) - if (ConflictingTypeSpecifier != TST_unspecified) { - // Special case: "auto auto" - duplicate 'auto', emit error - if (TypeSpecType == TST_auto && ConflictingTypeSpecifier == TST_auto) { - // Both are 'auto', emit "cannot combine with previous 'auto' declaration - // specifier" error This matches GCC's "duplicate 'auto'" behavior Note: - // We keep TypeSpecType = TST_auto (don't set to TST_error) so that later - // checks in SemaType.cpp can emit "not allowed in function prototype" and - // "not allowed in function return type" errors as needed. - const char *PrevSpec = "auto"; - unsigned DiagID = diag::err_invalid_decl_spec_combination; - S.Diag(ConflictingTypeSpecifierLoc, DiagID) << PrevSpec << PrevSpec; - // Clear the conflict tracking but keep TypeSpecType = TST_auto - ConflictingTypeSpecifier = TST_unspecified; - ConflictingTypeSpecifierLoc = SourceLocation(); - } else if ((S.getLangOpts().C23 && !S.getLangOpts().CPlusPlus) || - (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)) { - // In C23 or C++98, convert 'auto' to storage class specifier - if (TypeSpecType == TST_auto) { - // "auto int" case: Convert 'auto' to storage class specifier - 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). @@ -1602,7 +1440,6 @@ voi... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/208436 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
