<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 6/8/26 4:21 PM, Dave Blaikie via
      Dwarf-discuss wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAENS6EtXTcfPGBwEZ-Mfem+0g3vOvZuxW5Z7KBz9SZcffgv=uQ@mail.gmail.com">
      <pre wrap="" class="moz-quote-pre">On Thu, Jun 4, 2026 at 6:00 PM Cary Coutant <a class="moz-txt-link-rfc2396E" href="mailto:ccoutant@gmail.com"><ccoutant@gmail.com></a> wrote:
</pre>
      <blockquote type="cite">
        <blockquote type="cite">
          <pre wrap="" class="moz-quote-pre">
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.
</pre>
        </blockquote>
        <pre wrap="" class="moz-quote-pre">

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)

</pre>
        <blockquote type="cite">
          <pre wrap="" class="moz-quote-pre">
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).
</pre>
        </blockquote>
        <pre wrap="" class="moz-quote-pre">

In the PR, David noted:

</pre>
        <blockquote type="cite">
          <pre wrap="" class="moz-quote-pre">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.
</pre>
        </blockquote>
        <pre wrap="" class="moz-quote-pre">

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?
</pre>
      </blockquote>
      <pre wrap="" class="moz-quote-pre">
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.</pre>
    </blockquote>
    <p>That is specifically what I was thinking about in my two further
      scenarios.</p>
    <p>I'm going to argue that:</p>
    <p>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:</p>
    <p>t1<int> foo;</p>
    <p>t2<int> bar;<br>
      bar.m2=foo;</p>
    <p>but I would argue that they are different types from the
      perspective of DWARF.</p>
    <p>foo is a t1 instantiated with a T parameter referencing an int.<br>
      bar.m2 is a t1 instantiated with a T (t1's T) parameter
      referencing t2's T parameter that then references an int. </p>
    <p>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.</p>
    <p>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.</p>
    <p>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.   </p>
    <blockquote type="cite"
cite="mid:CAENS6EtXTcfPGBwEZ-Mfem+0g3vOvZuxW5Z7KBz9SZcffgv=uQ@mail.gmail.com">
      <pre wrap="" class="moz-quote-pre">
</pre>
      <blockquote type="cite">
        <pre wrap="" class="moz-quote-pre">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?
</pre>
      </blockquote>
      <pre wrap="" class="moz-quote-pre">
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.</pre>
    </blockquote>
    See my arguments above.
    <blockquote type="cite"
cite="mid:CAENS6EtXTcfPGBwEZ-Mfem+0g3vOvZuxW5Z7KBz9SZcffgv=uQ@mail.gmail.com">
      <pre wrap="" class="moz-quote-pre">

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.
</pre>
    </blockquote>
    <p>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
      <a class="moz-txt-link-freetext" href="https://github.com/llnl/raja">https://github.com/llnl/raja</a> or its slightly better mannered
      cousin Kokkos <a class="moz-txt-link-freetext" href="https://github.com/kokkos/kokkos">https://github.com/kokkos/kokkos</a></p>
    <blockquote type="cite"
cite="mid:CAENS6EtXTcfPGBwEZ-Mfem+0g3vOvZuxW5Z7KBz9SZcffgv=uQ@mail.gmail.com">
      <pre wrap="" class="moz-quote-pre">
</pre>
      <blockquote type="cite">
        <pre wrap="" class="moz-quote-pre">
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?
</pre>
      </blockquote>
      <pre wrap="" class="moz-quote-pre">
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.</pre>
    </blockquote>
    <p>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.</p>
    <p>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. </p>
    <p>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.</p>
    <p>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: "<i>DWARF does not
        represent the generic template definition, but does represent
        each instantiation.</i>" (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.</p>
    <p>-ben</p>
    <blockquote type="cite"
cite="mid:CAENS6EtXTcfPGBwEZ-Mfem+0g3vOvZuxW5Z7KBz9SZcffgv=uQ@mail.gmail.com">
      <pre wrap="" class="moz-quote-pre">

- Dave
</pre>
    </blockquote>
  </body>
</html>