[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