From cebcb269103d831c565d26ab28149b41d18da7cf Mon Sep 17 00:00:00 2001 From: Giuliano Belinassi Date: Sat, 20 Jul 2024 15:02:47 -0300 Subject: [PATCH] Extend parent RecordDecl analysis for EnumDecls If the current declaration is a EnumDecl and it is inside a nested struct we also fall in the case we need to output the parent RecordDecl as well. Signed-off-by: Giuliano Belinassi --- libcextract/Closure.hh | 42 ++++++++++++++++++------------- testsuite/small/record-nested-4.c | 33 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 18 deletions(-) create mode 100644 testsuite/small/record-nested-4.c diff --git a/libcextract/Closure.hh b/libcextract/Closure.hh index 3874982..4d0c55f 100644 --- a/libcextract/Closure.hh +++ b/libcextract/Closure.hh @@ -235,6 +235,25 @@ class DeclClosureVisitor : public RecursiveASTVisitor return VISITOR_CONTINUE; } + bool ParentRecordDeclHelper(TagDecl *decl) + { + /* 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)); + } + + return VISITOR_CONTINUE; + } + bool VisitRecordDecl(RecordDecl *decl) { /* If this is a C++ record decl, then analyze it as such. */ @@ -253,24 +272,11 @@ 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(decl); } + TRY_TO(ParentRecordDeclHelper(decl)); + Closure.Add_Decl_And_Prevs(decl); + return VISITOR_CONTINUE; } @@ -287,10 +293,10 @@ class DeclClosureVisitor : public RecursiveASTVisitor typedef enum { CONSTANT = 1 } A; */ return VisitTypedefNameDecl(typedecl); - } else { - Closure.Add_Decl_And_Prevs(decl); } + TRY_TO(ParentRecordDeclHelper(decl)); + Closure.Add_Decl_And_Prevs(decl); return VISITOR_CONTINUE; } diff --git a/testsuite/small/record-nested-4.c b/testsuite/small/record-nested-4.c new file mode 100644 index 0000000..03a3b93 --- /dev/null +++ b/testsuite/small/record-nested-4.c @@ -0,0 +1,33 @@ +/* { dg-options "-DCE_EXTRACT_FUNCTIONS=f -DCE_NO_EXTERNALIZATION" }*/ + +extern int strncasecmp (const char *__s1, const char *__s2, unsigned long __n) + __attribute__ ((__nothrow__ )) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1, 2))); + +extern unsigned long strlen (const char *__s) + __attribute__ ((__nothrow__ )) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1))); + +struct config { + enum sched_prio { + SCHED_ERR = -1, + SCHED_HIGH, + SCHED_DEFAULT, + SCHED_LOW + } prio; + unsigned int verbose; +}; + +/** clang-extract: from source.c:1511:1 */ +enum sched_prio f(const char *str) +{ + if (strncasecmp("high", str, strlen(str)) == 0) + return SCHED_HIGH; + else if (strncasecmp("default", str, strlen(str)) == 0) + return SCHED_DEFAULT; + else if (strncasecmp("low", str, strlen(str)) == 0) + return SCHED_LOW; + else + return SCHED_ERR; +} + +/* { dg-final { scan-tree-dump "struct config *{" } } */ +/* { dg-final { scan-tree-dump " *enum sched_prio *{" } } */