@@ -2014,6 +2014,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
20142014 .Case (" is_aggregate" , TypeTrait::UTT_IsAggregate)
20152015 .Case (" is_constructible" , TypeTrait::TT_IsConstructible)
20162016 .Case (" is_final" , TypeTrait::UTT_IsFinal)
2017+ .Case (" is_abstract" , TypeTrait::UTT_IsAbstract)
20172018 .Default (std::nullopt );
20182019}
20192020
@@ -2774,6 +2775,75 @@ static void DiagnoseNonAggregateReason(Sema &SemaRef, SourceLocation Loc,
27742775 DiagnoseNonAggregateReason (SemaRef, Loc, D);
27752776}
27762777
2778+ static void DiagnoseNonAbstractReason (Sema &SemaRef, SourceLocation Loc,
2779+ const CXXRecordDecl *D) {
2780+ // If this type has any abstract base classes, their respective virtual
2781+ // functions must have been overridden.
2782+ for (const CXXBaseSpecifier &B : D->bases ()) {
2783+ if (B.getType ()->castAsCXXRecordDecl ()->isAbstract ()) {
2784+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2785+ << diag::TraitNotSatisfiedReason::OverridesAllPureVirtual
2786+ << B.getType () << B.getSourceRange ();
2787+ }
2788+ }
2789+ }
2790+
2791+ static void DiagnoseNonAbstractReason (Sema &SemaRef, SourceLocation Loc,
2792+ QualType T) {
2793+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait)
2794+ << T << diag::TraitName::Abstract;
2795+
2796+ if (T->isReferenceType ()) {
2797+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2798+ << diag::TraitNotSatisfiedReason::Ref;
2799+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2800+ << diag::TraitNotSatisfiedReason::NotStructOrClass;
2801+ return ;
2802+ }
2803+
2804+ if (T->isUnionType ()) {
2805+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2806+ << diag::TraitNotSatisfiedReason::UnionType;
2807+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2808+ << diag::TraitNotSatisfiedReason::NotStructOrClass;
2809+ return ;
2810+ }
2811+
2812+ if (SemaRef.Context .getAsArrayType (T)) {
2813+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2814+ << diag::TraitNotSatisfiedReason::ArrayType;
2815+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2816+ << diag::TraitNotSatisfiedReason::NotStructOrClass;
2817+ return ;
2818+ }
2819+
2820+ if (T->isFunctionType ()) {
2821+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2822+ << diag::TraitNotSatisfiedReason::FunctionType;
2823+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2824+ << diag::TraitNotSatisfiedReason::NotStructOrClass;
2825+ return ;
2826+ }
2827+
2828+ if (T->isPointerType ()) {
2829+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2830+ << diag::TraitNotSatisfiedReason::PointerType;
2831+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2832+ << diag::TraitNotSatisfiedReason::NotStructOrClass;
2833+ return ;
2834+ }
2835+
2836+ if (!T->isStructureOrClassType ()) {
2837+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2838+ << diag::TraitNotSatisfiedReason::NotStructOrClass;
2839+ return ;
2840+ }
2841+
2842+ const CXXRecordDecl *D = T->getAsCXXRecordDecl ();
2843+ if (D->hasDefinition ())
2844+ DiagnoseNonAbstractReason (SemaRef, Loc, D);
2845+ }
2846+
27772847void Sema::DiagnoseTypeTraitDetails (const Expr *E) {
27782848 E = E->IgnoreParenImpCasts ();
27792849 if (E->containsErrors ())
@@ -2818,6 +2888,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
28182888 DiagnoseIsFinalReason (*this , E->getBeginLoc (), QT); // unsatisfied
28192889 break ;
28202890 }
2891+ case UTT_IsAbstract:
2892+ DiagnoseNonAbstractReason (*this , E->getBeginLoc (), Args[0 ]);
2893+ break ;
28212894 default :
28222895 break ;
28232896 }
0 commit comments