c++: constrained nested partial specialization [PR92103]
When determining the most specialized partial specialization of a primary template that is nested inside a class template, we first tsubst the outer template arguments into the TEMPLATE_DECL of each partial specialization, and then check for satisfaction of each of the new TEMPLATE_DECL's constraints. But tsubst_template_decl does not currently guarantee that constraints from the original DECL_TEMPLATE_RESULT get reattached to the new DECL_TEMPLATE_RESULT. In the testcase below, this leads to the constraints_satisfied_p check in most_specialized_partial_spec to trivially return true for each of the partial specializations. I'm not sure if such a guarantee would be desirable, but in this case we can just check constraints_satisfied_p on the original TEMPLATE_DECL instead of on the tsubsted TEMPLATE_DECL here, which is what this patch does (alongside some reorganizing). gcc/cp/ChangeLog: PR c++/92103 * pt.c (most_specialized_partial_spec): Reorganize the loop over DECL_TEMPLATE_SPECIALIZATIONS. Check constraints_satisfied_p on the original template declaration, not on the tsubsted one. gcc/testsuite/ChangeLog: PR c++/92103 * g++.dg/cpp2a/concepts-partial-spec7.C: New test.
This commit is contained in:
parent
3fb68f2e66
commit
aee69073cd
19
gcc/cp/pt.c
19
gcc/cp/pt.c
@ -24488,21 +24488,22 @@ most_specialized_partial_spec (tree target, tsubst_flags_t complain)
|
||||
|
||||
for (t = DECL_TEMPLATE_SPECIALIZATIONS (main_tmpl); t; t = TREE_CHAIN (t))
|
||||
{
|
||||
tree spec_args;
|
||||
tree spec_tmpl = TREE_VALUE (t);
|
||||
const tree ospec_tmpl = TREE_VALUE (t);
|
||||
|
||||
tree spec_tmpl;
|
||||
if (outer_args)
|
||||
{
|
||||
/* Substitute in the template args from the enclosing class. */
|
||||
++processing_template_decl;
|
||||
spec_tmpl = tsubst (spec_tmpl, outer_args, tf_none, NULL_TREE);
|
||||
spec_tmpl = tsubst (ospec_tmpl, outer_args, tf_none, NULL_TREE);
|
||||
--processing_template_decl;
|
||||
if (spec_tmpl == error_mark_node)
|
||||
return error_mark_node;
|
||||
}
|
||||
else
|
||||
spec_tmpl = ospec_tmpl;
|
||||
|
||||
if (spec_tmpl == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
spec_args = get_partial_spec_bindings (tmpl, spec_tmpl, args);
|
||||
tree spec_args = get_partial_spec_bindings (tmpl, spec_tmpl, args);
|
||||
if (spec_args)
|
||||
{
|
||||
if (outer_args)
|
||||
@ -24511,9 +24512,9 @@ most_specialized_partial_spec (tree target, tsubst_flags_t complain)
|
||||
/* Keep the candidate only if the constraints are satisfied,
|
||||
or if we're not compiling with concepts. */
|
||||
if (!flag_concepts
|
||||
|| constraints_satisfied_p (spec_tmpl, spec_args))
|
||||
|| constraints_satisfied_p (ospec_tmpl, spec_args))
|
||||
{
|
||||
list = tree_cons (spec_args, TREE_VALUE (t), list);
|
||||
list = tree_cons (spec_args, ospec_tmpl, list);
|
||||
TREE_TYPE (list) = TREE_TYPE (t);
|
||||
}
|
||||
}
|
||||
|
22
gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec7.C
Normal file
22
gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec7.C
Normal file
@ -0,0 +1,22 @@
|
||||
// PR c++/92103
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
template<int M>
|
||||
struct traits
|
||||
{
|
||||
template<int N>
|
||||
struct equal_to
|
||||
{ static constexpr bool value = false; };
|
||||
|
||||
template<int N> requires (M == N)
|
||||
struct equal_to<N>
|
||||
{ static constexpr bool value = true; };
|
||||
|
||||
template<int N> requires (M < 0) || (N < 0)
|
||||
struct equal_to<N>
|
||||
{ };
|
||||
};
|
||||
|
||||
static_assert(traits<0>::equal_to<0>::value);
|
||||
static_assert(!traits<0>::equal_to<1>::value);
|
||||
static_assert(traits<-1>::equal_to<0>::value); // { dg-error "not a member" }
|
Loading…
Reference in New Issue
Block a user