https://github.com/akash-manna-sky created 
https://github.com/llvm/llvm-project/pull/225088

Fixes #204059

When a function template's return type contains a member access whose 
nested-name-specifier starts with a template type parameter, e.g. 
`decltype(t.U::template B<>::MEM)`, the parser records `U` as the first 
qualifier found in scope. During substitution, `TransformFirstQualifierInScope` 
fetched `U`'s template argument without checking that one exists. Two callers 
legitimately substitute with an incomplete list: explicit template argument 
substitution before deduction (`k<S>(S{})`), and partial deduction for code 
completion signature help (`k(`). The first hit an out-of-bounds index, the 
second a null argument, and both tripped an assertion.

Every other parameter handler in the instantiator checks `hasTemplateArgument` 
first and records the substitution as incomplete. This does the same here, 
leaving the qualifier dependent so the expression is rebuilt as a dependent 
member access. Signature help then shows the candidate with `U` unresolved, and 
the explicit call correctly reports that `U` could not be inferred.


>From fd37024356fb53bbf655d56662974a0dbed0e119 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Mon, 21 Sep 2026 19:19:43 +0530
Subject: [PATCH] [clang] Fix assertion when substituting an incomplete
 template argument list into a member access qualified by a template parameter

TemplateInstantiator::TransformFirstQualifierInScope fetched the template
argument for a template type parameter that begins the nested-name-specifier
of a dependent member access without checking that the argument exists.
Explicit template argument substitution and partial deduction for signature
help both substitute with an incomplete list on purpose, so the lookup hit an
out-of-bounds index or a null argument.

Check hasTemplateArgument first, like every other parameter handler in the
instantiator, mark the substitution incomplete and keep the qualifier
dependent.

Fixes #204059
---
 clang/docs/ReleaseNotes.md                  |  6 ++++++
 clang/lib/Sema/SemaTemplateInstantiate.cpp  |  5 +++++
 clang/test/CodeCompletion/GH204059.cpp      | 10 ++++++++++
 clang/test/SemaTemplate/dependent-names.cpp |  9 +++++++++
 4 files changed, 30 insertions(+)
 create mode 100644 clang/test/CodeCompletion/GH204059.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index f4a34a37aff52..5dc50122e01da 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -724,6 +724,12 @@ features cannot lower the translation-unit ABI level;
 - Fixed an issue where an explicit specialization of a constexpr variable would
   result in a link error. (#GH219796)
 
+- Fixed an assertion when substituting an incomplete set of template arguments
+  (explicitly specified, or partially deduced during code completion) into a
+  member access whose nested-name-specifier starts with a template parameter
+  that has no corresponding argument yet, such as
+  `decltype(t.U::template B<>::MEM)`. (#GH204059)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp 
b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 20b16c3e49bea..6aeb5d06062cd 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2072,6 +2072,11 @@ 
TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
       = cast<TemplateTypeParmType>(getSema().Context.getTypeDeclType(TTPD));
 
     if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
+      if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(), TTP->getIndex())) 
{
+        IsIncomplete = true;
+        return BailOutOnIncomplete ? nullptr : D;
+      }
+
       // FIXME: This needs testing w/ member access expressions.
       TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getIndex());
 
diff --git a/clang/test/CodeCompletion/GH204059.cpp 
b/clang/test/CodeCompletion/GH204059.cpp
new file mode 100644
index 0000000000000..cc7648bd5107b
--- /dev/null
+++ b/clang/test/CodeCompletion/GH204059.cpp
@@ -0,0 +1,10 @@
+template <class T, class U>
+auto k(T t) -> decltype(t.U::template B<>::MEM);
+
+struct S {};
+
+void f() {
+  k(S{});
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-1):5 %s -o - 
| FileCheck %s
+  // CHECK: OVERLOAD: [#decltype(t.U::template B<>::MEM)#]k(<#T t#>)
+}
diff --git a/clang/test/SemaTemplate/dependent-names.cpp 
b/clang/test/SemaTemplate/dependent-names.cpp
index d6bd670841c08..bb838ece6ccc5 100644
--- a/clang/test/SemaTemplate/dependent-names.cpp
+++ b/clang/test/SemaTemplate/dependent-names.cpp
@@ -481,3 +481,12 @@ namespace TransformNestedName {
   template <typename T::template X<N<T>::State::kA>>
   inline void N<T>::F() {}
 } // namespace TransformNestedName
+
+namespace GH204059 {
+  template <class T, class U>
+  auto k(T t) -> decltype(t.U::template B<>::MEM); // expected-note 
{{candidate template ignored: couldn't infer template argument 'U'}}
+  struct S {};
+  void f() {
+    k<S>(S{}); // expected-error {{no matching function for call to 'k'}}
+  }
+} // namespace GH204059

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to