On Thu, Jun 4, 2026 at 6:00 PM Cary Coutant <[email protected]> wrote:
>>
>> template<typename T> struct t1 {
>>   T n1;
>> };
>>
>> template<typename T> struct t2 {
>>   T m1;
>>   t1<T> m2;
>> };
>>
>> int main()
>> {
>>   t2<int> v1;
>>   return 0;
>> }
>>
>> Based on the current specification, the type of m1 should reference
>> a template parameter entry.  This is a bug in gcc which has already
>> been described [1].  llvm/clang attempted to fix this in PR [2].
>>
>> Also for m2 we can see that there is no information that its type was
>> originally described by a template type parameter of t2.  However,
>> there is no specification addressing this specific case in the DWARF
>> Standard.
>
>
> Like Ben, I'm not sure I see why this isn't possible given the current spec. 
> The type attribute for v1 should point to a type DIE for t2<int>, which will 
> have a template type parameter and two data members, m1 and m2. Briefly:
>
> L1: DW_TAG_structure_type (name: t2<int>)
> L2:   DW_TAG_template_type_parameter (name: T, type: ref to type int)
> L3:   DW_TAG_member (name: m1, type: ref to L2) [NOTE 1]
> L4:   DW_TAG_member (name: m2, type: ref to type t1<T>) [NOTE 2]
>
> NOTE 1: This is the bug you point out where gcc and clang don't do what the 
> spec says, and put a ref to type int instead of to the template type 
> parameter entry.
>
> NOTE 2: This is the part that may not be so obvious. We want a ref to a DIE 
> that represents the type t1<T> rather than t1<int>. I think we can have that, 
> but that new type entry will need to be a child of the t2<int> type. 
> Otherwise, it won't be able to reference the template type parameter entry 
> (technically, it *could*, but pointing from one type DIE into the interior of 
> another is ugly, and could conceivably cause problems down the road).
>
> L1: DW_TAG_structure_type (name: t2<int>)
> L2:   DW_TAG_template_type_parameter (name: T, type: ref to type int)
> L3:   DW_TAG_member (name: m1, type: ref to L2)
> L4:   DW_TAG_member (name: m2, type: ref to L5)
> L5:   DW_TAG_structure_type (name: t1<T>)
> L6:     DW_TAG_template_type_parameter (name: T, type: ref to type int)
> L7:     DW_TAG_member (name: n1, type: ref to L6)
>
>>
>> Besides missing consumer support (e.g. GDB or LLDB), missing support for
>> nested templates was one further reason why the llvm PR [2] was rejected
>> by David Blaikie.  I discussed this topic with him since I am working on
>> the enablement in GDB and submitted a patch series [3] to support template
>> type resolution based on the current DWARF specification.  David Blaikie
>> asked me to submit a DWARF issue for this, since we could not come up with
>> a useful specification for the nested case (type of m2 in the example
>> above).
>
>
> In the PR, David noted:
>
>> That's basically my point, sorry, that v1 must be represented as 
>> "trait::type" (because it has to be canonical) and so if many uses, like 
>> this one, of a type in a template can't reference the 
>> DW_TAG_template_type_parameter, because it's non-canonical - I'm not sure 
>> there's a lot of value in making it work for the subset of cases where it is 
>> workable.
>
>
> I guess I don't understand the part about "it has to be canonical". David, 
> can you explain why the approach I used above wouldn't work for the PR's 
> example with trait::type?

Consider some further use of t1<int> elsewhere (in some t3<int> that's
similar to t2<int>, or independently, etc) - the consumer needs to
know that t1<int> is the same type as t1<T> inside t1<int>.
Also from a debug info size perspective, we wouldn't want to duplicate
the type description of t2<int> with all its members, etc.

> If we need something canonical (and if I understand what that means), could 
> we also have a canonical instantiation of the type for t1<int> at the 
> outermost scope, and add an attribute to the entry for t1<T> at L5 that 
> points to that canonical instantiation — maybe call it DW_AT_canonical_type?

Possibly, though it gets verbose (we would want tnhe t1<T> at L5 to be
only a declaration, not a definition, for instance - so it doesn't
contain a duplicate description of all of t1<int>'s members). In the
above case, we could emit t1<T> as a typedef, or at least handle it
similarly to a typedef.

And there are more complicated situations, like this:

template<typename T1>
struct t1 {
  typedef U1 = T1;
};
template<typename T2>
struct t2 {
  typedef U2 = t1<T2>::U1;
};
int main() {
  t2<int>::U2 x;
}

Following the above direction you're suggesting Cary, I suppose we
could still emit a declaration for t1<T2> inside t2<int>, and have
that declaration contain the U1 typedef referring to the T1 parameter
(with a value of T2) - though it does feel a bit awkward/verbose to
me. In template heavy code this may produce a lot of new declarations
to describe these template parameter mappings.

I think there's probably some worse cases of template parameter use
I'm not thinking of... but haven't come up with them yet.

>
> There's also the concern that the compilers currently don't generate what the 
> DWARF spec says they should, and if they did, the debuggers wouldn't be able 
> to handle it. And if David's point above is right that we can represent the 
> simple case, but not the more complex ones, is it worth doing it even for the 
> simple cases? If the spec is calling for something that can't be done in the 
> general case, should we remove it from the spec?

That'd be the direction I'd lean. I'd at least be inclined to leave it
out/not say one way or the other - if a producer and consumer can
agree to do this sort of thing in some cases and they're OK with it
not being a complete solution, I wouldn't be so firm as to say they
shouldn't be allowed to - just that in my capacity as an LLVM/clang
debug info maintainer, I don't think it's the right direction
there/anywhere I'd have ownership over, at my current understanding of
the situation.

- Dave
-- 
Dwarf-discuss mailing list
[email protected]
https://lists.dwarfstd.org/mailman/listinfo/dwarf-discuss

Reply via email to