abort calling getTypeSize

With the following sample code:

template <class T, size_t extraSize >
struct OSS_STRUCTURE_PAD_DELTA : public T
{
char pad[ extraSize ] ;
} ;

and an ast visitor that calls getTypeSize():

bool VisitFieldDecl( FieldDecl * f )
{
RecordDecl * r = f->getParent() ;
const QualType & theMembersClassType = m_context.getRecordType( r ) ;

TypeSourceInfo * pThisFieldSourceInfo = f->getTypeSourceInfo() ;

TypeLoc thisFieldTypeLoc = pThisFieldSourceInfo->getTypeLoc() ;

const QualType & thisFieldQualType = thisFieldTypeLoc.getType() ;

size_t szInBits = m_context.getTypeSize( thisFieldQualType ) ;
size_t offsetInBits = m_context.getFieldOffset( f ) ;

cout
<< “[” << offsetInBits/8 << “]:\t”
<< theMembersClassType.getAsString( m_pp ) << “::” << thisFieldQualType.getAsString( m_pp ) << “\t” << f->getNameAsString()
<< "\tsize: " << szInBits/8 << endl ;
;

return true ;
}

I get the following abort:

t.C:5:20: error: unknown type name ‘size_t’
template <class T, size_t extraSize >
^
Should not see dependent types
UNREACHABLE executed at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/ASTContext.cpp:1322!

Program received signal SIGABRT, Aborted.
0x00002aaaab39ef45 in raise () from /lib64/libc.so.6
(gdb) where
#0 0x00002aaaab39ef45 in raise () from /lib64/libc.so.6
#1 0x00002aaaab3a0340 in abort () from /lib64/libc.so.6
#2 0x0000000000f024b8 in llvm::llvm_unreachable_internal (msg=0x132c728 “Should not see dependent types”,
file=0x132bd18 “/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/ASTContext.cpp”, line=1322)
at /home/hotellnx94/peeterj/clang/sources/llvm/lib/Support/ErrorHandling.cpp:98
#3 0x0000000000c1c5e4 in clang::ASTContext::getTypeInfoImpl (this=0x1b36050, T=0x1b55aa0)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/ASTContext.cpp:1322
#4 0x0000000000c1c509 in clang::ASTContext::getTypeInfo (this=0x1b36050, T=0x1b55aa0)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/ASTContext.cpp:1301
#5 0x000000000046229d in clang::ASTContext::getTypeInfo (this=0x1b36050, T=…)
at /home/hotellnx94/peeterj/clang/debug48rt/include/clang/AST/ASTContext.h:1473
#6 0x0000000000462221 in clang::ASTContext::getTypeSize (this=0x1b36050, T=…)
at /home/hotellnx94/peeterj/clang/debug48rt/include/clang/AST/ASTContext.h:1478
#7 0x0000000000462068 in MyASTVisitor::VisitFieldDecl (this=0x7fffffffc010, f=0x1b55b00) at ./memberdumper.h:25
#8 0x0000000000461f75 in clang::RecursiveASTVisitor::WalkUpFromFieldDecl (this=0x7fffffffc010, D=0x1b55b00)
at /home/hotellnx94/peeterj/clang/debug48rt/include/clang/AST/DeclNodes.inc:313
#9 0x00000000004208bd in clang::RecursiveASTVisitor::TraverseFieldDecl (this=0x7fffffffc010, D=0x1b55b00)
at /home/hotellnx94/peeterj/clang/debug48rt/include/clang/AST/RecursiveASTVisitor.h:1665
#10 0x000000000041e0f4 in clang::RecursiveASTVisitor::TraverseDecl (this=0x7fffffffc010, D=0x1b55b00)
at /home/hotellnx94/peeterj/clang/debug48rt/include/clang/AST/DeclNodes.inc:313
#11 0x0000000000421993 in clang::RecursiveASTVisitor::TraverseDeclContextHelper (this=0x7fffffffc010, DC=0x1b3e2d8)
at /home/hotellnx94/peeterj/clang/debug48rt/include/clang/AST/RecursiveASTVisitor.h:1232
#12 0x000000000041fe5a in clang::RecursiveASTVisitor::TraverseCXXRecordDecl (this=0x7fffffffc010, D=0x1b3e2a0)
at /home/hotellnx94/peeterj/clang/debug48rt/include/clang/AST/RecursiveASTVisitor.h:1588

Is this a known problem? I’m running a recent snapshot:

Path: .
URL: http://llvm.org/svn/llvm-project/llvm/trunk
Repository Root: http://llvm.org/svn/llvm-project
Repository UUID: 91177308-0d34-0410-b5e6-96231b3b80d8
Revision: 175922
Node Kind: directory
Schedule: normal
Last Changed Author: ahatanak
Last Changed Rev: 175920
Last Changed Date: 2013-02-22 16:10:03 -0500 (Fri, 22 Feb 2013)
Properties Last Updated: 2013-02-22 16:49:48 -0500 (Fri, 22 Feb 2013)

It is by design. You can not compute a sizeof of a dependent type,
and type of 'pad' is value-dependent on 'extraSize'.

Dmitri

Fair enough. However, I’m doing this in an AST visitor, attempting to dump our the size and offset information for any structures encountered. How would I check whether or not the field in question is appropriate for a call to getTypeSize()?

Peeter

You can check for dependent types with isDependentType(). Note that
one can not compute size of an incomplete type, too.

Dmitri

Thanks Dmitri,

That avoids the abort with that particular template in our source. However, for other places, isDependentType() seems a bit more stringent than required. For example, the m_pNext field of the following class:

template
struct noInheritance
{
noInheritance<DATA_TYP>* m_pNext;
int m_priKey;
};

gets flagged as a dependent type, yet this is something that one should logically be able to execute getTypeSize() on [and in fact one can without trouble].

Peeter,

I may be wrong, but I would say that it is by design, and you don't
really want to do what you are doing right now. There's no practical
sense in examining record layout of a dependent record type. Sure,
you can get the expected results in that particular case, but what
about:

template<typename T>
struct S {
  T t;
  int i;
};

Whatever offset of 'i' you will get, it will be wrong, because it
depends on sizeof(T) and record layout rules applied to that.

You might want to examine the layout of an instantiation instead.

Dmitri

Okay, that makes sense. I can drive this from a CXXRecordDecl visitor,
something like:

bool VisitCXXRecordDecl( CXXRecordDecl * r )
{
   if ( r->isThisDeclarationADefinition() )
   {
      for ( CXXRecordDecl::field_iterator b = r->field_begin(), e =
r->field_end() ;
            b != e ; ++b )
      {
         const FieldDecl * a = *b ;

         myVisitFieldDecl( a ) ;
      }
   }

   return true ;
}

I found getInstantiatedFromMemberClass() in the docs, and it appears I can
use this to see if the template is an instantiation. However I'm having
trouble figuring out how to tell if the CXXRecordDecl is a template or not
(since I want to visit the fields of all instantanted template class decls
and all the fields of the plain old non-template classes).

I don't see a isTemplateClass() or anything like that? How would such a
check be done?

I found getInstantiatedFromMemberClass() in the docs, and it appears I can
use this to see if the template is an instantiation.

It will not handle all cases, just what it says -- only for member
classes. Try CXXRecordDecl::getMemberSpecializationInfo().

I don't see a isTemplateClass() or anything like that? How would such a
check be done?

Try CXXRecordDecl::getDescribedClassTemplate() -- it will return a
corresponding ClassTemplateDecl given a CXXRecordDecl for 'A' in:
template<typename T> struct A {};

Dmitri

Okay, that worked nicely for that source. Going back to the source I
started with, I hit a different abort, in llvm_unreachable_internal()
instead:

Should not see dependent types
UNREACHABLE executed at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/ASTContext.cpp:1322!

Program received signal SIGABRT, Aborted.
0x00002aaaab39ef45 in raise () from /lib64/libc.so.6
(gdb) where
#0 0x00002aaaab39ef45 in raise () from /lib64/libc.so.6
#1 0x00002aaaab3a0340 in abort () from /lib64/libc.so.6
#2 0x0000000000f0281c in llvm::llvm_unreachable_internal (msg=0x132cbc8
"Should not see dependent types",
    file=0x132c1b8
"/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/ASTContext.cpp",
line=1322)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/lib/Support/ErrorHandling.cpp:98
#3 0x0000000000c1c948 in clang::ASTContext::getTypeInfoImpl
(this=0x1b38300, T=0x39190b0)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/ASTContext.cpp:1322
#4 0x0000000000c1c86d in clang::ASTContext::getTypeInfo (this=0x1b38300,
T=0x39190b0)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/ASTContext.cpp:1301
#5 0x0000000000c1c752 in clang::ASTContext::getTypeInfoInChars
(this=0x1b38300, T=0x39190b0)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/ASTContext.cpp:1286
#6 0x0000000000c1c7cc in clang::ASTContext::getTypeInfoInChars
(this=0x1b38300, T=...)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/ASTContext.cpp:1293
#7 0x0000000000d65b47 in (anonymous
namespace)::RecordLayoutBuilder::LayoutField (this=0x7fffffffa690,
D=0x39195a0)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp:2068
#8 0x0000000000d64af6 in (anonymous
namespace)::RecordLayoutBuilder::LayoutFields (this=0x7fffffffa690,
D=0x39193f0)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp:1835
#9 0x0000000000d63ded in (anonymous
namespace)::RecordLayoutBuilder::Layout (this=0x7fffffffa690, RD=0x39193f0)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp:1651
#10 0x0000000000d6715d in clang::ASTContext::getASTRecordLayout
(this=0x1b38300, D=0x39193f0)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp:2484
#11 0x0000000000d6775f in getFieldOffset (C=..., FD=0x3919600) at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp:2582
#12 0x0000000000d677bc in clang::ASTContext::getFieldOffset
(this=0x1b38300, VD=0x3919600)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp:2589
#13 0x0000000000464785 in MyASTVisitor::myVisitFieldDecl
(this=0x7fffffffb700, classname=..., f=0x3919600) at ./memberdumper.h:12

I'm having trouble producing a standalone sample for this internal error.
I'm guessing this isn't expected or a known issue.

Okay, that worked nicely for that source. Going back to the source I
started with, I hit a different abort, in llvm_unreachable_internal()
instead:

Should not see dependent types

[...]

#11 0x0000000000d6775f in getFieldOffset (C=..., FD=0x3919600) at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp:2582
#12 0x0000000000d677bc in clang::ASTContext::getFieldOffset (this=0x1b38300,
VD=0x3919600)
    at
/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp:2589
#13 0x0000000000464785 in MyASTVisitor::myVisitFieldDecl
(this=0x7fffffffb700, classname=..., f=0x3919600) at ./memberdumper.h:12

I guess you are calling getFieldOffset for a field that has a
dependent type? You could dump the record or the field to see what it
is (->dump()).

Dmitri

I guess you are calling getFieldOffset for a field that has a
dependent type? You could dump the record or the field to see what it
is (->dump()).

(gdb) p RD->dump()
CXXRecordDecl 0x391a9f0 <.../include/sqlm_metrics.h:2218:4, line:2228:4>
struct MetricsPartition

-FullComment 0x3922c30 <line:2217:7, col:35>
`-ParagraphComment 0x3922c00 <col:7, col:35>
  `-TextComment 0x3922bd0 <col:7, col:35> Text=" Metrics Partition

Definition"

-CXXRecordDecl 0x391ab00 <line:2218:4, col:11> struct MetricsPartition
-FieldDecl 0x391aba0 <line:2221:7, col:25> metricData 'T'

...

You were right that this appears to be a dependent type. The declaration
was an embedded struct within another explicit template class:

   template <class T>
   class metricsOuter: public allocatorObj
   {
   protected:

      Uint64 m_numPartitions;

      struct MetricsPartition
      {
         T metricData;
   ...

This inner class MetricsPartition doesn't get identitifed as a template
class by getDescribeClassTemplate(). The code I'd used for that
identification was:

   bool VisitCXXRecordDecl( CXXRecordDecl * r )
   {
      if ( r && r->getDescribedClassTemplate() )
      {
         r = r->getInstantiatedFromMemberClass() ;
      }

      if ( r && r->isThisDeclarationADefinition() )
      {

This code properly identifies the outer class as a template class, but not
the inner, perhaps because the template nature of that class is implicit.
Is there a way to identify such an implicit template class as such (or
perhaps just identify some way that this class has dependent members
(without finding out the hard way with the abort)).