https://github.com/cor3ntin created https://github.com/llvm/llvm-project/pull/172150
In Kona, WG21 decided to revert trivial relocation (P2786). Given that the notion of replaceability that was introduced at the same time does not appear to be used by clang 21 users, and is less likely to come back, it is easier to fully remove wholesale. Subsequent patches will deal with relocation. >From fd1194ff9bcda2f0f6cdd6da395096a31cfb4b57 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <[email protected]> Date: Sat, 13 Dec 2025 11:47:39 +0100 Subject: [PATCH] [Clang][C++26] Remove the notion of replaceability. In Kona, WG21 decided to revert trivial relocation (P2786). Given that the notion of replaceability that was introduced at the same time does not appear to be used by clang 21 users, and is less likely to come back, it is easier to fully remove wholesale. Subsequent patches will deal with relocation. --- .../clang-tidy/modernize/TypeTraitsCheck.cpp | 1 - clang/docs/LanguageExtensions.rst | 2 - clang/include/clang/AST/ASTContext.h | 1 - clang/include/clang/Basic/Attr.td | 8 - .../clang/Basic/DiagnosticParseKinds.td | 21 +- .../clang/Basic/DiagnosticSemaKinds.td | 3 - clang/include/clang/Basic/TokenKinds.def | 1 - clang/include/clang/Parse/Parser.h | 9 +- clang/include/clang/Sema/Sema.h | 9 +- clang/lib/Parse/ParseDeclCXX.cpp | 49 +---- clang/lib/Parse/Parser.cpp | 1 - clang/lib/Sema/SemaDecl.cpp | 13 +- clang/lib/Sema/SemaTypeTraits.cpp | 182 +----------------- .../Parser/cxx2c-trivially-relocatable.cpp | 29 +-- .../SemaCXX/cxx2c-trivially-relocatable.cpp | 91 ++------- clang/test/SemaCXX/ptrauth-type-traits.cpp | 20 -- .../type-traits-unsatisfied-diags-std.cpp | 21 -- .../SemaCXX/type-traits-unsatisfied-diags.cpp | 159 +-------------- 18 files changed, 58 insertions(+), 562 deletions(-) diff --git a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp index 06982b8698e0c..66a6f07efd7bb 100644 --- a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp @@ -83,7 +83,6 @@ static const llvm::StringSet<> ValueTraits = { "is_pointer_interconvertible_base_of", "is_polymorphic", "is_reference", - "is_replaceable", "is_rvalue_reference", "is_same", "is_scalar", diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 87d38e7d99e50..0270d3e07bf76 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2044,8 +2044,6 @@ The following type trait primitives are supported by Clang. Those traits marked is trivially relocatable, as defined by the C++26 standard [meta.unary.prop]. Note that when relocating the caller code should ensure that if the object is polymorphic, the dynamic type is of the most derived type. Padding bytes should not be copied. -* ``__builtin_is_replaceable`` (C++): Returns true if an object - is replaceable, as defined by the C++26 standard [meta.unary.prop]. * ``__is_trivially_equality_comparable`` (Clang): Returns true if comparing two objects of the provided type is known to be equivalent to comparing their object representations. Note that types containing padding bytes are never diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index f64e29be3205f..1484ead2d9bfd 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -666,7 +666,6 @@ class ASTContext : public RefCountedBase<ASTContext> { public: struct CXXRecordDeclRelocationInfo { unsigned IsRelocatable; - unsigned IsReplaceable; }; std::optional<CXXRecordDeclRelocationInfo> getRelocationInfoForCXXRecord(const CXXRecordDecl *) const; diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index d8d1675f245a1..4a5f0ea73f518 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1952,14 +1952,6 @@ def TriviallyRelocatable : InheritableAttr { let Documentation = [InternalOnly]; } -def Replaceable : InheritableAttr { - let Spellings = [CustomKeyword<"replaceable_if_eligible">]; - let SemaHandler = 0; - // Omitted from docs, since this is language syntax, not an attribute, as far - // as users are concerned. - let Documentation = [InternalOnly]; -} - def MinSize : InheritableAttr { let Spellings = [Clang<"minsize">]; let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 9401377002223..bbaa9db2723ed 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1077,14 +1077,15 @@ def ext_ms_abstract_keyword : ExtWarn< "'abstract' keyword is a Microsoft extension">, InGroup<MicrosoftAbstract>; -def ext_relocatable_keyword : ExtWarn< - "'%select{trivially_relocatable_if_eligible|replaceable_if_eligible}0' " - "keyword is a C++2c extension">, - InGroup<CXX26>; -def warn_relocatable_keyword : Warning< - "'%select{trivially_relocatable|replaceable}0_if_eligible' " - "keyword is incompatible with standards before C++2c">, - DefaultIgnore, InGroup<CXXPre26Compat>; +def ext_relocatable_keyword + : ExtWarn< + "'trivially_relocatable_if_eligible' keyword is a C++2c extension">, + InGroup<CXX26>; +def warn_relocatable_keyword + : Warning<"'trivially_relocatable_if_eligible' keyword is incompatible " + "with standards before C++2c">, + DefaultIgnore, + InGroup<CXXPre26Compat>; def err_access_specifier_interface : Error< "interface types cannot specify '%select{private|protected}0' access">; @@ -1092,8 +1093,8 @@ def err_access_specifier_interface : Error< def err_duplicate_class_virt_specifier : Error< "class already marked '%0'">; -def err_duplicate_class_relocation_specifier : Error< - "class already marked '%select{trivially_relocatable_if_eligible|replaceable_if_eligible}0'">; +def err_duplicate_class_relocation_specifier + : Error<"class already marked 'trivially_relocatable_if_eligible'">; def err_duplicate_virt_specifier : Error< "class member already marked '%0'">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9147b6a041c70..9a75ab3b1b3c3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1770,7 +1770,6 @@ def err_user_defined_msg_constexpr : Error< def note_unsatisfied_trait : Note<"%0 is not %enum_select<TraitName>{" "%TriviallyRelocatable{trivially relocatable}|" - "%Replaceable{replaceable}|" "%TriviallyCopyable{trivially copyable}|" "%Empty{empty}|" "%StandardLayout{standard-layout}|" @@ -1792,8 +1791,6 @@ def note_unsatisfied_trait_reason "class type}|" "%NTRBase{has a non-trivially-relocatable base %1}|" "%NTRField{has a non-trivially-relocatable member %1 of type %2}|" - "%NonReplaceableBase{has a non-replaceable base %1}|" - "%NonReplaceableField{has a non-replaceable member %1 of type %2}|" "%NTCBase{has a non-trivially-copyable base %1}|" "%NTCField{has a non-trivially-copyable member %1 of type %2}|" "%NonEmptyMember{has a non-static data member %1 of type %2}|" diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 564d6010181cc..235ffbaa874a6 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -564,7 +564,6 @@ TYPE_TRAIT_2(/*EmptySpellingName*/, IsDeducible, KEYCXX) TYPE_TRAIT_1(__builtin_is_cpp_trivially_relocatable, IsCppTriviallyRelocatable, KEYCXX) TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX) TYPE_TRAIT_1(__is_bitwise_cloneable, IsBitwiseCloneable, KEYALL) -TYPE_TRAIT_1(__builtin_is_replaceable, IsReplaceable, KEYCXX) TYPE_TRAIT_1(__builtin_structured_binding_size, StructuredBindingSize, KEYCXX) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 58eb1c0a7c114..c67fb32af1eef 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2835,7 +2835,6 @@ class Parser : public CodeCompletionHandler { mutable IdentifierInfo *Ident_GNU_final; mutable IdentifierInfo *Ident_override; mutable IdentifierInfo *Ident_trivially_relocatable_if_eligible; - mutable IdentifierInfo *Ident_replaceable_if_eligible; /// Representation of a class that has been parsed, including /// any member function declarations or definitions that need to be @@ -3129,7 +3128,7 @@ class Parser : public CodeCompletionHandler { /// isClassCompatibleKeyword - Determine whether the next token is a C++11 /// 'final', a C++26 'trivially_relocatable_if_eligible', - /// 'replaceable_if_eligible', or Microsoft 'sealed' or 'abstract' contextual + /// or Microsoft 'sealed' or 'abstract' contextual /// keyword. bool isClassCompatibleKeyword() const; @@ -3603,12 +3602,8 @@ class Parser : public CodeCompletionHandler { bool isCXX2CTriviallyRelocatableKeyword() const; void ParseCXX2CTriviallyRelocatableSpecifier(SourceLocation &TRS); - bool isCXX2CReplaceableKeyword(Token Tok) const; - bool isCXX2CReplaceableKeyword() const; - void ParseCXX2CReplaceableSpecifier(SourceLocation &MRS); - /// 'final', a C++26 'trivially_relocatable_if_eligible', - /// 'replaceable_if_eligible', or Microsoft 'sealed' or 'abstract' contextual + /// or Microsoft 'sealed' or 'abstract' contextual /// keyword. bool isClassCompatibleKeyword(Token Tok) const; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index d14b5dc5ffaa4..1ddfae54b4b4b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4366,7 +4366,6 @@ class Sema final : public SemaBase { bool IsFinalSpelledSealed, bool IsAbstract, SourceLocation TriviallyRelocatable, - SourceLocation Replaceable, SourceLocation LBraceLoc); /// ActOnTagFinishDefinition - Invoked once we have finished parsing @@ -4375,7 +4374,7 @@ class Sema final : public SemaBase { SourceRange BraceRange); ASTContext::CXXRecordDeclRelocationInfo - CheckCXX2CRelocatableAndReplaceable(const clang::CXXRecordDecl *D); + CheckCXX2CRelocatable(const clang::CXXRecordDecl *D); void ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context); @@ -8733,12 +8732,6 @@ class Sema final : public SemaBase { bool IsCXXTriviallyRelocatableType(QualType T); bool IsCXXTriviallyRelocatableType(const CXXRecordDecl &RD); - //// Determines if a type is replaceable - /// according to the C++26 rules. - // FIXME: This is in Sema because it requires - // overload resolution, can we move to ASTContext? - bool IsCXXReplaceableType(QualType T); - /// Check the operands of ?: under C++ semantics. /// /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index d8ed7e3ff96bd..6b67a2aa99cc7 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2498,40 +2498,13 @@ void Parser::ParseCXX2CTriviallyRelocatableSpecifier(SourceLocation &TRS) { Diag(Tok.getLocation(), getLangOpts().CPlusPlus26 ? diag::warn_relocatable_keyword - : diag::ext_relocatable_keyword) - << /*relocatable*/ 0; + : diag::ext_relocatable_keyword); TRS = ConsumeToken(); } -bool Parser::isCXX2CReplaceableKeyword(Token Tok) const { - if (!getLangOpts().CPlusPlus || Tok.isNot(tok::identifier)) - return false; - if (!Ident_replaceable_if_eligible) - Ident_replaceable_if_eligible = - &PP.getIdentifierTable().get("replaceable_if_eligible"); - IdentifierInfo *II = Tok.getIdentifierInfo(); - return II == Ident_replaceable_if_eligible; -} - -bool Parser::isCXX2CReplaceableKeyword() const { - return isCXX2CReplaceableKeyword(Tok); -} - -void Parser::ParseCXX2CReplaceableSpecifier(SourceLocation &MRS) { - assert(isCXX2CReplaceableKeyword() && - "expected a replaceable_if_eligible specifier"); - - Diag(Tok.getLocation(), getLangOpts().CPlusPlus26 - ? diag::warn_relocatable_keyword - : diag::ext_relocatable_keyword) - << /*replaceable*/ 1; - - MRS = ConsumeToken(); -} - bool Parser::isClassCompatibleKeyword(Token Tok) const { - if (isCXX2CTriviallyRelocatableKeyword(Tok) || isCXX2CReplaceableKeyword(Tok)) + if (isCXX2CTriviallyRelocatableKeyword(Tok)) return true; VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok); return Specifier == VirtSpecifiers::VS_Final || @@ -3587,7 +3560,6 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, bool IsFinalSpelledSealed = false; bool IsAbstract = false; SourceLocation TriviallyRelocatable; - SourceLocation Replaceable; // Parse the optional 'final' keyword. if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { @@ -3599,23 +3571,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, auto Skipped = Tok; ConsumeToken(); Diag(Skipped, diag::err_duplicate_class_relocation_specifier) - << /*trivial_relocatable*/ 0 << TriviallyRelocatable; + << TriviallyRelocatable; } else { ParseCXX2CTriviallyRelocatableSpecifier(TriviallyRelocatable); } continue; } - if (isCXX2CReplaceableKeyword(Tok)) { - if (Replaceable.isValid()) { - auto Skipped = Tok; - ConsumeToken(); - Diag(Skipped, diag::err_duplicate_class_relocation_specifier) - << /*replaceable*/ 1 << Replaceable; - } else { - ParseCXX2CReplaceableSpecifier(Replaceable); - } - continue; - } break; } if (isCXX11FinalKeyword()) { @@ -3654,7 +3615,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, Diag(FinalLoc, diag::ext_warn_gnu_final); } assert((FinalLoc.isValid() || AbstractLoc.isValid() || - TriviallyRelocatable.isValid() || Replaceable.isValid()) && + TriviallyRelocatable.isValid()) && "not a class definition"); // Parse any C++11 attributes after 'final' keyword. @@ -3729,7 +3690,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) Actions.ActOnStartCXXMemberDeclarations( getCurScope(), TagDecl, FinalLoc, IsFinalSpelledSealed, IsAbstract, - TriviallyRelocatable, Replaceable, T.getOpenLocation()); + TriviallyRelocatable, T.getOpenLocation()); // C++ 11p3: Members of a class defined with the keyword class are private // by default. Members of a class defined with the keywords struct or union diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 7b425dd3dda43..1f32bf8009ded 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -515,7 +515,6 @@ void Parser::Initialize() { Ident_abstract = nullptr; Ident_override = nullptr; Ident_trivially_relocatable_if_eligible = nullptr; - Ident_replaceable_if_eligible = nullptr; Ident_GNU_final = nullptr; Ident_import = nullptr; Ident_module = nullptr; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 47bd7295e93f6..9285238e4dfb9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -18794,10 +18794,12 @@ bool Sema::ActOnDuplicateDefinition(Scope *S, Decl *Prev, return true; } -void Sema::ActOnStartCXXMemberDeclarations( - Scope *S, Decl *TagD, SourceLocation FinalLoc, bool IsFinalSpelledSealed, - bool IsAbstract, SourceLocation TriviallyRelocatable, - SourceLocation Replaceable, SourceLocation LBraceLoc) { +void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, + SourceLocation FinalLoc, + bool IsFinalSpelledSealed, + bool IsAbstract, + SourceLocation TriviallyRelocatable, + SourceLocation LBraceLoc) { AdjustDeclIfTemplate(TagD); CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD); @@ -18820,9 +18822,6 @@ void Sema::ActOnStartCXXMemberDeclarations( Record->addAttr( TriviallyRelocatableAttr::Create(Context, TriviallyRelocatable)); - if (Replaceable.isValid()) - Record->addAttr(ReplaceableAttr::Create(Context, Replaceable)); - // C++ [class]p2: // [...] The class-name is also inserted into the scope of the // class itself; this is known as the injected-class-name. For diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index 38877967af05e..f9d223a67e393 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -211,49 +211,15 @@ static bool IsEligibleForTrivialRelocation(Sema &SemaRef, return !D->hasDeletedDestructor(); } -// [C++26][class.prop] -// A class C is eligible for replacement unless -static bool IsEligibleForReplacement(Sema &SemaRef, const CXXRecordDecl *D) { - - for (const CXXBaseSpecifier &B : D->bases()) { - const auto *BaseDecl = B.getType()->getAsCXXRecordDecl(); - if (!BaseDecl) - continue; - // it has a base class that is not a replaceable class - if (!BaseDecl->isDependentType() && - !SemaRef.IsCXXReplaceableType(B.getType())) - return false; - } - - for (const FieldDecl *Field : D->fields()) { - if (Field->getType()->isDependentType()) - continue; - - // it has a non-static data member that is not of a replaceable type, - if (!SemaRef.IsCXXReplaceableType(Field->getType())) - return false; - } - return !D->hasDeletedDestructor(); -} - ASTContext::CXXRecordDeclRelocationInfo -Sema::CheckCXX2CRelocatableAndReplaceable(const CXXRecordDecl *D) { - ASTContext::CXXRecordDeclRelocationInfo Info{false, false}; +Sema::CheckCXX2CRelocatable(const CXXRecordDecl *D) { + ASTContext::CXXRecordDeclRelocationInfo Info{false}; if (!getLangOpts().CPlusPlus || D->isInvalidDecl()) return Info; assert(D->hasDefinition()); - // This is part of "eligible for replacement", however we defer it - // to avoid extraneous computations. - auto HasSuitableSMP = [&] { - return hasSuitableConstructorForRelocation(*this, D, - /*AllowUserDefined=*/true) && - hasSuitableMoveAssignmentOperatorForRelocation( - *this, D, /*AllowUserDefined=*/true); - }; - auto IsUnion = [&, Is = std::optional<bool>{}]() mutable { if (!Is.has_value()) Is = D->isUnion() && !D->hasUserDeclaredCopyConstructor() && @@ -289,26 +255,6 @@ Sema::CheckCXX2CRelocatableAndReplaceable(const CXXRecordDecl *D) { return IsDefaultMovable(); }(); - Info.IsReplaceable = [&] { - if (D->isDependentType()) - return false; - - // A class C is a replaceable class if it is eligible for replacement - if (!IsEligibleForReplacement(*this, D)) - return false; - - // has the replaceable_if_eligible class-property-specifier - if (D->hasAttr<ReplaceableAttr>()) - return HasSuitableSMP(); - - // is a union with no user-declared special member functions, or - if (IsUnion()) - return HasSuitableSMP(); - - // is default-movable. - return IsDefaultMovable(); - }(); - return Info; } @@ -316,8 +262,7 @@ bool Sema::IsCXXTriviallyRelocatableType(const CXXRecordDecl &RD) { if (std::optional<ASTContext::CXXRecordDeclRelocationInfo> Info = getASTContext().getRelocationInfoForCXXRecord(&RD)) return Info->IsRelocatable; - ASTContext::CXXRecordDeclRelocationInfo Info = - CheckCXX2CRelocatableAndReplaceable(&RD); + ASTContext::CXXRecordDeclRelocationInfo Info = CheckCXX2CRelocatable(&RD); getASTContext().setRelocationInfoForCXXRecord(&RD, Info); return Info.IsRelocatable; } @@ -346,34 +291,6 @@ bool Sema::IsCXXTriviallyRelocatableType(QualType Type) { return false; } -static bool IsCXXReplaceableType(Sema &S, const CXXRecordDecl *RD) { - if (std::optional<ASTContext::CXXRecordDeclRelocationInfo> Info = - S.getASTContext().getRelocationInfoForCXXRecord(RD)) - return Info->IsReplaceable; - ASTContext::CXXRecordDeclRelocationInfo Info = - S.CheckCXX2CRelocatableAndReplaceable(RD); - S.getASTContext().setRelocationInfoForCXXRecord(RD, Info); - return Info.IsReplaceable; -} - -bool Sema::IsCXXReplaceableType(QualType Type) { - if (Type.isConstQualified() || Type.isVolatileQualified()) - return false; - - if (Type->isVariableArrayType()) - return false; - - QualType BaseElementType = - getASTContext().getBaseElementType(Type.getUnqualifiedType()); - if (BaseElementType->isIncompleteType()) - return false; - if (BaseElementType->isScalarType()) - return true; - if (const auto *RD = BaseElementType->getAsCXXRecordDecl()) - return ::IsCXXReplaceableType(*this, RD); - return false; -} - /// Checks that type T is not a VLA. /// /// @returns @c true if @p T is VLA and a diagnostic was emitted, @@ -526,7 +443,6 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, case UTT_IsTriviallyRelocatable: case UTT_IsTriviallyEqualityComparable: case UTT_IsCppTriviallyRelocatable: - case UTT_IsReplaceable: case UTT_CanPassInRegs: // Per the GCC type traits documentation, T shall be a complete type, cv void, // or an array of unknown bound. But GCC actually imposes the same constraints @@ -1128,8 +1044,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return T.isBitwiseCloneableType(C); case UTT_IsCppTriviallyRelocatable: return Self.IsCXXTriviallyRelocatableType(T); - case UTT_IsReplaceable: - return Self.IsCXXReplaceableType(T); case UTT_CanPassInRegs: if (CXXRecordDecl *RD = T->getAsCXXRecordDecl(); RD && !T.hasQualifiers()) return RD->canPassInRegisters(); @@ -2019,7 +1933,6 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) { return llvm::StringSwitch<std::optional<TypeTrait>>(Name) .Case("is_trivially_relocatable", TypeTrait::UTT_IsCppTriviallyRelocatable) - .Case("is_replaceable", TypeTrait::UTT_IsReplaceable) .Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable) .Case("is_assignable", TypeTrait::BTT_IsAssignable) .Case("is_empty", TypeTrait::UTT_IsEmpty) @@ -2202,92 +2115,6 @@ static void DiagnoseNonTriviallyRelocatableReason(Sema &SemaRef, SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D; } -static void DiagnoseNonReplaceableReason(Sema &SemaRef, SourceLocation Loc, - const CXXRecordDecl *D) { - for (const CXXBaseSpecifier &B : D->bases()) { - assert(B.getType()->getAsCXXRecordDecl() && "invalid base?"); - if (!SemaRef.IsCXXReplaceableType(B.getType())) - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::NonReplaceableBase << B.getType() - << B.getSourceRange(); - } - for (const FieldDecl *Field : D->fields()) { - if (!SemaRef.IsCXXReplaceableType(Field->getType())) - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::NonReplaceableField << Field - << Field->getType() << Field->getSourceRange(); - } - if (D->hasDeletedDestructor()) - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::DeletedDtr << /*Deleted*/ 0 - << D->getDestructor()->getSourceRange(); - - if (!D->hasSimpleMoveConstructor() && !D->hasSimpleCopyConstructor()) { - const auto *Decl = cast<CXXConstructorDecl>( - LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/false)); - if (Decl && Decl->isDeleted()) - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::DeletedCtr - << Decl->isMoveConstructor() << Decl->getSourceRange(); - } - if (!D->hasSimpleMoveAssignment() && !D->hasSimpleCopyAssignment()) { - CXXMethodDecl *Decl = - LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/true); - if (Decl && Decl->isDeleted()) - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::DeletedAssign - << Decl->isMoveAssignmentOperator() << Decl->getSourceRange(); - } - - if (D->hasAttr<ReplaceableAttr>()) - return; - DiagnoseNonDefaultMovable(SemaRef, Loc, D); -} - -static void DiagnoseNonReplaceableReason(Sema &SemaRef, SourceLocation Loc, - QualType T) { - SemaRef.Diag(Loc, diag::note_unsatisfied_trait) - << T << diag::TraitName::Replaceable; - - if (T->isVariablyModifiedType()) - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::VLA; - - if (T->isReferenceType()) - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::Ref; - T = T.getNonReferenceType(); - - if (T.isConstQualified()) - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::Const; - - if (T.isVolatileQualified()) - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::Volatile; - - bool IsArray = T->isArrayType(); - T = SemaRef.getASTContext().getBaseElementType(T.getUnqualifiedType()); - - if (T->isScalarType()) - return; - - const CXXRecordDecl *D = T->getAsCXXRecordDecl(); - if (!D) { - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::NotScalarOrClass << IsArray; - return; - } - - if (D->isInvalidDecl()) - return; - - if (D->hasDefinition()) - DiagnoseNonReplaceableReason(SemaRef, Loc, D); - - SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D; -} - static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef, SourceLocation Loc, const CXXRecordDecl *D) { @@ -2871,9 +2698,6 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) { case UTT_IsCppTriviallyRelocatable: DiagnoseNonTriviallyRelocatableReason(*this, E->getBeginLoc(), Args[0]); break; - case UTT_IsReplaceable: - DiagnoseNonReplaceableReason(*this, E->getBeginLoc(), Args[0]); - break; case UTT_IsTriviallyCopyable: DiagnoseNonTriviallyCopyableReason(*this, E->getBeginLoc(), Args[0]); break; diff --git a/clang/test/Parser/cxx2c-trivially-relocatable.cpp b/clang/test/Parser/cxx2c-trivially-relocatable.cpp index 255e3e4f4460d..e47fe2a32972c 100644 --- a/clang/test/Parser/cxx2c-trivially-relocatable.cpp +++ b/clang/test/Parser/cxx2c-trivially-relocatable.cpp @@ -17,26 +17,15 @@ class I trivially_relocatable_if_eligible trivially_relocatable_if_eligible fina // cxx03-warning@-3 {{'final' keyword is a C++11 extension}} class trivially_relocatable_if_eligible trivially_relocatable_if_eligible {}; // cxx11-warning@-1 {{'trivially_relocatable_if_eligible' keyword is a C++2c extension}} -class J replaceable_if_eligible{}; -// cxx11-warning@-1 {{'replaceable_if_eligible' keyword is a C++2c extension}} -class K replaceable_if_eligible replaceable_if_eligible {}; -// expected-error@-1 {{class already marked 'replaceable_if_eligible'}} -// cxx11-warning@-2 {{'replaceable_if_eligible' keyword is a C++2c extension}} -class replaceable_if_eligible replaceable_if_eligible {}; -// cxx11-warning@-1 {{'replaceable_if_eligible' keyword is a C++2c extension}} -class L replaceable_if_eligible trivially_relocatable_if_eligible final {}; -// cxx11-warning@-1 {{'replaceable_if_eligible' keyword is a C++2c extension}} -// cxx11-warning@-2 {{'trivially_relocatable_if_eligible' keyword is a C++2c extension}} -// cxx03-warning@-3 {{'final' keyword is a C++11 extension}} -class M replaceable_if_eligible final trivially_relocatable_if_eligible {}; +class L trivially_relocatable_if_eligible final {}; // cxx11-warning@-1 {{'trivially_relocatable_if_eligible' keyword is a C++2c extension}} -// cxx11-warning@-2 {{'replaceable_if_eligible' keyword is a C++2c extension}} -// cxx03-warning@-3 {{'final' keyword is a C++11 extension}} -class N final trivially_relocatable_if_eligible replaceable_if_eligible {}; +// cxx03-warning@-2 {{'final' keyword is a C++11 extension}} +class M final trivially_relocatable_if_eligible {}; // cxx11-warning@-1 {{'trivially_relocatable_if_eligible' keyword is a C++2c extension}} -// cxx11-warning@-2 {{'replaceable_if_eligible' keyword is a C++2c extension}} -// cxx03-warning@-3 {{'final' keyword is a C++11 extension}} -class O trivially_relocatable_if_eligible replaceable_if_eligible final {}; +// cxx03-warning@-2 {{'final' keyword is a C++11 extension}} +class N final trivially_relocatable_if_eligible {}; // cxx11-warning@-1 {{'trivially_relocatable_if_eligible' keyword is a C++2c extension}} -// cxx11-warning@-2 {{'replaceable_if_eligible' keyword is a C++2c extension}} -// cxx03-warning@-3 {{'final' keyword is a C++11 extension}} +// cxx03-warning@-2 {{'final' keyword is a C++11 extension}} +class O trivially_relocatable_if_eligible final {}; +// cxx11-warning@-1 {{'trivially_relocatable_if_eligible' keyword is a C++2c extension}} +// cxx03-warning@-2 {{'final' keyword is a C++11 extension}} diff --git a/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp b/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp index c6919447798da..1fdce9cf2ec0b 100644 --- a/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp +++ b/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp @@ -227,31 +227,12 @@ struct UserProvidedMoveAssign { }; struct Empty{}; -static_assert(__builtin_is_replaceable(Empty)); -struct S1 replaceable_if_eligible{}; -static_assert(__builtin_is_replaceable(S1)); - -static_assert(__builtin_is_replaceable(DefaultedMove)); -static_assert(__builtin_is_replaceable(DefaultedCopy)); -static_assert(__builtin_is_replaceable(DefaultedMoveAssign)); - -static_assert(!__builtin_is_replaceable(DeletedMove)); -static_assert(!__builtin_is_replaceable(DeletedCopy)); -static_assert(!__builtin_is_replaceable(DeletedMoveAssign)); -static_assert(!__builtin_is_replaceable(DeletedDtr)); - -static_assert(!__builtin_is_replaceable(UserProvidedMove)); -static_assert(!__builtin_is_replaceable(UserProvidedCopy)); -static_assert(!__builtin_is_replaceable(UserProvidedMoveAssign)); struct DeletedCopyTpl { template <typename U> DeletedCopyTpl(const U&) = delete; }; -static_assert(__builtin_is_replaceable(DeletedCopyTpl)); - -using NotReplaceable = DeletedMove; template <typename T> struct WithBase : T{}; @@ -265,59 +246,23 @@ struct WithVirtual { WithVirtual& operator=(WithVirtual&&) = default; }; -static_assert(__builtin_is_replaceable(S<int>)); -static_assert(!__builtin_is_replaceable(S<volatile int>)); -static_assert(!__builtin_is_replaceable(S<const int>)); -static_assert(!__builtin_is_replaceable(S<const int&>)); -static_assert(!__builtin_is_replaceable(S<int&>)); -static_assert(__builtin_is_replaceable(S<int[2]>)); -static_assert(!__builtin_is_replaceable(S<const int[2]>)); -static_assert(__builtin_is_replaceable(WithBase<S<int>>)); -static_assert(!__builtin_is_replaceable(WithBase<S<const int>>)); -static_assert(!__builtin_is_replaceable(WithBase<UserProvidedMove>)); -static_assert(__builtin_is_replaceable(WithVBase<S<int>>)); -static_assert(!__builtin_is_replaceable(WithVBase<S<const int>>)); -static_assert(!__builtin_is_replaceable(WithVBase<UserProvidedMove>)); -static_assert(__builtin_is_replaceable(WithVirtual)); - -int n = 4; // expected-note 2{{declared here}} +int n = 4; // expected-note {{declared here}} static_assert(!__builtin_is_cpp_trivially_relocatable(int[n])); // expected-warning@-1 {{variable length arrays in C++ are a Clang extension}} // expected-note@-2 {{read of non-const variable 'n' is not allowed in a constant expression}} -static_assert(!__builtin_is_replaceable(int[n])); -// expected-warning@-1 {{variable length arrays in C++ are a Clang extension}} -// expected-note@-2 {{read of non-const variable 'n' is not allowed in a constant expression}} -struct U1 replaceable_if_eligible { - ~U1() = delete; - U1(U1&&) = default; - U1& operator=(U1&&) = default; - -}; -static_assert(!__builtin_is_replaceable(U1)); - -struct U2 replaceable_if_eligible { - U2(const U2&) = delete; -}; -static_assert(!__builtin_is_replaceable(U2)); - - -template <typename T> -struct WithVBaseExplicit replaceable_if_eligible : virtual T{}; -static_assert(__builtin_is_replaceable(WithVBaseExplicit<S<int>>)); - -struct S42 trivially_relocatable_if_eligible replaceable_if_eligible { +struct S42 trivially_relocatable_if_eligible { S42(S42&&); S42& operator=(S42&&) = default; }; -struct S43 trivially_relocatable_if_eligible replaceable_if_eligible { +struct S43 trivially_relocatable_if_eligible { S43(S43&&) = default; S43& operator=(S43&&); }; -struct Copyable1Explicit replaceable_if_eligible { +struct Copyable1Explicit { Copyable1Explicit(Copyable1Explicit const &) = default; }; @@ -326,7 +271,7 @@ struct Copyable1 { }; -struct CopyAssign1Explicit replaceable_if_eligible { +struct CopyAssign1Explicit { CopyAssign1Explicit & operator=(const CopyAssign1Explicit&) = default; }; @@ -338,26 +283,22 @@ struct UserDeleted1 { UserDeleted1(const UserDeleted1&) = delete; }; static_assert(!__builtin_is_cpp_trivially_relocatable(UserDeleted1)); -static_assert(!__builtin_is_replaceable(UserDeleted1)); struct UserDeleted2 { UserDeleted2(UserDeleted2&&) = delete; }; static_assert(!__builtin_is_cpp_trivially_relocatable(UserDeleted2)); -static_assert(!__builtin_is_replaceable(UserDeleted2)); struct UserDeleted3 { UserDeleted3 operator=(UserDeleted3); }; static_assert(!__builtin_is_cpp_trivially_relocatable(UserDeleted3)); -static_assert(!__builtin_is_replaceable(UserDeleted3)); struct UserDeleted4 { UserDeleted4 operator=(UserDeleted4&&); }; static_assert(!__builtin_is_cpp_trivially_relocatable(UserDeleted4)); -static_assert(!__builtin_is_replaceable(UserDeleted4)); } @@ -396,53 +337,43 @@ struct A { ~A (); }; A::~A () = default; static_assert (!__builtin_is_cpp_trivially_relocatable(A)); -static_assert (!__builtin_is_replaceable(A)); struct B { B(const B&); }; B::B (const B&) = default; static_assert (!__builtin_is_cpp_trivially_relocatable(B)); -static_assert (!__builtin_is_replaceable(B)); struct C { C& operator=(const C&); }; C& C::operator=(const C&) = default; static_assert (!__builtin_is_cpp_trivially_relocatable(C)); -static_assert (!__builtin_is_replaceable(C)); } namespace GH144232 { -struct E trivially_relocatable_if_eligible replaceable_if_eligible { +struct E trivially_relocatable_if_eligible { E (E &&); E &operator= (E &&) = default; }; -struct F trivially_relocatable_if_eligible replaceable_if_eligible { +struct F trivially_relocatable_if_eligible { F (F &&) = default; F &operator= (F &&); }; -struct G trivially_relocatable_if_eligible replaceable_if_eligible { G (G const &) = default; }; - -struct I trivially_relocatable_if_eligible replaceable_if_eligible { I &operator= (const I &) = default; }; +struct G trivially_relocatable_if_eligible { G (G const &) = default; }; -struct J trivially_relocatable_if_eligible replaceable_if_eligible { J (J const &); }; -struct K trivially_relocatable_if_eligible replaceable_if_eligible { K (K const &); }; +struct I trivially_relocatable_if_eligible { I &operator= (const I &) = default; }; +struct J trivially_relocatable_if_eligible { J (J const &); }; +struct K trivially_relocatable_if_eligible { K (K const &); }; -static_assert (__builtin_is_replaceable (E)); static_assert (__builtin_is_cpp_trivially_relocatable(E)); -static_assert (__builtin_is_replaceable (F)); static_assert (__builtin_is_cpp_trivially_relocatable(F)); -static_assert (__builtin_is_replaceable (G)); static_assert (__builtin_is_cpp_trivially_relocatable(G)); -static_assert (__builtin_is_replaceable (I)); static_assert (__builtin_is_cpp_trivially_relocatable(I)); -static_assert (__builtin_is_replaceable (J)); static_assert (__builtin_is_cpp_trivially_relocatable(J)); -static_assert (__builtin_is_replaceable (K)); static_assert (__builtin_is_cpp_trivially_relocatable(K)); } diff --git a/clang/test/SemaCXX/ptrauth-type-traits.cpp b/clang/test/SemaCXX/ptrauth-type-traits.cpp index a81ef1cce25b6..be4e17aa81ceb 100644 --- a/clang/test/SemaCXX/ptrauth-type-traits.cpp +++ b/clang/test/SemaCXX/ptrauth-type-traits.cpp @@ -320,26 +320,6 @@ static_assert( __builtin_is_cpp_trivially_relocatable(RelocatableAddressDiscrimi static_assert(!__builtin_is_cpp_trivially_relocatable(EmbdeddedAddressDiscriminatedPolymorphicClass)); static_assert(!__builtin_is_cpp_trivially_relocatable(RelocatableEmbdeddedAddressDiscriminatedPolymorphicClass)); -static_assert( __builtin_is_replaceable(AddressDiscriminatedPtr)); -static_assert( __builtin_is_replaceable(AddressDiscriminatedInt64)); -static_assert( __builtin_is_replaceable(AddressDiscriminatedFields)); -static_assert( __builtin_is_replaceable(RelocatableAddressDiscriminatedFields)); -static_assert( __builtin_is_replaceable(AddressDiscriminatedFieldInBaseClass)); -static_assert(!__builtin_is_replaceable(NonAddressDiscriminatedVTablePtr)); -static_assert(!__builtin_is_replaceable(NonAddressDiscriminatedVTablePtr2)); -static_assert(!__builtin_is_replaceable(RelocatableNonAddressDiscriminatedVTablePtr)); -static_assert(!__builtin_is_replaceable(RelocatableNonAddressDiscriminatedVTablePtr2)); -static_assert(!__builtin_is_replaceable(AddressDiscriminatedVTablePtr)); -static_assert(!__builtin_is_replaceable(RelocatableAddressDiscriminatedVTablePtr)); -static_assert(!__builtin_is_replaceable(NoAddressDiscriminatedBaseClasses)); -static_assert(!__builtin_is_replaceable(RelocatableNoAddressDiscriminatedBaseClasses)); -static_assert(!__builtin_is_replaceable(AddressDiscriminatedPrimaryBase)); -static_assert(!__builtin_is_replaceable(AddressDiscriminatedSecondaryBase)); -static_assert(!__builtin_is_replaceable(RelocatableAddressDiscriminatedPrimaryBase)); -static_assert(!__builtin_is_replaceable(RelocatableAddressDiscriminatedSecondaryBase)); -static_assert(!__builtin_is_replaceable(EmbdeddedAddressDiscriminatedPolymorphicClass)); -static_assert(!__builtin_is_replaceable(RelocatableEmbdeddedAddressDiscriminatedPolymorphicClass)); - static_assert( __is_bitwise_cloneable(AddressDiscriminatedPtr) == !ADDR_DISC_ENABLED); static_assert( __is_bitwise_cloneable(AddressDiscriminatedInt64) == !ADDR_DISC_ENABLED); static_assert( __is_bitwise_cloneable(AddressDiscriminatedFields) == !ADDR_DISC_ENABLED); diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp index 3e03a79275232..8a9f3bc400d20 100644 --- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp +++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp @@ -591,24 +591,3 @@ void test() { // expected-note@#concept10 {{because it is a cv void type}} } } - - -namespace std { -template <typename T> -struct is_replaceable { - static constexpr bool value = __builtin_is_replaceable(T); -}; - -template <typename T> -constexpr bool is_replaceable_v = __builtin_is_replaceable(T); - -} - -static_assert(std::is_replaceable<int&>::value); -// expected-error@-1 {{static assertion failed due to requirement 'std::is_replaceable<int &>::value'}} \ -// expected-note@-1 {{'int &' is not replaceable}} \ -// expected-note@-1 {{because it is a reference type}} -static_assert(std::is_replaceable_v<int&>); -// expected-error@-1 {{static assertion failed due to requirement 'std::is_replaceable_v<int &>'}} \ -// expected-note@-1 {{'int &' is not replaceable}} \ -// expected-note@-1 {{because it is a reference type}} diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp index 22740418f09f5..2ab5b6ec372ed 100644 --- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp +++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp @@ -144,138 +144,6 @@ static_assert(__builtin_is_cpp_trivially_relocatable(U2)); // expected-note@#tr-U2 {{'U2' defined here}} } -namespace replaceable { - -extern int vla_size; -static_assert(__builtin_is_replaceable(int[vla_size])); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(int[vla_size])'}} \ -// expected-note@-1 {{'int[vla_size]' is not replaceable}} \ -// expected-note@-1 {{because it is a variably-modified type}} - -struct S; // expected-note {{forward declaration of 'replaceable::S'}} -static_assert(__builtin_is_replaceable(S)); -// expected-error@-1 {{incomplete type 'S' used in type trait expression}} - -static_assert(__builtin_is_replaceable(const volatile int)); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(const volatile int)}} \ -// expected-note@-1 {{'const volatile int' is not replaceable}} \ -// expected-note@-1 {{because it is const}} \ -// expected-note@-1 {{because it is volatile}} - - -static_assert(__builtin_is_replaceable(void())); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(void ())}} \ -// expected-note@-1 {{'void ()' is not replaceable}} \ -// expected-note@-1 {{because it is not a scalar or class type}} - -struct B { - virtual ~B(); -}; -struct S : virtual B { // #replaceable-S - S(); - int & a; - const int ci; - B & b; - B c; - ~S(); -}; -static_assert(__builtin_is_replaceable(S)); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(replaceable::S)'}} \ -// expected-note@-1 {{'S' is not replaceable}} \ -// expected-note@-1 {{because it has a non-replaceable base 'B'}} \ -// expected-note@-1 {{because it has a non-replaceable member 'a' of type 'int &'}} \ -// expected-note@-1 {{because it has a non-replaceable member 'ci' of type 'const int'}} \ -// expected-note@-1 {{because it has a non-replaceable member 'b' of type 'B &'}} \ -// expected-note@-1 {{because it has a non-replaceable member 'c' of type 'B'}} \ -// expected-note@-1 {{because it has a user-provided destructor}} \ -// expected-note@-1 {{because it has a deleted copy assignment operator}} -// expected-note@#replaceable-S {{'S' defined here}} - -struct S2 { // #replaceable-S2 - S2(S2&&); - S2& operator=(const S2&); -}; -static_assert(__builtin_is_replaceable(S2)); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(replaceable::S2)'}} \ -// expected-note@-1 {{'S2' is not replaceable}} \ -// expected-note@-1 {{because it has a user provided move constructor}} \ -// expected-note@-1 {{because it has a user provided copy assignment operator}} \ -// expected-note@#replaceable-S2 {{'S2' defined here}} - - -struct S3 { // #replaceable-S3 - ~S3() = delete; -}; -static_assert(__builtin_is_replaceable(S3)); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(replaceable::S3)'}} \ -// expected-note@-1 {{'S3' is not replaceable}} \ -// expected-note@-1 {{because it has a deleted destructor}} \ -// expected-note@#replaceable-S3 {{'S3' defined here}} - - -union U { // #replaceable-U - U(const U&); - U(U&&); - U& operator=(const U&); - U& operator=(U&&); -}; -static_assert(__builtin_is_replaceable(U)); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(replaceable::U)'}} \ -// expected-note@-1 {{'U' is not replaceable}} \ -// expected-note@-1 {{because it is a union with a user-declared copy constructor}} \ -// expected-note@-1 {{because it is a union with a user-declared copy assignment operator}} \ -// expected-note@-1 {{because it is a union with a user-declared move constructor}} \ -// expected-note@-1 {{because it is a union with a user-declared move assignment operator}} -// expected-note@#replaceable-U {{'U' defined here}} -struct S4 replaceable_if_eligible { // #replaceable-S4 - ~S4(); - B b; -}; -static_assert(__builtin_is_replaceable(S4)); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(replaceable::S4)'}} \ -// expected-note@-1 {{'S4' is not replaceable}} \ -// expected-note@-1 {{because it has a non-replaceable member 'b' of type 'B'}} \ -// expected-note@#replaceable-S4 {{'S4' defined here}} - -union U2 replaceable_if_eligible { // #replaceable-U2 - U2(const U2&); - U2(U2&&); - B b; -}; -static_assert(__builtin_is_replaceable(U2)); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(replaceable::U2)'}} \ -// expected-note@-1 {{'U2' is not replaceable}} \ -// expected-note@-1 {{because it has a deleted destructor}} \ -// expected-note@-1 {{because it has a non-replaceable member 'b' of type 'B'}} \ -// expected-note@-1 {{because it has a deleted copy assignment operator}} \ -// expected-note@#replaceable-U2 {{'U2' defined here}} - -struct UD1 { // #replaceable-UD1 - UD1(const UD1&) = delete; - UD1 & operator=(const UD1&) = delete; - -}; -static_assert(__builtin_is_replaceable(UD1)); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(replaceable::UD1)'}} \ -// expected-note@-1 {{'UD1' is not replaceable}} \ -// expected-note@-1 {{because it has a deleted copy constructor}} \ -// expected-note@-1 {{because it has a deleted copy assignment operator}} \ -// expected-note@#replaceable-UD1 {{'UD1' defined here}} - - -struct UD2 { // #replaceable-UD2 - UD2(UD2&&) = delete; - UD2 & operator=(UD2&&) = delete; -}; -static_assert(__builtin_is_replaceable(UD2)); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(replaceable::UD2)'}} \ -// expected-note@-1 {{'UD2' is not replaceable}} \ -// expected-note@-1 {{because it has a deleted move constructor}} \ -// expected-note@-1 {{because it has a deleted move assignment operator}} \ -// expected-note@#replaceable-UD2 {{'UD2' defined here}} - -} - namespace GH143325 { struct Foo { // expected-note {{previous definition is here}} @@ -320,7 +188,7 @@ static_assert(__builtin_is_cpp_trivially_relocatable(UnionOfPolymorphic)); } -struct GH143599 { // expected-note 2 {{'GH143599' defined here}} +struct GH143599 { // expected-note {{'GH143599' defined here}} ~GH143599 (); GH143599(const GH143599&); GH143599& operator=(const GH143599&); @@ -336,13 +204,6 @@ static_assert (__builtin_is_cpp_trivially_relocatable(GH143599)); // expected-note@-1 {{because it has a user provided copy assignment operator}} \ // expected-note@-1 {{because it has a user-provided destructor}} -static_assert (__builtin_is_replaceable(GH143599)); -// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(GH143599)'}} \ -// expected-note@-1 {{'GH143599' is not replaceable}} \ -// expected-note@-1 {{because it has a user provided copy constructor}} \ -// expected-note@-1 {{because it has a user provided copy assignment operator}} \ -// expected-note@-1 {{because it has a user-provided destructor}} - namespace trivially_copyable { struct B { virtual ~B(); @@ -663,7 +524,7 @@ namespace is_empty_tests { // expected-error@-1 {{static assertion failed due to requirement '__is_empty(is_empty_tests::Derived)'}} \ // expected-note@-1 {{'Derived' is not empty}} \ // expected-note@-1 {{because it has a base class 'Base' that is not empty}} \ - // expected-note@#e-Derived {{'Derived' defined here}} + // expected-note@#e-Derived {{'Derived' defined here}} // Combination of the above. struct Multi : Base, virtual EB { // #e-Multi @@ -681,15 +542,15 @@ namespace is_empty_tests { // Zero-width bit-field. struct BitField { int : 0; }; // #e-BitField - static_assert(__is_empty(BitField)); // no diagnostics + static_assert(__is_empty(BitField)); // no diagnostics - // Dependent bit-field width. + // Dependent bit-field width. template <int N> struct DependentBitField { int : N; }; // #e-DependentBitField static_assert(__is_empty(DependentBitField<0>)); // no diagnostics - static_assert(__is_empty(DependentBitField<2>)); + static_assert(__is_empty(DependentBitField<2>)); // expected-error@-1 {{static assertion failed due to requirement '__is_empty(is_empty_tests::DependentBitField<2>)'}} \ // expected-note@-1 {{'DependentBitField<2>' is not empty}} \ // expected-note@-1 {{because it field '' is a non-zero-length bit-field}} \ @@ -738,7 +599,7 @@ union U { // #sl-U int x; // #sl-UF1 private: int y; // #sl-UF2 -}; +}; static_assert(__is_standard_layout(U)); // expected-error@-1 {{static assertion failed due to requirement '__is_standard_layout(standard_layout_tests::U)'}} \ // expected-note@-1 {{'U' is not standard-layout}} \ @@ -750,7 +611,7 @@ static_assert(__is_standard_layout(U)); // Single base class is OK struct BaseClass{ int a; }; // #sl-BaseClass struct DerivedOK : BaseClass {}; // #sl-DerivedOK -static_assert(__is_standard_layout(DerivedOK)); +static_assert(__is_standard_layout(DerivedOK)); // Primitive types should be standard layout static_assert(__is_standard_layout(int)); // #sl-Int @@ -760,11 +621,11 @@ static_assert(__is_standard_layout(float)); // #sl-Float struct Base1 { int a; }; // #sl-Base1 struct Base2 { int b; }; // #sl-Base2 struct DerivedClass : Base1, Base2 {}; // #sl-DerivedClass -static_assert(__is_standard_layout(DerivedClass)); +static_assert(__is_standard_layout(DerivedClass)); // expected-error@-1 {{static assertion failed due to requirement '__is_standard_layout(standard_layout_tests::DerivedClass)'}} \ // expected-note@-1 {{'DerivedClass' is not standard-layout}} \ // expected-note@-1 {{because it has multiple base classes with data members}} \ -// expected-note@#sl-DerivedClass {{'DerivedClass' defined here}} +// expected-note@#sl-DerivedClass {{'DerivedClass' defined here}} // Inheritance hierarchy with multiple classes having data members struct BaseA { int a; }; // #sl-BaseA @@ -809,7 +670,7 @@ static_assert(__is_standard_layout(E)); // expected-note@#sl-E {{'E' defined here}} // F inherits D but only an unnamed bitfield -// This should still fail because F ends up with a +// This should still fail because F ends up with a // base class with a data member and its own unnamed bitfield // which is not allowed in standard layout struct F : D { int : 0; }; // #sl-F _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
