@@ -19270,6 +19270,43 @@ static void ComputeSpecialMemberFunctionsEligiblity(Sema &S,
1927019270 CXXSpecialMemberKind::MoveAssignment);
1927119271}
1927219272
19273+ bool Sema::EntirelyFunctionPointers(const RecordDecl *Record) {
19274+ // Check to see if a FieldDecl is a pointer to a function.
19275+ auto IsFunctionPointerOrForwardDecl = [&](const Decl *D) {
19276+ const FieldDecl *FD = dyn_cast<FieldDecl>(D);
19277+ if (!FD) {
19278+ // Check whether this is a forward declaration that was inserted by
19279+ // Clang. This happens when a non-forward declared / defined type is
19280+ // used, e.g.:
19281+ //
19282+ // struct foo {
19283+ // struct bar *(*f)();
19284+ // struct bar *(*g)();
19285+ // };
19286+ //
19287+ // "struct bar" shows up in the decl AST as a "RecordDecl" with an
19288+ // incomplete definition.
19289+ if (const auto *TD = dyn_cast<TagDecl>(D))
19290+ return !TD->isCompleteDefinition();
19291+ return false;
19292+ }
19293+ QualType FieldType = FD->getType().getDesugaredType(Context);
19294+ if (isa<PointerType>(FieldType)) {
19295+ QualType PointeeType = cast<PointerType>(FieldType)->getPointeeType();
19296+ return PointeeType.getDesugaredType(Context)->isFunctionType();
19297+ }
19298+ // If a member is a struct entirely of function pointers, that counts too.
19299+ if (const RecordType *RT = FieldType->getAs<RecordType>()) {
19300+ const RecordDecl *Record = RT->getDecl();
19301+ if (Record->isStruct() && EntirelyFunctionPointers(Record))
19302+ return true;
19303+ }
19304+ return false;
19305+ };
19306+
19307+ return llvm::all_of(Record->decls(), IsFunctionPointerOrForwardDecl);
19308+ }
19309+
1927319310void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
1927419311 ArrayRef<Decl *> Fields, SourceLocation LBrac,
1927519312 SourceLocation RBrac,
@@ -19607,41 +19644,13 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
1960719644 // Handle attributes before checking the layout.
1960819645 ProcessDeclAttributeList(S, Record, Attrs);
1960919646
19610- // Check to see if a FieldDecl is a pointer to a function.
19611- auto IsFunctionPointerOrForwardDecl = [&](const Decl *D) {
19612- const FieldDecl *FD = dyn_cast<FieldDecl>(D);
19613- if (!FD) {
19614- // Check whether this is a forward declaration that was inserted by
19615- // Clang. This happens when a non-forward declared / defined type is
19616- // used, e.g.:
19617- //
19618- // struct foo {
19619- // struct bar *(*f)();
19620- // struct bar *(*g)();
19621- // };
19622- //
19623- // "struct bar" shows up in the decl AST as a "RecordDecl" with an
19624- // incomplete definition.
19625- if (const auto *TD = dyn_cast<TagDecl>(D))
19626- return !TD->isCompleteDefinition();
19627- return false;
19628- }
19629- QualType FieldType = FD->getType().getDesugaredType(Context);
19630- if (isa<PointerType>(FieldType)) {
19631- QualType PointeeType = cast<PointerType>(FieldType)->getPointeeType();
19632- return PointeeType.getDesugaredType(Context)->isFunctionType();
19633- }
19634- return false;
19635- };
19636-
1963719647 // Maybe randomize the record's decls. We automatically randomize a record
1963819648 // of function pointers, unless it has the "no_randomize_layout" attribute.
19639- if (!getLangOpts().CPlusPlus &&
19649+ if (!getLangOpts().CPlusPlus && !getLangOpts().RandstructSeed.empty() &&
19650+ !Record->isRandomized() && !Record->isUnion() &&
1964019651 (Record->hasAttr<RandomizeLayoutAttr>() ||
1964119652 (!Record->hasAttr<NoRandomizeLayoutAttr>() &&
19642- llvm::all_of(Record->decls(), IsFunctionPointerOrForwardDecl))) &&
19643- !Record->isUnion() && !getLangOpts().RandstructSeed.empty() &&
19644- !Record->isRandomized()) {
19653+ EntirelyFunctionPointers(Record)))) {
1964519654 SmallVector<Decl *, 32> NewDeclOrdering;
1964619655 if (randstruct::randomizeStructureLayout(Context, Record,
1964719656 NewDeclOrdering))
0 commit comments