From d49aa60dfc1cb6c4e13b5be90bc8b707457d5dd3 Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Thu, 13 Jun 2024 17:08:49 -0300 Subject: [PATCH] FunctionDepsFinder: Check for declarations inside another declaration Closes: #44 Signed-off-by: Marcos Paulo de Souza --- libcextract/FunctionDepsFinder.cpp | 28 ++++++++++++++++++++++++++++ libcextract/FunctionDepsFinder.hh | 24 ++++++++++++++++++++++++ testsuite/linux/typedef-1.c | 19 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 testsuite/linux/typedef-1.c diff --git a/libcextract/FunctionDepsFinder.cpp b/libcextract/FunctionDepsFinder.cpp index 90f78b0..fac6192 100644 --- a/libcextract/FunctionDepsFinder.cpp +++ b/libcextract/FunctionDepsFinder.cpp @@ -623,6 +623,34 @@ void FunctionDependencyFinder::Remove_Redundant_Decls(void) { } } } + + /* + * Check if there wasn't any symbol that is being defined in the same + * interval and remove it. Otherwise we might clash the types. + * + * One example of how this can happen is then we have something like + * + * typedef struct { + * ... + * } x, y; + * + * In the process of creating the closure we might reach the following + * situation: + * + * typdef struct { + * ... + * } x; + * + * typedef struct { + * + * } x, y; + * + * Which then breaks the one-definition-rule. In such cases, remove the + * previous declaration in the same code range, since the later will + * contain both definitions either way. + */ + if (Decl *range_decl = Closure.insideRangeOfDecl(decl)) + Closure.Remove_Decl(range_decl); } } /* Handle the case where an enum is declared as: diff --git a/libcextract/FunctionDepsFinder.hh b/libcextract/FunctionDepsFinder.hh index 928e859..ac5c1e8 100644 --- a/libcextract/FunctionDepsFinder.hh +++ b/libcextract/FunctionDepsFinder.hh @@ -43,6 +43,30 @@ class ClosureSet Dependencies.insert(decl); } + /* + * Check if the same Decl was already added into the closure but for a + * different typename. + */ + Decl *insideRangeOfDecl(Decl *decl) + { + SourceRange range = decl->getSourceRange(); + + for (auto it = Dependencies.begin(); it != Dependencies.end(); ++it) { + if (TypedefDecl *cur_decl = dyn_cast(*it)) { + SourceRange cur_range = cur_decl->getSourceRange(); + + // Avoid comparing to itself + if (cur_range == range) + continue; + + if (PrettyPrint::Contains_From_LineCol(range, cur_range)) + return cur_decl; + } + } + + return nullptr; + } + inline std::unordered_set &Get_Set(void) { return Dependencies; diff --git a/testsuite/linux/typedef-1.c b/testsuite/linux/typedef-1.c new file mode 100644 index 0000000..97d7b9e --- /dev/null +++ b/testsuite/linux/typedef-1.c @@ -0,0 +1,19 @@ +/* { dg-options "-DCE_EXTRACT_FUNCTIONS=f" } */ + +typedef struct { + int id; + int val; +} st1, st2; + +int f(void) +{ + st1 s1; + st2 s2; + + s1.id = 10; + s2.val = 5; +} +/* { dg-final { scan-tree-dump "int f\(void\)" } } */ +/* { dg-final { scan-tree-dump "} st1, st2;" } } */ +/* { dg-final { scan-tree-dump-not "} st1;" } } */ +/* { dg-final { scan-tree-dump-not "} st2;" } } */