ASTImporter triggers assertions in some cases.

Hi Guys,
I’ve noticed that the ASTImporter fails to import some named decls from due to an invalid linkagecache (in TagDecl::setTypedefNameForAnonDecl()).
Running with assertions disabled never terminates.
However, while trying to build an minimal reproducible example, i stumbled on a different error regarding templated structs with frienddecls.
I think they may be related because i found this commit:

The following test fails:

// svn: E155007
// unittests/AST/ASTImporterTest.cpp

TEST(ImportExpr, TemplatedStructFriend) {
MatchVerifier Verifier;
“void foo() {}; \n”
“inline namespace D {\n”
" template\n"
" struct declToImport {\n"
" friend bool f(const declToImport &);\n"
" };\n"
" template class declToImport;\n"
“}\n”, Lang_CXX, “”, Lang_CXX, Verifier, decl()));


clang/llvm/tools/clang/lib/AST/DeclFriend.cpp, line 43.> 0 ASTTests 0x0000000104f8e135 l
lvm::sys::PrintStackTrace(llvm::raw_ostream&) + 101
1 ASTTests 0x0000000104f8e779 PrintStackTraceSignalHandler(void*) + 25
2 ASTTests 0x0000000104f8a6d9 llvm::sys::RunSignalHandlers() + 425
3 ASTTests 0x0000000104f8ec92 SignalHandler(int) + 354
4 libsystem_platform.dylib 0x00007fff9e3eebba _sigtramp + 26

Thanks in advance,
Gaetano Checinski

This patch seemed related so I gave it a try, but unfortunately the issue persists:

It might gives some clues as a to a fix though.

The following test fails on my machine:

// svn: E155007
// unittests/AST/ASTImporterTest.cpp

TEST(ImportExpr, ImportIOstream) {
MatchVerifier Verifier;
#include \n”
“inline namespace D {\n”
" template\n"
" struct declToImport {};\n"
“}\n”, Lang_CXX, “”, Lang_CXX, Verifier, decl()));

It seems that the astImporter is not completely deterministic.
In anycase, I encounter one of two errors:

  1. If it calls TagDecl::setTypedefDeclForAnonDecl it fails as assert(T->isLinkageValid()); is false
  2. If it parses a FriendDecl it gets stuck in an infinite loop :

Decl ASTNodeImporter::VisitFriendDecl(FriendDecl D) {

│3437 while (ImportedFriend) {
│3438 if (D->getFriendDecl() && ImportedFriend->getFriendDecl()) {
// ^^^ evaluates to false
│3439 if (Context.IsStructurallyEquivalent(D->getFriendDecl(),
│3440 ImportedFriend->getFriendDecl()))
│3441 return Importer.Imported(D, ImportedFriend);
│3443 } else if (D->getFriendType() && ImportedFriend->getFriendType()) {
│3444 if (Importer.IsStructurallyEquivalent(
// ^^^ always false
│3445 D->getFriendType()->getType(),
│3446 ImportedFriend->getFriendType()->getType(), true))
│3447 return Importer.Imported(D, ImportedFriend);
│3448 }
│3449 ImportedFriend = ImportedFriend->getNextFriend();
// ^^^ returns always the same frienddecl;
// why does a Frienddecl has itself as a friend ?
│3450 }

Does anybody have an idea what’s going on?

Looks like this is related to one of my commits. Will check tomorrow.

18.01.2017 19:05, Gaetano Checinski via cfe-dev пишет: