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
