From 9c982647f2c3deb0fbf5cf9c6d08c96ae2b0a949 Mon Sep 17 00:00:00 2001 From: Giuliano Belinassi Date: Fri, 19 Jul 2024 14:04:12 -0300 Subject: [PATCH] Fix nested struct being discarded if parent struct is flagged as partial When clang detects that a certain struct doesn't need a full definition, i.e. its size is not required, then the flag CompleteDefinitionRequired is set to false. But in the following case: ``` struct Fts3Table { struct Fts3Index { int nPrefix; } *aIndex; }; int fts3PrefixParameter( const char *zParam, int *pnIndex, struct Fts3Index **apIndex ){ int a = sizeof(struct Fts3Index); return 0; } ``` this results in the nested struct `Fts3Index` not being output as its parent struct `Fts3Table` is marked as CompleteDefinitionRequired as false. In such cases we have to force CompleteDefinitionRequired of the parent struct as true so that its inner structs can be output. Signed-off-by: Giuliano Belinassi --- libcextract/Closure.hh | 33 ++++++++++++++++++++----------- testsuite/small/record-nested-3.c | 19 ++++++++++++++++++ 2 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 testsuite/small/record-nested-3.c diff --git a/libcextract/Closure.hh b/libcextract/Closure.hh index fd26d33..6e25c46 100644 --- a/libcextract/Closure.hh +++ b/libcextract/Closure.hh @@ -195,18 +195,14 @@ class DeclClosureVisitor : public RecursiveASTVisitor return VISITOR_CONTINUE /* Special Traversal functions which marks if a Decl was already analyzed. - This macro generates them. */ -#define DEF_MARKING_TRAVERSE_DECL(DECL) \ - bool Traverse##DECL(DECL *decl) \ - { \ - DO_NOT_RUN_IF_ALREADY_ANALYZED(decl); \ - Mark_As_Analyzed(decl); \ - return RecursiveASTVisitor::Traverse##DECL(decl); \ - } - - /* Override of TraverseDecl that marks that the given Decl was analyzed. So + Override of TraverseDecl that marks that the given Decl was analyzed. So far it seems we only need this function for now. */ - DEF_MARKING_TRAVERSE_DECL(Decl); + bool TraverseDecl(Decl *decl) + { + DO_NOT_RUN_IF_ALREADY_ANALYZED(decl); + Mark_As_Analyzed(decl); + return RecursiveASTVisitor::TraverseDecl(decl); + } /* -------- C Declarations ----------------- */ @@ -266,6 +262,20 @@ class DeclClosureVisitor : public RecursiveASTVisitor typedef struct { int a; } A; */ return VisitTypedefNameDecl(typedecl); } else { + /* In case this references a struct/union defined inside a struct (nested + struct), then we also need to analyze the parent struct. */ + RecordDecl *parent = dyn_cast(decl->getLexicalDeclContext()); + if (parent) { + /* If the parent struct is flagged as not needing a complete definition + then we need to set it to true, else the nested struct won't be + output as of only a partial definition of the parent struct is + output. */ + parent->setCompleteDefinitionRequired(true); + + /* Analyze parent struct. */ + TRY_TO(TraverseDecl(parent)); + } + Closure.Add_Decl_And_Prevs(Maybe_Partial_Decl(decl)); } @@ -547,5 +557,4 @@ class DeclClosureVisitor : public RecursiveASTVisitor std::unordered_set AnalyzedDecls; #undef TRY_TO #undef DO_NOT_RUN_IF_ALREADY_ANALYZED -#undef DEF_MARKING_TRAVERSE_DECL }; diff --git a/testsuite/small/record-nested-3.c b/testsuite/small/record-nested-3.c new file mode 100644 index 0000000..219d520 --- /dev/null +++ b/testsuite/small/record-nested-3.c @@ -0,0 +1,19 @@ +/* { dg-options "-DCE_EXTRACT_FUNCTIONS=fts3PrefixParameter -DCE_NO_EXTERNALIZATION" }*/ + +struct Fts3Table { + struct Fts3Index { + int nPrefix; + } *aIndex; +}; + +int fts3PrefixParameter( + const char *zParam, + int *pnIndex, + struct Fts3Index **apIndex +){ + int a = sizeof(struct Fts3Index); + return 0; +} + +/* { dg-final { scan-tree-dump "struct Fts3Table *{" } } */ +/* { dg-final { scan-tree-dump "} *\*aIndex;" } } */