From f3a2cfc10394143bbe30a6af00be8b68c1c0d607 Mon Sep 17 00:00:00 2001 From: David Blaikie <dblaikie@gmail.com> Date: Thu, 10 Feb 2022 14:40:25 -0800 Subject: [PATCH] DebugInfo: Don't simplify any template referencing a lambda Lambda names aren't entirely canonical (as demonstrated by the cross-project-test added here) at the moment (we should fix that for a bunch of reasons) - even if the template referencing them is non-simplified, other names referencing /that/ template can't be simplified either because type units might cause a different template to be picked up that would conflict with the expected name. (other than for roundtripping precision, it'd be OK to simplify types that reference types that reference lambdas - but best be consistent between the roundtrip/verify mode and the actual simplified template names mode) --- clang/lib/CodeGen/CGDebugInfo.cpp | 58 +++++++++++++++---- .../debug-info-simple-template-names.cpp | 8 ++- .../simplified_template_names.cpp | 1 + ...template_names_noncanonical_type_units.cpp | 40 +++++++++++++ 4 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names_noncanonical_type_units.cpp diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 1a9080604a79..cca5576aac07 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -4975,6 +4975,52 @@ llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls( return GVE; } +static bool ReferencesAnonymousEntity(ArrayRef<TemplateArgument> Args); +static bool ReferencesAnonymousEntity(RecordType *RT) { + // Unnamed classes/lambdas can't be reconstituted due to a lack of column + // info we produce in the DWARF, so we can't get Clang's full name back. + // But so long as it's not one of those, it doesn't matter if some sub-type + // of the record (a template parameter) can't be reconstituted - because the + // un-reconstitutable type itself will carry its own name. + const auto *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return false; + if (!RD->getIdentifier()) + return true; + auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD); + if (!TSpecial) + return false; + return ReferencesAnonymousEntity(TSpecial->getTemplateArgs().asArray()); +} +static bool ReferencesAnonymousEntity(ArrayRef<TemplateArgument> Args) { + return llvm::any_of(Args, [&](const TemplateArgument &TA) { + switch (TA.getKind()) { + case TemplateArgument::Pack: + return ReferencesAnonymousEntity(TA.getPackAsArray()); + case TemplateArgument::Type: { + struct ReferencesAnonymous + : public RecursiveASTVisitor<ReferencesAnonymous> { + bool ReferencesAnonymous = false; + bool VisitRecordType(RecordType *RT) { + if (ReferencesAnonymousEntity(RT)) { + ReferencesAnonymous = true; + return false; + } + return true; + } + }; + ReferencesAnonymous RT; + RT.TraverseType(TA.getAsType()); + if (RT.ReferencesAnonymous) + return true; + break; + } + default: + break; + } + return false; + }); +} namespace { struct ReconstitutableType : public RecursiveASTVisitor<ReconstitutableType> { bool Reconstitutable = true; @@ -5002,16 +5048,8 @@ struct ReconstitutableType : public RecursiveASTVisitor<ReconstitutableType> { Reconstitutable &= !isNoexceptExceptionSpec(FT->getExceptionSpecType()); return Reconstitutable; } - bool TraverseRecordType(RecordType *RT) { - // Unnamed classes/lambdas can't be reconstituted due to a lack of column - // info we produce in the DWARF, so we can't get Clang's full name back. - // But so long as it's not one of those, it doesn't matter if some sub-type - // of the record (a template parameter) can't be reconstituted - because the - // un-reconstitutable type itself will carry its own name. - const auto *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); - if (!RD) - return true; - if (RD->isLambda() || !RD->getIdentifier()) { + bool VisitRecordType(RecordType *RT) { + if (ReferencesAnonymousEntity(RT)) { Reconstitutable = false; return false; } diff --git a/clang/test/CodeGenCXX/debug-info-simple-template-names.cpp b/clang/test/CodeGenCXX/debug-info-simple-template-names.cpp index 73a8f49967a7..344bd93020f6 100644 --- a/clang/test/CodeGenCXX/debug-info-simple-template-names.cpp +++ b/clang/test/CodeGenCXX/debug-info-simple-template-names.cpp @@ -48,9 +48,11 @@ void f() { // since we don't emit the column number. Also lambdas and unnamed classes are // ambiguous with each other - there's no DWARF that designates a lambda as // anything other than another unnamed class/struct. - auto A = [] {}; - f1<decltype(A)>(); - // CHECK: !DISubprogram(name: "f1<(lambda at {{.*}}debug-info-simple-template-names.cpp:[[# @LINE - 2]]:12)>", + auto Lambda = [] {}; + f1<decltype(Lambda)>(); + // CHECK: !DISubprogram(name: "f1<(lambda at {{.*}}debug-info-simple-template-names.cpp:[[# @LINE - 2]]:17)>", + f1<t1<t1<decltype(Lambda)>>>(); + // CHECK: !DISubprogram(name: "f1<t1<t1<(lambda at {{.*}}> > >", struct { } unnamed_struct; f1<decltype(unnamed_struct)>(); 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 index 61ac76db832c..d608039959df 100644 --- 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 @@ -216,6 +216,7 @@ int main() { f1<t3<t3<int>>>(); f1<decltype(L)>(); t3<decltype(L)> v1; + f1<t3<t3<decltype(L)>>>(); f1<int(float)>(); f1<void(...)>(); f1<void(int, ...)>(); diff --git a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names_noncanonical_type_units.cpp b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names_noncanonical_type_units.cpp new file mode 100644 index 000000000000..65c6bba6746f --- /dev/null +++ b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/simplified_template_names_noncanonical_type_units.cpp @@ -0,0 +1,40 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: mkdir %t/incl +// RUN: mv %t/header.h %t/incl/header.h +// RUN: cd %t +// RUN: %clang %target_itanium_abi_host_triple -g -o %t/a.out \ +// RUN: -Xclang -gsimple-template-names=mangled \ +// RUN: -Xclang -debug-forward-template-params \ +// RUN: -std=c++20 -fdebug-types-section -I incl a.cpp b.cpp +// RUN: llvm-dwarfdump --verify %t/a.out + +//--- header.h +template <typename T> struct t1 {}; +inline auto f1() { + auto T = [] {}; + t1<decltype(T)> v; + return v; +} +inline auto f2() { + struct { + } T; + t1<decltype(T)> v; + return v; +} +void a(); +//--- a.cpp +#include "incl/header.h" +template <typename T> void ft() {} +void a() { + ft<decltype(f1())>(); + ft<decltype(f2())>(); +} +//--- b.cpp +#include "header.h" +template <typename T> void ft() {} +int main() { + a(); + ft<decltype(f1())>(); + ft<decltype(f2())>(); +} -- GitLab