[clang] [clang-tools-extra] [WIP] [clang][DebugInfo] Use mangling number and scope to create unambiguous names for anonymous structures (PR #168533)
Michael Buch via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 17 02:25:30 PST 2026
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/168533
>From b92ba6de4c63f699c66b35f0c7a8d9f14319d9c2 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 16 Feb 2026 16:09:27 +0000
Subject: [PATCH 1/3] [clang][TypePrinter] Introduce AnonymousTagMode enum
---
clang-tools-extra/clangd/AST.cpp | 3 ++-
clang-tools-extra/clangd/FindSymbols.cpp | 3 ++-
clang-tools-extra/clangd/Hover.cpp | 3 ++-
clang-tools-extra/clangd/InlayHints.cpp | 4 ++--
clang/include/clang/AST/PrettyPrinter.h | 21 ++++++++++++-------
clang/lib/AST/Decl.cpp | 7 +++++--
clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 3 ++-
clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | 6 ++++--
clang/lib/Index/USRGeneration.cpp | 3 ++-
clang/lib/Interpreter/InterpreterUtils.cpp | 3 ++-
clang/lib/Sema/SemaChecking.cpp | 3 ++-
clang/lib/Sema/SemaCodeComplete.cpp | 3 ++-
clang/lib/Tooling/ASTDiff/ASTDiff.cpp | 3 ++-
clang/tools/libclang/CIndex.cpp | 11 ++++++++--
clang/unittests/AST/TypePrinterTest.cpp | 15 ++++++++-----
clang/unittests/Tooling/QualTypeNamesTest.cpp | 3 ++-
16 files changed, 64 insertions(+), 30 deletions(-)
diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index 3bcc89d360cdb..ccbf68af15ea7 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -215,7 +215,8 @@ std::string printQualifiedName(const NamedDecl &ND) {
Policy.SuppressScope = true;
// (unnamed struct), not (unnamed struct at /path/to/foo.cc:42:1).
// In clangd, context is usually available and paths are mostly noise.
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
ND.printQualifiedName(OS, Policy);
assert(!StringRef(QName).starts_with("::"));
return QName;
diff --git a/clang-tools-extra/clangd/FindSymbols.cpp b/clang-tools-extra/clangd/FindSymbols.cpp
index 243746056aed0..62a2cee6283b4 100644
--- a/clang-tools-extra/clangd/FindSymbols.cpp
+++ b/clang-tools-extra/clangd/FindSymbols.cpp
@@ -390,7 +390,8 @@ std::string getSymbolDetail(ASTContext &Ctx, const NamedDecl &ND) {
PrintingPolicy P(Ctx.getPrintingPolicy());
P.SuppressScope = true;
P.SuppressUnwrittenScope = true;
- P.AnonymousTagLocations = false;
+ P.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
P.PolishForDeclaration = true;
std::string Detail;
llvm::raw_string_ostream OS(Detail);
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index 3ce0d6258ea62..f47c105bdb107 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -70,7 +70,8 @@ namespace clangd {
namespace {
PrintingPolicy getPrintingPolicy(PrintingPolicy Base) {
- Base.AnonymousTagLocations = false;
+ Base.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
Base.TerseOutput = true;
Base.PolishForDeclaration = true;
Base.ConstantsAsWritten = true;
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 2290fbd98056d..749af4cc85c60 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -390,8 +390,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
MainFileBuf = Invalid ? StringRef{} : Buf;
TypeHintPolicy.SuppressScope = true; // keep type names short
- TypeHintPolicy.AnonymousTagLocations =
- false; // do not print lambda locations
+ TypeHintPolicy.AnonymousTagNameStyle = llvm::to_underlying(
+ PrintingPolicy::AnonymousTagMode::None); // do not print lambda location
// Not setting PrintCanonicalTypes for "auto" allows
// SuppressDefaultTemplateArgs (set by default) to have an effect.
diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h
index 1564204833e64..b6cd8ee70188d 100644
--- a/clang/include/clang/AST/PrettyPrinter.h
+++ b/clang/include/clang/AST/PrettyPrinter.h
@@ -58,6 +58,15 @@ class PrintingCallbacks {
struct PrintingPolicy {
enum class SuppressInlineNamespaceMode : uint8_t { None, Redundant, All };
+ enum class AnonymousTagMode : uint8_t {
+ None,
+
+ /// When printing an anonymous tag name, also print the location of that
+ /// entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just prints
+ /// "(anonymous)" for the name.
+ SourceLocation
+ };
+
/// Create a default printing policy for the specified language.
PrintingPolicy(const LangOptions &LO)
: Indentation(2), SuppressSpecifiers(false),
@@ -67,8 +76,9 @@ struct PrintingPolicy {
SuppressInlineNamespace(
llvm::to_underlying(SuppressInlineNamespaceMode::Redundant)),
SuppressInitializers(false), ConstantArraySizeAsWritten(false),
- AnonymousTagLocations(true), SuppressStrongLifetime(false),
- SuppressLifetimeQualifiers(false),
+ AnonymousTagNameStyle(
+ llvm::to_underlying(AnonymousTagMode::SourceLocation)),
+ SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
SuppressTemplateArgsInCXXConstructors(false),
SuppressDefaultTemplateArgs(true), Bool(LO.Bool),
Nullptr(LO.CPlusPlus11 || LO.C23), NullptrTypeInNamespace(LO.CPlusPlus),
@@ -196,11 +206,8 @@ struct PrintingPolicy {
LLVM_PREFERRED_TYPE(bool)
unsigned ConstantArraySizeAsWritten : 1;
- /// When printing an anonymous tag name, also print the location of that
- /// entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just prints
- /// "(anonymous)" for the name.
- LLVM_PREFERRED_TYPE(bool)
- unsigned AnonymousTagLocations : 1;
+ LLVM_PREFERRED_TYPE(AnonymousTagMode)
+ unsigned AnonymousTagNameStyle : 1;
/// When true, suppress printing of the __strong lifetime qualifier in ARC.
LLVM_PREFERRED_TYPE(bool)
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 66c625f41158a..d7d61e7e29a6f 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1800,7 +1800,8 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
// suppress tag in name
Copy.SuppressTagKeyword = true;
Copy.SuppressTagKeywordInAnonNames = false;
- Copy.AnonymousTagLocations = false;
+ Copy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
RD->printName(OS, Copy);
} else if (const auto *FD = dyn_cast<FunctionDecl>(DC)) {
const FunctionProtoType *FT = nullptr;
@@ -4994,7 +4995,9 @@ void TagDecl::printAnonymousTagDecl(llvm::raw_ostream &OS,
if (!SuppressTagKeywordInName)
OS << ' ' << getKindName();
- if (Policy.AnonymousTagLocations) {
+ if (Policy.AnonymousTagNameStyle ==
+ llvm::to_underlying(
+ PrintingPolicy::AnonymousTagMode::SourceLocation)) {
PresumedLoc PLoc =
getASTContext().getSourceManager().getPresumedLoc(getLocation());
if (PLoc.isValid()) {
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 5b84a33c86821..4aa3e34b3bc65 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -518,7 +518,8 @@ static StringRef getNodeName(const RecordDecl &Node,
llvm::raw_svector_ostream OS(Scratch);
PrintingPolicy Copy(Node.getASTContext().getPrintingPolicy());
- Copy.AnonymousTagLocations = false;
+ Copy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
Node.printName(OS, Copy);
return OS.str();
diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
index 6966d4097d64a..efe4e78afc304 100644
--- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -419,7 +419,8 @@ ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
// Do not include location in anonymous decls.
PrintingPolicy Policy = CI.getASTContext().getPrintingPolicy();
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
CI.getASTContext().setPrintingPolicy(Policy);
if (!CI.getFrontendOpts().ExtractAPIIgnoresFileList.empty()) {
@@ -522,7 +523,8 @@ WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI,
// Do not include location in anonymous decls.
PrintingPolicy Policy = CI.getASTContext().getPrintingPolicy();
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
CI.getASTContext().setPrintingPolicy(Policy);
if (!CI.getFrontendOpts().ExtractAPIIgnoresFileList.empty()) {
diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp
index 08835ea786997..1aeecad9bbd65 100644
--- a/clang/lib/Index/USRGeneration.cpp
+++ b/clang/lib/Index/USRGeneration.cpp
@@ -659,7 +659,8 @@ static void printQualifier(llvm::raw_ostream &Out, const LangOptions &LangOpts,
PO.SuppressTagKeyword = true;
PO.SuppressUnwrittenScope = true;
PO.ConstantArraySizeAsWritten = false;
- PO.AnonymousTagLocations = false;
+ PO.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
NNS.print(Out, PO);
}
diff --git a/clang/lib/Interpreter/InterpreterUtils.cpp b/clang/lib/Interpreter/InterpreterUtils.cpp
index a19f96c80b94f..ec80f891a060c 100644
--- a/clang/lib/Interpreter/InterpreterUtils.cpp
+++ b/clang/lib/Interpreter/InterpreterUtils.cpp
@@ -107,7 +107,8 @@ std::string GetFullTypeName(ASTContext &Ctx, QualType QT) {
QualType FQT = TypeName::getFullyQualifiedType(QT, Ctx);
PrintingPolicy Policy(Ctx.getPrintingPolicy());
Policy.SuppressScope = false;
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
return FQT.getAsString(Policy);
}
} // namespace clang
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 45006bfc11644..f48d272206930 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -493,7 +493,8 @@ struct BuiltinDumpStructGenerator {
BuiltinDumpStructGenerator(Sema &S, CallExpr *TheCall)
: S(S), TheCall(TheCall), ErrorTracker(S.getDiagnostics()),
Policy(S.Context.getPrintingPolicy()) {
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
}
Expr *makeOpaqueValueExpr(Expr *Inner) {
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 4a3559955ade3..d67b26c81bb09 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -2043,7 +2043,8 @@ static bool WantTypesInContext(SemaCodeCompletion::ParserCompletionContext CCC,
static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context,
const Preprocessor &PP) {
PrintingPolicy Policy = Sema::getPrintingPolicy(Context, PP);
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
Policy.SuppressStrongLifetime = true;
Policy.SuppressUnwrittenScope = true;
Policy.CleanUglifiedParameters = true;
diff --git a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
index d70a679cc8dd0..9481e5fcf15a2 100644
--- a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
+++ b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
@@ -260,7 +260,8 @@ struct PreorderVisitor : public RecursiveASTVisitor<PreorderVisitor> {
SyntaxTree::Impl::Impl(SyntaxTree *Parent, ASTContext &AST)
: Parent(Parent), AST(AST), TypePP(AST.getLangOpts()) {
- TypePP.AnonymousTagLocations = false;
+ TypePP.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
}
SyntaxTree::Impl::Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST)
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 15eec87652451..4c83f4ede59b0 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -5659,7 +5659,9 @@ clang_PrintingPolicy_getProperty(CXPrintingPolicy Policy,
case CXPrintingPolicy_ConstantArraySizeAsWritten:
return P->ConstantArraySizeAsWritten;
case CXPrintingPolicy_AnonymousTagLocations:
- return P->AnonymousTagLocations;
+ return P->AnonymousTagNameStyle ==
+ llvm::to_underlying(
+ PrintingPolicy::AnonymousTagMode::SourceLocation);
case CXPrintingPolicy_SuppressStrongLifetime:
return P->SuppressStrongLifetime;
case CXPrintingPolicy_SuppressLifetimeQualifiers:
@@ -5733,7 +5735,12 @@ void clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy,
P->ConstantArraySizeAsWritten = Value;
return;
case CXPrintingPolicy_AnonymousTagLocations:
- P->AnonymousTagLocations = Value;
+ if (Value)
+ P->AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::SourceLocation);
+ else
+ P->AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
return;
case CXPrintingPolicy_SuppressStrongLifetime:
P->SuppressStrongLifetime = Value;
diff --git a/clang/unittests/AST/TypePrinterTest.cpp b/clang/unittests/AST/TypePrinterTest.cpp
index de4cfa4074eba..e2f2c9e4fec70 100644
--- a/clang/unittests/AST/TypePrinterTest.cpp
+++ b/clang/unittests/AST/TypePrinterTest.cpp
@@ -315,14 +315,16 @@ TEST(TypePrinter, NestedNameSpecifiers) {
Code, {}, varDecl(hasName("imem"), hasType(qualType().bind("id"))),
"struct (unnamed)", [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = true;
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
}));
ASSERT_TRUE(PrintedTypeMatches(
Code, {}, varDecl(hasName("imem"), hasType(qualType().bind("id"))),
"struct (unnamed)", [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = false;
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
}));
// Further levels of nesting print the entire scope.
@@ -331,14 +333,16 @@ TEST(TypePrinter, NestedNameSpecifiers) {
"union level1()::Inner::Inner(int)::(unnamed struct)::(unnamed)",
[](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = true;
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
}));
ASSERT_TRUE(PrintedTypeMatches(
Code, {}, fieldDecl(hasName("u"), hasType(qualType().bind("id"))),
"union (unnamed)", [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = false;
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
}));
}
@@ -357,6 +361,7 @@ TEST(TypePrinter, NestedNameSpecifiersTypedef) {
Code, {}, fieldDecl(hasName("bar"), hasType(qualType().bind("id"))),
"struct foo::(anonymous struct)::(unnamed)", [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = true;
- Policy.AnonymousTagLocations = false;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::None);
}));
}
diff --git a/clang/unittests/Tooling/QualTypeNamesTest.cpp b/clang/unittests/Tooling/QualTypeNamesTest.cpp
index 3dfc94a9d27de..cb83d6e86cb23 100644
--- a/clang/unittests/Tooling/QualTypeNamesTest.cpp
+++ b/clang/unittests/Tooling/QualTypeNamesTest.cpp
@@ -22,7 +22,8 @@ struct TypeNameVisitor : TestVisitor {
if (ExpectedName != "") {
PrintingPolicy Policy(Context->getPrintingPolicy());
Policy.SuppressScope = false;
- Policy.AnonymousTagLocations = true;
+ Policy.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::SourceLocation);
Policy.PolishForDeclaration = true;
Policy.SuppressUnwrittenScope = true;
std::string ActualName = TypeName::getFullyQualifiedName(
>From 31a726a3cda7bdfd816b675d12b9eb614c960ebc Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 16 Feb 2026 16:23:08 +0000
Subject: [PATCH 2/3] [clang][TypePrinter] Helper to print tag locations
---
clang/include/clang/AST/Decl.h | 3 +++
clang/lib/AST/Decl.cpp | 48 ++++++++++++++++++----------------
2 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 5c46c912186c4..c3cd74a5b34db 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3774,6 +3774,9 @@ class TagDecl : public TypeDecl,
void printAnonymousTagDecl(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const;
+ void printAnonymousTagDeclLocation(llvm::raw_ostream &OS,
+ const PrintingPolicy &Policy) const;
+
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index d7d61e7e29a6f..8109dfb381458 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4961,6 +4961,30 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
}
}
+void TagDecl::printAnonymousTagDeclLocation(
+ llvm::raw_ostream &OS, const PrintingPolicy &Policy) const {
+ PresumedLoc PLoc =
+ getASTContext().getSourceManager().getPresumedLoc(getLocation());
+ if (!PLoc.isValid())
+ return;
+
+ OS << " at ";
+ StringRef File = PLoc.getFilename();
+ llvm::SmallString<1024> WrittenFile(File);
+ if (auto *Callbacks = Policy.Callbacks)
+ WrittenFile = Callbacks->remapPath(File);
+ // Fix inconsistent path separator created by
+ // clang::DirectoryLookup::LookupFile when the file path is relative
+ // path.
+ llvm::sys::path::Style Style =
+ llvm::sys::path::is_absolute(WrittenFile)
+ ? llvm::sys::path::Style::native
+ : (Policy.MSVCFormatting ? llvm::sys::path::Style::windows_backslash
+ : llvm::sys::path::Style::posix);
+ llvm::sys::path::native(WrittenFile, Style);
+ OS << WrittenFile << ':' << PLoc.getLine() << ':' << PLoc.getColumn();
+}
+
void TagDecl::printAnonymousTagDecl(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const {
if (TypedefNameDecl *Typedef = getTypedefNameForAnonDecl()) {
@@ -4997,28 +5021,8 @@ void TagDecl::printAnonymousTagDecl(llvm::raw_ostream &OS,
if (Policy.AnonymousTagNameStyle ==
llvm::to_underlying(
- PrintingPolicy::AnonymousTagMode::SourceLocation)) {
- PresumedLoc PLoc =
- getASTContext().getSourceManager().getPresumedLoc(getLocation());
- if (PLoc.isValid()) {
- OS << " at ";
- StringRef File = PLoc.getFilename();
- llvm::SmallString<1024> WrittenFile(File);
- if (auto *Callbacks = Policy.Callbacks)
- WrittenFile = Callbacks->remapPath(File);
- // Fix inconsistent path separator created by
- // clang::DirectoryLookup::LookupFile when the file path is relative
- // path.
- llvm::sys::path::Style Style =
- llvm::sys::path::is_absolute(WrittenFile)
- ? llvm::sys::path::Style::native
- : (Policy.MSVCFormatting
- ? llvm::sys::path::Style::windows_backslash
- : llvm::sys::path::Style::posix);
- llvm::sys::path::native(WrittenFile, Style);
- OS << WrittenFile << ':' << PLoc.getLine() << ':' << PLoc.getColumn();
- }
- }
+ PrintingPolicy::AnonymousTagMode::SourceLocation))
+ printAnonymousTagDeclLocation(OS, Policy);
OS << (Policy.MSVCFormatting ? '\'' : ')');
}
>From 06004d020a17cd06b97ca1c94332338e8b1a311c Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Fri, 14 Nov 2025 16:28:19 +0000
Subject: [PATCH 3/3] [clang][TypePrinter] Add AnonymousTagMode::CanonicalName
---
clang/include/clang/AST/Decl.h | 5 +++--
clang/include/clang/AST/PrettyPrinter.h | 6 ++++--
clang/lib/AST/Decl.cpp | 15 ++++++++++-----
clang/lib/AST/TypePrinter.cpp | 12 +++++++++---
clang/lib/CodeGen/CGDebugInfo.cpp | 4 ++++
clang/test/DebugInfo/CXX/prefix-map-lambda.cpp | 10 ----------
.../test/DebugInfo/CXX/simple-template-names.cpp | 12 ++++++------
.../DebugInfo/Generic/Inputs/debug-info-slash.cpp | 2 --
.../DebugInfo/Generic/Inputs/debug-info-slash.h | 6 ------
clang/test/DebugInfo/Generic/debug-prefix-map.cpp | 11 -----------
clang/test/DebugInfo/Generic/slash.test | 10 ----------
11 files changed, 36 insertions(+), 57 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/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index c3cd74a5b34db..4b869d9d2404a 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 b6cd8ee70188d..dd878b450c807 100644
--- a/clang/include/clang/AST/PrettyPrinter.h
+++ b/clang/include/clang/AST/PrettyPrinter.h
@@ -64,7 +64,9 @@ struct PrintingPolicy {
/// When printing an anonymous tag name, also print the location of that
/// entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just prints
/// "(anonymous)" for the name.
- SourceLocation
+ SourceLocation,
+
+ CanonicalName,
};
/// Create a default printing policy for the specified language.
@@ -207,7 +209,7 @@ struct PrintingPolicy {
unsigned ConstantArraySizeAsWritten : 1;
LLVM_PREFERRED_TYPE(AnonymousTagMode)
- unsigned AnonymousTagNameStyle : 1;
+ unsigned AnonymousTagNameStyle : 2;
/// When true, suppress printing of the __strong lifetime qualifier in ARC.
LLVM_PREFERRED_TYPE(bool)
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 8109dfb381458..5ae702fa6814e 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>;
@@ -5016,12 +5018,15 @@ void TagDecl::printAnonymousTagDecl(llvm::raw_ostream &OS,
OS << "unnamed";
}
+ if (Policy.AnonymousTagNameStyle ==
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::CanonicalName))
+ OS << getASTContext().getManglingNumber(this);
+
if (!SuppressTagKeywordInName)
OS << ' ' << getKindName();
if (Policy.AnonymousTagNameStyle ==
- llvm::to_underlying(
- PrintingPolicy::AnonymousTagMode::SourceLocation))
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::SourceLocation))
printAnonymousTagDeclLocation(OS, Policy);
OS << (Policy.MSVCFormatting ? '\'' : ')');
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 3a2f6a1486ddf..11c784ed5378f 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1533,20 +1533,26 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) {
}
}
+ const IdentifierInfo *II = D->getIdentifier();
+ const bool PrintingCanonicalAnonName =
+ !II &&
+ Policy.AnonymousTagNameStyle ==
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::CanonicalName);
+
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=*/PrintingCanonicalAnonName);
}
- if (const IdentifierInfo *II = D->getIdentifier())
+ if (II)
OS << II->getName();
else {
clang::PrintingPolicy Copy(Policy);
-
// Suppress the redundant tag keyword if we just printed one.
if (PrintedKindDecoration) {
Copy.SuppressTagKeywordInAnonNames = true;
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 5e452245ee627..580d93bc9b21c 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -27,6 +27,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/LambdaCapture.h"
+#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/VTableBuilder.h"
@@ -39,6 +40,7 @@
#include "clang/Lex/ModuleMap.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Constants.h"
@@ -430,6 +432,8 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const {
PP.UsePreferredNames = false;
PP.AlwaysIncludeTypeForTemplateArgument = true;
PP.UseEnumerators = false;
+ PP.AnonymousTagNameStyle =
+ llvm::to_underlying(PrintingPolicy::AnonymousTagMode::CanonicalName);
// 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 a682a087e1406..446d3ced99a26 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<(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)>();
- // 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
@@ -145,5 +145,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>"
}
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
More information about the cfe-commits
mailing list