@@ -19309,6 +19309,43 @@ static void ComputeSpecialMemberFunctionsEligiblity(Sema &S,
1930919309 CXXSpecialMemberKind::MoveAssignment);
1931019310}
1931119311
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+
1931219349void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
1931319350 ArrayRef<Decl *> Fields, SourceLocation LBrac,
1931419351 SourceLocation RBrac,
@@ -19646,41 +19683,13 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
1964619683 // Handle attributes before checking the layout.
1964719684 ProcessDeclAttributeList(S, Record, Attrs);
1964819685
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-
1967619686 // Maybe randomize the record's decls. We automatically randomize a record
1967719687 // 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() &&
1967919690 (Record->hasAttr<RandomizeLayoutAttr>() ||
1968019691 (!Record->hasAttr<NoRandomizeLayoutAttr>() &&
19681- llvm::all_of(Record->decls(), IsFunctionPointerOrForwardDecl))) &&
19682- !Record->isUnion() && !getLangOpts().RandstructSeed.empty() &&
19683- !Record->isRandomized()) {
19692+ EntirelyFunctionPointers(Record)))) {
1968419693 SmallVector<Decl *, 32> NewDeclOrdering;
1968519694 if (randstruct::randomizeStructureLayout(Context, Record,
1968619695 NewDeclOrdering))
0 commit comments