clang::CXXRecordDecl::data __assert_fail. Clang problem, or bug in my VisitCXXRecordDecl() implementation?

I’ve got an AST visitor defined with the following method:

class MyASTVisitor : public RecursiveASTVisitor
{


bool VisitCXXRecordDecl( CXXRecordDecl* r )

{
cout << "VisitCXXRecordDecl:: CLASS: " << r->getName().str() << endl ;

for ( CXXRecordDecl::base_class_iterator b = r->bases_begin(), e = r->bases_end() ;
b != e ; ++b )
{
CXXBaseSpecifier & a = *b ;

const QualType & q = a.getType() ;

cout << r->getName().str() << " : " << q.getAsString() << endl ;
}

return true ;
}

This is triggering the following assertion:

classvisitor: /home/peeterj/clang/optimized/include/clang/AST/DeclCXX.h:522: struct DefinitionData &clang::CXXRecordDecl::data(): Assertion `DefinitionData && “queried property of class with no definition”’ failed.

Program received signal SIGABRT, Aborted.
0x00007ffff6f20645 in raise () from /lib64/libc.so.6
(gdb) where
#0 0x00007ffff6f20645 in raise () from /lib64/libc.so.6
#1 0x00007ffff6f21c33 in abort () from /lib64/libc.so.6
#2 0x00007ffff6f19329 in __assert_fail () from /lib64/libc.so.6
#3 0x0000000000467b85 in clang::CXXRecordDecl::data (this=0x155f740) at /home/peeterj/clang/optimized/include/clang/AST/DeclCXX.h:522
#4 0x0000000000467ade in clang::CXXRecordDecl::bases_begin (this=0x155f740) at /home/peeterj/clang/optimized/include/clang/AST/DeclCXX.h:640
#5 0x00000000004681af in MyASTVisitor::VisitCXXRecordDecl (this=0x7fffffff8f70, r=0x155f740) at classvisitor.cpp:61
#6 0x0000000000467ffa in clang::RecursiveASTVisitor::WalkUpFromCXXRecordDecl (this=0x7fffffff8f70, D=0x155f740)
at /home/peeterj/clang/optimized/include/clang/AST/DeclNodes.inc:207
#7 0x000000000041f13f in clang::RecursiveASTVisitor::TraverseCXXRecordDecl (this=0x7fffffff8f70, D=0x155f740)
at /home/peeterj/clang/optimized/include/clang/AST/RecursiveASTVisitor.h:1586
#8 0x000000000041d0f9 in clang::RecursiveASTVisitor::TraverseDecl (this=0x7fffffff8f70, D=0x155f740)
at /home/peeterj/clang/optimized/include/clang/AST/DeclNodes.inc:207
#9 0x000000000041c7f4 in MyASTConsumer::HandleTopLevelDecl (this=0x7fffffff8f60, DR=…) at classvisitor.cpp:122
#10 0x0000000000612c75 in clang::ParseAST(clang::Sema&, bool, bool) ()
#11 0x0000000000612f70 in clang::ParseAST(clang::Preprocessor&, clang::ASTConsumer*, clang::ASTContext&, bool, clang::TranslationUnitKind, clang::CodeCompleteConsumer*, bool) ()
#12 0x0000000000419b31 in main (argc=77, argv=0x7fffffffd008) at classvisitor.cpp:314
(gdb) frame 5
#5 0x00000000004681af in MyASTVisitor::VisitCXXRecordDecl (this=0x7fffffff8f70, r=0x155f740) at classvisitor.cpp:61
61 for ( CXXRecordDecl::base_class_iterator b = r->bases_begin(), e = r->bases_end() ;
(gdb) p *r
$1 = {clang::RecordDecl = {clang::TagDecl = {clang::TypeDecl = {clang::NamedDecl = {clang::Decl = {_vptr$Decl = 0x132a350,
NextInContextAndBits = {Value = 0}, DeclCtx = {Val = {Value = 20481056}}, Loc = {ID = 1203259}, DeclKind = 25, InvalidDecl = 0,
HasAttrs = 0, Implicit = 0, Used = 0, Referenced = 0, Access = 3, FromASTFile = 0, Hidden = 0, IdentifierNamespace = 6,
HasCachedLinkage = 0, CachedLinkage = 0}, Name = {Ptr = 22363280}}, TypeForDecl = 0x155f7d0, LocStart = {
ID = 1203253}}, clang::DeclContext = {DeclKind = 25, ExternalLexicalStorage = 0, ExternalVisibleStorage = 0, LookupPtr = {Value = 0},
FirstDecl = 0x0, LastDecl = 0x0}, <clang::Redeclarableclang::TagDecl> = {RedeclLink = {NextAndIsPrevious = {Value = 22411074}}},
TagDeclKind = 3, IsCompleteDefinition = false, IsBeingDefined = false, IsEmbeddedInDeclarator = false, IsFreeStanding = true,
NumPositiveBits = 0, NumNegativeBits = 0, IsScoped = false, IsScopedUsingClassTag = false, IsFixed = false, RBraceLoc = {ID = 0},
TypedefNameDeclOrQualifier = {Val = {Value = 0}}}, HasFlexibleArrayMember = false, AnonymousStructOrUnion = false, HasObjectMember = false,
LoadedFieldsFromExternalStorage = false}, DefinitionData = 0x0, TemplateOrInstantiation = {Val = {Value = 0}}}

Is it appropriate for me to be attempting to iterate over the base classes in this CXXRecordDecl() override, or is this a bug in the AST visitor library?

$ ~/clang/optimized/bin/clang --version

clang version 3.3 (trunk 169628)
Target: x86_64-unknown-linux-gnu
Thread model: posix

Peeter Joot wrote:

I've got an AST visitor defined with the following method:

class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor>
{

...
   bool VisitCXXRecordDecl( CXXRecordDecl* r )
   {
      cout << "VisitCXXRecordDecl:: CLASS: " << r->getName().str() << endl ;

      for ( CXXRecordDecl::base_class_iterator b = r->bases_begin(), e = r->bases_end() ;
            b != e ; ++b )
      {
         CXXBaseSpecifier & a = *b ;

         const QualType & q = a.getType() ;

         cout << r->getName().str() << " : " << q.getAsString() << endl ;
      }

      return true ;
   }

This is triggering the following assertion:

classvisitor: /home/peeterj/clang/optimized/include/clang/AST/DeclCXX.h:522: struct DefinitionData &clang::CXXRecordDecl::data(): Assertion `DefinitionData && "queried property of class with no definition"' failed.

Program received signal SIGABRT, Aborted.
0x00007ffff6f20645 in raise () from /lib64/libc.so.6
(gdb) where
#0 0x00007ffff6f20645 in raise () from /lib64/libc.so.6
#1 0x00007ffff6f21c33 in abort () from /lib64/libc.so.6
#2 0x00007ffff6f19329 in __assert_fail () from /lib64/libc.so.6
#3 0x0000000000467b85 in clang::CXXRecordDecl::data (this=0x155f740) at /home/peeterj/clang/optimized/include/clang/AST/DeclCXX.h:522
#4 0x0000000000467ade in clang::CXXRecordDecl::bases_begin (this=0x155f740) at /home/peeterj/clang/optimized/include/clang/AST/DeclCXX.h:640
#5 0x00000000004681af in MyASTVisitor::VisitCXXRecordDecl (this=0x7fffffff8f70, r=0x155f740) at classvisitor.cpp:61
#6 0x0000000000467ffa in clang::RecursiveASTVisitor<MyASTVisitor>::WalkUpFromCXXRecordDecl (this=0x7fffffff8f70, D=0x155f740)
    at /home/peeterj/clang/optimized/include/clang/AST/DeclNodes.inc:207
#7 0x000000000041f13f in clang::RecursiveASTVisitor<MyASTVisitor>::TraverseCXXRecordDecl (this=0x7fffffff8f70, D=0x155f740)
    at /home/peeterj/clang/optimized/include/clang/AST/RecursiveASTVisitor.h:1586
#8 0x000000000041d0f9 in clang::RecursiveASTVisitor<MyASTVisitor>::TraverseDecl (this=0x7fffffff8f70, D=0x155f740)
    at /home/peeterj/clang/optimized/include/clang/AST/DeclNodes.inc:207
#9 0x000000000041c7f4 in MyASTConsumer::HandleTopLevelDecl (this=0x7fffffff8f60, DR=...) at classvisitor.cpp:122
#10 0x0000000000612c75 in clang::ParseAST(clang::Sema&, bool, bool) ()
#11 0x0000000000612f70 in clang::ParseAST(clang::Preprocessor&, clang::ASTConsumer*, clang::ASTContext&, bool, clang::TranslationUnitKind, clang::CodeCompleteConsumer*, bool) ()
#12 0x0000000000419b31 in main (argc=77, argv=0x7fffffffd008) at classvisitor.cpp:314
(gdb) frame 5
#5 0x00000000004681af in MyASTVisitor::VisitCXXRecordDecl (this=0x7fffffff8f70, r=0x155f740) at classvisitor.cpp:61
61 for ( CXXRecordDecl::base_class_iterator b = r->bases_begin(), e = r->bases_end() ;
(gdb) p *r
$1 = {<clang::RecordDecl> = {<clang::TagDecl> = {<clang::TypeDecl> = {<clang::NamedDecl> = {<clang::Decl> = {_vptr$Decl = 0x132a350,
            NextInContextAndBits = {Value = 0}, DeclCtx = {Val = {Value = 20481056}}, Loc = {ID = 1203259}, DeclKind = 25, InvalidDecl = 0,
            HasAttrs = 0, Implicit = 0, Used = 0, Referenced = 0, Access = 3, FromASTFile = 0, Hidden = 0, IdentifierNamespace = 6,
            HasCachedLinkage = 0, CachedLinkage = 0}, Name = {Ptr = 22363280}}, TypeForDecl = 0x155f7d0, LocStart = {
          ID = 1203253}}, <clang::DeclContext> = {DeclKind = 25, ExternalLexicalStorage = 0, ExternalVisibleStorage = 0, LookupPtr = {Value = 0},
        FirstDecl = 0x0, LastDecl = 0x0}, <clang::Redeclarable<clang::TagDecl>> = {RedeclLink = {NextAndIsPrevious = {Value = 22411074}}},
      TagDeclKind = 3, IsCompleteDefinition = false, IsBeingDefined = false, IsEmbeddedInDeclarator = false, IsFreeStanding = true,
      NumPositiveBits = 0, NumNegativeBits = 0, IsScoped = false, IsScopedUsingClassTag = false, IsFixed = false, RBraceLoc = {ID = 0},
      TypedefNameDeclOrQualifier = {Val = {Value = 0}}}, HasFlexibleArrayMember = false, AnonymousStructOrUnion = false, HasObjectMember = false,
    LoadedFieldsFromExternalStorage = false}, DefinitionData = 0x0, TemplateOrInstantiation = {Val = {Value = 0}}}

Is it appropriate for me to be attempting to iterate over the base classes in this CXXRecordDecl() override, or is this a bug in the AST visitor library?

If I am correct, you can iterate over the base classes only if this CXXRecordDecl is a definition.

- Yang

Thanks Yang,

How would I determine if this CXXRecordDecl is a definition or not?

Peeter

Peeter Joot wrote:

Thanks Yang,

How would I determine if this CXXRecordDecl is a definition or not?

You can use isThisDeclarationADefinition member function.

- Yang

You can actually use these members for any class which is defined (no
matter which declaration is the definition); use hasDefinition to
check that.