[clang] [clang-tools-extra] [clang][TypePrinter] Unify printing of anonymous/unnamed tag types (PR #169445)
Michael Buch via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 28 06:13:52 PST 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/169445
>From 34c5c5188bb898255bbc16ba4d4dc23c2c62fd37 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 25 Nov 2025 09:46:57 +0900
Subject: [PATCH 1/8] [clang][TypePrinter] Make printing of anonymous/unnamed
tag types consistent
In https://github.com/llvm/llvm-project/pull/168534 we made the `TypePrinter` re-use `printNestedNameSpecifier` for printing scopes. However, the way that the names of anonymous/unnamed get printed by the two are slightly inconsistent with each other.
`printNestedNameSpecifier` calls all `TagType`s without an identifer `(anonymous)`. On the other hand, `TypePrinter` prints them slightly more accurate (it differentiates anonymous vs. unnamed decls) and allows for some additional customization points. E.g., with `MSVCFormatting`, it will print `\`'` instead of `()`. `printNestedNameSpecifier` already accounts for `MSVCFormatting` for namespaces, but doesn't for `TagType`s. This inconsistency means that if an unnamed tag is printed as part of a scope it's displayed as `(anonymous struct)`, but if it's the entity being whose scope is being printed, then it shows as `(unnamed struct)`.
This patch moves the printing of anonymous/unnamed tags into a common helper and re-uses it from `TypePrinter` and `printNestedNameSpecifier`. We also do this from the AST matchers because they were aligned with how `printNestedNameSpecifier` represents the name.
I wasn't sure where to put the helper, so I just put it in `TypeBase.h` for now. Though I suspect there's a better home for it, possibly `DeclBase.h`?
---
clang/include/clang/AST/TypeBase.h | 4 +
clang/lib/AST/Decl.cpp | 5 +-
clang/lib/AST/TypePrinter.cpp | 106 ++++++++++--------
clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 10 +-
clang/unittests/AST/NamedDeclPrinterTest.cpp | 28 +++++
clang/unittests/AST/TypePrinterTest.cpp | 2 +-
.../ASTMatchers/ASTMatchersNarrowingTest.cpp | 33 +++++-
7 files changed, 133 insertions(+), 55 deletions(-)
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index f07861f50fe8c..2f27deda2cd66 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -7374,6 +7374,10 @@ bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
ArrayRef<TemplateArgument> Args,
unsigned Depth);
+void printAnonymousTagDecl(llvm::raw_ostream &OS, const TagDecl *D,
+ const PrintingPolicy &Policy,
+ bool PrintKindDecoration, bool PrintTagLocations);
+
/// Represents a qualified type name for which the type name is
/// dependent.
///
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 591457b1d66b4..c9bb414a9a1de 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -35,6 +35,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
+#include "clang/AST/TypeBase.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
@@ -1793,7 +1794,9 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
if (TypedefNameDecl *TD = RD->getTypedefNameForAnonDecl())
OS << *TD;
else if (!RD->getIdentifier())
- OS << "(anonymous " << RD->getKindName() << ')';
+ printAnonymousTagDecl(OS, llvm::cast<TagDecl>(RD), P,
+ /*PrintKindDecoration=*/true,
+ /*AllowSourceLocations=*/false);
else
OS << *RD;
} else if (const auto *FD = dyn_cast<FunctionDecl>(DC)) {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index d2881d5ac518a..93bd068ccee08 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
+#include "clang/AST/TypeBase.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/ExceptionSpecificationType.h"
@@ -1518,11 +1519,11 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) {
return;
}
- bool HasKindDecoration = false;
+ bool PrintKindDecoration = Policy.AnonymousTagLocations;
if (T->isCanonicalUnqualified()) {
if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) {
- HasKindDecoration = true;
+ PrintKindDecoration = false;
OS << D->getKindName();
OS << ' ';
}
@@ -1546,51 +1547,10 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) {
else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) {
assert(Typedef->getIdentifier() && "Typedef without identifier?");
OS << Typedef->getIdentifier()->getName();
- } else {
- // Make an unambiguous representation for anonymous types, e.g.
- // (anonymous enum at /usr/include/string.h:120:9)
- OS << (Policy.MSVCFormatting ? '`' : '(');
-
- if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) {
- OS << "lambda";
- HasKindDecoration = true;
- } else if ((isa<RecordDecl>(D) && cast<RecordDecl>(D)->isAnonymousStructOrUnion())) {
- OS << "anonymous";
- } else {
- OS << "unnamed";
- }
-
- if (Policy.AnonymousTagLocations) {
- // 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();
-
- PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc(
- D->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();
- }
- }
-
- OS << (Policy.MSVCFormatting ? '\'' : ')');
- }
+ } else
+ printAnonymousTagDecl(OS, D, Policy,
+ /*PrintKindDecoration=*/PrintKindDecoration,
+ /*PrintTagLocations=*/Policy.AnonymousTagLocations);
// If this is a class template specialization, print the template
// arguments.
@@ -2469,6 +2429,58 @@ static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,
return false;
}
+void clang::printAnonymousTagDecl(llvm::raw_ostream &OS, const TagDecl *D,
+ const PrintingPolicy &Policy,
+ bool PrintKindDecoration,
+ bool PrintTagLocations) {
+ assert(D);
+
+ // Make an unambiguous representation for anonymous types, e.g.
+ // (anonymous enum at /usr/include/string.h:120:9)
+ OS << (Policy.MSVCFormatting ? '`' : '(');
+
+ if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) {
+ PrintKindDecoration = false;
+ OS << "lambda";
+ } else if ((isa<RecordDecl>(D) &&
+ cast<RecordDecl>(D)->isAnonymousStructOrUnion())) {
+ OS << "anonymous";
+ } else {
+ OS << "unnamed";
+ }
+
+ // 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 (PrintKindDecoration)
+ OS << " " << D->getKindName();
+
+ if (PrintTagLocations) {
+ PresumedLoc PLoc =
+ D->getASTContext().getSourceManager().getPresumedLoc(D->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();
+ }
+ }
+
+ OS << (Policy.MSVCFormatting ? '\'' : ')');
+}
+
bool clang::isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
const NamedDecl *Param,
ArrayRef<TemplateArgument> Args,
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 0874b3d0c45f5..e83a6e97ec638 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/TypeBase.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/LLVM.h"
#include "clang/Lex/Lexer.h"
@@ -514,7 +515,14 @@ static StringRef getNodeName(const RecordDecl &Node,
return Node.getName();
}
Scratch.clear();
- return ("(anonymous " + Node.getKindName() + ")").toStringRef(Scratch);
+
+ llvm::raw_svector_ostream OS(Scratch);
+
+ printAnonymousTagDecl(
+ OS, llvm::cast<TagDecl>(&Node), Node.getASTContext().getPrintingPolicy(),
+ /*PrintKindDecoration=*/true, /*PrintTagLocations=*/false);
+
+ return OS.str();
}
static StringRef getNodeName(const NamespaceDecl &Node,
diff --git a/clang/unittests/AST/NamedDeclPrinterTest.cpp b/clang/unittests/AST/NamedDeclPrinterTest.cpp
index cd833725b448d..2fdda1929b2a3 100644
--- a/clang/unittests/AST/NamedDeclPrinterTest.cpp
+++ b/clang/unittests/AST/NamedDeclPrinterTest.cpp
@@ -265,3 +265,31 @@ TEST(NamedDeclPrinter, NestedNameSpecifierTemplateArgs) {
ASSERT_TRUE(
PrintedNestedNameSpecifierMatches(Code, "method", "vector<int>::"));
}
+
+TEST(NamedDeclPrinter, NestedNameSpecifierLambda) {
+ const char *Code =
+ R"(
+ auto l = [] {
+ struct Foo {
+ void method();
+ };
+ };
+)";
+ ASSERT_TRUE(PrintedNestedNameSpecifierMatches(
+ Code, "method", "(lambda)::operator()()::Foo::"));
+}
+
+TEST(NamedDeclPrinter, NestedNameSpecifierAnonymousTags) {
+ const char *Code =
+ R"(
+ struct Foo {
+ struct {
+ struct {
+ void method();
+ } i;
+ };
+ };
+)";
+ ASSERT_TRUE(PrintedNestedNameSpecifierMatches(
+ Code, "method", "Foo::(anonymous)::(unnamed)::"));
+}
diff --git a/clang/unittests/AST/TypePrinterTest.cpp b/clang/unittests/AST/TypePrinterTest.cpp
index 3cadf9b265bd1..de4cfa4074eba 100644
--- a/clang/unittests/AST/TypePrinterTest.cpp
+++ b/clang/unittests/AST/TypePrinterTest.cpp
@@ -328,7 +328,7 @@ TEST(TypePrinter, NestedNameSpecifiers) {
// Further levels of nesting print the entire scope.
ASSERT_TRUE(PrintedTypeMatches(
Code, {}, fieldDecl(hasName("u"), hasType(qualType().bind("id"))),
- "union level1()::Inner::Inner(int)::(anonymous struct)::(unnamed)",
+ "union level1()::Inner::Inner(int)::(unnamed struct)::(unnamed)",
[](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = true;
Policy.AnonymousTagLocations = false;
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 5d452355d0e43..697623c8a48e8 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2709,25 +2709,48 @@ TEST_P(ASTMatchersTest, HasName_MatchesAnonymousNamespaces) {
EXPECT_TRUE(matches(code, recordDecl(hasName("::a::C"))));
}
-TEST_P(ASTMatchersTest, HasName_MatchesAnonymousOuterClasses) {
+TEST_P(ASTMatchersTest, HasName_MatchesUnnamedOuterClasses) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(matches("class A { class { class C; } x; };",
- recordDecl(hasName("A::(anonymous class)::C"))));
+ recordDecl(hasName("A::(unnamed class)::C"))));
EXPECT_TRUE(matches("class A { class { class C; } x; };",
- recordDecl(hasName("::A::(anonymous class)::C"))));
+ recordDecl(hasName("::A::(unnamed class)::C"))));
EXPECT_FALSE(matches("class A { class { class C; } x; };",
recordDecl(hasName("::A::C"))));
EXPECT_TRUE(matches("class A { struct { class C; } x; };",
- recordDecl(hasName("A::(anonymous struct)::C"))));
+ recordDecl(hasName("A::(unnamed struct)::C"))));
EXPECT_TRUE(matches("class A { struct { class C; } x; };",
- recordDecl(hasName("::A::(anonymous struct)::C"))));
+ recordDecl(hasName("::A::(unnamed struct)::C"))));
EXPECT_FALSE(matches("class A { struct { class C; } x; };",
recordDecl(hasName("::A::C"))));
}
+TEST_P(ASTMatchersTest, HasName_MatchesAnonymousOuterClasses) {
+ if (!GetParam().isCXX()) {
+ return;
+ }
+
+ EXPECT_TRUE(matches(
+ "class A { struct { struct { class C; } x; }; };",
+ recordDecl(hasName("A::(anonymous struct)::(unnamed struct)::C"))));
+ EXPECT_TRUE(matches(
+ "class A { struct { struct { class C; } x; }; };",
+ recordDecl(hasName("::A::(anonymous struct)::(unnamed struct)::C"))));
+ EXPECT_FALSE(matches("class A { struct { struct { class C; } x; }; };",
+ recordDecl(hasName("A::(unnamed struct)::C"))));
+ EXPECT_TRUE(matches(
+ "class A { class { public: struct { class C; } x; }; };",
+ recordDecl(hasName("A::(anonymous class)::(unnamed struct)::C"))));
+ EXPECT_TRUE(matches(
+ "class A { class { public: struct { class C; } x; }; };",
+ recordDecl(hasName("::A::(anonymous class)::(unnamed struct)::C"))));
+ EXPECT_FALSE(matches("class A { class { public: struct { class C; } x; }; };",
+ recordDecl(hasName("A::(unnamed struct)::C"))));
+}
+
TEST_P(ASTMatchersTest, HasName_MatchesFunctionScope) {
if (!GetParam().isCXX()) {
return;
>From 65f11ed0c51516708e33aab27777edc07c5f1d0b Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 25 Nov 2025 12:55:37 +0900
Subject: [PATCH 2/8] fixup! fix test
---
clang/unittests/AST/NamedDeclPrinterTest.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/unittests/AST/NamedDeclPrinterTest.cpp b/clang/unittests/AST/NamedDeclPrinterTest.cpp
index 2fdda1929b2a3..599ccd7f06fc6 100644
--- a/clang/unittests/AST/NamedDeclPrinterTest.cpp
+++ b/clang/unittests/AST/NamedDeclPrinterTest.cpp
@@ -283,7 +283,8 @@ TEST(NamedDeclPrinter, NestedNameSpecifierAnonymousTags) {
const char *Code =
R"(
struct Foo {
- struct {
+ class {
+ public:
struct {
void method();
} i;
@@ -291,5 +292,5 @@ TEST(NamedDeclPrinter, NestedNameSpecifierAnonymousTags) {
};
)";
ASSERT_TRUE(PrintedNestedNameSpecifierMatches(
- Code, "method", "Foo::(anonymous)::(unnamed)::"));
+ Code, "method", "Foo::(anonymous class)::(unnamed struct)::"));
}
>From 8bf71d786ddf97016796209079d35238223cd09d Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 25 Nov 2025 13:40:48 +0900
Subject: [PATCH 3/8] fixup! fix more tests
---
clang/test/ASTMerge/struct/test.c | 4 ++--
.../Inputs/expected-plists/lambda-notes.cpp.plist | 2 +-
.../test/Analysis/analyzer-note-analysis-entry-points.cpp | 6 +++---
clang/test/Analysis/bug_hash_test.cpp | 2 +-
clang/test/Analysis/debug-CallGraph.cpp | 8 ++++----
.../inlining/Inputs/expected-plists/path-notes.cpp.plist | 2 +-
clang/test/CodeGenCXX/predefined-expr.cpp | 2 +-
clang/test/Index/print-type.c | 2 +-
clang/test/Layout/ms-x86-alias-avoidance-padding.cpp | 4 ++--
clang/test/SemaCXX/builtin-bswapg.cpp | 6 +++---
clang/test/SemaCXX/cxx2b-consteval-propagate.cpp | 2 +-
clang/test/SemaCXX/undefined-internal.cpp | 2 +-
12 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/clang/test/ASTMerge/struct/test.c b/clang/test/ASTMerge/struct/test.c
index d11234472ef29..fe500e6b1ba82 100644
--- a/clang/test/ASTMerge/struct/test.c
+++ b/clang/test/ASTMerge/struct/test.c
@@ -44,10 +44,10 @@
// CHECK: struct2.c:72:7: note: field 'i' has type 'int' here
// CHECK: struct2.c:76:5: warning: external variable 'x13' declared with incompatible types in different translation units ('S13' vs. 'S13')
// CHECK: struct1.c:79:5: note: declared here with type 'S13'
-// CHECK: struct1.c:130:7: warning: type 'struct DeepUnnamedError::(anonymous union)::(anonymous union)::(unnamed at [[PATH_TO_INPUTS:.+]]struct1.c:130:7)' has incompatible definitions in different translation units
+// CHECK: struct1.c:130:7: warning: type 'struct DeepUnnamedError::(unnamed union)::(unnamed union)::(unnamed at [[PATH_TO_INPUTS:.+]]struct1.c:130:7)' has incompatible definitions in different translation units
// CHECK: struct1.c:131:14: note: field 'i' has type 'long' here
// CHECK: struct2.c:128:15: note: field 'i' has type 'float' here
-// CHECK: struct1.c:129:5: warning: type 'union DeepUnnamedError::(anonymous union)::(unnamed at [[PATH_TO_INPUTS]]struct1.c:129:5)' has incompatible definitions in different translation units
+// CHECK: struct1.c:129:5: warning: type 'union DeepUnnamedError::(unnamed union)::(unnamed at [[PATH_TO_INPUTS]]struct1.c:129:5)' has incompatible definitions in different translation units
// CHECK: struct1.c:132:9: note: field 'S' has type 'struct (unnamed struct at [[PATH_TO_INPUTS]]struct1.c:130:7)' here
// CHECK: struct2.c:129:9: note: field 'S' has type 'struct (unnamed struct at [[PATH_TO_INPUTS]]struct2.c:127:7)' here
// CHECK: struct2.c:138:3: warning: external variable 'x16' declared with incompatible types in different translation units ('struct DeepUnnamedError' vs. 'struct DeepUnnamedError')
diff --git a/clang/test/Analysis/Inputs/expected-plists/lambda-notes.cpp.plist b/clang/test/Analysis/Inputs/expected-plists/lambda-notes.cpp.plist
index 5c7768cb97ef4..d5859dca9630b 100644
--- a/clang/test/Analysis/Inputs/expected-plists/lambda-notes.cpp.plist
+++ b/clang/test/Analysis/Inputs/expected-plists/lambda-notes.cpp.plist
@@ -174,7 +174,7 @@
<key>type</key><string>Division by zero</string>
<key>check_name</key><string>core.DivideZero</string>
<!-- This hash is experimental and going to change! -->
- <key>issue_hash_content_of_line_in_context</key><string>bd4eed3234018edced5efc2ed5562a74</string>
+ <key>issue_hash_content_of_line_in_context</key><string>d3cd158ad0fd8ce44df89c6779a1faec</string>
<key>issue_context_kind</key><string>C++ method</string>
<key>issue_context</key><string>operator()</string>
<key>issue_hash_function_offset</key><string>1</string>
diff --git a/clang/test/Analysis/analyzer-note-analysis-entry-points.cpp b/clang/test/Analysis/analyzer-note-analysis-entry-points.cpp
index 7d321bfae61c9..d0cf3a334e647 100644
--- a/clang/test/Analysis/analyzer-note-analysis-entry-points.cpp
+++ b/clang/test/Analysis/analyzer-note-analysis-entry-points.cpp
@@ -51,10 +51,10 @@ void checkASTCodeBodyHasAnalysisEntryPoints() {
}
void notInvokedLambdaScope() {
- // CHECK: note: [debug] analyzing from notInvokedLambdaScope()::(anonymous class)::operator()()
+ // CHECK: note: [debug] analyzing from notInvokedLambdaScope()::(lambda)::operator()()
// CHECK-NEXT: | auto notInvokedLambda = []() {
// CHECK-NEXT: | ^
- // textout-note at +1 {{[debug] analyzing from notInvokedLambdaScope()::(anonymous class)::operator()()}}
+ // textout-note at +1 {{[debug] analyzing from notInvokedLambdaScope()::(lambda)::operator()()}}
auto notInvokedLambda = []() {
// common-warning at +1 {{REACHABLE}} textout-note at +1 {{REACHABLE}}
clang_analyzer_warnIfReached();
@@ -72,4 +72,4 @@ void invokedLambdaScope() {
clang_analyzer_warnIfReached();
};
invokedLambda(); // textout-note {{Calling 'operator()'}}
-}
\ No newline at end of file
+}
diff --git a/clang/test/Analysis/bug_hash_test.cpp b/clang/test/Analysis/bug_hash_test.cpp
index 7b812a76558dd..184d3a9dce255 100644
--- a/clang/test/Analysis/bug_hash_test.cpp
+++ b/clang/test/Analysis/bug_hash_test.cpp
@@ -65,7 +65,7 @@ void AA::X::OutOfLine() {
void testLambda() {
[]() {
- clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void testLambda()::(anonymous class)::operator()() const$29$clang_analyzer_hashDump(5);$Category}}
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void testLambda()::(lambda)::operator()() const$29$clang_analyzer_hashDump(5);$Category}}
}();
}
diff --git a/clang/test/Analysis/debug-CallGraph.cpp b/clang/test/Analysis/debug-CallGraph.cpp
index 120bb38d3bb33..04d6e5f14f963 100644
--- a/clang/test/Analysis/debug-CallGraph.cpp
+++ b/clang/test/Analysis/debug-CallGraph.cpp
@@ -97,14 +97,14 @@ namespace CallDecl {
}
// CHECK:--- Call graph Dump ---
-// CHECK-NEXT: {{Function: < root > calls: get5 add test_add mmm foo aaa < > bbb ddd ccc eee fff do_nothing test_single_call SomeNS::templ SomeNS::templ SomeNS::templUser Lambdas::Callee Lambdas::f1 Lambdas::f1\(\)::\(anonymous class\)::operator\(\) Lambdas::f1\(\)::\(anonymous class\)::operator\(\) CallDecl::SomeDef CallDecl::Caller CallDecl::SomeDecl CallDecl::SomeOtherDecl $}}
+// CHECK-NEXT: {{Function: < root > calls: get5 add test_add mmm foo aaa < > bbb ddd ccc eee fff do_nothing test_single_call SomeNS::templ SomeNS::templ SomeNS::templUser Lambdas::Callee Lambdas::f1 Lambdas::f1\(\)::\(lambda\)::operator\(\) Lambdas::f1\(\)::\(lambda\)::operator\(\) CallDecl::SomeDef CallDecl::Caller CallDecl::SomeDecl CallDecl::SomeOtherDecl $}}
// CHECK-NEXT: {{Function: CallDecl::Caller calls: CallDecl::SomeDecl CallDecl::SomeOtherDecl $}}
// CHECK-NEXT: {{Function: CallDecl::SomeOtherDecl calls: CallDecl::SomeDef $}}
// CHECK-NEXT: {{Function: CallDecl::SomeDecl calls: $}}
// CHECK-NEXT: {{Function: CallDecl::SomeDef calls: $}}
-// CHECK-NEXT: {{Function: Lambdas::f1 calls: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) Lambdas::f1\(\)::\(anonymous class\)::operator\(\) $}}
-// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) calls: Lambdas::Callee $}}
-// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) calls: Lambdas::Callee $}}
+// CHECK-NEXT: {{Function: Lambdas::f1 calls: Lambdas::f1\(\)::\(lambda\)::operator\(\) Lambdas::f1\(\)::\(lambda\)::operator\(\) $}}
+// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(lambda\)::operator\(\) calls: Lambdas::Callee $}}
+// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(lambda\)::operator\(\) calls: Lambdas::Callee $}}
// CHECK-NEXT: {{Function: Lambdas::Callee calls: $}}
// CHECK-NEXT: {{Function: SomeNS::templUser calls: SomeNS::templ SomeNS::templ $}}
// CHECK-NEXT: {{Function: SomeNS::templ calls: eee $}}
diff --git a/clang/test/Analysis/inlining/Inputs/expected-plists/path-notes.cpp.plist b/clang/test/Analysis/inlining/Inputs/expected-plists/path-notes.cpp.plist
index 6215d48ebd2c8..62aaf0fe8e2d5 100644
--- a/clang/test/Analysis/inlining/Inputs/expected-plists/path-notes.cpp.plist
+++ b/clang/test/Analysis/inlining/Inputs/expected-plists/path-notes.cpp.plist
@@ -722,7 +722,7 @@
<key>type</key><string>Dereference of null pointer</string>
<key>check_name</key><string>core.NullDereference</string>
<!-- This hash is experimental and going to change! -->
- <key>issue_hash_content_of_line_in_context</key><string>efde323086a985fe1e8ccc6cd0123c12</string>
+ <key>issue_hash_content_of_line_in_context</key><string>c13b0c1fd27df0a9d9c0b4c125ade016</string>
<key>issue_context_kind</key><string>C++ method</string>
<key>issue_context</key><string>method</string>
<key>issue_hash_function_offset</key><string>1</string>
diff --git a/clang/test/CodeGenCXX/predefined-expr.cpp b/clang/test/CodeGenCXX/predefined-expr.cpp
index 815bcbb3bd899..48c1205d80d39 100644
--- a/clang/test/CodeGenCXX/predefined-expr.cpp
+++ b/clang/test/CodeGenCXX/predefined-expr.cpp
@@ -10,7 +10,7 @@
// CHECK-DAG: private unnamed_addr constant [103 x i8] c"static void ClassWithTemplateTemplateParam<char>::staticMember() [T = char, Param = NS::ClassTemplate]\00"
// CHECK-DAG: private unnamed_addr constant [106 x i8] c"void OuterClass<int *>::MiddleClass::InnerClass<float>::memberFunction(T, U) const [T = int *, U = float]\00"
// CHECK-DAG: private unnamed_addr constant [51 x i8] c"void functionTemplateWithCapturedStmt(T) [T = int]\00"
-// CHECK-DAG: private unnamed_addr constant [76 x i8] c"auto functionTemplateWithLambda(int)::(anonymous class)::operator()() const\00"
+// CHECK-DAG: private unnamed_addr constant [76 x i8] c"auto functionTemplateWithLambda(int)::(lambda)::operator()() const\00"
// CHECK-DAG: private unnamed_addr constant [65 x i8] c"void functionTemplateWithUnnamedTemplateParameter(T) [T = float]\00"
// CHECK-DAG: private unnamed_addr constant [60 x i8] c"void functionTemplateExplicitSpecialization(T) [T = double]\00"
diff --git a/clang/test/Index/print-type.c b/clang/test/Index/print-type.c
index 9fb85f8da4e66..3ceecbd90b250 100644
--- a/clang/test/Index/print-type.c
+++ b/clang/test/Index/print-type.c
@@ -71,7 +71,7 @@ _Atomic(unsigned long) aul;
// CHECK: TypeRef=struct Struct:16:8 [type=struct Struct] [typekind=Record] [isPOD=1]
// CHECK: StructDecl=struct (unnamed at {{.*}}):18:1 (Definition) [type=struct (unnamed at {{.*}}print-type.c:18:1)] [typekind=Record] [isPOD=1] [nbFields=2] [isAnon=1] [isAnonRecDecl=0]
// CHECK: StructDecl=struct (unnamed at {{.*}}):23:1 (Definition) [type=struct (unnamed at {{.*}}print-type.c:23:1)] [typekind=Record] [isPOD=1] [nbFields=1] [isAnon=1] [isAnonRecDecl=0]
-// CHECK: StructDecl=struct (anonymous at {{.*}}):24:3 (Definition) [type=struct (anonymous struct)::(anonymous at {{.*}}print-type.c:24:3)] [typekind=Record] [isPOD=1] [nbFields=2] [isAnon=1] [isAnonRecDecl=1]
+// CHECK: StructDecl=struct (anonymous at {{.*}}):24:3 (Definition) [type=struct (unnamed struct)::(anonymous at {{.*}}print-type.c:24:3)] [typekind=Record] [isPOD=1] [nbFields=2] [isAnon=1] [isAnonRecDecl=1]
// CHECK: FieldDecl=x:25:17 (Definition) [type=_Atomic(int)] [typekind=Atomic] [valuetype=int] [valuetypekind=Int] [isPOD=0] [isAnonRecDecl=0]
// CHECK: FieldDecl=y:26:9 (Definition) [type=int] [typekind=Int] [isPOD=1] [isAnonRecDecl=0]
// CHECK: StructDecl=struct (unnamed at {{.*}}):30:10 (Definition) [type=struct (unnamed at {{.*}}print-type.c:30:10)] [typekind=Record] [isPOD=1] [nbFields=2] [isAnon=1] [isAnonRecDecl=0]
diff --git a/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp b/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp
index bc6a56ef37538..a83810e28741b 100644
--- a/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp
+++ b/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp
@@ -49,7 +49,7 @@ struct AT3 : AT2, AT1 {
// CHECK-NEXT: 0 | struct AT2 (base)
// CHECK-NEXT: 0 | struct AT0 t
// CHECK-NEXT: 0 | union AT0::(unnamed at {{.*}} x
-// CHECK-NEXT: 0 | struct AT0::(anonymous union)::(unnamed at {{.*}} y
+// CHECK-NEXT: 0 | struct AT0::(unnamed union)::(unnamed at {{.*}} y
// CHECK-NEXT: 0 | int a
// CHECK-NEXT: 4 | struct AT t (empty)
// CHECK: 0 | int b
@@ -66,7 +66,7 @@ struct AT3 : AT2, AT1 {
// CHECK-X64-NEXT: 0 | struct AT2 (base)
// CHECK-X64-NEXT: 0 | struct AT0 t
// CHECK-X64-NEXT: 0 | union AT0::(unnamed at {{.*}} x
-// CHECK-X64-NEXT: 0 | struct AT0::(anonymous union)::(unnamed at {{.*}} y
+// CHECK-X64-NEXT: 0 | struct AT0::(unnamed union)::(unnamed at {{.*}} y
// CHECK-X64-NEXT: 0 | int a
// CHECK-X64-NEXT: 4 | struct AT t (empty)
// CHECK-X64: 0 | int b
diff --git a/clang/test/SemaCXX/builtin-bswapg.cpp b/clang/test/SemaCXX/builtin-bswapg.cpp
index 9d8d103e77c51..539390fa9b606 100644
--- a/clang/test/SemaCXX/builtin-bswapg.cpp
+++ b/clang/test/SemaCXX/builtin-bswapg.cpp
@@ -135,13 +135,13 @@ void test_lambda_errors() {
lambda(1.0f);
// expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'float')}}
- // expected-note at -2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()<float>' requested here}}
+ // expected-note at -2 {{in instantiation of function template specialization 'test_lambda_errors()::(lambda)::operator()<float>' requested here}}
lambda(1.0l);
// expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'long double')}}
- // expected-note at -2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()<long double>' requested here}}
+ // expected-note at -2 {{in instantiation of function template specialization 'test_lambda_errors()::(lambda)::operator()<long double>' requested here}}
lambda("hello");
// expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'const char *')}}
- // expected-note at -2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()<const char *>' requested here}}
+ // expected-note at -2 {{in instantiation of function template specialization 'test_lambda_errors()::(lambda)::operator()<const char *>' requested here}}
}
template <class... Args> void test_variadic_template_argument_count(Args... args) {
diff --git a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
index ff104243a9735..6da589dcf1b25 100644
--- a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
+++ b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
@@ -636,7 +636,7 @@ template <typename T>
struct scope_exit {
T t;
constexpr ~scope_exit() { t(); }
- // expected-error at -1 {{call to immediate function 'GH109096::(anonymous class)::operator()' is not a constant expression}} \
+ // expected-error at -1 {{call to immediate function 'GH109096::(lambda)::operator()' is not a constant expression}} \
// expected-note at -1 {{implicit use of 'this' pointer is only allowed within the evaluation}}
};
diff --git a/clang/test/SemaCXX/undefined-internal.cpp b/clang/test/SemaCXX/undefined-internal.cpp
index 9745f097c76b7..9cd27ee2c981b 100644
--- a/clang/test/SemaCXX/undefined-internal.cpp
+++ b/clang/test/SemaCXX/undefined-internal.cpp
@@ -227,7 +227,7 @@ namespace test7 {
namespace test8 {
typedef struct {
- void bar(); // expected-warning {{function 'test8::(anonymous struct)::bar' has internal linkage but is not defined}}
+ void bar(); // expected-warning {{function 'test8::(unnamed struct)::bar' has internal linkage but is not defined}}
void foo() {
bar(); // expected-note {{used here}}
}
>From 46da940963df1119735abf36720683c0438981b9 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 25 Nov 2025 13:43:42 +0900
Subject: [PATCH 4/8] fixup! fix SemaObjCXX/arc-0x.mm test
---
clang/test/SemaObjCXX/arc-0x.mm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/SemaObjCXX/arc-0x.mm b/clang/test/SemaObjCXX/arc-0x.mm
index a7418eceb244b..dd8b8e80c2817 100644
--- a/clang/test/SemaObjCXX/arc-0x.mm
+++ b/clang/test/SemaObjCXX/arc-0x.mm
@@ -195,8 +195,8 @@ void test() {
};
static union { // expected-error {{call to implicitly-deleted default constructor of}}
- union { // expected-note-re {{default constructor of '(unnamed union at {{.*}}' is implicitly deleted because field 'test_union::(anonymous union)::(anonymous union at {{.*}})' has a deleted default constructor}}
- union { // expected-note-re {{default constructor of '(anonymous union at {{.*}}' is implicitly deleted because field 'test_union::(anonymous union)::(anonymous union)::(anonymous union at {{.*}})' has a deleted default constructor}}
+ union { // expected-note-re {{default constructor of '(unnamed union at {{.*}}' is implicitly deleted because field 'test_union::(unnamed union)::(anonymous union at {{.*}})' has a deleted default constructor}}
+ union { // expected-note-re {{default constructor of '(anonymous union at {{.*}}' is implicitly deleted because field 'test_union::(unnamed union)::(anonymous union)::(anonymous union at {{.*}})' has a deleted default constructor}}
__weak id g1; // expected-note-re {{default constructor of '(anonymous union at {{.*}}' is implicitly deleted because variant field 'g1' is an ObjC pointer}}
int g2;
};
>From c867f709bef5bdf2579941781fe6668b73884875 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 25 Nov 2025 21:30:20 +0900
Subject: [PATCH 5/8] fixup! fix more tests
---
clang/test/CodeGen/block-with-perdefinedexpr.cpp | 4 ++--
clang/test/CodeGenCXX/predefined-expr.cpp | 8 ++++----
clang/test/SemaCXX/predefined-expr.cpp | 12 ++++++------
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/clang/test/CodeGen/block-with-perdefinedexpr.cpp b/clang/test/CodeGen/block-with-perdefinedexpr.cpp
index 890c2d6358569..597971e6fb6be 100644
--- a/clang/test/CodeGen/block-with-perdefinedexpr.cpp
+++ b/clang/test/CodeGen/block-with-perdefinedexpr.cpp
@@ -67,11 +67,11 @@ class Foo {
}
void inside_lambda() {
auto lambda = []() {
- // CHECK-DAG: @__PRETTY_FUNCTION__.___ZZN12foonamespace3Foo13inside_lambdaEvENKUlvE_clEv_block_invoke = private unnamed_addr constant [92 x i8] c"auto foonamespace::Foo::inside_lambda()::(anonymous class)::operator()() const_block_invoke\00", align 1
+ // CHECK-DAG: @__PRETTY_FUNCTION__.___ZZN12foonamespace3Foo13inside_lambdaEvENKUlvE_clEv_block_invoke = private unnamed_addr constant [83 x i8] c"auto foonamespace::Foo::inside_lambda()::(lambda)::operator()() const_block_invoke\00", align 1
const char * (^block1)() = ^() {
return __PRETTY_FUNCTION__;
};
- // CHECK-DAG: @__PRETTY_FUNCTION__.___ZZN12foonamespace3Foo13inside_lambdaEvENKUlvE_clEv_block_invoke_2 = private unnamed_addr constant [94 x i8] c"auto foonamespace::Foo::inside_lambda()::(anonymous class)::operator()() const_block_invoke_2\00", align 1
+ // CHECK-DAG: @__PRETTY_FUNCTION__.___ZZN12foonamespace3Foo13inside_lambdaEvENKUlvE_clEv_block_invoke_2 = private unnamed_addr constant [85 x i8] c"auto foonamespace::Foo::inside_lambda()::(lambda)::operator()() const_block_invoke_2\00", align 1
const char * (^block2)() = ^() {
return __PRETTY_FUNCTION__;
};
diff --git a/clang/test/CodeGenCXX/predefined-expr.cpp b/clang/test/CodeGenCXX/predefined-expr.cpp
index 48c1205d80d39..1f036c5d520c9 100644
--- a/clang/test/CodeGenCXX/predefined-expr.cpp
+++ b/clang/test/CodeGenCXX/predefined-expr.cpp
@@ -10,7 +10,7 @@
// CHECK-DAG: private unnamed_addr constant [103 x i8] c"static void ClassWithTemplateTemplateParam<char>::staticMember() [T = char, Param = NS::ClassTemplate]\00"
// CHECK-DAG: private unnamed_addr constant [106 x i8] c"void OuterClass<int *>::MiddleClass::InnerClass<float>::memberFunction(T, U) const [T = int *, U = float]\00"
// CHECK-DAG: private unnamed_addr constant [51 x i8] c"void functionTemplateWithCapturedStmt(T) [T = int]\00"
-// CHECK-DAG: private unnamed_addr constant [76 x i8] c"auto functionTemplateWithLambda(int)::(lambda)::operator()() const\00"
+// CHECK-DAG: private unnamed_addr constant [67 x i8] c"auto functionTemplateWithLambda(int)::(lambda)::operator()() const\00"
// CHECK-DAG: private unnamed_addr constant [65 x i8] c"void functionTemplateWithUnnamedTemplateParameter(T) [T = float]\00"
// CHECK-DAG: private unnamed_addr constant [60 x i8] c"void functionTemplateExplicitSpecialization(T) [T = double]\00"
@@ -28,13 +28,13 @@
// CHECK-DAG: private unnamed_addr constant [46 x i8] c"void NS::Base::functionTemplate1(T) [T = int]\00"
// CHECK-DAG: private unnamed_addr constant [23 x i8] c"anonymousUnionFunction\00"
-// CHECK-DAG: private unnamed_addr constant [83 x i8] c"void NS::ContainerForAnonymousRecords::(anonymous union)::anonymousUnionFunction()\00"
+// CHECK-DAG: private unnamed_addr constant [81 x i8] c"void NS::ContainerForAnonymousRecords::(unnamed union)::anonymousUnionFunction()\00"
// CHECK-DAG: private unnamed_addr constant [24 x i8] c"anonymousStructFunction\00"
-// CHECK-DAG: private unnamed_addr constant [85 x i8] c"void NS::ContainerForAnonymousRecords::(anonymous struct)::anonymousStructFunction()\00"
+// CHECK-DAG: private unnamed_addr constant [83 x i8] c"void NS::ContainerForAnonymousRecords::(unnamed struct)::anonymousStructFunction()\00"
// CHECK-DAG: private unnamed_addr constant [23 x i8] c"anonymousClassFunction\00"
-// CHECK-DAG: private unnamed_addr constant [83 x i8] c"void NS::ContainerForAnonymousRecords::(anonymous class)::anonymousClassFunction()\00"
+// CHECK-DAG: private unnamed_addr constant [81 x i8] c"void NS::ContainerForAnonymousRecords::(unnamed class)::anonymousClassFunction()\00"
// CHECK-DAG: private unnamed_addr constant [12 x i8] c"~Destructor\00"
// CHECK-DAG: private unnamed_addr constant [30 x i8] c"NS::Destructor::~Destructor()\00"
diff --git a/clang/test/SemaCXX/predefined-expr.cpp b/clang/test/SemaCXX/predefined-expr.cpp
index 8cba0d41a2997..ea41f0b505d31 100644
--- a/clang/test/SemaCXX/predefined-expr.cpp
+++ b/clang/test/SemaCXX/predefined-expr.cpp
@@ -26,8 +26,8 @@ int baz() {
[]() {
static_assert(sizeof(__func__) == 11, "operator()");
static_assert(sizeof(__FUNCTION__) == 11, "operator()");
- static_assert(sizeof(__PRETTY_FUNCTION__) == 50,
- "auto baz()::<anonymous class>::operator()() const");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 41,
+ "auto baz()::<lambda>::operator()() const");
return 0;
}
();
@@ -56,8 +56,8 @@ int main() {
[]() {
static_assert(sizeof(__func__) == 11, "operator()");
static_assert(sizeof(__FUNCTION__) == 11, "operator()");
- static_assert(sizeof(__PRETTY_FUNCTION__) == 51,
- "auto main()::<anonymous class>::operator()() const");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 42,
+ "auto main()::<lambda>::operator()() const");
return 0;
}
();
@@ -87,8 +87,8 @@ int main() {
{
static_assert(sizeof(__func__) == 11, "operator()");
static_assert(sizeof(__FUNCTION__) == 11, "operator()");
- static_assert(sizeof(__PRETTY_FUNCTION__) == 51,
- "auto main()::<anonymous class>::operator()() const");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 42,
+ "auto main()::<lambda>::operator()() const");
}
}
();
>From 4c9b161b903b94023a39559b2e49200bb410364f Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 26 Nov 2025 07:38:56 +0900
Subject: [PATCH 6/8] fixup! fix SymbolCollectorTests.cpp
---
clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
index 1ce28c91a420c..d62aebab72bf9 100644
--- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
@@ -1471,7 +1471,7 @@ TEST_F(SymbolCollectorTest, NamelessSymbols) {
)";
runSymbolCollector(Header, /*Main=*/"");
EXPECT_THAT(Symbols, UnorderedElementsAre(qName("Foo"),
- qName("(anonymous struct)::a")));
+ qName("(unnamed struct)::a")));
}
TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
>From e6d55c092dbbc304280dc2e698c7afc26cb45bc0 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 26 Nov 2025 07:39:36 +0900
Subject: [PATCH 7/8] fixup! fix FindSymbolsTests.cpp
---
clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp | 2 +-
clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
index 5b1630eb00cb1..217305a7c60c2 100644
--- a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
@@ -106,7 +106,7 @@ TEST(WorkspaceSymbols, Unnamed) {
ElementsAre(AllOf(qName("UnnamedStruct"),
withKind(SymbolKind::Variable))));
EXPECT_THAT(getSymbols(TU, "InUnnamed"),
- ElementsAre(AllOf(qName("(anonymous struct)::InUnnamed"),
+ ElementsAre(AllOf(qName("(unnamed struct)::InUnnamed"),
withKind(SymbolKind::Field))));
}
diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
index d62aebab72bf9..94116fca3cbb2 100644
--- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
@@ -1470,8 +1470,8 @@ TEST_F(SymbolCollectorTest, NamelessSymbols) {
} Foo;
)";
runSymbolCollector(Header, /*Main=*/"");
- EXPECT_THAT(Symbols, UnorderedElementsAre(qName("Foo"),
- qName("(unnamed struct)::a")));
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(qName("Foo"), qName("(unnamed struct)::a")));
}
TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
>From 6610098860a3cb960d64434646f01026a58d3168 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 26 Nov 2025 10:25:03 +0900
Subject: [PATCH 8/8] fixup! implement TagDecl::printName
---
clang/include/clang/AST/Decl.h | 3 +
clang/include/clang/AST/PrettyPrinter.h | 7 +-
clang/include/clang/AST/TypeBase.h | 4 -
clang/lib/AST/Decl.cpp | 89 +++++++++++++++----
clang/lib/AST/TypePrinter.cpp | 79 ++++------------
clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 6 +-
clang/test/SemaCXX/builtin-dump-struct.cpp | 2 +-
clang/unittests/AST/TypePrinterTest.cpp | 11 +--
8 files changed, 108 insertions(+), 93 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index ee2321dd158d4..ea3bfe13813d5 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3771,6 +3771,9 @@ class TagDecl : public TypeDecl,
/// True if this decl is currently being defined.
void setBeingDefined(bool V = true) { TagDeclBits.IsBeingDefined = V; }
+ void printAnonymousTagDecl(llvm::raw_ostream &OS,
+ const PrintingPolicy &Policy) const;
+
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h
index fd995a653d167..1e95e0a27e27c 100644
--- a/clang/include/clang/AST/PrettyPrinter.h
+++ b/clang/include/clang/AST/PrettyPrinter.h
@@ -60,8 +60,10 @@ struct PrintingPolicy {
/// Create a default printing policy for the specified language.
PrintingPolicy(const LangOptions &LO)
: Indentation(2), SuppressSpecifiers(false),
- SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false),
- SuppressScope(false), SuppressUnwrittenScope(false),
+ SuppressTagKeyword(LO.CPlusPlus),
+ SuppressTagKeywordInAnonymousTagNames(false),
+ IncludeTagDefinition(false), SuppressScope(false),
+ SuppressUnwrittenScope(false),
SuppressInlineNamespace(SuppressInlineNamespaceMode::Redundant),
SuppressInitializers(false), ConstantArraySizeAsWritten(false),
AnonymousTagLocations(true), SuppressStrongLifetime(false),
@@ -121,6 +123,7 @@ struct PrintingPolicy {
/// \endcode
LLVM_PREFERRED_TYPE(bool)
unsigned SuppressTagKeyword : 1;
+ unsigned SuppressTagKeywordInAnonymousTagNames : 1;
/// When true, include the body of a tag definition.
///
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index 2f27deda2cd66..f07861f50fe8c 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -7374,10 +7374,6 @@ bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
ArrayRef<TemplateArgument> Args,
unsigned Depth);
-void printAnonymousTagDecl(llvm::raw_ostream &OS, const TagDecl *D,
- const PrintingPolicy &Policy,
- bool PrintKindDecoration, bool PrintTagLocations);
-
/// Represents a qualified type name for which the type name is
/// dependent.
///
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index c9bb414a9a1de..2d1890b8e213b 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1790,15 +1790,17 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
}
else
OS << *ND;
- } else if (const auto *RD = dyn_cast<RecordDecl>(DC)) {
- if (TypedefNameDecl *TD = RD->getTypedefNameForAnonDecl())
- OS << *TD;
- else if (!RD->getIdentifier())
- printAnonymousTagDecl(OS, llvm::cast<TagDecl>(RD), P,
- /*PrintKindDecoration=*/true,
- /*AllowSourceLocations=*/false);
- else
- OS << *RD;
+ } else if (const auto *RD = llvm::dyn_cast<RecordDecl>(DC)) {
+ PrintingPolicy Copy(P);
+ // As part of a scope we want to print anonymous names as:
+ // ..::(anonymous struct)::..
+ //
+ // I.e., suppress tag locations, suppress leading keyword, *don't*
+ // suppress tag in name
+ Copy.SuppressTagKeyword = true;
+ Copy.SuppressTagKeywordInAnonymousTagNames = false;
+ Copy.AnonymousTagLocations = false;
+ RD->printName(OS, Copy);
} else if (const auto *FD = dyn_cast<FunctionDecl>(DC)) {
const FunctionProtoType *FT = nullptr;
if (FD->hasWrittenPrototype())
@@ -4957,19 +4959,76 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
}
}
+void TagDecl::printAnonymousTagDecl(llvm::raw_ostream &OS,
+ const PrintingPolicy &Policy) const {
+ if (TypedefNameDecl *Typedef = getTypedefNameForAnonDecl()) {
+ assert(Typedef->getIdentifier() && "Typedef without identifier?");
+ OS << Typedef->getIdentifier()->getName();
+ return;
+ }
+
+ bool SuppressTagKeywordInName = Policy.SuppressTagKeywordInAnonymousTagNames;
+
+ // Emit leading keyword. Since we printed a leading keyword make sure we
+ // don't print the tag as part of the name too.
+ if (!Policy.SuppressTagKeyword) {
+ OS << getKindName() << ' ';
+ SuppressTagKeywordInName = true;
+ }
+
+ // Make an unambiguous representation for anonymous types, e.g.
+ // (anonymous enum at /usr/include/string.h:120:9)
+ OS << (Policy.MSVCFormatting ? '`' : '(');
+
+ if (isa<CXXRecordDecl>(this) && cast<CXXRecordDecl>(this)->isLambda()) {
+ OS << "lambda";
+ SuppressTagKeywordInName = true;
+ } else if ((isa<RecordDecl>(this) &&
+ cast<RecordDecl>(this)->isAnonymousStructOrUnion())) {
+ OS << "anonymous";
+ } else {
+ OS << "unnamed";
+ }
+
+ if (!SuppressTagKeywordInName)
+ OS << ' ' << getKindName();
+
+ if (Policy.AnonymousTagLocations) {
+ 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();
+ }
+ }
+
+ OS << (Policy.MSVCFormatting ? '\'' : ')');
+}
+
void TagDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const {
DeclarationName Name = getDeclName();
// If the name is supposed to have an identifier but does not have one, then
// the tag is anonymous and we should print it differently.
if (Name.isIdentifier() && !Name.getAsIdentifierInfo()) {
- // If the caller wanted to print a qualified name, they've already printed
- // the scope. And if the caller doesn't want that, the scope information
- // is already printed as part of the type.
- PrintingPolicy Copy(Policy);
- Copy.SuppressScope = true;
- QualType(getASTContext().getCanonicalTagType(this)).print(OS, Copy);
+ printAnonymousTagDecl(OS, Policy);
+
return;
}
+
// Otherwise, do the normal printing.
Name.print(OS, Policy);
}
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 93bd068ccee08..61c27782c7468 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1519,18 +1519,19 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) {
return;
}
- bool PrintKindDecoration = Policy.AnonymousTagLocations;
-
+ bool PrintedKindDecoration = false;
if (T->isCanonicalUnqualified()) {
if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) {
- PrintKindDecoration = false;
+ PrintedKindDecoration = true;
OS << D->getKindName();
OS << ' ';
}
} else {
OS << TypeWithKeyword::getKeywordName(T->getKeyword());
- if (T->getKeyword() != ElaboratedTypeKeyword::None)
+ if (T->getKeyword() != ElaboratedTypeKeyword::None) {
+ PrintedKindDecoration = true;
OS << ' ';
+ }
}
if (!Policy.FullyQualifiedName && !T->isCanonicalUnqualified()) {
@@ -1544,13 +1545,17 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) {
if (const IdentifierInfo *II = D->getIdentifier())
OS << II->getName();
- else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) {
- assert(Typedef->getIdentifier() && "Typedef without identifier?");
- OS << Typedef->getIdentifier()->getName();
- } else
- printAnonymousTagDecl(OS, D, Policy,
- /*PrintKindDecoration=*/PrintKindDecoration,
- /*PrintTagLocations=*/Policy.AnonymousTagLocations);
+ else {
+ clang::PrintingPolicy Copy(Policy);
+
+ // Suppress the redundant tag keyword if we just printed one.
+ if (PrintedKindDecoration) {
+ Copy.SuppressTagKeywordInAnonymousTagNames = true;
+ Copy.SuppressTagKeyword = true;
+ }
+
+ D->printName(OS, Copy);
+ }
// If this is a class template specialization, print the template
// arguments.
@@ -2429,58 +2434,6 @@ static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,
return false;
}
-void clang::printAnonymousTagDecl(llvm::raw_ostream &OS, const TagDecl *D,
- const PrintingPolicy &Policy,
- bool PrintKindDecoration,
- bool PrintTagLocations) {
- assert(D);
-
- // Make an unambiguous representation for anonymous types, e.g.
- // (anonymous enum at /usr/include/string.h:120:9)
- OS << (Policy.MSVCFormatting ? '`' : '(');
-
- if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) {
- PrintKindDecoration = false;
- OS << "lambda";
- } else if ((isa<RecordDecl>(D) &&
- cast<RecordDecl>(D)->isAnonymousStructOrUnion())) {
- OS << "anonymous";
- } else {
- OS << "unnamed";
- }
-
- // 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 (PrintKindDecoration)
- OS << " " << D->getKindName();
-
- if (PrintTagLocations) {
- PresumedLoc PLoc =
- D->getASTContext().getSourceManager().getPresumedLoc(D->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();
- }
- }
-
- OS << (Policy.MSVCFormatting ? '\'' : ')');
-}
-
bool clang::isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
const NamedDecl *Param,
ArrayRef<TemplateArgument> Args,
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index e83a6e97ec638..2e3d392c22db1 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -518,9 +518,9 @@ static StringRef getNodeName(const RecordDecl &Node,
llvm::raw_svector_ostream OS(Scratch);
- printAnonymousTagDecl(
- OS, llvm::cast<TagDecl>(&Node), Node.getASTContext().getPrintingPolicy(),
- /*PrintKindDecoration=*/true, /*PrintTagLocations=*/false);
+ PrintingPolicy Copy(Node.getASTContext().getPrintingPolicy());
+ Copy.AnonymousTagLocations = false;
+ Node.printName(OS, Copy);
return OS.str();
}
diff --git a/clang/test/SemaCXX/builtin-dump-struct.cpp b/clang/test/SemaCXX/builtin-dump-struct.cpp
index 91ffa7c8c05bd..7c039c899431f 100644
--- a/clang/test/SemaCXX/builtin-dump-struct.cpp
+++ b/clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -142,7 +142,7 @@ B {
int anon1 = 6
int anon2 = 7
int anon3 = 8
- struct (unnamed) c = {
+ struct (unnamed struct) c = {
int m = 9
}
int && r = reference to 10
diff --git a/clang/unittests/AST/TypePrinterTest.cpp b/clang/unittests/AST/TypePrinterTest.cpp
index de4cfa4074eba..507830f40ad0f 100644
--- a/clang/unittests/AST/TypePrinterTest.cpp
+++ b/clang/unittests/AST/TypePrinterTest.cpp
@@ -313,14 +313,14 @@ TEST(TypePrinter, NestedNameSpecifiers) {
// their scope.
ASSERT_TRUE(PrintedTypeMatches(
Code, {}, varDecl(hasName("imem"), hasType(qualType().bind("id"))),
- "struct (unnamed)", [](PrintingPolicy &Policy) {
+ "struct (unnamed struct)", [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = true;
Policy.AnonymousTagLocations = false;
}));
ASSERT_TRUE(PrintedTypeMatches(
Code, {}, varDecl(hasName("imem"), hasType(qualType().bind("id"))),
- "struct (unnamed)", [](PrintingPolicy &Policy) {
+ "struct (unnamed struct)", [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = false;
Policy.AnonymousTagLocations = false;
}));
@@ -328,7 +328,7 @@ TEST(TypePrinter, NestedNameSpecifiers) {
// Further levels of nesting print the entire scope.
ASSERT_TRUE(PrintedTypeMatches(
Code, {}, fieldDecl(hasName("u"), hasType(qualType().bind("id"))),
- "union level1()::Inner::Inner(int)::(unnamed struct)::(unnamed)",
+ "union level1()::Inner::Inner(int)::(unnamed struct)::(unnamed union)",
[](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = true;
Policy.AnonymousTagLocations = false;
@@ -336,7 +336,7 @@ TEST(TypePrinter, NestedNameSpecifiers) {
ASSERT_TRUE(PrintedTypeMatches(
Code, {}, fieldDecl(hasName("u"), hasType(qualType().bind("id"))),
- "union (unnamed)", [](PrintingPolicy &Policy) {
+ "union (unnamed union)", [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = false;
Policy.AnonymousTagLocations = false;
}));
@@ -355,7 +355,8 @@ TEST(TypePrinter, NestedNameSpecifiersTypedef) {
ASSERT_TRUE(PrintedTypeMatches(
Code, {}, fieldDecl(hasName("bar"), hasType(qualType().bind("id"))),
- "struct foo::(anonymous struct)::(unnamed)", [](PrintingPolicy &Policy) {
+ "struct foo::(anonymous struct)::(unnamed struct)",
+ [](PrintingPolicy &Policy) {
Policy.FullyQualifiedName = true;
Policy.AnonymousTagLocations = false;
}));
More information about the cfe-commits
mailing list