Skip to content

Commit

Permalink
[cpp-clang] Don't parse fields for forward declarations.
Browse files Browse the repository at this point in the history
Previously, esbmc would try to parse fields of forward declarations.
Consider this code:
```cpp
class a; // #1
class b; // #2
class a { // #3
  b *c;
};
class b : a {}; // #4
```
When parsing #1, clang would resolve the actual definition for us.
This means that we would skip ahead to #3 and try to parse the fields
of `a`. When doing this, we will encounter `b` and try to get a type
for it. This will ultimately fail, because we are still defining `a`,
but `b` extends `a` and so `a` must be a _complete_ type which it is
not at that point.

We can avoid this problem by _not_ continuing to parse fields if the
declaration is not a complete one.
When now parsing #1, we would not skip ahead to #3 anymore.
Similarly, when parsing #2, we would not skip ahead to #4 anymore.
There is still a slight problem:
when parsing #3 we would however still have a problem.
We would try to get a type for `b` again, which would then fail
again, because `a` is not yet complete.

This problem is easily solved, by not recording structs in the
context if we already have a symbol there for it.
  • Loading branch information
intrigus authored and lucasccordeiro committed Apr 14, 2024
1 parent b2e8e7a commit 670d872
Showing 1 changed file with 10 additions and 4 deletions.
14 changes: 10 additions & 4 deletions src/clang-c-frontend/clang_c_convert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ bool clang_c_convertert::get_struct_union_class(const clang::RecordDecl &rd)
if (!rd_def)
return false;

if (!rd.isCompleteDefinition())
return false;

/* Don't continue if it's not incomplete; use the .incomplete() flag to avoid
* infinite recursion if the type we're defining refers to itself
* (via pointers): it either is already being defined (up the stack somewhere)
Expand Down Expand Up @@ -1053,10 +1056,13 @@ bool clang_c_convertert::get_type(const clang::Type &the_type, typet &new_type)

std::string id, name;
get_decl_name(rd, name, id);

/* record in context if not already there */
if (get_struct_union_class(rd))
return true;
symbolt *s = context.find_symbol(id);
if (!s)
{
/* record in context if not already there */
if (get_struct_union_class(rd))
return true;
}

/* symbolic type referring to that type */
new_type = symbol_typet(id);
Expand Down

0 comments on commit 670d872

Please sign in to comment.