@@ -104,6 +104,7 @@ static CXXMethodDecl *LookupSpecialMemberFromXValue(Sema &SemaRef,
104104 OverloadCandidateSet::iterator Best;
105105 switch (OCS.BestViableFunction (SemaRef, LookupLoc, Best)) {
106106 case OR_Success:
107+ case OR_Deleted:
107108 return cast<CXXMethodDecl>(Best->Function );
108109 default :
109110 return nullptr ;
@@ -120,7 +121,8 @@ static bool hasSuitableConstructorForRelocation(Sema &SemaRef,
120121
121122 CXXMethodDecl *Decl =
122123 LookupSpecialMemberFromXValue (SemaRef, D, /* Assign=*/ false );
123- return Decl && Decl->isUserProvided () == AllowUserDefined;
124+ return Decl && Decl->isUserProvided () == AllowUserDefined &&
125+ !Decl->isDeleted ();
124126}
125127
126128static bool hasSuitableMoveAssignmentOperatorForRelocation (
@@ -135,7 +137,8 @@ static bool hasSuitableMoveAssignmentOperatorForRelocation(
135137 if (!Decl)
136138 return false ;
137139
138- return Decl && Decl->isUserProvided () == AllowUserDefined;
140+ return Decl && Decl->isUserProvided () == AllowUserDefined &&
141+ !Decl->isDeleted ();
139142}
140143
141144// [C++26][class.prop]
@@ -1940,6 +1943,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
19401943 return llvm::StringSwitch<std::optional<TypeTrait>>(Name)
19411944 .Case (" is_trivially_relocatable" ,
19421945 TypeTrait::UTT_IsCppTriviallyRelocatable)
1946+ .Case (" is_replaceable" , TypeTrait::UTT_IsReplaceable)
19431947 .Case (" is_trivially_copyable" , TypeTrait::UTT_IsTriviallyCopyable)
19441948 .Default (std::nullopt );
19451949}
@@ -2005,35 +2009,8 @@ static ExtractedTypeTraitInfo ExtractTypeTraitFromExpression(const Expr *E) {
20052009 return std::nullopt ;
20062010}
20072011
2008- static void DiagnoseNonTriviallyRelocatableReason (Sema &SemaRef,
2009- SourceLocation Loc,
2010- const CXXRecordDecl *D) {
2011- for (const CXXBaseSpecifier &B : D->bases ()) {
2012- assert (B.getType ()->getAsCXXRecordDecl () && " invalid base?" );
2013- if (B.isVirtual ())
2014- SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2015- << diag::TraitNotSatisfiedReason::VBase << B.getType ()
2016- << B.getSourceRange ();
2017- if (!SemaRef.IsCXXTriviallyRelocatableType (B.getType ()))
2018- SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2019- << diag::TraitNotSatisfiedReason::NTRBase << B.getType ()
2020- << B.getSourceRange ();
2021- }
2022- for (const FieldDecl *Field : D->fields ()) {
2023- if (!Field->getType ()->isReferenceType () &&
2024- !SemaRef.IsCXXTriviallyRelocatableType (Field->getType ()))
2025- SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2026- << diag::TraitNotSatisfiedReason::NTRField << Field
2027- << Field->getType () << Field->getSourceRange ();
2028- }
2029- if (D->hasDeletedDestructor ())
2030- SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2031- << diag::TraitNotSatisfiedReason::DeletedDtr << /* Deleted*/ 0
2032- << D->getDestructor ()->getSourceRange ();
2033-
2034- if (D->hasAttr <TriviallyRelocatableAttr>())
2035- return ;
2036-
2012+ static void DiagnoseNonDefaultMovable (Sema &SemaRef, SourceLocation Loc,
2013+ const CXXRecordDecl *D) {
20372014 if (D->isUnion ()) {
20382015 auto DiagSPM = [&](CXXSpecialMemberKind K, bool Has) {
20392016 if (Has)
@@ -2074,6 +2051,37 @@ static void DiagnoseNonTriviallyRelocatableReason(Sema &SemaRef,
20742051 << Dtr->getSourceRange ();
20752052}
20762053
2054+ static void DiagnoseNonTriviallyRelocatableReason (Sema &SemaRef,
2055+ SourceLocation Loc,
2056+ const CXXRecordDecl *D) {
2057+ for (const CXXBaseSpecifier &B : D->bases ()) {
2058+ assert (B.getType ()->getAsCXXRecordDecl () && " invalid base?" );
2059+ if (B.isVirtual ())
2060+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2061+ << diag::TraitNotSatisfiedReason::VBase << B.getType ()
2062+ << B.getSourceRange ();
2063+ if (!SemaRef.IsCXXTriviallyRelocatableType (B.getType ()))
2064+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2065+ << diag::TraitNotSatisfiedReason::NTRBase << B.getType ()
2066+ << B.getSourceRange ();
2067+ }
2068+ for (const FieldDecl *Field : D->fields ()) {
2069+ if (!Field->getType ()->isReferenceType () &&
2070+ !SemaRef.IsCXXTriviallyRelocatableType (Field->getType ()))
2071+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2072+ << diag::TraitNotSatisfiedReason::NTRField << Field
2073+ << Field->getType () << Field->getSourceRange ();
2074+ }
2075+ if (D->hasDeletedDestructor ())
2076+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2077+ << diag::TraitNotSatisfiedReason::DeletedDtr << /* Deleted*/ 0
2078+ << D->getDestructor ()->getSourceRange ();
2079+
2080+ if (D->hasAttr <TriviallyRelocatableAttr>())
2081+ return ;
2082+ DiagnoseNonDefaultMovable (SemaRef, Loc, D);
2083+ }
2084+
20772085static void DiagnoseNonTriviallyRelocatableReason (Sema &SemaRef,
20782086 SourceLocation Loc,
20792087 QualType T) {
@@ -2102,6 +2110,92 @@ static void DiagnoseNonTriviallyRelocatableReason(Sema &SemaRef,
21022110 SemaRef.Diag (D->getLocation (), diag::note_defined_here) << D;
21032111}
21042112
2113+ static void DiagnoseNonReplaceableReason (Sema &SemaRef, SourceLocation Loc,
2114+ const CXXRecordDecl *D) {
2115+ for (const CXXBaseSpecifier &B : D->bases ()) {
2116+ assert (B.getType ()->getAsCXXRecordDecl () && " invalid base?" );
2117+ if (!SemaRef.IsCXXReplaceableType (B.getType ()))
2118+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2119+ << diag::TraitNotSatisfiedReason::NonReplaceableBase << B.getType ()
2120+ << B.getSourceRange ();
2121+ }
2122+ for (const FieldDecl *Field : D->fields ()) {
2123+ if (!SemaRef.IsCXXReplaceableType (Field->getType ()))
2124+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2125+ << diag::TraitNotSatisfiedReason::NonReplaceableField << Field
2126+ << Field->getType () << Field->getSourceRange ();
2127+ }
2128+ if (D->hasDeletedDestructor ())
2129+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2130+ << diag::TraitNotSatisfiedReason::DeletedDtr << /* Deleted*/ 0
2131+ << D->getDestructor ()->getSourceRange ();
2132+
2133+ if (!D->hasSimpleMoveConstructor () && !D->hasSimpleCopyConstructor ()) {
2134+ const auto *Decl = cast<CXXConstructorDecl>(
2135+ LookupSpecialMemberFromXValue (SemaRef, D, /* Assign=*/ false ));
2136+ if (Decl && Decl->isDeleted ())
2137+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2138+ << diag::TraitNotSatisfiedReason::DeletedCtr
2139+ << Decl->isMoveConstructor () << Decl->getSourceRange ();
2140+ }
2141+ if (!D->hasSimpleMoveAssignment () && !D->hasSimpleCopyAssignment ()) {
2142+ CXXMethodDecl *Decl =
2143+ LookupSpecialMemberFromXValue (SemaRef, D, /* Assign=*/ true );
2144+ if (Decl && Decl->isDeleted ())
2145+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2146+ << diag::TraitNotSatisfiedReason::DeletedAssign
2147+ << Decl->isMoveAssignmentOperator () << Decl->getSourceRange ();
2148+ }
2149+
2150+ if (D->hasAttr <ReplaceableAttr>())
2151+ return ;
2152+ DiagnoseNonDefaultMovable (SemaRef, Loc, D);
2153+ }
2154+
2155+ static void DiagnoseNonReplaceableReason (Sema &SemaRef, SourceLocation Loc,
2156+ QualType T) {
2157+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait)
2158+ << T << diag::TraitName::Replaceable;
2159+
2160+ if (T->isVariablyModifiedType ())
2161+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2162+ << diag::TraitNotSatisfiedReason::VLA;
2163+
2164+ if (T->isReferenceType ())
2165+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2166+ << diag::TraitNotSatisfiedReason::Ref;
2167+ T = T.getNonReferenceType ();
2168+
2169+ if (T.isConstQualified ())
2170+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2171+ << diag::TraitNotSatisfiedReason::Const;
2172+
2173+ if (T.isVolatileQualified ())
2174+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2175+ << diag::TraitNotSatisfiedReason::Volatile;
2176+
2177+ bool IsArray = T->isArrayType ();
2178+ T = SemaRef.getASTContext ().getBaseElementType (T.getUnqualifiedType ());
2179+
2180+ if (T->isScalarType ())
2181+ return ;
2182+
2183+ const CXXRecordDecl *D = T->getAsCXXRecordDecl ();
2184+ if (!D) {
2185+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2186+ << diag::TraitNotSatisfiedReason::NotScalarOrClass << IsArray;
2187+ return ;
2188+ }
2189+
2190+ if (D->isInvalidDecl ())
2191+ return ;
2192+
2193+ if (D->hasDefinition ())
2194+ DiagnoseNonReplaceableReason (SemaRef, Loc, D);
2195+
2196+ SemaRef.Diag (D->getLocation (), diag::note_defined_here) << D;
2197+ }
2198+
21052199static void DiagnoseNonTriviallyCopyableReason (Sema &SemaRef,
21062200 SourceLocation Loc,
21072201 const CXXRecordDecl *D) {
@@ -2192,6 +2286,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
21922286 case UTT_IsCppTriviallyRelocatable:
21932287 DiagnoseNonTriviallyRelocatableReason (*this , E->getBeginLoc (), Args[0 ]);
21942288 break ;
2289+ case UTT_IsReplaceable:
2290+ DiagnoseNonReplaceableReason (*this , E->getBeginLoc (), Args[0 ]);
2291+ break ;
21952292 case UTT_IsTriviallyCopyable:
21962293 DiagnoseNonTriviallyCopyableReason (*this , E->getBeginLoc (), Args[0 ]);
21972294 break ;
0 commit comments