@@ -1959,6 +1959,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
1959
1959
.Case (" is_trivially_copyable" , TypeTrait::UTT_IsTriviallyCopyable)
1960
1960
.Case (" is_assignable" , TypeTrait::BTT_IsAssignable)
1961
1961
.Case (" is_empty" , TypeTrait::UTT_IsEmpty)
1962
+ .Case (" is_standard_layout" , TypeTrait::UTT_IsStandardLayout)
1962
1963
.Default (std::nullopt);
1963
1964
}
1964
1965
@@ -2382,6 +2383,150 @@ static void DiagnoseIsEmptyReason(Sema &S, SourceLocation Loc, QualType T) {
2382
2383
}
2383
2384
}
2384
2385
2386
+ static bool hasMultipleDataBaseClassesWithFields (const CXXRecordDecl *D) {
2387
+ int NumBasesWithFields = 0 ;
2388
+ for (const CXXBaseSpecifier &Base : D->bases ()) {
2389
+ const CXXRecordDecl *BaseRD = Base.getType ()->getAsCXXRecordDecl ();
2390
+ if (!BaseRD || BaseRD->isInvalidDecl ())
2391
+ continue ;
2392
+
2393
+ for (const FieldDecl *Field : BaseRD->fields ()) {
2394
+ if (!Field->isUnnamedBitField ()) {
2395
+ if (++NumBasesWithFields > 1 )
2396
+ return true ; // found more than one base class with fields
2397
+ break ; // no need to check further fields in this base class
2398
+ }
2399
+ }
2400
+ }
2401
+ return false ;
2402
+ }
2403
+
2404
+ static void DiagnoseNonStandardLayoutReason (Sema &SemaRef, SourceLocation Loc,
2405
+ const CXXRecordDecl *D) {
2406
+ for (const CXXBaseSpecifier &B : D->bases ()) {
2407
+ assert (B.getType ()->getAsCXXRecordDecl () && " invalid base?" );
2408
+ if (B.isVirtual ()) {
2409
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2410
+ << diag::TraitNotSatisfiedReason::VBase << B.getType ()
2411
+ << B.getSourceRange ();
2412
+ }
2413
+ if (!B.getType ()->isStandardLayoutType ()) {
2414
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2415
+ << diag::TraitNotSatisfiedReason::NonStandardLayoutBase << B.getType ()
2416
+ << B.getSourceRange ();
2417
+ }
2418
+ }
2419
+ // Check for mixed access specifiers in fields.
2420
+ const FieldDecl *FirstField = nullptr ;
2421
+ AccessSpecifier FirstAccess = AS_none;
2422
+
2423
+ for (const FieldDecl *Field : D->fields ()) {
2424
+ if (Field->isUnnamedBitField ())
2425
+ continue ;
2426
+
2427
+ // Record the first field we see
2428
+ if (!FirstField) {
2429
+ FirstField = Field;
2430
+ FirstAccess = Field->getAccess ();
2431
+ continue ;
2432
+ }
2433
+
2434
+ // Check if the field has a different access specifier than the first one.
2435
+ if (Field->getAccess () != FirstAccess) {
2436
+ // Emit a diagnostic about mixed access specifiers.
2437
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2438
+ << diag::TraitNotSatisfiedReason::MixedAccess;
2439
+
2440
+ SemaRef.Diag (FirstField->getLocation (), diag::note_defined_here)
2441
+ << FirstField;
2442
+
2443
+ SemaRef.Diag (Field->getLocation (), diag::note_unsatisfied_trait_reason)
2444
+ << diag::TraitNotSatisfiedReason::MixedAccessField << Field
2445
+ << FirstField;
2446
+
2447
+ // No need to check further fields, as we already found mixed access.
2448
+ break ;
2449
+ }
2450
+ }
2451
+ if (hasMultipleDataBaseClassesWithFields (D)) {
2452
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2453
+ << diag::TraitNotSatisfiedReason::MultipleDataBase;
2454
+ }
2455
+ if (D->isPolymorphic ()) {
2456
+ // Find the best location to point “defined here” at.
2457
+ const CXXMethodDecl *VirtualMD = nullptr ;
2458
+ // First, look for a virtual method.
2459
+ for (const auto *M : D->methods ()) {
2460
+ if (M->isVirtual ()) {
2461
+ VirtualMD = M;
2462
+ break ;
2463
+ }
2464
+ }
2465
+ if (VirtualMD) {
2466
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2467
+ << diag::TraitNotSatisfiedReason::VirtualFunction << VirtualMD;
2468
+ SemaRef.Diag (VirtualMD->getLocation (), diag::note_defined_here)
2469
+ << VirtualMD;
2470
+ } else {
2471
+ // If no virtual method, point to the record declaration itself.
2472
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2473
+ << diag::TraitNotSatisfiedReason::VirtualFunction << D;
2474
+ SemaRef.Diag (D->getLocation (), diag::note_defined_here) << D;
2475
+ }
2476
+ }
2477
+ for (const FieldDecl *Field : D->fields ()) {
2478
+ if (!Field->getType ()->isStandardLayoutType ()) {
2479
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2480
+ << diag::TraitNotSatisfiedReason::NonStandardLayoutMember << Field
2481
+ << Field->getType () << Field->getSourceRange ();
2482
+ }
2483
+ }
2484
+ // Find any indirect base classes that have fields.
2485
+ if (D->hasDirectFields ()) {
2486
+ const CXXRecordDecl *Indirect = nullptr ;
2487
+ D->forallBases ([&](const CXXRecordDecl *BaseDef) {
2488
+ if (BaseDef->hasDirectFields ()) {
2489
+ Indirect = BaseDef;
2490
+ return false ; // stop traversal
2491
+ }
2492
+ return true ; // continue to the next base
2493
+ });
2494
+ if (Indirect) {
2495
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2496
+ << diag::TraitNotSatisfiedReason::IndirectBaseWithFields << Indirect
2497
+ << Indirect->getSourceRange ();
2498
+ }
2499
+ }
2500
+ }
2501
+
2502
+ static void DiagnoseNonStandardLayoutReason (Sema &SemaRef, SourceLocation Loc,
2503
+ QualType T) {
2504
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait)
2505
+ << T << diag::TraitName::StandardLayout;
2506
+
2507
+ // Check type-level exclusion first.
2508
+ if (T->isVariablyModifiedType ()) {
2509
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2510
+ << diag::TraitNotSatisfiedReason::VLA;
2511
+ return ;
2512
+ }
2513
+
2514
+ if (T->isReferenceType ()) {
2515
+ SemaRef.Diag (Loc, diag::note_unsatisfied_trait_reason)
2516
+ << diag::TraitNotSatisfiedReason::Ref;
2517
+ return ;
2518
+ }
2519
+ T = T.getNonReferenceType ();
2520
+ const CXXRecordDecl *D = T->getAsCXXRecordDecl ();
2521
+ if (!D || D->isInvalidDecl ())
2522
+ return ;
2523
+
2524
+ if (D->hasDefinition ())
2525
+ DiagnoseNonStandardLayoutReason (SemaRef, Loc, D);
2526
+
2527
+ SemaRef.Diag (D->getLocation (), diag::note_defined_here) << D;
2528
+ }
2529
+
2385
2530
void Sema::DiagnoseTypeTraitDetails (const Expr *E) {
2386
2531
E = E->IgnoreParenImpCasts ();
2387
2532
if (E->containsErrors ())
@@ -2408,6 +2553,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
2408
2553
case UTT_IsEmpty:
2409
2554
DiagnoseIsEmptyReason (*this , E->getBeginLoc (), Args[0 ]);
2410
2555
break ;
2556
+ case UTT_IsStandardLayout:
2557
+ DiagnoseNonStandardLayoutReason (*this , E->getBeginLoc (), Args[0 ]);
2558
+ break ;
2411
2559
default :
2412
2560
break ;
2413
2561
}
0 commit comments