@@ -19309,6 +19309,43 @@ static void ComputeSpecialMemberFunctionsEligiblity(Sema &S,
19309
19309
CXXSpecialMemberKind::MoveAssignment);
19310
19310
}
19311
19311
19312
+ bool Sema::EntirelyFunctionPointers(const RecordDecl *Record) {
19313
+ // Check to see if a FieldDecl is a pointer to a function.
19314
+ auto IsFunctionPointerOrForwardDecl = [&](const Decl *D) {
19315
+ const FieldDecl *FD = dyn_cast<FieldDecl>(D);
19316
+ if (!FD) {
19317
+ // Check whether this is a forward declaration that was inserted by
19318
+ // Clang. This happens when a non-forward declared / defined type is
19319
+ // used, e.g.:
19320
+ //
19321
+ // struct foo {
19322
+ // struct bar *(*f)();
19323
+ // struct bar *(*g)();
19324
+ // };
19325
+ //
19326
+ // "struct bar" shows up in the decl AST as a "RecordDecl" with an
19327
+ // incomplete definition.
19328
+ if (const auto *TD = dyn_cast<TagDecl>(D))
19329
+ return !TD->isCompleteDefinition();
19330
+ return false;
19331
+ }
19332
+ QualType FieldType = FD->getType().getDesugaredType(Context);
19333
+ if (isa<PointerType>(FieldType)) {
19334
+ QualType PointeeType = cast<PointerType>(FieldType)->getPointeeType();
19335
+ return PointeeType.getDesugaredType(Context)->isFunctionType();
19336
+ }
19337
+ // If a member is a struct entirely of function pointers, that counts too.
19338
+ if (const RecordType *RT = FieldType->getAs<RecordType>()) {
19339
+ const RecordDecl *Record = RT->getDecl();
19340
+ if (Record->isStruct() && EntirelyFunctionPointers(Record))
19341
+ return true;
19342
+ }
19343
+ return false;
19344
+ };
19345
+
19346
+ return llvm::all_of(Record->decls(), IsFunctionPointerOrForwardDecl);
19347
+ }
19348
+
19312
19349
void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
19313
19350
ArrayRef<Decl *> Fields, SourceLocation LBrac,
19314
19351
SourceLocation RBrac,
@@ -19646,41 +19683,13 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
19646
19683
// Handle attributes before checking the layout.
19647
19684
ProcessDeclAttributeList(S, Record, Attrs);
19648
19685
19649
- // Check to see if a FieldDecl is a pointer to a function.
19650
- auto IsFunctionPointerOrForwardDecl = [&](const Decl *D) {
19651
- const FieldDecl *FD = dyn_cast<FieldDecl>(D);
19652
- if (!FD) {
19653
- // Check whether this is a forward declaration that was inserted by
19654
- // Clang. This happens when a non-forward declared / defined type is
19655
- // used, e.g.:
19656
- //
19657
- // struct foo {
19658
- // struct bar *(*f)();
19659
- // struct bar *(*g)();
19660
- // };
19661
- //
19662
- // "struct bar" shows up in the decl AST as a "RecordDecl" with an
19663
- // incomplete definition.
19664
- if (const auto *TD = dyn_cast<TagDecl>(D))
19665
- return !TD->isCompleteDefinition();
19666
- return false;
19667
- }
19668
- QualType FieldType = FD->getType().getDesugaredType(Context);
19669
- if (isa<PointerType>(FieldType)) {
19670
- QualType PointeeType = cast<PointerType>(FieldType)->getPointeeType();
19671
- return PointeeType.getDesugaredType(Context)->isFunctionType();
19672
- }
19673
- return false;
19674
- };
19675
-
19676
19686
// Maybe randomize the record's decls. We automatically randomize a record
19677
19687
// of function pointers, unless it has the "no_randomize_layout" attribute.
19678
- if (!getLangOpts().CPlusPlus &&
19688
+ if (!getLangOpts().CPlusPlus && !getLangOpts().RandstructSeed.empty() &&
19689
+ !Record->isRandomized() && !Record->isUnion() &&
19679
19690
(Record->hasAttr<RandomizeLayoutAttr>() ||
19680
19691
(!Record->hasAttr<NoRandomizeLayoutAttr>() &&
19681
- llvm::all_of(Record->decls(), IsFunctionPointerOrForwardDecl))) &&
19682
- !Record->isUnion() && !getLangOpts().RandstructSeed.empty() &&
19683
- !Record->isRandomized()) {
19692
+ EntirelyFunctionPointers(Record)))) {
19684
19693
SmallVector<Decl *, 32> NewDeclOrdering;
19685
19694
if (randstruct::randomizeStructureLayout(Context, Record,
19686
19695
NewDeclOrdering))
0 commit comments