@@ -1947,6 +1947,8 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
19471947 TypeTrait::UTT_IsCppTriviallyRelocatable)
19481948 .Case (" is_replaceable" , TypeTrait::UTT_IsReplaceable)
19491949 .Case (" is_trivially_copyable" , TypeTrait::UTT_IsTriviallyCopyable)
1950+ .Case (" is_constructible" , TypeTrait::TT_IsConstructible)
1951+ .Case (" is_standard_layout" , TypeTrait::UTT_IsStandardLayout)
19501952 .Default (std::nullopt );
19511953}
19521954
@@ -2257,21 +2259,180 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
22572259 }
22582260}
22592261
2260- static void DiagnoseNonTriviallyCopyableReason (Sema &SemaRef,
2261- SourceLocation Loc, QualType T) {
2262+ static void DiagnoseNonConstructibleReason (
2263+ Sema &SemaRef, SourceLocation Loc,
2264+ const llvm::SmallVector<clang::QualType, 1 > &Ts) {
2265+ if (Ts.empty ()) {
2266+ return ;
2267+ }
2268+
2269+ bool ContainsVoid = false ;
2270+ for (const QualType &ArgTy : Ts) {
2271+ ContainsVoid |= ArgTy->isVoidType ();
2272+ }
2273+
2274+ if (ContainsVoid)
2275+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2276+ << diag::TraitNotSatisfiedReason::CVVoidType;
2277+
2278+ QualType T = Ts[0 ];
2279+ if (T->isFunctionType ())
2280+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2281+ << diag::TraitNotSatisfiedReason::FunctionType;
2282+
2283+ if (T->isIncompleteArrayType ())
2284+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2285+ << diag::TraitNotSatisfiedReason::IncompleteArrayType;
2286+
2287+ const CXXRecordDecl *D = T->getAsCXXRecordDecl ();
2288+ if (!D || D->isInvalidDecl () || !D->hasDefinition ())
2289+ return ;
2290+
2291+ llvm::BumpPtrAllocator OpaqueExprAllocator;
2292+ SmallVector<Expr *, 2 > ArgExprs;
2293+ ArgExprs.reserve (Ts.size () - 1 );
2294+ for (unsigned I = 1 , N = Ts.size (); I != N; ++I) {
2295+ QualType ArgTy = Ts[I];
2296+ if (ArgTy->isObjectType () || ArgTy->isFunctionType ())
2297+ ArgTy = SemaRef.Context .getRValueReferenceType (ArgTy);
2298+ ArgExprs.push_back (
2299+ new (OpaqueExprAllocator.Allocate <OpaqueValueExpr>())
2300+ OpaqueValueExpr (Loc, ArgTy.getNonLValueExprType (SemaRef.Context ),
2301+ Expr::getValueKindForType (ArgTy)));
2302+ }
2303+
2304+ EnterExpressionEvaluationContext Unevaluated (
2305+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
2306+ Sema::ContextRAII TUContext (SemaRef,
2307+ SemaRef.Context .getTranslationUnitDecl ());
2308+ InitializedEntity To (InitializedEntity::InitializeTemporary (T));
2309+ InitializationKind InitKind (InitializationKind::CreateDirect (Loc, Loc, Loc));
2310+ InitializationSequence Init (SemaRef, To, InitKind, ArgExprs);
2311+
2312+ Init.Diagnose (SemaRef, To, InitKind, ArgExprs);
2313+ SemaRef.Diag (D->getLocation (), diag::note_defined_here) << D;
2314+ }
2315+
2316+ static void DiagnoseNonStandardLayoutReason (Sema &SemaRef, SourceLocation Loc,
2317+ QualType T) {
22622318 SemaRef.Diag (Loc, diag::note_unsatisfied_trait)
2263- << T << diag::TraitName::TriviallyCopyable ;
2319+ << T << diag::TraitName::StandardLayout ;
22642320
2265- if (T->isReferenceType ())
2321+ // Check type-level exclusion first
2322+ if (T->isVariablyModifiedType ()) {
2323+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2324+ << diag::TraitNotSatisfiedReason::VLA;
2325+ return ;
2326+ }
2327+
2328+ if (T->isReferenceType ()) {
22662329 SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
22672330 << diag::TraitNotSatisfiedReason::Ref;
2331+ return ;
2332+ }
2333+ T = T.getNonReferenceType ();
2334+ const CXXRecordDecl *D = T->getAsCXXRecordDecl ();
2335+ if (!D || D->isInvalidDecl ())
2336+ return ;
2337+
2338+ if (D->hasDefinition ())
2339+ DiagnoseNonStandardLayoutReason (SemaRef, Loc, D);
2340+
2341+ SemaRef.Diag (D->getLocation (), diag::note_defined_here) << D;
2342+ }
2343+
2344+ static bool hasMixedAccessSpecifier (const CXXRecordDecl *D) {
2345+ AccessSpecifier FirstAccess = AS_none;
2346+ for (const FieldDecl *Field : D->fields ()) {
2347+ if (Field->isUnnamedBitField ())
2348+ continue ;
2349+ AccessSpecifier FieldAccess = Field->getAccess ();
2350+ if (FirstAccess == AS_none) {
2351+ FirstAccess = FieldAccess;
2352+ } else if (FieldAccess != FirstAccess) {
2353+ return true ;
2354+ }
2355+ }
2356+ return false ;
2357+ }
22682358
2359+ static bool hasMultipleDataBaseClassesWithFields (const CXXRecordDecl *D) {
2360+ int NumBasesWithFields = 0 ;
2361+ for (const CXXBaseSpecifier &Base : D->bases ()) {
2362+ const CXXRecordDecl *BaseRD = Base.getType ()->getAsCXXRecordDecl ();
2363+ if (!BaseRD || BaseRD->isInvalidDecl ())
2364+ continue ;
2365+
2366+ for (const FieldDecl *Field : BaseRD->fields ()) {
2367+ if (!Field->isUnnamedBitField ()) {
2368+ ++NumBasesWithFields;
2369+ break ; // Only count the base once.
2370+ }
2371+ }
2372+ }
2373+ return NumBasesWithFields > 1 ;
2374+ }
2375+
2376+ static void DiagnoseNonStandardLayoutReason (Sema &SemaRef, SourceLocation Loc,
2377+ const CXXRecordDecl *D) {
2378+ for (const CXXBaseSpecifier &B : D->bases ()) {
2379+ assert (B.getType ()->getAsCXXRecordDecl () && " invalid base?" );
2380+ if (B.isVirtual ()) {
2381+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2382+ << diag::TraitNotSatisfiedReason::VBase << B.getType ()
2383+ << B.getSourceRange ();
2384+ }
2385+ if (!B.getType ()->isStandardLayoutType ()) {
2386+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2387+ << diag::TraitNotSatisfiedReason::NonStdLayoutBase << B.getType ()
2388+ << B.getSourceRange ();
2389+ }
2390+ }
2391+ if (hasMixedAccessSpecifier (D)) {
2392+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2393+ << diag::TraitNotSatisfiedReason::MixedAccess;
2394+ }
2395+ if (hasMultipleDataBaseClassesWithFields (D)) {
2396+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2397+ << diag::TraitNotSatisfiedReason::MultipleDataBase;
2398+ }
2399+ if (D->isPolymorphic ()) {
2400+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2401+ << diag::TraitNotSatisfiedReason::VirtualFunction;
2402+ }
2403+ for (const FieldDecl *Field : D->fields ()) {
2404+ if (!Field->getType ()->isStandardLayoutType ()) {
2405+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2406+ << diag::TraitNotSatisfiedReason::NonStdLayoutMember << Field
2407+ << Field->getType () << Field->getSourceRange ();
2408+ }
2409+ }
2410+ }
2411+
2412+ static void DiagnoseNonStandardLayoutReason (Sema &SemaRef, SourceLocation Loc,
2413+ QualType T) {
2414+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait)
2415+ << T << diag::TraitName::StandardLayout;
2416+
2417+ // Check type-level exclusion first
2418+ if (T->isVariablyModifiedType ()) {
2419+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2420+ << diag::TraitNotSatisfiedReason::VLA;
2421+ return ;
2422+ }
2423+
2424+ if (T->isReferenceType ()) {
2425+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2426+ << diag::TraitNotSatisfiedReason::Ref;
2427+ return ;
2428+ }
2429+ T = T.getNonReferenceType ();
22692430 const CXXRecordDecl *D = T->getAsCXXRecordDecl ();
22702431 if (!D || D->isInvalidDecl ())
22712432 return ;
22722433
22732434 if (D->hasDefinition ())
2274- DiagnoseNonTriviallyCopyableReason (SemaRef, Loc, D);
2435+ DiagnoseNonStandardLayoutReason (SemaRef, Loc, D);
22752436
22762437 SemaRef.Diag (D->getLocation (), diag::note_defined_here) << D;
22772438}
@@ -2296,6 +2457,12 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
22962457 case UTT_IsTriviallyCopyable:
22972458 DiagnoseNonTriviallyCopyableReason (*this , E->getBeginLoc (), Args[0 ]);
22982459 break ;
2460+ case TT_IsConstructible:
2461+ DiagnoseNonConstructibleReason (*this , E->getBeginLoc (), Args);
2462+ break ;
2463+ case UTT_IsStandardLayout:
2464+ DiagnoseNonStandardLayoutReason (*this , E->getBeginLoc (), Args[0 ]);
2465+ break ;
22992466 default :
23002467 break ;
23012468 }
0 commit comments