From: Patrick Palka Date: Sat, 1 Apr 2023 16:01:30 +0000 (-0400) Subject: c++: NTTP constraint depending on outer parms [PR109160] X-Git-Tag: basepoints/gcc-14~236 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a5de246535db1b4fdc61287f27de0fdd074fc4b3;p=thirdparty%2Fgcc.git c++: NTTP constraint depending on outer parms [PR109160] Here we're crashing during satisfaction for the NTTP 'C auto V' ultimately because convert_template_argument / unify don't pass all outer template arguments to do_auto_deduction, and during satisfaction we need to know all arguments. While these callers do pass some outer arguments, they are only sufficient to properly substitute the (level-lowered) 'auto' and are not necessarily the entire set. Fortunately it seems these callers have access to the full set of outer arguments via convert_template_argument's 'in_decl' parameter and unify's 'tparms' parameter. So this patch adds a new parameter to do_auto_deduction, used only during adc_unify deduction, through which these callers can pass the enclosing (partially instantiated) template and from which do_auto_deduction can obtain _all_ outer template arguments for sake of satisfaction. This patch also ensures that the 'in_decl' argument passed to coerce_template_parms is always a TEMPLATE_DECL, which in turn allows us to pass it as-is to do_auto_deduction; the only coerce_template_parms caller that needed adjustment was tsubst_decl it seems. PR c++/109160 gcc/cp/ChangeLog: * cp-tree.h (do_auto_deduction): Add defaulted tmpl parameter. * pt.cc (convert_template_argument): Pass 'in_decl' as 'tmpl' to do_auto_deduction. (tsubst_decl) : Pass 'tmpl' instead of 't' as 'in_decl' to coerce_template_parms. (unify) : Pass TPARMS_PRIMARY_TEMPLATE as 'tmpl' to do_auto_deduction. (do_auto_deduction): Document default arguments. Rename local variable 'tmpl' to 'ctmpl'. Use 'tmpl' to obtain a full set of template arguments for satisfaction in the adc_unify case. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-placeholder12.C: New test. --- diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d450b3d5b78a..622752ae4e6e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7326,7 +7326,8 @@ extern tree do_auto_deduction (tree, tree, tree, auto_deduction_context = adc_unspecified, tree = NULL_TREE, - int = LOOKUP_NORMAL); + int = LOOKUP_NORMAL, + tree = NULL_TREE); extern tree type_uses_auto (tree); extern tree type_uses_auto_or_concept (tree); extern void append_type_to_template_for_access_check (tree, tree, tree, diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 022f295b36f8..4429ae66b682 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -8644,7 +8644,7 @@ convert_template_argument (tree parm, else if (tree a = type_uses_auto (t)) { t = do_auto_deduction (t, arg, a, complain, adc_unify, args, - LOOKUP_IMPLICIT); + LOOKUP_IMPLICIT, /*tmpl=*/in_decl); if (t == error_mark_node) return error_mark_node; } @@ -15252,7 +15252,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) the template. */ argvec = (coerce_template_parms (DECL_TEMPLATE_PARMS (gen_tmpl), - argvec, t, complain)); + argvec, tmpl, complain)); if (argvec == error_mark_node) RETURN (error_mark_node); hash = spec_hasher::hash (gen_tmpl, argvec); @@ -24730,7 +24730,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, if (tree a = type_uses_auto (tparm)) { tparm = do_auto_deduction (tparm, arg, a, - complain, adc_unify, targs); + complain, adc_unify, targs, + LOOKUP_NORMAL, + TPARMS_PRIMARY_TEMPLATE (tparms)); if (tparm == error_mark_node) return 1; } @@ -30779,13 +30781,20 @@ unparenthesized_id_or_class_member_access_p (tree init) adc_requirement contexts to communicate the necessary template arguments to satisfaction. OUTER_TARGS is ignored in other contexts. - For partial-concept-ids, extra args may be appended to the list of deduced - template arguments prior to determining constraint satisfaction. */ + Additionally for adc_unify contexts TMPL is the template for which TYPE + is a template parameter type. + + For partial-concept-ids, extra args from OUTER_TARGS, TMPL and the current + scope may be appended to the list of deduced template arguments prior to + determining constraint satisfaction as appropriate. */ tree do_auto_deduction (tree type, tree init, tree auto_node, - tsubst_flags_t complain, auto_deduction_context context, - tree outer_targs, int flags) + tsubst_flags_t complain /* = tf_warning_or_error */, + auto_deduction_context context /* = adc_unspecified */, + tree outer_targs /* = NULL_TREE */, + int flags /* = LOOKUP_NORMAL */, + tree tmpl /* = NULL_TREE */) { if (init == error_mark_node) return error_mark_node; @@ -30821,9 +30830,9 @@ do_auto_deduction (tree type, tree init, tree auto_node, /*return*/true))) init = r; - if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) + if (tree ctmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) /* C++17 class template argument deduction. */ - return do_class_deduction (type, tmpl, init, flags, complain); + return do_class_deduction (type, ctmpl, init, flags, complain); if (init == NULL_TREE || TREE_TYPE (init) == NULL_TREE) /* Nothing we can do with this, even in deduction context. */ @@ -30975,7 +30984,10 @@ do_auto_deduction (tree type, tree init, tree auto_node, } } - tree full_targs = add_to_template_args (outer_targs, targs); + tree full_targs = outer_targs; + if (context == adc_unify && tmpl) + full_targs = add_outermost_template_args (tmpl, full_targs); + full_targs = add_to_template_args (full_targs, targs); /* HACK: Compensate for callers not always communicating all levels of outer template arguments by filling in the outermost missing levels diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder12.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder12.C new file mode 100644 index 000000000000..22f0ac5e26a1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder12.C @@ -0,0 +1,29 @@ +// PR c++/109160 +// { dg-do compile { target c++20 } } + +template +concept C = B; + +template struct X { }; + +template +struct A { + template auto V> static void f(); + template auto V> static void g(X); + template auto V> static inline int value; + template auto V> struct D { }; +}; + +int main() { + A::f<0>(); + A::f<0>(); // { dg-error "no match|constraints" } + + A::g(X<0>{}); + A::g(X<0>{}); // { dg-error "no match|constraints" } + + bool v1 = A::value<0>; + bool v2 = A::value<0>; // { dg-error "constraints" } + + A::D<0> d1; + A::D<0> d2; // { dg-error "constraints" } +}