diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 1a9080604a79f6d703ae74a0568bd6ee093df1b5..cca5576aac07289feef023d4842f28c3188c33e4 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 73a8f49967a76a95c87de058e71a7f980e648bc9..344bd93020f6fc348e8409ac35b1ab8d2dc64134 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 61ac76db832c0dc13ed19c46287788dd8cc809c4..d608039959dffd7f730e294dcc3447434468bae8 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 0000000000000000000000000000000000000000..65c6bba6746f4c35402beeff2a90ddfaedf90f2c --- /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())>(); +}