[cfe-dev] [ASTImporter][CrossTU] inconsistent enumerators

Rafael·Stahl via cfe-dev cfe-dev at lists.llvm.org
Mon Nov 13 03:16:54 PST 2017


Deal all

While using the static analyzer with cross translation unit support ( 
https://reviews.llvm.org/D30691 ), I stumbled upon an issue that is most 
likely related to the ASTImporter.

I'm using a custom checker, but this should be reproduced by just 
running the scan-build tool.

A simple reproducing example:

main.c:

---------------------------------------
void foo();
void moo();

int main()
{
     foo();
     moo();
}
---------------------------------------

foo.c:

---------------------------------------
#include "thing.h"

void foo()
{
     (void)THING_VALUE;
}

void conflict(thing_t type)
{
}
---------------------------------------

moo.c:

---------------------------------------
#include "thing.h"

void moo()
{
     conflict(THING_VALUE);
}
---------------------------------------

thing.h:

---------------------------------------
typedef enum {
     THING_VALUE
} thing_t;

void conflict(thing_t type);
---------------------------------------

Notes on particularities of this example:

- main.c needs to NOT include the header
- main() needs to call the functions in this order
- foo() needs to reference the enumerator
- the enum needs to be typedef'd

If any of the above points do not apply, the issue does not appear.

The issue:

---------------------------------------
In file included from moo.c:1:
thing.h:1:9: warning: type 'thing_t' has incompatible
       definitions in different translation units [-Wodr]
typedef enum {
         ^
thing.h:2:5: note: enumerator 'THING_VALUE' with value 0 here
     THING_VALUE
     ^
thing.h:1:9: note: no corresponding enumerator here
foo.c:8:6: error: external function 'conflict' declared
       with incompatible types in different translation units ('void 
(thing_t)' vs. 'void (thing_t)')
void conflict(thing_t type)
      ^
thing.h:5:6: note: declared here with type
       'void (thing_t)'
void conflict(thing_t type);
      ^
---------------------------------------

After importing conflict(thing_t) the ASTImporter compared the imported 
one with the original by structural equivalence. This reveals that in 
the imported enum the enumerators are missing, causing the above error.

In my real code, not this example, I was unable to dump the imported 
EnumDecl, because it eventually calls 
SourceManager::isBeforeInTranslationUnit with two SourceLocations from 
different files. Not sure if this is related.

I have tried adding:

for (const auto Enumerator : D->enumerators())
     D2->addDecl(Importer.Import(Enumerator));

before completing the definition in ASTNodeImporter::VisitEnumDecl(), 
but that results in:

exe: tools/clang/lib/AST/DeclBase.cpp:1374: void 
clang::DeclContext::addHiddenDecl(clang::Decl*): Assertion 
`!D->getNextDeclInContext() && D != LastDecl && "Decl already inserted 
into a DeclContext"' failed.

I'm not familiar enough with the ASTImporter to help myself further 
here. Does anyone know what could be the issue?

Best regards
Rafael Stahl


-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 5449 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20171113/4b2352e8/attachment.bin>


More information about the cfe-dev mailing list