Ben has submitted this as a proposal for the DWARF committee. This is Issue
260703.1:

https://dwarfstd.org/issues/260703.1.html

-cary


On Tue, Jun 9, 2026 at 9:00 AM Ben Woodard via Dwarf-discuss <
[email protected]> wrote:

>
> On 6/8/26 4:21 PM, Dave Blaikie via Dwarf-discuss wrote:
>
> On Thu, Jun 4, 2026 at 6:00 PM Cary Coutant <[email protected]> 
> <[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.
>
> That is specifically what I was thinking about in my two further scenarios.
>
> I'm going to argue that:
>
> t1<int> is not the same as the t1<T> declared inside of t2 even when t2 is
> instantiated with T being an int. They are certainly compatible types and
> the language rules probably allow something like:
>
> t1<int> foo;
>
> t2<int> bar;
> bar.m2=foo;
>
> but I would argue that they are different types from the perspective of
> DWARF.
>
> foo is a t1 instantiated with a T parameter referencing an int.
> bar.m2 is a t1 instantiated with a T (t1's T) parameter referencing t2's T
> parameter that then references an int.
>
> I believe that we NEED to convey that to consumers. C++ template
> metaprogramming is unbelievably hard to unscramble and trying to flatten
> everything down to its fundamental types is just going to make it harder.
>
> I think what bothers you is the combinatoric expansion that this can lead
> to within the type system and maybe the fact that DWARF types and the rules
> around them may need to differ slightly from the source language. However,
> the language and the DWARF actually are telling different stories. The
> compiler (with some help from the linker) wants to make sure that any
> program text may result from template expansion is not duplicated. This of
> course inclines producers toward flattening the template expansion. On the
> other hand, DWARF is there to connect the programmer's source view of the
> code they have written in the source language to the resulting binary after
> the producer has done its work. In this context, flattening the types in
> the template expansion misrepresents the programmers intent by presenting
> an intermediate step that the producer passed through when doing the
> template expansion.
>
> Remember if t1 had any methods, both the one from foo and the one from
> bar.m2 would point to the same program text. This isn't just about the size
> of the binary. It does not impact code generation. This is just debuginfo.
> It is about clearly showing the consumer the way that bar.m2 arrived at the
> instantiation t1<int> (where int is the
> unreferenced template type parameter) was by having t2 take a template
> parameter which was then passed to t1 as its template parameter.
>
> 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.
>
> See my arguments above.
>
> 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.
>
> If you want to see truly evil example of template metaprogramming, the
> likes of which will make your eyes bug and leave you with nightmares about
> being lost in a maze of twisty little passages which all look about the
> same, may I suggest Raja https://github.com/llnl/raja or its slightly
> better mannered cousin Kokkos https://github.com/kokkos/kokkos
>
> 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.
>
> I worry about timeline here. I think with DWARF6 we at least have
> something that at least _could_ work. There will be a big push in both
> producers and consumers to support DWARF6. I think that these things (which
> are arguably bugs in current toolchain's DWARF5 support) should be part of
> that enablement. I'll file the bugs and track them, My involvement with
> DWARF6 probably is going to continue through to the implementation in the
> toolchains.
>
> I believe that what you are really hoping for is a new design for how to
> support template instantiation in DWARF. With the rise of STL and generic
> programming and now with template metaprogramming, template instantiation
> is a much bigger part of C++ than it was when the current template
> instantiation support was added to DWARF and we are starting to see some of
> the problems with that original design. This problem being one of the
> problems. Another one is we have a huge amount of highly similar almost
> duplicated debuginfo. However, I feel like taking on that design challenge
> of how to more compactly represent the vastly increased use of templates in
> C++ is more of A DWARF7 project than a DWARF6 project.
>
> Unlike the DWARF for GPUs project which we are refining and hope to fully
> land in DWARF6, where we had a fairly complete design and implementation
> based on DWARF5, I have not even heard of the beginnings of discussions
> about a new model design for template instantiation yet. This is why I
> think it is best to push that off to DWARF7. I think we should add an
> example or two to D.11 about how this should work based upon what Cary and
> I have suggested for DWARF6, Then as part of the overall DWARF6 enablement
> in the toolchains, we get both the producers and consumers to fall in line
> with that standard.
>
> Then if possible, we come up with a better design for DWARF7. I believe
> that such a design may have at its core, a reconsideration of the policy of
> DWARF toward templates: "*DWARF does not represent the generic template
> definition, but does represent each instantiation.*" (ref section 2.22)
> However, starting with a reconsideration of that premise and marching all
> the way through to a workable design which handles all the scenarios that
> come up in modern C++ and in the even more modern current C++ standards
> where template meta programming are a much bigger factor is going to be
> quite a journey.
>
> -ben
>
> - Dave
>
> --
> Dwarf-discuss mailing list
> [email protected]
> https://lists.dwarfstd.org/mailman/listinfo/dwarf-discuss
>
-- 
Dwarf-discuss mailing list
[email protected]
https://lists.dwarfstd.org/mailman/listinfo/dwarf-discuss

Reply via email to