[clang] [AST] Fix an assertion failure in TypeName::getFullyQualifiedName (PR #159312)

Ilya Biryukov via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 17 04:54:27 PDT 2025


https://github.com/ilya-biryukov updated https://github.com/llvm/llvm-project/pull/159312

>From f62d7ec2f9ef14911ec9e0c52054c07ee7cf0538 Mon Sep 17 00:00:00 2001
From: Ilya Biryukov <ibiryukov at google.com>
Date: Wed, 17 Sep 2025 12:12:21 +0200
Subject: [PATCH] [AST] Fix an assertion failure in
 TypeName::getFullyQualifiedName

This popped up during our internal intergrates of upstream changes.
It started happening after ba9d1c41c41d568a798e0a8c38a89d294647c28d,
which started using `TemplateSpecializationType` in this place and
the code was not prepared to handle it.
---
 clang/lib/AST/QualTypeNames.cpp           |  9 ++--
 clang/unittests/AST/CMakeLists.txt        |  1 +
 clang/unittests/AST/QualTypeNamesTest.cpp | 56 +++++++++++++++++++++++
 3 files changed, 63 insertions(+), 3 deletions(-)
 create mode 100644 clang/unittests/AST/QualTypeNamesTest.cpp

diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp
index ee7fec3372fcf..a2f930911bfe5 100644
--- a/clang/lib/AST/QualTypeNames.cpp
+++ b/clang/lib/AST/QualTypeNames.cpp
@@ -58,9 +58,9 @@ static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
   NestedNameSpecifier NNS = std::nullopt;
 
   TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
-  // ArgTDecl won't be NULL because we asserted that this isn't a
-  // dependent context very early in the call chain.
-  assert(ArgTDecl != nullptr);
+  if (!ArgTDecl) // ArgTDecl can be null in dependent contexts.
+    return false;
+
   QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();
 
   if (QTName &&
@@ -252,6 +252,9 @@ createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *Decl,
                                     bool WithGlobalNsPrefix) {
   assert(Decl);
 
+  // Some declaration cannot be qualified.
+  if (Decl->isTemplateParameter())
+    return std::nullopt;
   const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
   const auto *Outer = dyn_cast<NamedDecl>(DC);
   const auto *OuterNS = dyn_cast<NamespaceDecl>(DC);
diff --git a/clang/unittests/AST/CMakeLists.txt b/clang/unittests/AST/CMakeLists.txt
index f27d34e8a0719..3a12a4a06a33a 100644
--- a/clang/unittests/AST/CMakeLists.txt
+++ b/clang/unittests/AST/CMakeLists.txt
@@ -26,6 +26,7 @@ add_clang_unittest(ASTTests
   ExternalASTSourceTest.cpp
   NamedDeclPrinterTest.cpp
   ProfilingTest.cpp
+  QualTypeNamesTest.cpp
   RandstructTest.cpp
   RawCommentForDeclTest.cpp
   RecursiveASTVisitorTest.cpp
diff --git a/clang/unittests/AST/QualTypeNamesTest.cpp b/clang/unittests/AST/QualTypeNamesTest.cpp
new file mode 100644
index 0000000000000..5b88391c84d08
--- /dev/null
+++ b/clang/unittests/AST/QualTypeNamesTest.cpp
@@ -0,0 +1,56 @@
+//===- unittests/AST/QualTypeNamesTest.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for helpers from QualTypeNames.h.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/QualTypeNames.h"
+#include "ASTPrint.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/TypeBase.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace {
+
+TEST(QualTypeNamesTest, TemplateParameters) {
+  constexpr llvm::StringLiteral Code = R"cpp(
+    template <template<class> class T> struct Foo {
+      using type_of_interest = T<int>;
+    };
+  )cpp";
+  auto AST = tooling::buildASTFromCode(Code);
+  ASSERT_NE(AST, nullptr);
+
+  auto &Ctx = AST->getASTContext();
+  auto FooLR = Ctx.getTranslationUnitDecl()->lookup(
+      DeclarationName(AST->getPreprocessor().getIdentifierInfo("Foo")));
+  ASSERT_TRUE(FooLR.isSingleResult());
+
+  auto TypeLR =
+      llvm::cast<ClassTemplateDecl>(FooLR.front())
+          ->getTemplatedDecl()
+          ->lookup(DeclarationName(
+              AST->getPreprocessor().getIdentifierInfo("type_of_interest")));
+  ASSERT_TRUE(TypeLR.isSingleResult());
+
+  auto Type = cast<TypeAliasDecl>(TypeLR.front())->getUnderlyingType();
+  ASSERT_TRUE(isa<TemplateSpecializationType>(Type));
+
+  EXPECT_EQ(TypeName::getFullyQualifiedName(Type, Ctx, Ctx.getPrintingPolicy()),
+            "T<int>");
+}
+
+} // namespace
+} // namespace clang



More information about the cfe-commits mailing list