Author: AZero13 Date: 2026-09-08T14:47:13+02:00 New Revision: 651d01e873c6fce3c8d300362585b1a5f98bb883
URL: https://github.com/llvm/llvm-project/commit/651d01e873c6fce3c8d300362585b1a5f98bb883 DIFF: https://github.com/llvm/llvm-project/commit/651d01e873c6fce3c8d300362585b1a5f98bb883.diff LOG: [clang][AST] Fix infinite recursion when printing fully qualified template parameters (#219044) This fixes an infinite recursion crash that was introduced in #206041. When printing a `DeclRefExpr` using `PrintingPolicy::FullyQualifiedName`, we were previously trying to print the fully qualified name of all decls. However, when the decl is a template parameter, its `DeclContext` is the template specialization itself. If a template specialization's arguments depend on that same template parameter (e.g., `template<int Count> struct View<int[Count]>`), attempting to print the qualified name forces Clang to recursively evaluate the enclosing context. This led to unbounded recursion (`View<int[Count]>::Count` -> `View<int[View<int[Count]>::Count]>::Count` and so on). Since template parameters are inherently scoped to their template declarations and do not require a fully qualified name, this patch resolves the issue by skipping `printQualifiedName` if the decl is a template parameter (`!VD->isTemplateParameter()`). Fixes #218076. Added: Modified: clang/lib/AST/StmtPrinter.cpp clang/unittests/AST/TypePrinterTest.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 77a3fcfd3ad08..a3da70962f4f5 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1378,7 +1378,8 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { bool CleanUglifiedParameter = Policy.CleanUglifiedParameters && isa<ParmVarDecl, NonTypeTemplateParmDecl>(VD); - if (Policy.FullyQualifiedName && !ForceAnonymous && !CleanUglifiedParameter) { + if (Policy.FullyQualifiedName && !ForceAnonymous && !CleanUglifiedParameter && + !VD->isTemplateParameter()) { VD->printQualifiedName(OS, Policy); } else { Node->getQualifier().print(OS, Policy); diff --git a/clang/unittests/AST/TypePrinterTest.cpp b/clang/unittests/AST/TypePrinterTest.cpp index 79f75909c57b5..8a319faabdb96 100644 --- a/clang/unittests/AST/TypePrinterTest.cpp +++ b/clang/unittests/AST/TypePrinterTest.cpp @@ -145,6 +145,24 @@ TEST(TypePrinter, TemplateArgumentExpressionFullyQualified) { [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; })); } +TEST(TypePrinter, TemplateSpecializationWithDependentSizedArrayType) { + llvm::StringLiteral Code = R"cpp( + template<typename Container> + struct View {}; + + template<int Count> + struct View<int[Count]> { + using Container = int[Count]; + }; + )cpp"; + + auto Matcher = + typeAliasDecl(hasName("Container"), hasType(qualType().bind("id"))); + ASSERT_TRUE(PrintedTypeMatches( + Code, {}, Matcher, "int[Count]", + [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; })); +} + TEST(TypePrinter, TemplateIdWithNTTP) { constexpr char Code[] = R"cpp( template <int N> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
