[clang] 651d01e - [clang][AST] Fix infinite recursion when printing fully qualified template parameters (#219044)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 8 05:47:18 PDT 2026
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>
More information about the cfe-commits
mailing list