-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[llvm][DebugInfo] Unwrap template parameters that are typedefs when reconstructing DIE names #168734
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[llvm][DebugInfo] Unwrap template parameters that are typedefs when reconstructing DIE names #168734
Conversation
|
@llvm/pr-subscribers-debuginfo Author: Michael Buch (Michael137) ChangesDepends on: When compiling with would produce following (minified) DWARF: Note how the Fixing this allows us to un-XFAIL the Full diff: https://github.com/llvm/llvm-project/pull/168734.diff 5 Files Affected:
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 << '<';
|
| appendQualifiedName(TypeAttr ? detail::resolveReferencedType(C, *TypeAttr) | ||
| : DieType()); | ||
|
|
||
| appendQualifiedName(detail::unwrapReferencedTypedefType(C)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't entirely sure if this was the right place. We could just unwrap the DIE in appendUnqualifiedNameBefore for DW_TAG_typedef. But that felt wrong (though that didn't fail any tests, so maybe we usually never get to appendUnqualifiedNameBefore for typedef types?). But still felt a bit off
🐧 Linux x64 Test Results
|
|
Hmm, probably for good reason, but: Why do it this way (having the canonical type printing ignore the preferred name), rather than the other way (fully embrace the preferred name, and use it when printing the DW_AT_name (when unsimplified or mangled)?) |
Here's the commit that disabled printing it for debug-info: Is this still an important property to maintain? Also, the reason we did the typedef indirection trick for LLDB was that we don't have a way to create a |
The first point, maintaining correspondence between textual ( The second point - inconsistency between DWARF producers - yeah, that still is a real thing... not sure what the right tradeoff is there...
Ah :/ bit unfortunate. But I'm not sure if I explained the problem I was pointing out - not that the typedef is a problem, but the fact that the DWARF produced for the template specialization varies depending on whether the typedef was produced for other reasons. We should probably not do that - we should probably produce and use the typedef always when it's the preferred name. |
dwblaikie
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed - it does seem like it could be nice if the type printed with the preferred name for consistency with the structural description - but the GCC/Clang compatibility is not /not/ a concern... so can't exactly fault this direction either.
…econstructing DIE names
5cc4ae9 to
ff6d6d3
Compare
Thanks for elaborating, this makes sense! Not great we have to do this for LLDB, but workable I suppose (given the whole AST restriction LLDB is working with -- i think we discussed using the demangled names for typenames, but decided using the
Aah I see, yes I didn't catch this point the first time I read the issue. I'll take a look at this when I get time |
Depends on:
When compiling with
-glldb, we repoint theDW_AT_typeof a DIE to be a typedef that refers to thepreferred_name. I.e.,:would produce following (minified) DWARF:
Note how the
DW_AT_typeof the template parameter is a typedef itself (instead of the canonical type). TheDWARFTypePrinterwould take theDW_AT_nameof this typedef when reconstructing the name off1, so we would end up with a verifier failure:Fixing this allows us to un-XFAIL the
simplified-template-names.cpptest incross-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.