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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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@+1 {{[debug] analyzing from notInvokedLambdaScope()::(anonymous class)::operator()()}} + // textout-note@+1 {{[debug] analyzing from notInvokedLambdaScope()::(lambda)::operator()()}} auto notInvokedLambda = []() { // common-warning@+1 {{REACHABLE}} textout-note@+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@-2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()<float>' requested here}} + // expected-note@-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@-2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()<long double>' requested here}} + // expected-note@-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@-2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()<const char *>' requested here}} + // expected-note@-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@-1 {{call to immediate function 'GH109096::(anonymous class)::operator()' is not a constant expression}} \ + // expected-error@-1 {{call to immediate function 'GH109096::(lambda)::operator()' is not a constant expression}} \ // expected-note@-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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 48c81ad8190e7352e0cb2327090afe53cd9f604f Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> 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 | 81 ++++------------- clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 6 +- clang/test/SemaCXX/builtin-dump-struct.cpp | 2 +- clang/unittests/AST/TypePrinterTest.cpp | 11 +-- 8 files changed, 110 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..3e54b39320191 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1519,18 +1519,20 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { return; } - bool PrintKindDecoration = Policy.AnonymousTagLocations; - + bool PrintedElaboratedKeyword = false; + 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) { + PrintedElaboratedKeyword = true; OS << ' '; + } } if (!Policy.FullyQualifiedName && !T->isCanonicalUnqualified()) { @@ -1544,13 +1546,18 @@ 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; + + if (PrintedElaboratedKeyword) + Copy.SuppressTagKeyword = true; + + D->printName(OS, Copy); + } // If this is a class template specialization, print the template // arguments. @@ -2429,58 +2436,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; })); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
