[clang] [clang] Assertion failure on template parameter deduction failure (PR #213166)
Oliver Hunt via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 30 15:50:29 PDT 2026
https://github.com/ojhunt created https://github.com/llvm/llvm-project/pull/213166
This assertion was due to template instantiation not recording the instantiation as incomplete when parameter deduction fails.
>From 469b688f32dac03a81d51e3195375db37be28177 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Thu, 30 Jul 2026 13:39:26 -0700
Subject: [PATCH] [clang] Assertion failure on template parameter deduction
failure
This assertion was due to template instantiation not recording the
instantiation as incomplete when parameter deduction fails.
---
clang/lib/Sema/SemaTemplateInstantiate.cpp | 24 +++++++++++++
...tion-after-parameter-deduction-failure.cpp | 35 +++++++++++++++++++
2 files changed, 59 insertions(+)
create mode 100644 clang/test/SemaTemplate/instantiation-after-parameter-deduction-failure.cpp
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 2cf2a4f85f830..b3d48218f5efe 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1992,6 +1992,30 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
*SemaRef.CurrentInstantiationScope->findInstantiationOf(D));
}
+ // ***REVIEWER***: Essentially cloned from the above TemplateTemplateParmDecl
+ // logic. This seems like the actual root cause fix, but prior "correct seeming"
+ // changes i've made against template code was gratuitously wrong.
+ // Biggest question: is it correct to use !getInstantiationOfIfExists as the
+ // test for failure?
+ // Errrr, ***REVIEWER*** again: I thought this was specific to errors, but I
+ // managed to come up with a couple of valid code tests that trip this
+ // assertion.
+ if (BailOutOnIncomplete && isa<ParmVarDecl>(D) &&
+ SemaRef.CurrentInstantiationScope &&
+ !SemaRef.CurrentInstantiationScope->getInstantiationOfIfExists(D)) {
+ assert(!SemaRef.CodeSynthesisContexts.empty() &&
+ SemaRef.CodeSynthesisContexts.back().Kind ==
+ Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution &&
+ "***REVIEWER***: it seemed like this is only mean to happen during "
+ "substitution, but i based that on adding a __builtin_trap() and "
+ "then looking at a few of the resulting crashing tests and they "
+ "were all in this mode. Is that expected/correct? the assertion "
+ "doesn't fire on any of the template tests"
+ "");
+ IsIncomplete = true;
+ return nullptr;
+ }
+
return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D), TemplateArgs);
}
diff --git a/clang/test/SemaTemplate/instantiation-after-parameter-deduction-failure.cpp b/clang/test/SemaTemplate/instantiation-after-parameter-deduction-failure.cpp
new file mode 100644
index 0000000000000..c5839f7ff3c6d
--- /dev/null
+++ b/clang/test/SemaTemplate/instantiation-after-parameter-deduction-failure.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
+
+namespace ambiguous_overload {
+template <class> struct S {
+ template <class T> S(T);
+};
+struct S1 {};
+struct S2 {
+ operator S1();
+};
+
+template <typename T> auto foo(T, S<decltype(0)>); // #declaration
+template <typename T> auto foo(T arg, decltype(arg)) {
+ foo(arg, S2{});
+ // expected-error at -1 {{function 'foo<ambiguous_overload::S1>' with deduced return type cannot be used before it is defined}}
+ // expected-note@#declaration {{'foo<ambiguous_overload::S1>' declared here}}
+ // expected-note@#instantiation {{in instantiation of function template specialization 'ambiguous_overload::foo<ambiguous_overload::S1>' requested here}}
+}
+
+void bar(S1 d) {
+ foo(d, S1{}); // #instantiation
+}
+}
+
+namespace explicit_specialization {
+ template <typename T> void foo(T, int);
+ template <typename T> void foo(T arg, decltype(arg));
+ template <> void foo(int, int) {}
+}
+
+namespace address_of {
+ template <typename T> void foo(T, int);
+ template <typename T> void foo(T arg, decltype(arg));
+ void (*p)(int, int) = foo;
+}
More information about the cfe-commits
mailing list