Evaluate expression for template class

Hey,

I’ve noticed that evaluating expressions involving templated classes seems to have some unexpected behavior.

I’ve created the following sample code to reproduce the issue:

template class foo
{
uint32_t data;
};

foo test;

int main() {
foo test2;
return 0;
}

I’ve set a breakpoint on main and evaluated the following expressions:
(lldb) p sizeof(foo)
(unsigned long) $0 = 4
(lldb) p sizeof(foo)
error: implicit instantiation of undefined template ‘foo’
template is declared here

It seems like expression evaluation can only find the specialized templated classes that were used in the current scope. Running the same example using GDB works as expected (both expressions are evaluated correctly).

Is this a known issue?
Does anybody have any insight, or familiarity with expression evaluation that would be able to point me in the right direction?

Thanks,
Scott

lldb can't currently create new template instantiations. It can only access ones that were generated in the binary you were debugging. The debug information doesn't have any code, so we can't create new instantiations from there. Having the debugger try to include headers into the expression context in the same way the compiler did originally is also tricky since we don't know the header search paths or defines that the compiler used when it built the template instantiations... Raphael has been working on doing this for the case where the C++ code is build into a clang module, but I don't think that work is done yet, and then you have to build your code with modules to use it...

The <int> expression is failing because clang is being smart and sees that though you mention foo<int> in reference to "test" you never actually use "test", so it doesn't actually have to make that instantiation. In the case where this works with gdb, did you build with clang or did you build with gcc? If the latter, this might be working for gdb because gcc emits code for the int template instantiation when you mention it, rather than only when you use it?

Does it also work for gdb when you try:

(gdb) p sizeof(foo<double>)

or any other type you haven't mentioned in your code?

Not that that really matters for what lldb would have to do, but it would be interesting to know...

Jim

I built with both clang and gcc, the behavior is the same (lldb fails to evaluate the expression, gdb succeeds).

Trying to evaluate a template type that hasn’t been instantiated fails in both lldb and gdb.
ie.
(gdb) p sizeof(foo)
No symbol “foo” in current context.
(lldb) p sizeof(foo)
error: implicit instantiation of undefined template ‘foo’
template is declared here

Looking at the debug info, both template instantiations are there, it seems like LLDB just isn’t finding it (while GDB is).

$readelf --debug-dump a.out | grep foo
0x00000000 666f6f00 5400696e 7400666f 6f3c696e foo.T.int.foo<in
0x00000080 00746573 74320066 6f6f3c76 6f69643e .test2.foo
<41> DW_AT_name : (indirect string, offset: 0xa): foo
<49> DW_AT_name : (indirect string, offset: 0x0): foo
<8f> DW_AT_name : (indirect string, offset: 0x87): foo
<97> DW_AT_name : (indirect string, offset: 0x0): foo
8d foo
3f foo

Interesting... What lldb & clang were you using? With current TOT clang & lldb I see:

(lldb) run
Process 83732 launched: '/tmp/template2' (x86_64)
Process 83732 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000fad template2`main at template.cpp:12
   9
   10 int main() {
   11 foo<void> test2;
-> 12 return 0;
        ^
   13 }

(lldb) expr sizeof(test)
(unsigned long) $0 = 4
(lldb) expr sizeof(test2)
(unsigned long) $1 = 4

That's good, we do know about both of these, but:

(lldb) expr sizeof(foo<void>)
error: use of undeclared identifier 'foo'
error: expected '(' for function-style cast or type construction
error: expected expression
(lldb) expr sizeof(foo<int>)
error: use of undeclared identifier 'foo'
error: expected '(' for function-style cast or type construction
error: expected expression

Jim

I’ve tried with LLVM 4, 7 and 8. They all fail to evaluate ‘sizeof(foo)’.

I’m also building with ‘-g’ which might be why ‘sizeof(foo)’ succeeds for me, but fails for you.

I've tried with LLVM 4, 7 and 8. They all fail to evaluate 'sizeof(foo<int>)'.

The fundamental problem is that DWARF doesn't represent templates per se. It only represents template instantiations. So there's nothing in the debug information called "foo". There is only "foo<int>" and "foo<void>". The other "disadvantage" lldb has compared to gdb is that gdb's "print" is all hand-built, so for instance, it would be easy for them to handle "sizeof" specially and just fine foo<int> in the DWARF and report its size. I don't know if they do that in this case, but they do in others. LLDB uses clang as its expression parser, which when it sees foo<int> apparently wants to find a decl called "foo" first, which we don't really have in the abstract. Presumably something in how we go from these instantiations to a representation of the template has changed from the version you are using to current TOT. Probably best to file a bug.

I'm also building with '-g' which might be why 'sizeof(foo<void>)' succeeds for me, but fails for you.

If I had built without -g you wouldn't see any source information in the transcript below (or any local variables, etc...)

Jim