[llvm] [llvm][DebugInfo] Unwrap template parameters that are typedefs when reconstructing DIE names (PR #168734)

via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 19 08:25:28 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-debuginfo

Author: Michael Buch (Michael137)

<details>
<summary>Changes</summary>

Depends on: 
* https://github.com/llvm/llvm-project/pull/168725

When compiling with `-glldb`, we repoint the `DW_AT_type` of a DIE to be a typedef that refers to the `preferred_name`. I.e.,:
```
template <typename T> structure t7;
using t7i = t7<int>;
template <typename T> struct __attribute__((__preferred_name__(t7i))) t7 {};
template <typename... Ts> void f1()

int main() { f1<t7i>(); }
```
would produce following (minified) DWARF:
```
DW_TAG_subprogram
  DW_AT_name      ("_STN|f1|<t7<int> >")
  DW_TAG_template_type_parameter
    DW_AT_type  (0x0000299c "t7i")
...
DW_TAG_typedef
  DW_AT_type      (0x000029a7 "t7<int>")
  DW_AT_name      ("t7i")
```

Note how the `DW_AT_type` of the template parameter is a typedef itself (instead of the canonical type). The `DWARFTypePrinter` would take the `DW_AT_name` of this typedef when reconstructing the name of `f1`, so we would end up with a verifier failure:
```
error: Simplified template DW_AT_name could not be reconstituted:
         original: f1<t7<int> >
    reconstituted: f1<t7i>
```

Fixing this allows us to un-XFAIL the `simplified-template-names.cpp` test in `cross-project-tests`. Unfortunately this is only tested on Darwin, where LLDB tuning is the default. AFAIK, there is no other case where the template parameter type wouldn't be canonical.

---
Full diff: https://github.com/llvm/llvm-project/pull/168734.diff


5 Files Affected:

- (added) cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/Inputs/simplified_template_names.cpp (+272) 
- (added) cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names-debug-types.test (+9) 
- (removed) cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names.cpp (-360) 
- (added) cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names.test (+5) 
- (modified) llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h (+19-3) 


``````````diff
diff --git a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/Inputs/simplified_template_names.cpp b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/Inputs/simplified_template_names.cpp
new file mode 100644
index 0000000000000..344005ee98141
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/Inputs/simplified_template_names.cpp
@@ -0,0 +1,272 @@
+#include <cstddef>
+#include <cstdint>
+template <typename... Ts> struct t1 {};
+template <typename... Ts> struct t2;
+struct udt {};
+namespace ns {
+struct udt {};
+namespace inner {
+template <typename T> struct ttp {};
+struct udt {};
+} // namespace inner
+template <template <typename> class T> void ttp_user() {}
+enum Enumeration : int { Enumerator1, Enumerator2, Enumerator3 = 1 };
+enum class EnumerationClass { Enumerator1, Enumerator2, Enumerator3 = 1 };
+enum : int { AnonEnum1, AnonEnum2, AnonEnum3 = 1 };
+enum EnumerationSmall : unsigned char { kNeg = 0xff };
+} // namespace ns
+template <typename... Ts> void f1() {
+  t1<Ts...> v1;
+  t2<Ts...> *v2;
+}
+template <bool b, int i> void f2() {}
+template <typename T, T... A> void f3() {}
+template <typename T, unsigned = 3> void f4() {}
+template <typename T, bool b = false> struct t3 {};
+extern template class t3<int>;
+template class t3<int>;
+struct outer_class {
+  struct inner_class {};
+};
+int i = 3;
+template <unsigned N> struct t4 {};
+namespace {
+struct t5 {};
+enum LocalEnum { LocalEnum1 };
+} // namespace
+template <typename... T1, typename T2 = int> void f5() {}
+template <typename T1, typename... T2> void f6() {}
+struct t6 {
+  template <typename T> void operator<<(int) {}
+  template <typename T> void operator<(int) {}
+  template <typename T> void operator<=(int) {}
+  template <typename T = int> operator t1<float> *() { return nullptr; }
+  template <typename T> void operator-(int) {}
+  template <typename T> void operator*(int) {}
+  template <typename T> void operator/(int) {}
+  template <typename T> void operator%(int) {}
+  template <typename T> void operator^(int) {}
+  template <typename T> void operator&(int) {}
+  template <typename T> void operator|(int) {}
+  template <typename T> void operator~() {}
+  template <typename T> void operator!() {}
+  template <typename T> void operator=(int) {}
+  template <typename T> void operator>(int) {}
+  template <typename T> void operator,(int) {}
+  template <typename T> void operator()() {}
+  template <typename T> void operator[](int) {}
+  template <typename T> void operator<=>(int) {}
+  template <typename T> void *operator new(std::size_t, T) {
+    __builtin_unreachable();
+  }
+  template <typename T> void operator delete(void *, T) {}
+  template <typename T> void *operator new[](std::size_t, T) {
+    __builtin_unreachable();
+  }
+  template <typename T> void operator delete[](void *, T) {}
+  template <typename T> int operator co_await() { __builtin_unreachable(); }
+};
+void operator"" _suff(unsigned long long) {}
+template <template <typename...> class T> void f7() {}
+template <template <typename...> class T, typename T2> void f8() {}
+template <typename T> struct t7;
+using t7i = t7<int>;
+template <typename T> struct __attribute__((__preferred_name__(t7i))) t7 {};
+struct t8 {
+  void mem();
+};
+namespace ns {
+inline namespace inl {
+template <typename T> struct t9 {};
+} // namespace inl
+} // namespace ns
+template <typename T> void (*f9())() { return nullptr; }
+struct t10 {
+  template <typename T = void> t10() {}
+};
+
+template <typename T> void operator_not_really() {}
+
+template <typename T, T... A> struct t11 {};
+
+struct t12 {
+  t11<LocalEnum, LocalEnum1> v1;
+};
+
+template <decltype(ns::AnonEnum1)> void f10() {}
+
+int main() {
+  struct {
+  } A;
+  auto L = [] {};
+  f1<int>();
+  f1<float>();
+  f1<bool>();
+  f1<double>();
+  f1<long>();
+  f1<short>();
+  f1<unsigned>();
+  f1<unsigned long long>();
+  f1<long long>();
+  f1<udt>();
+  f1<ns::udt>();
+  f1<ns::udt *>();
+  f1<ns::inner::udt>();
+  f1<t1<int>>();
+  f1<int, float>();
+  f1<int *>();
+  f1<int &>();
+  f1<int &&>();
+  f1<const int>();
+  f1<int[3]>();
+  f1<void>();
+  f1<outer_class::inner_class>();
+  f1<unsigned long>();
+  f2<true, 3>();
+  f3<ns::Enumeration, ns::Enumerator3, (ns::Enumeration)2>();
+  f3<ns::EnumerationClass, ns::EnumerationClass::Enumerator3,
+     (ns::EnumerationClass)2>();
+  f3<ns::EnumerationSmall, ns::kNeg>();
+  f3<decltype(ns::AnonEnum1), ns::AnonEnum3, (decltype(ns::AnonEnum1))2>();
+  f3<LocalEnum, LocalEnum1>();
+  f3<int *, &i>();
+  f3<int *, nullptr>();
+  t4<3> v2;
+  f3<unsigned long, 1>();
+  f3<unsigned long long, 1>();
+  f3<long, 1>();
+  f3<unsigned int, 1>();
+  f3<short, 1>();
+  f3<unsigned char, (char)0>();
+  f3<signed char, (char)0>();
+  f3<unsigned short, 1, 2>();
+  f3<char, 0, 1, 6, 7, 13, 14, 31, 32, 33, (char)127, (char)128>();
+  f3<__int128, ((__int128)9223372036854775807) * 2>();
+  f4<unsigned int>();
+  f1<t3<int>>();
+  f1<t3<t3<int>>>();
+  f1<decltype(L)>();
+  t3<decltype(L)> v1;
+  f1<t3<t3<decltype(L)>>>();
+  f1<int(float)>();
+  f1<void(...)>();
+  f1<void(int, ...)>();
+  f1<const int &>();
+  f1<const int *&>();
+  f1<t5>();
+  f1<decltype(nullptr)>();
+  f1<long *, long *>();
+  f1<long *, udt *>();
+  f1<void *const>();
+  f1<const void *const *>();
+  f1<void()>();
+  f1<void (*)()>();
+  f1<decltype(&L)>();
+  f1<decltype(A)>();
+  f1<decltype(&A)>();
+  f5<t1<int>>();
+  f5<>();
+  f6<t1<int>>();
+  f1<>();
+  f1<const void *, const void *>();
+  f1<t1<int *> *>();
+  f1<int *[]>();
+  t6 v6;
+  v6.operator<< <int>(1);
+  v6.operator< <int>(1);
+  v6.operator<= <int>(1);
+  v6.operator t1<float> *();
+  v6.operator- <int>(3);
+  v6.operator* <int>(3);
+  v6.operator/ <int>(3);
+  v6.operator% <int>(3);
+  v6.operator^ <int>(3);
+  v6.operator& <int>(3);
+  v6.operator| <int>(3);
+  v6.operator~ <int>();
+  v6.operator! <int>();
+  v6.operator= <int>(3);
+  v6.operator><int>(3);
+  v6.operator, <int>(3);
+  v6.operator()<int>();
+  v6.operator[]<int>(3);
+  v6.operator<=> <int>(3);
+  t6::operator new(0, 0);
+  t6::operator new[](0, 0);
+  t6::operator delete(nullptr, 0);
+  t6::operator delete[](nullptr, 0);
+  v6.operator co_await <int>();
+  42_suff;
+  struct t7 {};
+  f1<t7>();
+  f1<int (&)[3]>();
+  f1<int (*)[3]>();
+  f7<t1>();
+  f8<t1, int>();
+  using namespace ns;
+  ttp_user<inner::ttp>();
+  f1<int *, decltype(nullptr) *>();
+  t7i x;
+  f1<t7i>();
+  f7<ns::inl::t9>();
+  f1<_Atomic(int)>();
+  f1<int, long, volatile char>();
+  f1<__attribute__((__vector_size__(sizeof(int) * 2))) int>();
+  f1<int *const volatile>();
+  f1<const volatile void>();
+  f1<t1<decltype(L)>>();
+  t10 v3;
+  f1<void (::udt::*)() const>();
+  f1<void (::udt::*)() volatile &>();
+  f1<void (::udt::*)() const volatile &&>();
+  f9<int>();
+  f1<void (*const)()>();
+  f1<char const(&)[1]>();
+  f1<void() const &>();
+  f1<void() volatile &&>();
+  f1<void() const volatile>();
+  f1<int *const[1]>();
+  f1<int *const(&)[1]>();
+  f1<void (::udt::*const &)()>();
+  f1<void (*(int))(float)>();
+  f1<t1<int>[1]>();
+  f1<void (*)() noexcept>();
+  f1<void(decltype(A))>();
+  struct t8 {
+    decltype(A) m;
+  };
+  f1<void(t8, decltype(A))>();
+  f1<void(t8)>();
+  operator_not_really<int>();
+  t12 v4;
+  f1<_BitInt(3)>();
+  f1<const unsigned _BitInt(5)>();
+  f1<void(t1<>, t1<>)>();
+  f1<int t1<>::*>();
+  void fcc() __attribute__((swiftcall));
+  f1<decltype(fcc)>();
+  int fnrt() __attribute__((noreturn));
+  f1<decltype(fnrt)>();
+  f10<ns::AnonEnum1>();
+}
+void t8::mem() {
+  struct t7 {};
+  f1<t7>();
+  f1<decltype(&t8::mem)>();
+}
+namespace complex_type_units {
+void external_function();
+namespace {
+struct internal_type;
+}
+template <void (*)() = external_function> struct t2;
+template <typename = t2<>> class t3 {};
+template <typename = internal_type, typename = t3<>> struct t4 {};
+struct t5 {
+  t4<> v1;
+};
+void f1() {
+  t5 v1;
+  t3<> v2;
+}
+} // namespace complex_type_units
diff --git a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names-debug-types.test b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names-debug-types.test
new file mode 100644
index 0000000000000..74ce8f466b9ae
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names-debug-types.test
@@ -0,0 +1,9 @@
+// debug-types are not available for MachO.
+//
+// UNSUPPORTED: system-darwin
+//
+// RUN: %clang %target_itanium_abi_host_triple %p/Inputs/simplified_template_names.cpp -c -o - -gdwarf-4 -Xclang -gsimple-template-names=mangled -Xclang -debug-forward-template-params -std=c++20 -fdebug-types-section \
+// RUN:   | llvm-dwarfdump --verify -
+//
+// RUN: %clang %target_itanium_abi_host_triple %p/Inputs/simplified_template_names.cpp -c -o - -gdwarf-5 -Xclang -gsimple-template-names=mangled -Xclang -debug-forward-template-params -std=c++20 -fdebug-types-section \
+// RUN:   | llvm-dwarfdump --verify -
diff --git a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names.cpp b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names.cpp
deleted file mode 100644
index 956c7e37f0225..0000000000000
--- a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names.cpp
+++ /dev/null
@@ -1,360 +0,0 @@
-// UNSUPPORTED: system-darwin
-// RUN: %clang %target_itanium_abi_host_triple %s -c -o - -gdwarf-4 -Xclang -gsimple-template-names=mangled -Xclang -debug-forward-template-params -std=c++20 \
-// RUN:   | llvm-dwarfdump --verify -
-// RUN: %clang %target_itanium_abi_host_triple %s -c -o - -gdwarf-4 -Xclang -gsimple-template-names=mangled -Xclang -debug-forward-template-params -std=c++20 -gmlt -fdebug-info-for-profiling \
-// RUN:   | llvm-dwarfdump --verify -
-// RUN: %clang %target_itanium_abi_host_triple %s -c -o - -gdwarf-4 -Xclang -gsimple-template-names=mangled -Xclang -debug-forward-template-params -std=c++20 -fdebug-types-section \
-// RUN:   | llvm-dwarfdump --verify -
-// RUN: %clang %target_itanium_abi_host_triple %s -c -o - -gdwarf-5 -Xclang -gsimple-template-names=mangled -Xclang -debug-forward-template-params -std=c++20 -fdebug-types-section \
-// RUN:   | llvm-dwarfdump --verify -
-
-#include <cstdint>
-#include <cstddef>
-template<typename ...Ts>
-struct t1 {
-};
-template<typename ...Ts>
-struct t2;
-struct udt {
-};
-namespace ns {
-struct udt {
-};
-namespace inner {
-template<typename T> struct ttp { };
-struct udt { };
-}
-template<template<typename> class T>
-void ttp_user() { }
-enum Enumeration : int { Enumerator1, Enumerator2, Enumerator3 = 1 };
-enum class EnumerationClass { Enumerator1, Enumerator2, Enumerator3 = 1 };
-enum : int { AnonEnum1, AnonEnum2, AnonEnum3 = 1 };
-enum EnumerationSmall : unsigned char { kNeg = 0xff };
-}
-template <typename... Ts>
-void f1() {
-  t1<Ts...> v1;
-  t2<Ts...> *v2;
-}
-template<bool b, int i>
-void f2() {
-}
-template<typename T, T ...A>
-void f3() {
-}
-template<typename T, unsigned = 3>
-void f4() {
-}
-template<typename T, bool b = false>
-struct t3 { };
-extern template class t3<int>;
-template class t3<int>;
-struct outer_class {
-  struct inner_class {
-  };
-};
-int i = 3;
-template<unsigned N>
-struct t4 { };
-namespace {
-struct t5 { };
-enum LocalEnum { LocalEnum1 };
-}
-template<typename ...T1, typename T2 = int>
-void f5() { }
-template<typename T1, typename ...T2>
-void f6() { }
-struct t6 {
-  template<typename T>
-  void operator<<(int) {
-  }
-  template<typename T>
-  void operator<(int) {
-  }
-  template<typename T>
-  void operator<=(int) {
-  }
-  template<typename T = int>
-  operator t1<float>*() {
-    return nullptr;
-  }
-  template<typename T>
-  void operator-(int) {
-  }
-  template<typename T>
-  void operator*(int) {
-  }
-  template<typename T>
-  void operator/(int) {
-  }
-  template<typename T>
-  void operator%(int) {
-  }
-  template<typename T>
-  void operator^(int) {
-  }
-  template<typename T>
-  void operator&(int) {
-  }
-  template<typename T>
-  void operator|(int) {
-  }
-  template<typename T>
-  void operator~() {
-  }
-  template<typename T>
-  void operator!() {
-  }
-  template<typename T>
-  void operator=(int) {
-  }
-  template<typename T>
-  void operator>(int) {
-  }
-  template<typename T>
-  void operator,(int) {
-  }
-  template<typename T>
-  void operator()() {
-  }
-  template<typename T>
-  void operator[](int) {
-  }
-  template<typename T>
-  void operator<=>(int) {
-  }
-  template<typename T>
-  void* operator new(std::size_t, T) {
-    __builtin_unreachable();
-  }
-  template<typename T>
-  void operator delete(void*, T) {
-  }
-  template<typename T>
-  void* operator new[](std::size_t, T) {
-    __builtin_unreachable();
-  }
-  template<typename T>
-  void operator delete[](void*, T) {
-  }
-  template<typename T>
-  int operator co_await() { __builtin_unreachable(); }
-
-};
-void operator"" _suff(unsigned long long) {}
-template<template<typename...> class T> void f7() { }
-template<template<typename...> class T, typename T2> void f8() { }
-template<typename T>
-struct t7;
-using t7i = t7<int>;
-template<typename T>
-struct
-__attribute__((__preferred_name__(t7i)))
-t7 {
-};
-struct t8 {
-  void mem();
-};
-namespace ns {
-inline namespace inl {
-template<typename T> struct t9 { };
-}
-}
-template<typename T>
-void (*f9())() {
-  return nullptr;
-}
-struct t10 {
-  template<typename T = void>
-  t10() { }
-};
-
-template<typename T>
-void operator_not_really() {
-}
-
-template<typename T, T ...A>
-struct t11 {
-};
-
-struct t12 {
-  t11<LocalEnum, LocalEnum1> v1;
-};
-
-template<decltype(ns::AnonEnum1)>
-void f10() {
-}
-
-int main() {
-  struct { } A;
-  auto L = []{};
-  f1<int>();
-  f1<float>();
-  f1<bool>();
-  f1<double>();
-  f1<long>();
-  f1<short>();
-  f1<unsigned>();
-  f1<unsigned long long>();
-  f1<long long>();
-  f1<udt>();
-  f1<ns::udt>();
-  f1<ns::udt*>();
-  f1<ns::inner::udt>();
-  f1<t1<int>>();
-  f1<int, float>();
-  f1<int *>();
-  f1<int &>();
-  f1<int &&>();
-  f1<const int>();
-  f1<int[3]>();
-  f1<void>();
-  f1<outer_class::inner_class>();
-  f1<unsigned long>();
-  f2<true, 3>();
-  f3<ns::Enumeration, ns::Enumerator3, (ns::Enumeration)2>();
-  f3<ns::EnumerationClass, ns::EnumerationClass::Enumerator3, (ns::EnumerationClass)2>();
-  f3<ns::EnumerationSmall, ns::kNeg>();
-  f3<decltype(ns::AnonEnum1), ns::AnonEnum3, (decltype(ns::AnonEnum1))2>();
-  f3<LocalEnum, LocalEnum1>();
-  f3<int*, &i>();
-  f3<int*, nullptr>();
-  t4<3> v2;
-  f3<unsigned long, 1>();
-  f3<unsigned long long, 1>();
-  f3<long, 1>();
-  f3<unsigned int, 1>();
-  f3<short, 1>();
-  f3<unsigned char, (char)0>();
-  f3<signed char, (char)0>();
-  f3<unsigned short, 1, 2>();
-  f3<char, 0, 1, 6, 7, 13, 14, 31, 32, 33, (char)127, (char)128>();
-  f3<__int128, ((__int128)9223372036854775807) * 2>();
-  f4<unsigned int>();
-  f1<t3<int>>();
-  f1<t3<t3<int>>>();
-  f1<decltype(L)>();
-  t3<decltype(L)> v1;
-  f1<t3<t3<decltype(L)>>>();
-  f1<int(float)>();
-  f1<void(...)>();
-  f1<void(int, ...)>();
-  f1<const int &>();
-  f1<const int *&>();
-  f1<t5>();
-  f1<decltype(nullptr)>();
-  f1<long*, long*>();
-  f1<long*, udt*>();
-  f1<void *const>();
-  f1<const void *const *>();
-  f1<void()>();
-  f1<void(*)()>();
-  f1<decltype(&L)>();
-  f1<decltype(A)>();
-  f1<decltype(&A)>();
-  f5<t1<int>>();
-  f5<>();
-  f6<t1<int>>();
-  f1<>();
-  f1<const void*, const void*>();
-  f1<t1<int*>*>();
-  f1<int *[]>();
-  t6 v6;
-  v6.operator<< <int>(1);
-  v6.operator< <int>(1);
-  v6.operator<= <int>(1);
-  v6.operator t1<float>*();
-  v6.operator- <int>(3);
-  v6.operator* <int>(3);
-  v6.operator/ <int>(3);
-  v6.operator% <int>(3);
-  v6.operator^ <int>(3);
-  v6.operator& <int>(3);
-  v6.operator| <int>(3);
-  v6.operator~ <int>();
-  v6.operator! <int>();
-  v6.operator= <int>(3);
-  v6.operator> <int>(3);
-  v6.operator, <int>(3);
-  v6.operator() <int>();
-  v6.operator[] <int>(3);
-  v6.operator<=> <int>(3);
-  t6::operator new(0, 0);
-  t6::operator new[](0, 0);
-  t6::operator delete(nullptr, 0);
-  t6::operator delete[](nullptr, 0);
-  v6.operator co_await<int>();
-  42_suff;
-  struct t7 { };
-  f1<t7>();
-  f1<int(&)[3]>();
-  f1<int(*)[3]>();
-  f7<t1>();
-  f8<t1, int>();
-  using namespace ns;
-  ttp_user<inner::ttp>();
-  f1<int*, decltype(nullptr)*>();
-  t7i x;
-  f1<t7i>();
-  f7<ns::inl::t9>();
-  f1<_Atomic(int)>();
-  f1<int, long, volatile char>();
-  f1<__attribute__((__vector_size__(sizeof(int) * 2))) int>();
-  f1<int *const volatile>();
-  f1<const volatile void>();
-  f1<t1<decltype(L)>>();
-  t10 v3;
-  f1<void (::udt::*)() const>();
-  f1<void (::udt::*)() volatile &>();
-  f1<void (::udt::*)() const volatile &&>();
-  f9<int>();
-  f1<void (*const)()>();
-  f1<char const (&)[1]>();
-  f1<void () const &>();
-  f1<void () volatile &&>();
-  f1<void () const volatile>();
-  f1<int *const[1]>();
-  f1<int *const(&)[1]>();
-  f1<void (::udt::* const&)()>();
-  f1<void (*(int))(float)>();
-  f1<t1<int>[1]>();
-  f1<void (*)() noexcept>();
-  f1<void (decltype(A))>();
-  struct t8 { decltype(A) m; };
-  f1<void(t8, decltype(A))>();
-  f1<void(t8)>();
-  operator_not_really<int>();
-  t12 v4;
-  f1<_BitInt(3)>();
-  f1<const unsigned _BitInt(5)>();
-  f1<void(t1<>, t1<>)>();
-  f1<int t1<>::*>();
-  void fcc() __attribute__((swiftcall));
-  f1<decltype(fcc)>();
-  int fnrt() __attribute__((noreturn));
-  f1<decltype(fnrt)>();
-  f10<ns::AnonEnum1>();
-}
-void t8::mem() {
-  struct t7 { };
-  f1<t7>();
-  f1<decltype(&t8::mem)>();
-}
-namespace complex_type_units {
-void external_function();
-namespace {
-struct internal_type;
-}
-template <void (*)() = external_function> struct t2;
-template <typename = t2<>> class t3 {};
-template <typename = internal_type, typename = t3<>>
-struct t4 {
-};
-struct t5 {
-    t4<> v1;
-};
-void f1() {
-  t5 v1;
-  t3<> v2;
-}
-}
diff --git a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names.test b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names.test
new file mode 100644
index 0000000000000..5a0da903e2a8b
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names.test
@@ -0,0 +1,5 @@
+// RUN: %clang %target_itanium_abi_host_triple %p/Inputs/simplified_template_names.cpp -c -o - -gdwarf-4 -Xclang -gsimple-template-names=mangled -Xclang -debug-forward-template-params -std=c++20 -gtemplate-alias \
+// RUN:   | llvm-dwarfdump --verify -
+//
+// RUN: %clang %target_itanium_abi_host_triple %p/Inputs/simplified_template_names.cpp -c -o - -gdwarf-4 -Xclang -gsimple-template-names=mangled -Xclang -debug-forward-template-params -std=c++20 -gmlt -fdebug-info-for-profiling -gtemplate-alias \
+// RUN:   | llvm-dwarfdump --verify -
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
index a760f773055d2..b26d0fc013da4 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -161,6 +161,23 @@ const char *toString(std::optional<DWARFFormValueType> F) {
   }
   return nullptr;
 }
+
+/// Resolve the DW_AT_type of \c D until we reach a DIE that is not a
+/// DW_TAG_typedef.
+template <typename DieType> DieType unwrapReferencedTypedefType(DieType D) {
+  auto TypeAttr = D.find(dwarf::DW_AT_type);
+  if (!TypeAttr)
+    return DieType();
+
+  auto Unwrapped = detail::resolveReferencedType(D, *TypeAttr);
+  if (!Unwrapped)
+    return DieType();
+
+  if (Unwrapped.getTag() == dwarf::DW_TAG_typedef)
+    return unwrapReferencedTypedefType(Unwrapped);
+
+  return Unwrapped;
+}
 } // namespace detail
 
 template <typename DieType>
@@ -553,10 +570,9 @@ bool DWARFTypePrinter<DieType>::appendTemplateParameters(DieType D,
     }
     if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
       continue;
-    auto TypeAttr = C.find(dwarf::DW_AT_type);
     Sep();
-    appendQualifiedName(TypeAttr ? detail::resolveReferencedType(C, *TypeAttr)
-                                 : DieType());
+
+    appendQualifiedName(detail::unwrapReferencedTypedefType(C));
   }
   if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
     OS << '<';

``````````

</details>


https://github.com/llvm/llvm-project/pull/168734


More information about the llvm-commits mailing list