llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Giovanni B. (Z3rox-dev)

<details>
<summary>Changes</summary>

## Summary

`checkMoreSpecializedThanPrimary()` emits 
`ext_partial_spec_not_more_specialized_than_primary` but did not mark the 
partial specialization as invalid. Additionally, 
`ActOnClassTemplateSpecialization()` unconditionally called 
`Specialization-&gt;setInvalidDecl(Invalid)` where `Invalid` was `false` for 
partial specializations, clearing any invalid flag set by 
`CheckTemplatePartialSpecialization`.

This caused the invalid partial specialization to still be selected during 
template argument deduction. Using it for instantiation produced dependent 
expressions (`CXXUnresolvedConstructExpr`) in non-dependent contexts, leading 
to an assertion failure:
```
assert(!Init-&gt;isValueDependent()) in VarDecl::evaluateValueImpl
```

## Root Cause

Two-part issue in `SemaTemplate.cpp`:

1. **Missing invalidation**: `checkMoreSpecializedThanPrimary()` emitted the 
diagnostic but never called `Partial-&gt;setInvalidDecl()`.
2. **Flag clearing**: `ActOnClassTemplateSpecialization()` called 
`Specialization-&gt;setInvalidDecl(Invalid)` at the end, where `Invalid` is 
`false` for partial specializations. Since `Specialization` and `Partial` are 
the same pointer (set at line 8987), this unconditionally cleared the invalid 
flag even if `CheckTemplatePartialSpecialization` had just set it.

The guard in `DeduceTemplateArguments()` (SemaTemplateDeduction.cpp:3406) 
already checks `Partial-&gt;isInvalidDecl()` and returns `TDK_Invalid` — so 
once the partial spec is properly marked invalid, it is excluded from deduction.

## Fix

1. Add `Partial-&gt;setInvalidDecl()` in `checkMoreSpecializedThanPrimary()` 
after the diagnostic.
2. Change `ActOnClassTemplateSpecialization()` to use `if (Invalid) 
Specialization-&gt;setInvalidDecl()` — only sets the flag, never clears it.

## Test Plan

- New regression test: 
`clang/test/SemaTemplate/partial-spec-not-more-specialized-invalid.cpp` (exact 
reproducer from #<!-- -->181410)
- Updated 2 existing tests to match new behavior (invalid partial specs are now 
excluded from deduction)
- Full `check-clang`: **50,534 tests, 0 failures** (46,308 passed, 28 
expectedly failed)

&gt; AI tools were used to assist with root cause analysis and tracing the code 
paths in this fix.

Fixes #<!-- -->181410


---
Full diff: https://github.com/llvm/llvm-project/pull/181614.diff


4 Files Affected:

- (modified) clang/lib/Sema/SemaTemplate.cpp (+11-1) 
- (modified) clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp 
(+3-3) 
- (added) clang/test/SemaTemplate/partial-spec-not-more-specialized-invalid.cpp 
(+30) 
- (modified) clang/test/SemaTemplate/temp_arg_nontype.cpp (+1-4) 


``````````diff
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 3497ff7856eed..5cdfa97c6c35e 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4229,6 +4229,12 @@ static void checkMoreSpecializedThanPrimary(Sema &S, 
PartialSpecDecl *Partial) {
          diag::ext_partial_spec_not_more_specialized_than_primary)
       << isa<VarTemplateDecl>(Template);
 
+  // Mark the partial specialization as invalid so it won't be selected
+  // during template argument deduction. Using an invalid partial
+  // specialization for instantiation can produce dependent expressions
+  // in non-dependent contexts, leading to crashes in later phases.
+  Partial->setInvalidDecl();
+
   if (Info.hasSFINAEDiagnostic()) {
     PartialDiagnosticAt Diag = {SourceLocation(),
                                 PartialDiagnostic::NullDiagnostic()};
@@ -9108,7 +9114,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
   if (SkipBody && SkipBody->ShouldSkip)
     return SkipBody->Previous;
 
-  Specialization->setInvalidDecl(Invalid);
+  // Only mark invalid if determined here; don't clear a flag already set
+  // by CheckTemplatePartialSpecialization (e.g., for a partial specialization
+  // that is not more specialized than the primary template).
+  if (Invalid)
+    Specialization->setInvalidDecl();
   inferGslOwnerPointerAttribute(Specialization);
   return Specialization;
 }
diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp 
b/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
index ab4c663d24c7d..0bc69909b51c5 100644
--- a/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
@@ -108,15 +108,15 @@ namespace PR9021b {
 
 namespace PartialSpecialization {
   template<typename T, typename U, typename V = U>
-  struct X0; // expected-note 2{{template is declared here}}
+  struct X0; // expected-note 4{{template is declared here}}
 
   template<typename ...Ts>
   struct X0<Ts...> { // expected-error {{class template partial specialization 
is not more specialized than the primary template}}
   };
 
   X0<int> x0i; // expected-error{{too few template arguments for class 
template 'X0'}}
-  X0<int, float> x0if;
-  X0<int, float, double> x0ifd;
+  X0<int, float> x0if; // expected-error {{implicit instantiation of undefined 
template 'PartialSpecialization::X0<int, float>'}}
+  X0<int, float, double> x0ifd; // expected-error {{implicit instantiation of 
undefined template 'PartialSpecialization::X0<int, float, double>'}}
 }
 
 namespace FixedAliasTemplate {
diff --git 
a/clang/test/SemaTemplate/partial-spec-not-more-specialized-invalid.cpp 
b/clang/test/SemaTemplate/partial-spec-not-more-specialized-invalid.cpp
new file mode 100644
index 0000000000000..5439081a5dedf
--- /dev/null
+++ b/clang/test/SemaTemplate/partial-spec-not-more-specialized-invalid.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++20 -verify -emit-llvm-only %s
+// Regression test for https://github.com/llvm/llvm-project/issues/181410
+//
+// A class template partial specialization diagnosed as "not more specialized
+// than the primary template" was not marked invalid, so it was still selected
+// during template argument deduction. Using it for instantiation produced
+// dependent expressions in non-dependent contexts, causing an assertion
+// failure in CodeGen: assert(!Init->isValueDependent()).
+
+template <int>
+struct integer_sequence {};
+
+template <int>
+struct array {};
+
+template <int*>
+struct MetaValuesHelper; // expected-note 2{{template is declared here}}
+
+template <typename TupleName, TupleName kValues>
+struct MetaValuesHelper<kValues> { // expected-error {{class template partial 
specialization is not more specialized than the primary template}}
+  template <int... Is>
+  static array<stdget<Is>(kValues)...> MetaValuesFunc(integer_sequence<Is...>);
+};
+
+int kBaseIndexRegistersUsed;
+
+// Previously this crashed with: assert(!Init->isValueDependent())
+// Now the invalid partial specialization is excluded from deduction,
+// and the primary template (which is only forward-declared) is used instead.
+array<0> u = 
decltype(MetaValuesHelper<&kBaseIndexRegistersUsed>::MetaValuesFunc(integer_sequence<0>{})){};
 // expected-error {{implicit instantiation of undefined template 
'MetaValuesHelper<&kBaseIndexRegistersUsed>'}}
diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp 
b/clang/test/SemaTemplate/temp_arg_nontype.cpp
index bd0bf3cfdbc59..e94bd4e8aa1ee 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp
@@ -391,10 +391,7 @@ namespace partial_order_different_types {
   template<int N, typename T, typename U, T V> struct A<0, N, T, U, V> {}; // 
#P1
   template<int N, typename T, typename U, U V> struct A<0, N, T, U, V>;    // 
#P2
   // expected-error@-1 {{class template partial specialization is not more 
specialized than the primary template}}
-  A<0, 0, int, int, 0> a;
-  // expected-error@-1 {{ambiguous partial specializations}}
-  // expected-note@#P1 {{partial specialization matches}}
-  // expected-note@#P2 {{partial specialization matches}}
+  A<0, 0, int, int, 0> a; // OK: #P2 is invalid and excluded; only #P1 matches.
 }
 
 namespace partial_order_references {

``````````

</details>


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

Reply via email to