https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/168533
>From b831720a3e0a8b6d100a0e04f330228f2a0caf3e Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Fri, 14 Nov 2025 16:28:19 +0000 Subject: [PATCH 1/3] [clang][TypePrinter] Add CanonicalAnonymousLambdaName --- clang/include/clang/AST/Decl.h | 5 +++-- clang/include/clang/AST/PrettyPrinter.h | 8 +++++++- clang/lib/AST/Decl.cpp | 8 +++++--- clang/lib/AST/TypePrinter.cpp | 23 +++++++++++++++++------ 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index ee2321dd158d4..9254101d37939 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -357,9 +357,10 @@ class NamedDecl : public Decl { /// including the '::' at the end. E.g. /// when `printQualifiedName(D)` prints "A::B::i", /// this function prints "A::B::". - void printNestedNameSpecifier(raw_ostream &OS) const; void printNestedNameSpecifier(raw_ostream &OS, - const PrintingPolicy &Policy) const; + bool AllowFunctionContext = false) const; + void printNestedNameSpecifier(raw_ostream &OS, const PrintingPolicy &Policy, + bool AllowFunctionContext = false) const; // FIXME: Remove string version. std::string getQualifiedNameAsString() const; diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index fd995a653d167..9bb6a7f203cf5 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -79,7 +79,8 @@ struct PrintingPolicy { PrintAsCanonical(false), PrintInjectedClassNameWithArguments(true), UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false), CleanUglifiedParameters(false), EntireContentsOfLargeArray(true), - UseEnumerators(true), UseHLSLTypes(LO.HLSL) {} + UseEnumerators(true), UseHLSLTypes(LO.HLSL), + CanonicalAnonymousLambdaName(false) {} /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -346,6 +347,11 @@ struct PrintingPolicy { LLVM_PREFERRED_TYPE(bool) unsigned UseHLSLTypes : 1; + // TODO: this shouldn't be specific to unnamed lambdas, but also unnamed + // structures/unions/enums (?) + LLVM_PREFERRED_TYPE(bool) + unsigned CanonicalAnonymousLambdaName : 1; + /// Callbacks to use to allow the behavior of printing to be customized. const PrintingCallbacks *Callbacks = nullptr; }; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 555aa5c050ffd..ee1ff41b937c8 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1711,12 +1711,14 @@ void NamedDecl::printQualifiedName(raw_ostream &OS, } } -void NamedDecl::printNestedNameSpecifier(raw_ostream &OS) const { +void NamedDecl::printNestedNameSpecifier(raw_ostream &OS, + bool AllowFunctionContext) const { printNestedNameSpecifier(OS, getASTContext().getPrintingPolicy()); } void NamedDecl::printNestedNameSpecifier(raw_ostream &OS, - const PrintingPolicy &P) const { + const PrintingPolicy &P, + bool AllowFunctionContext) const { const DeclContext *Ctx = getDeclContext(); // For ObjC methods and properties, look through categories and use the @@ -1733,7 +1735,7 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS, Ctx = CI; } - if (Ctx->isFunctionOrMethod()) + if (Ctx->isFunctionOrMethod() && !AllowFunctionContext) return; using ContextsTy = SmallVector<const DeclContext *, 8>; diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index d2881d5ac518a..ed50fe71e0537 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1532,16 +1532,23 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { OS << ' '; } + const IdentifierInfo *II = D->getIdentifier(); + const bool IsLambda = + isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda(); + const bool PrintingCanonicalLambdaName = + !II && IsLambda && Policy.CanonicalAnonymousLambdaName; + if (!Policy.FullyQualifiedName && !T->isCanonicalUnqualified()) { T->getQualifier().print(OS, Policy); } else if (!Policy.SuppressScope) { // Compute the full nested-name-specifier for this type. // In C, this will always be empty except when the type // being printed is anonymous within other Record. - D->printNestedNameSpecifier(OS, Policy); + D->printNestedNameSpecifier( + OS, Policy, /*AllowFunctionContext=*/PrintingCanonicalLambdaName); } - if (const IdentifierInfo *II = D->getIdentifier()) + if (II) OS << II->getName(); else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) { assert(Typedef->getIdentifier() && "Typedef without identifier?"); @@ -1549,12 +1556,15 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { } else { // Make an unambiguous representation for anonymous types, e.g. // (anonymous enum at /usr/include/string.h:120:9) - OS << (Policy.MSVCFormatting ? '`' : '('); + const bool AddParen = !PrintingCanonicalLambdaName || Policy.AnonymousTagLocations; + if (AddParen) + OS << (Policy.MSVCFormatting ? '`' : '('); - if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) { + if (IsLambda) { OS << "lambda"; HasKindDecoration = true; - } else if ((isa<RecordDecl>(D) && cast<RecordDecl>(D)->isAnonymousStructOrUnion())) { + } else if ((isa<RecordDecl>(D) && + cast<RecordDecl>(D)->isAnonymousStructOrUnion())) { OS << "anonymous"; } else { OS << "unnamed"; @@ -1589,7 +1599,8 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { } } - OS << (Policy.MSVCFormatting ? '\'' : ')'); + if (AddParen) + OS << (Policy.MSVCFormatting ? '\'' : ')'); } // If this is a class template specialization, print the template >From 8dc734a54d8cf770d2206ab4e99f05440de203b0 Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Fri, 14 Nov 2025 16:28:39 +0000 Subject: [PATCH 2/3] [clang][DebugInfo] Canonical lambda names in debug-info --- clang/lib/AST/TypePrinter.cpp | 7 +++++-- clang/lib/CodeGen/CGDebugInfo.cpp | 1 + clang/test/DebugInfo/CXX/prefix-map-lambda.cpp | 10 ---------- clang/test/DebugInfo/CXX/simple-template-names.cpp | 4 ++-- .../DebugInfo/Generic/Inputs/debug-info-slash.cpp | 2 -- .../test/DebugInfo/Generic/Inputs/debug-info-slash.h | 6 ------ clang/test/DebugInfo/Generic/debug-prefix-map.cpp | 11 ----------- clang/test/DebugInfo/Generic/slash.test | 10 ---------- 8 files changed, 8 insertions(+), 43 deletions(-) delete mode 100644 clang/test/DebugInfo/CXX/prefix-map-lambda.cpp delete mode 100644 clang/test/DebugInfo/Generic/Inputs/debug-info-slash.cpp delete mode 100644 clang/test/DebugInfo/Generic/Inputs/debug-info-slash.h delete mode 100644 clang/test/DebugInfo/Generic/debug-prefix-map.cpp delete mode 100644 clang/test/DebugInfo/Generic/slash.test diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index ed50fe71e0537..ec65a7d6f438d 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1556,12 +1556,15 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { } else { // Make an unambiguous representation for anonymous types, e.g. // (anonymous enum at /usr/include/string.h:120:9) - const bool AddParen = !PrintingCanonicalLambdaName || Policy.AnonymousTagLocations; + const bool AddParen = !PrintingCanonicalLambdaName; if (AddParen) OS << (Policy.MSVCFormatting ? '`' : '('); if (IsLambda) { OS << "lambda"; + if (PrintingCanonicalLambdaName) + OS << D->getASTContext().getManglingNumber(D); + HasKindDecoration = true; } else if ((isa<RecordDecl>(D) && cast<RecordDecl>(D)->isAnonymousStructOrUnion())) { @@ -1570,7 +1573,7 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { OS << "unnamed"; } - if (Policy.AnonymousTagLocations) { + if (Policy.AnonymousTagLocations && !PrintingCanonicalLambdaName) { // Suppress the redundant tag keyword if we just printed one. // We don't have to worry about ElaboratedTypes here because you can't // refer to an anonymous type with one. diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 1489b5116e6ce..15d8d26d3a87a 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -422,6 +422,7 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const { PP.UsePreferredNames = false; PP.AlwaysIncludeTypeForTemplateArgument = true; PP.UseEnumerators = false; + PP.CanonicalAnonymousLambdaName = true; // Apply -fdebug-prefix-map. PP.Callbacks = &PrintCB; diff --git a/clang/test/DebugInfo/CXX/prefix-map-lambda.cpp b/clang/test/DebugInfo/CXX/prefix-map-lambda.cpp deleted file mode 100644 index f0fb1a312c8be..0000000000000 --- a/clang/test/DebugInfo/CXX/prefix-map-lambda.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple \ -// RUN: -fdebug-prefix-map=%S=/SOURCE_ROOT %s -emit-llvm -o - | FileCheck %s - -template <typename T> void b(T) {} -void c() { - // CHECK: !DISubprogram(name: "b<(lambda at - // CHECK-SAME: SOURCE_ROOT - // CHECK-SAME: [[@LINE+1]]:{{[0-9]+}})>" - b([]{}); -} diff --git a/clang/test/DebugInfo/CXX/simple-template-names.cpp b/clang/test/DebugInfo/CXX/simple-template-names.cpp index 3c8ff2780b66a..c6d21fc656709 100644 --- a/clang/test/DebugInfo/CXX/simple-template-names.cpp +++ b/clang/test/DebugInfo/CXX/simple-template-names.cpp @@ -70,9 +70,9 @@ void f() { // anything other than another unnamed class/struct. auto Lambda = [] {}; f1<decltype(Lambda)>(); - // CHECK: !DISubprogram(name: "f1<(lambda at {{.*}}simple-template-names.cpp:[[# @LINE - 2]]:17)>", + // CHECK: !DISubprogram(name: "f1<f()::lambda1>", f1<t1<t1<decltype(Lambda)>>>(); - // CHECK: !DISubprogram(name: "f1<t1<t1<(lambda at {{.*}}> > >", + // CHECK: !DISubprogram(name: "f1<t1<t1<f()::lambda1> > >", struct { } unnamed_struct; f1<decltype(unnamed_struct)>(); diff --git a/clang/test/DebugInfo/Generic/Inputs/debug-info-slash.cpp b/clang/test/DebugInfo/Generic/Inputs/debug-info-slash.cpp deleted file mode 100644 index 563077ed342a1..0000000000000 --- a/clang/test/DebugInfo/Generic/Inputs/debug-info-slash.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "Inputs/debug-info-slash.h" -int main() { a(); return 0; } diff --git a/clang/test/DebugInfo/Generic/Inputs/debug-info-slash.h b/clang/test/DebugInfo/Generic/Inputs/debug-info-slash.h deleted file mode 100644 index 9092f4a5e8170..0000000000000 --- a/clang/test/DebugInfo/Generic/Inputs/debug-info-slash.h +++ /dev/null @@ -1,6 +0,0 @@ -template <typename... T> -void f1() {} -void a() { - auto Lambda = [] {}; - f1<decltype(Lambda)>(); -} diff --git a/clang/test/DebugInfo/Generic/debug-prefix-map.cpp b/clang/test/DebugInfo/Generic/debug-prefix-map.cpp deleted file mode 100644 index 174bef5a07699..0000000000000 --- a/clang/test/DebugInfo/Generic/debug-prefix-map.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=./UNLIKELY_PATH/empty %s -emit-llvm -o - | FileCheck %s - -struct alignas(64) an { - struct { - unsigned char x{0}; - } arr[64]; -}; - -struct an *pan = new an; - -// CHECK: !DISubprogram(name: "(unnamed struct at ./UNLIKELY_PATH/empty{{/|\\\\}}{{.*}}", diff --git a/clang/test/DebugInfo/Generic/slash.test b/clang/test/DebugInfo/Generic/slash.test deleted file mode 100644 index 0e42912c18d21..0000000000000 --- a/clang/test/DebugInfo/Generic/slash.test +++ /dev/null @@ -1,10 +0,0 @@ -RUN: rm -rf %t-dir -RUN: mkdir -p %t-dir/header/Inputs -RUN: cp %S/Inputs/debug-info-slash.cpp %t-dir/ -RUN: cp %S/Inputs/debug-info-slash.h %t-dir/header/Inputs -RUN: cd %t-dir -RUN: %clang -target x86_64-pc-win32 -emit-llvm -S -g %t-dir/debug-info-slash.cpp -Iheader -o - | FileCheck --check-prefix=WIN %s -RUN: %clang -target x86_64-linux-gnu -emit-llvm -S -g %t-dir/debug-info-slash.cpp -Iheader -o - | FileCheck --check-prefix=LINUX %s - -WIN: lambda at header\\Inputs\\debug-info-slash.h -LINUX: lambda at header/Inputs/debug-info-slash.h >From 6fd0246d91333e484e814dd9492bd796892f2b76 Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Fri, 14 Nov 2025 17:28:48 +0000 Subject: [PATCH 3/3] [clang][DebugInfo] Treat unnamed records the same as lambdas --- clang/include/clang/AST/PrettyPrinter.h | 6 ++-- clang/lib/AST/TypePrinter.cpp | 35 ++++++++----------- clang/lib/CodeGen/CGDebugInfo.cpp | 2 +- .../DebugInfo/CXX/simple-template-names.cpp | 12 +++---- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index 9bb6a7f203cf5..4c5a34b90fc72 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -80,7 +80,7 @@ struct PrintingPolicy { UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false), CleanUglifiedParameters(false), EntireContentsOfLargeArray(true), UseEnumerators(true), UseHLSLTypes(LO.HLSL), - CanonicalAnonymousLambdaName(false) {} + CanonicalAnonymousEntities(false) {} /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -347,10 +347,8 @@ struct PrintingPolicy { LLVM_PREFERRED_TYPE(bool) unsigned UseHLSLTypes : 1; - // TODO: this shouldn't be specific to unnamed lambdas, but also unnamed - // structures/unions/enums (?) LLVM_PREFERRED_TYPE(bool) - unsigned CanonicalAnonymousLambdaName : 1; + unsigned CanonicalAnonymousEntities : 1; /// Callbacks to use to allow the behavior of printing to be customized. const PrintingCallbacks *Callbacks = nullptr; diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index ec65a7d6f438d..eeb565b921fad 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1533,10 +1533,8 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { } const IdentifierInfo *II = D->getIdentifier(); - const bool IsLambda = - isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda(); - const bool PrintingCanonicalLambdaName = - !II && IsLambda && Policy.CanonicalAnonymousLambdaName; + const bool PrintingCanonicalAnonName = + !II && Policy.CanonicalAnonymousEntities; if (!Policy.FullyQualifiedName && !T->isCanonicalUnqualified()) { T->getQualifier().print(OS, Policy); @@ -1545,7 +1543,7 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { // In C, this will always be empty except when the type // being printed is anonymous within other Record. D->printNestedNameSpecifier( - OS, Policy, /*AllowFunctionContext=*/PrintingCanonicalLambdaName); + OS, Policy, /*AllowFunctionContext=*/PrintingCanonicalAnonName); } if (II) @@ -1556,15 +1554,10 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { } else { // Make an unambiguous representation for anonymous types, e.g. // (anonymous enum at /usr/include/string.h:120:9) - const bool AddParen = !PrintingCanonicalLambdaName; - if (AddParen) - OS << (Policy.MSVCFormatting ? '`' : '('); + OS << (Policy.MSVCFormatting ? '`' : '('); - if (IsLambda) { + if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) { OS << "lambda"; - if (PrintingCanonicalLambdaName) - OS << D->getASTContext().getManglingNumber(D); - HasKindDecoration = true; } else if ((isa<RecordDecl>(D) && cast<RecordDecl>(D)->isAnonymousStructOrUnion())) { @@ -1573,13 +1566,16 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { OS << "unnamed"; } - if (Policy.AnonymousTagLocations && !PrintingCanonicalLambdaName) { - // Suppress the redundant tag keyword if we just printed one. - // We don't have to worry about ElaboratedTypes here because you can't - // refer to an anonymous type with one. - if (!HasKindDecoration) - OS << " " << D->getKindName(); + if (PrintingCanonicalAnonName) + OS << D->getASTContext().getManglingNumber(D); + + // Suppress the redundant tag keyword if we just printed one. + // We don't have to worry about ElaboratedTypes here because you can't + // refer to an anonymous type with one. + if (!HasKindDecoration) + OS << " " << D->getKindName(); + if (Policy.AnonymousTagLocations && !PrintingCanonicalAnonName) { PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc( D->getLocation()); if (PLoc.isValid()) { @@ -1602,8 +1598,7 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { } } - if (AddParen) - OS << (Policy.MSVCFormatting ? '\'' : ')'); + OS << (Policy.MSVCFormatting ? '\'' : ')'); } // If this is a class template specialization, print the template diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 15d8d26d3a87a..2851f1c7a5049 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -422,7 +422,7 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const { PP.UsePreferredNames = false; PP.AlwaysIncludeTypeForTemplateArgument = true; PP.UseEnumerators = false; - PP.CanonicalAnonymousLambdaName = true; + PP.CanonicalAnonymousEntities = true; // Apply -fdebug-prefix-map. PP.Callbacks = &PrintCB; diff --git a/clang/test/DebugInfo/CXX/simple-template-names.cpp b/clang/test/DebugInfo/CXX/simple-template-names.cpp index c6d21fc656709..9021bed07be6e 100644 --- a/clang/test/DebugInfo/CXX/simple-template-names.cpp +++ b/clang/test/DebugInfo/CXX/simple-template-names.cpp @@ -70,18 +70,18 @@ void f() { // anything other than another unnamed class/struct. auto Lambda = [] {}; f1<decltype(Lambda)>(); - // CHECK: !DISubprogram(name: "f1<f()::lambda1>", + // CHECK: !DISubprogram(name: "f1<f()::(lambda1)>", f1<t1<t1<decltype(Lambda)>>>(); - // CHECK: !DISubprogram(name: "f1<t1<t1<f()::lambda1> > >", + // CHECK: !DISubprogram(name: "f1<t1<t1<f()::(lambda1)> > >", struct { } unnamed_struct; f1<decltype(unnamed_struct)>(); - // CHECK: !DISubprogram(name: "f1<(unnamed struct at {{.*}}simple-template-names.cpp:[[# @LINE - 3]]:3)>", + // CHECK: !DISubprogram(name: "f1<f()::(unnamed1 struct)>", f1<void (decltype(unnamed_struct))>(); - // CHECK: !DISubprogram(name: "f1<void ((unnamed struct at {{.*}}simple-template-names.cpp:[[# @LINE - 5]]:3))>", + // CHECK: !DISubprogram(name: "f1<void (f()::(unnamed1 struct))>", enum {} unnamed_enum; f1<decltype(unnamed_enum)>(); - // CHECK: !DISubprogram(name: "f1<(unnamed enum at {{.*}}simple-template-names.cpp:[[# @LINE - 2]]:3)>", + // CHECK: !DISubprogram(name: "f1<f()::(unnamed1 enum)>", // Declarations can't readily be reversed as the value in the DWARF only // contains the address of the value - we'd have to do symbol lookup to find @@ -144,5 +144,5 @@ void f() { // CHECK: !DISubprogram(name: "f1<int () __attribute__((noreturn))>", f4<UnnamedEnum1>(); - // CHECK: !DISubprogram(name: "f4<((unnamed enum at {{.*}}))0>" + // CHECK: !DISubprogram(name: "f4<((unnamed1 enum))0>" } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
