* [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] @ 2022-02-14 16:32 Patrick Palka 2022-02-14 16:37 ` Patrick Palka 2022-02-15 23:39 ` Jason Merrill 0 siblings, 2 replies; 8+ messages in thread From: Patrick Palka @ 2022-02-14 16:32 UTC (permalink / raw) To: gcc-patches Here the template context for the atomic constraint has two levels of template arguments, but since it depends only on the innermost argument T we use a single-level argument vector during substitution into the constraint (built by get_mapped_args). We eventually pass this vector to do_auto_deduction as part of checking the return-type-requirement inside the atom, but do_auto_deduction expects outer_targs to be a full set of arguments for sake of satisfaction. do_auto_deduction has a workaround in place to compensate for callers that pass only the innermost arguments as outer_targs, but here we're passing the _outermost_ arguments. Since the former situation should now (after r12-7101) only occur with adc_unify callers and the latter only with adc_requirement callers, this patch conditions the existing workaround according to the auto_deduction_context: if the context is adc_requirement, we add dummy innermost levels, otherwise we add dummy outermost levels as before and also assert that the context is adc_unify. Bootstrapped and regtested on x86_64-pc-linux-gnu and tested on cmcstl2 and range-v3, does this look OK for trunk? PR c++/104527 gcc/cp/ChangeLog: * pt.cc (do_auto_deduction): When template argument levels are missing from outer_targs, fill in the innermost rather than the outermost levels with dummy args if the context is adc_requirement, otherwise also assert that the context is adc_unify. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-return-req4.C: New test. --- gcc/cp/pt.cc | 28 +++++++++++++------ .../g++.dg/cpp2a/concepts-return-req4.C | 24 ++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 1b18e2a7787..4ff2710b8ba 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30215,20 +30215,32 @@ do_auto_deduction (tree type, tree init, tree auto_node, tree full_targs = add_to_template_args (outer_targs, targs); - /* HACK: Compensate for callers not always communicating all levels of - outer template arguments by filling in the outermost missing levels - with dummy levels before checking satisfaction. We'll still crash - if the constraint depends on a template argument belonging to one of - these missing levels, but this hack otherwise allows us to handle a - large subset of possible constraints (including all non-dependent - constraints). */ if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node) - TMPL_ARGS_DEPTH (full_targs))) { tree dummy_levels = make_tree_vec (missing_levels); for (int i = 0; i < missing_levels; ++i) TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0); - full_targs = add_to_template_args (dummy_levels, full_targs); + if (context == adc_requirement) + /* We're checking a requires-expr's return-type-requirement that's + part of an atomic constraint that doesn't depend on any innermost + template arguments, so OUTER_TARGS (built by get_mapped_args) is + missing at least one innermost level. Fill in the innermost + levels of OUTER_TARGS with dummy levels. */ + full_targs = add_to_template_args + (add_to_template_args (outer_targs, dummy_levels), targs); + else + { + /* Otherwise, fill in the _outermost_ levels with dummy levels. + This compensates for adc_unify callers that only pass the + innermost level of template arguments as OUTER_TARGS. We'll + still crash if the constraint depends on a template argument + belonging to one of these missing levels, but this hack + otherwise allows us to handle a large subset of possible + constraints (including all non-dependent constraints). */ + gcc_checking_assert (context == adc_unify); + full_targs = add_to_template_args (dummy_levels, full_targs); + } } if (!constraints_satisfied_p (auto_node, full_targs)) diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C new file mode 100644 index 00000000000..471946bc8eb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C @@ -0,0 +1,24 @@ +// PR c++/104527 +// { dg-do compile { target c++20 } } + +template<class T, class U> +concept is_same = __is_same(T, U); + +template<class T> +struct A { + template<class...> + requires requires { { 0 } -> is_same<T>; } + struct B {}; + + template<class...> + requires requires { { 1 } -> is_same<T>; } + static void f(); +}; + +A<int>::B<> a1; +A<bool>::B<> a2; // { dg-error "constraint" } + +int main() { + A<int>::f(); + A<bool>::f(); // { dg-error "no match" } +} -- 2.35.1.102.g2b9c120970 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] 2022-02-14 16:32 [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] Patrick Palka @ 2022-02-14 16:37 ` Patrick Palka 2022-02-15 23:39 ` Jason Merrill 1 sibling, 0 replies; 8+ messages in thread From: Patrick Palka @ 2022-02-14 16:37 UTC (permalink / raw) To: Patrick Palka; +Cc: gcc-patches, jason On Mon, 14 Feb 2022, Patrick Palka wrote: > Here the template context for the atomic constraint has two levels of > template arguments, but since it depends only on the innermost argument > T we use a single-level argument vector during substitution into the > constraint (built by get_mapped_args). We eventually pass this vector > to do_auto_deduction as part of checking the return-type-requirement > inside the atom, but do_auto_deduction expects outer_targs to be a full > set of arguments for sake of satisfaction. > > do_auto_deduction has a workaround in place to compensate for callers > that pass only the innermost arguments as outer_targs, but here we're > passing the _outermost_ arguments. Since the former situation should > now (after r12-7101) only occur with adc_unify callers and the latter Whoops, this should be r12-6919 (after which we pass outer_targs appropriately during adc_variable_type deduction of non-function-scope variables), not r12-7101, sorry about that. > only with adc_requirement callers, this patch conditions the existing > workaround according to the auto_deduction_context: if the context is > adc_requirement, we add dummy innermost levels, otherwise we add dummy > outermost levels as before and also assert that the context is adc_unify. > > Bootstrapped and regtested on x86_64-pc-linux-gnu and tested on cmcstl2 > and range-v3, does this look OK for trunk? > > PR c++/104527 > > gcc/cp/ChangeLog: > > * pt.cc (do_auto_deduction): When template argument levels are > missing from outer_targs, fill in the innermost rather than the > outermost levels with dummy args if the context is > adc_requirement, otherwise also assert that the context is > adc_unify. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/concepts-return-req4.C: New test. > --- > gcc/cp/pt.cc | 28 +++++++++++++------ > .../g++.dg/cpp2a/concepts-return-req4.C | 24 ++++++++++++++++ > 2 files changed, 44 insertions(+), 8 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index 1b18e2a7787..4ff2710b8ba 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -30215,20 +30215,32 @@ do_auto_deduction (tree type, tree init, tree auto_node, > > tree full_targs = add_to_template_args (outer_targs, targs); > > - /* HACK: Compensate for callers not always communicating all levels of > - outer template arguments by filling in the outermost missing levels > - with dummy levels before checking satisfaction. We'll still crash > - if the constraint depends on a template argument belonging to one of > - these missing levels, but this hack otherwise allows us to handle a > - large subset of possible constraints (including all non-dependent > - constraints). */ > if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node) > - TMPL_ARGS_DEPTH (full_targs))) > { > tree dummy_levels = make_tree_vec (missing_levels); > for (int i = 0; i < missing_levels; ++i) > TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0); > - full_targs = add_to_template_args (dummy_levels, full_targs); > + if (context == adc_requirement) > + /* We're checking a requires-expr's return-type-requirement that's > + part of an atomic constraint that doesn't depend on any innermost > + template arguments, so OUTER_TARGS (built by get_mapped_args) is > + missing at least one innermost level. Fill in the innermost > + levels of OUTER_TARGS with dummy levels. */ > + full_targs = add_to_template_args > + (add_to_template_args (outer_targs, dummy_levels), targs); > + else > + { > + /* Otherwise, fill in the _outermost_ levels with dummy levels. > + This compensates for adc_unify callers that only pass the > + innermost level of template arguments as OUTER_TARGS. We'll > + still crash if the constraint depends on a template argument > + belonging to one of these missing levels, but this hack > + otherwise allows us to handle a large subset of possible > + constraints (including all non-dependent constraints). */ > + gcc_checking_assert (context == adc_unify); > + full_targs = add_to_template_args (dummy_levels, full_targs); > + } > } > > if (!constraints_satisfied_p (auto_node, full_targs)) > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > new file mode 100644 > index 00000000000..471946bc8eb > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > @@ -0,0 +1,24 @@ > +// PR c++/104527 > +// { dg-do compile { target c++20 } } > + > +template<class T, class U> > +concept is_same = __is_same(T, U); > + > +template<class T> > +struct A { > + template<class...> > + requires requires { { 0 } -> is_same<T>; } > + struct B {}; > + > + template<class...> > + requires requires { { 1 } -> is_same<T>; } > + static void f(); > +}; > + > +A<int>::B<> a1; > +A<bool>::B<> a2; // { dg-error "constraint" } > + > +int main() { > + A<int>::f(); > + A<bool>::f(); // { dg-error "no match" } > +} > -- > 2.35.1.102.g2b9c120970 > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] 2022-02-14 16:32 [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] Patrick Palka 2022-02-14 16:37 ` Patrick Palka @ 2022-02-15 23:39 ` Jason Merrill 2022-02-16 19:56 ` Patrick Palka 1 sibling, 1 reply; 8+ messages in thread From: Jason Merrill @ 2022-02-15 23:39 UTC (permalink / raw) To: Patrick Palka, gcc-patches On 2/14/22 11:32, Patrick Palka wrote: > Here the template context for the atomic constraint has two levels of > template arguments, but since it depends only on the innermost argument > T we use a single-level argument vector during substitution into the > constraint (built by get_mapped_args). We eventually pass this vector > to do_auto_deduction as part of checking the return-type-requirement > inside the atom, but do_auto_deduction expects outer_targs to be a full > set of arguments for sake of satisfaction. Could we note the current number of levels in the map and use that in get_mapped_args instead of the highest level parameter we happened to use? > do_auto_deduction has a workaround in place to compensate for callers > that pass only the innermost arguments as outer_targs, but here we're > passing the _outermost_ arguments. Since the former situation should > now (after r12-7101) only occur with adc_unify callers and the latter > only with adc_requirement callers, this patch conditions the existing > workaround according to the auto_deduction_context: if the context is > adc_requirement, we add dummy innermost levels, otherwise we add dummy > outermost levels as before and also assert that the context is adc_unify. > > Bootstrapped and regtested on x86_64-pc-linux-gnu and tested on cmcstl2 > and range-v3, does this look OK for trunk? > > PR c++/104527 > > gcc/cp/ChangeLog: > > * pt.cc (do_auto_deduction): When template argument levels are > missing from outer_targs, fill in the innermost rather than the > outermost levels with dummy args if the context is > adc_requirement, otherwise also assert that the context is > adc_unify. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/concepts-return-req4.C: New test. > --- > gcc/cp/pt.cc | 28 +++++++++++++------ > .../g++.dg/cpp2a/concepts-return-req4.C | 24 ++++++++++++++++ > 2 files changed, 44 insertions(+), 8 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index 1b18e2a7787..4ff2710b8ba 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -30215,20 +30215,32 @@ do_auto_deduction (tree type, tree init, tree auto_node, > > tree full_targs = add_to_template_args (outer_targs, targs); > > - /* HACK: Compensate for callers not always communicating all levels of > - outer template arguments by filling in the outermost missing levels > - with dummy levels before checking satisfaction. We'll still crash > - if the constraint depends on a template argument belonging to one of > - these missing levels, but this hack otherwise allows us to handle a > - large subset of possible constraints (including all non-dependent > - constraints). */ > if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node) > - TMPL_ARGS_DEPTH (full_targs))) > { > tree dummy_levels = make_tree_vec (missing_levels); > for (int i = 0; i < missing_levels; ++i) > TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0); > - full_targs = add_to_template_args (dummy_levels, full_targs); > + if (context == adc_requirement) > + /* We're checking a requires-expr's return-type-requirement that's > + part of an atomic constraint that doesn't depend on any innermost > + template arguments, so OUTER_TARGS (built by get_mapped_args) is > + missing at least one innermost level. Fill in the innermost > + levels of OUTER_TARGS with dummy levels. */ > + full_targs = add_to_template_args > + (add_to_template_args (outer_targs, dummy_levels), targs); > + else > + { > + /* Otherwise, fill in the _outermost_ levels with dummy levels. > + This compensates for adc_unify callers that only pass the > + innermost level of template arguments as OUTER_TARGS. We'll > + still crash if the constraint depends on a template argument > + belonging to one of these missing levels, but this hack > + otherwise allows us to handle a large subset of possible > + constraints (including all non-dependent constraints). */ > + gcc_checking_assert (context == adc_unify); > + full_targs = add_to_template_args (dummy_levels, full_targs); > + } > } > > if (!constraints_satisfied_p (auto_node, full_targs)) > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > new file mode 100644 > index 00000000000..471946bc8eb > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > @@ -0,0 +1,24 @@ > +// PR c++/104527 > +// { dg-do compile { target c++20 } } > + > +template<class T, class U> > +concept is_same = __is_same(T, U); > + > +template<class T> > +struct A { > + template<class...> > + requires requires { { 0 } -> is_same<T>; } > + struct B {}; > + > + template<class...> > + requires requires { { 1 } -> is_same<T>; } > + static void f(); > +}; > + > +A<int>::B<> a1; > +A<bool>::B<> a2; // { dg-error "constraint" } > + > +int main() { > + A<int>::f(); > + A<bool>::f(); // { dg-error "no match" } > +} ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] 2022-02-15 23:39 ` Jason Merrill @ 2022-02-16 19:56 ` Patrick Palka 2022-03-01 13:13 ` Patrick Palka 2022-03-10 19:43 ` Jason Merrill 0 siblings, 2 replies; 8+ messages in thread From: Patrick Palka @ 2022-02-16 19:56 UTC (permalink / raw) To: Jason Merrill; +Cc: Patrick Palka, gcc-patches On Tue, 15 Feb 2022, Jason Merrill wrote: > On 2/14/22 11:32, Patrick Palka wrote: > > Here the template context for the atomic constraint has two levels of > > template arguments, but since it depends only on the innermost argument > > T we use a single-level argument vector during substitution into the > > constraint (built by get_mapped_args). We eventually pass this vector > > to do_auto_deduction as part of checking the return-type-requirement > > inside the atom, but do_auto_deduction expects outer_targs to be a full > > set of arguments for sake of satisfaction. > > Could we note the current number of levels in the map and use that in > get_mapped_args instead of the highest level parameter we happened to use? Ah yeah, that seems to work nicely. IIUC it should suffice to remember whether the atomic constraint expression came from a concept definition. If it did, then the depth of the argument vector returned by get_mapped_args must be one, otherwise (as in the testcase) it must be the same as the template depth of the constrained entity, which is the depth of ARGS. How does the following look? Bootstrapped and regtested on x86_64-pc-linux-gnu and also on cmcstl2 and range-v3. -- >8 -- Subject: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] Here the template context for the atomic constraint has two levels of template parameters, but since it depends only on the innermost parameter T we use a single-level argument vector (built by get_mapped_args) during substitution into the atom. We eventually pass this vector to do_auto_deduction as part of checking the return-type-requirement within the atom, but do_auto_deduction expects outer_targs to be a full set of arguments for sake of satisfaction. This patch fixes this by making get_mapped_args always return an argument vector whose depth corresponds to the template depth of the context in which the atomic constraint expression was written, instead of the highest parameter level that the expression happens to use. PR c++/104527 gcc/cp/ChangeLog: * constraint.cc (normalize_atom): Set ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P appropriately. (get_mapped_args): Make static, adjust parameters. Always return a vector whose depth corresponds to the template depth of the context of the atomic constraint expression. Micro-optimize by passing false as exact to safe_grow_cleared and by collapsing a multi-level depth-one argument vector. (satisfy_atom): Adjust call to get_mapped_args and diagnose_atomic_constraint. (diagnose_atomic_constraint): Replace map parameter with an args parameter. * cp-tree.h (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P): Define. (get_mapped_args): Remove declaration. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-return-req4.C: New test. --- gcc/cp/constraint.cc | 64 +++++++++++-------- gcc/cp/cp-tree.h | 7 +- .../g++.dg/cpp2a/concepts-return-req4.C | 24 +++++++ 3 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 12db7e5cf14..306e28955c6 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -764,6 +764,8 @@ normalize_atom (tree t, tree args, norm_info info) tree ci = build_tree_list (t, info.context); tree atom = build1 (ATOMIC_CONSTR, ci, map); + if (info.in_decl && concept_definition_p (info.in_decl)) + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true; if (!info.generate_diagnostics ()) { /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal @@ -2826,33 +2828,37 @@ satisfaction_value (tree t) return boolean_true_node; } -/* Build a new template argument list with template arguments corresponding - to the parameters used in an atomic constraint. */ +/* Build a new template argument vector according to the parameter + mapping of the atomic constraint T, using arguments from ARGS. */ -tree -get_mapped_args (tree map) +static tree +get_mapped_args (tree t, tree args) { + tree map = ATOMIC_CONSTR_MAP (t); + /* No map, no arguments. */ if (!map) return NULL_TREE; - /* Find the mapped parameter with the highest level. */ - int count = 0; - for (tree p = map; p; p = TREE_CHAIN (p)) - { - int level; - int index; - template_parm_level_and_index (TREE_VALUE (p), &level, &index); - if (level > count) - count = level; - } + /* Determine the depth of the resulting argument vector. */ + int depth; + if (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (t)) + /* The expression of this atomic constraint comes from a concept definition, + whose template depth is always one, so the resulting argument vector + will also have depth one. */ + depth = 1; + else + /* Otherwise, the expression of this atomic constraint was written in + the context of the constrained entity, whose template depth is that + of ARGS. */ + depth = TMPL_ARGS_DEPTH (args); /* Place each argument at its corresponding position in the argument list. Note that the list will be sparse (not all arguments supplied), but instantiation is guaranteed to only use the parameters in the mapping, so null arguments would never be used. */ - auto_vec< vec<tree> > lists (count); - lists.quick_grow_cleared (count); + auto_vec< vec<tree> > lists (depth); + lists.quick_grow_cleared (depth); for (tree p = map; p; p = TREE_CHAIN (p)) { int level; @@ -2862,12 +2868,12 @@ get_mapped_args (tree map) /* Insert the argument into its corresponding position. */ vec<tree> &list = lists[level - 1]; if (index >= (int)list.length ()) - list.safe_grow_cleared (index + 1, true); + list.safe_grow_cleared (index + 1, /*exact=*/false); list[index] = TREE_PURPOSE (p); } /* Build the new argument list. */ - tree args = make_tree_vec (lists.length ()); + args = make_tree_vec (lists.length ()); for (unsigned i = 0; i != lists.length (); ++i) { vec<tree> &list = lists[i]; @@ -2879,6 +2885,16 @@ get_mapped_args (tree map) } SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0); + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args) + && TMPL_ARGS_DEPTH (args) == 1) + { + /* Micro-optimization: represent a depth-one argument vector + using a single level. */ + tree level = TMPL_ARGS_LEVEL (args, 1); + ggc_free (args); + args = level; + } + return args; } @@ -2933,7 +2949,7 @@ satisfy_atom (tree t, tree args, sat_info info) } /* Rebuild the argument vector from the parameter mapping. */ - args = get_mapped_args (map); + args = get_mapped_args (t, args); /* Apply the parameter mapping (i.e., just substitute). */ tree expr = ATOMIC_CONSTR_EXPR (t); @@ -2955,7 +2971,7 @@ satisfy_atom (tree t, tree args, sat_info info) if (!same_type_p (TREE_TYPE (result), boolean_type_node)) { if (info.noisy ()) - diagnose_atomic_constraint (t, map, result, info); + diagnose_atomic_constraint (t, args, result, info); return cache.save (inst_cache.save (error_mark_node)); } @@ -2974,7 +2990,7 @@ satisfy_atom (tree t, tree args, sat_info info) } result = satisfaction_value (result); if (result == boolean_false_node && info.diagnose_unsatisfaction_p ()) - diagnose_atomic_constraint (t, map, result, info); + diagnose_atomic_constraint (t, args, result, info); return cache.save (inst_cache.save (result)); } @@ -3642,11 +3658,10 @@ diagnose_trait_expr (tree expr, tree args) } } -/* Diagnose a substitution failure in the atomic constraint T when applied - with the instantiated parameter mapping MAP. */ +/* Diagnose a substitution failure in the atomic constraint T using ARGS. */ static void -diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info) +diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info) { /* If the constraint is already ill-formed, we've previously diagnosed the reason. We should still say why the constraints aren't satisfied. */ @@ -3667,7 +3682,6 @@ diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info) /* Generate better diagnostics for certain kinds of expressions. */ tree expr = ATOMIC_CONSTR_EXPR (t); STRIP_ANY_LOCATION_WRAPPER (expr); - tree args = get_mapped_args (map); switch (TREE_CODE (expr)) { case TRAIT_EXPR: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f253b32c3f2..dc2429a8406 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -466,6 +466,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; IMPLICIT_CONV_EXPR_NONTYPE_ARG (in IMPLICIT_CONV_EXPR) BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (in BASELINK) BIND_EXPR_VEC_DTOR (in BIND_EXPR) + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR) 2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE) ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) @@ -1679,6 +1680,11 @@ check_constraint_info (tree t) #define ATOMIC_CONSTR_MAP_INSTANTIATED_P(NODE) \ TREE_LANG_FLAG_0 (ATOMIC_CONSTR_CHECK (NODE)) +/* Whether the expression for this atomic constraint belongs to a + concept definition. */ +#define ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P(NODE) \ + TREE_LANG_FLAG_1 (ATOMIC_CONSTR_CHECK (NODE)) + /* The expression of an atomic constraint. */ #define ATOMIC_CONSTR_EXPR(NODE) \ CONSTR_EXPR (ATOMIC_CONSTR_CHECK (NODE)) @@ -8306,7 +8312,6 @@ extern tree evaluate_requires_expr (tree); extern tree tsubst_constraint (tree, tree, tsubst_flags_t, tree); extern tree tsubst_constraint_info (tree, tree, tsubst_flags_t, tree); extern tree tsubst_parameter_mapping (tree, tree, tsubst_flags_t, tree); -extern tree get_mapped_args (tree); struct processing_constraint_expression_sentinel { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C new file mode 100644 index 00000000000..471946bc8eb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C @@ -0,0 +1,24 @@ +// PR c++/104527 +// { dg-do compile { target c++20 } } + +template<class T, class U> +concept is_same = __is_same(T, U); + +template<class T> +struct A { + template<class...> + requires requires { { 0 } -> is_same<T>; } + struct B {}; + + template<class...> + requires requires { { 1 } -> is_same<T>; } + static void f(); +}; + +A<int>::B<> a1; +A<bool>::B<> a2; // { dg-error "constraint" } + +int main() { + A<int>::f(); + A<bool>::f(); // { dg-error "no match" } +} -- 2.35.1.129.gb80121027d ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] 2022-02-16 19:56 ` Patrick Palka @ 2022-03-01 13:13 ` Patrick Palka 2022-03-10 19:43 ` Jason Merrill 1 sibling, 0 replies; 8+ messages in thread From: Patrick Palka @ 2022-03-01 13:13 UTC (permalink / raw) To: Jason Merrill; +Cc: GCC Patches On Wed, Feb 16, 2022 at 2:56 PM Patrick Palka <ppalka@redhat.com> wrote: > > On Tue, 15 Feb 2022, Jason Merrill wrote: > > > On 2/14/22 11:32, Patrick Palka wrote: > > > Here the template context for the atomic constraint has two levels of > > > template arguments, but since it depends only on the innermost argument > > > T we use a single-level argument vector during substitution into the > > > constraint (built by get_mapped_args). We eventually pass this vector > > > to do_auto_deduction as part of checking the return-type-requirement > > > inside the atom, but do_auto_deduction expects outer_targs to be a full > > > set of arguments for sake of satisfaction. > > > > Could we note the current number of levels in the map and use that in > > get_mapped_args instead of the highest level parameter we happened to use? > > Ah yeah, that seems to work nicely. IIUC it should suffice to remember > whether the atomic constraint expression came from a concept definition. > If it did, then the depth of the argument vector returned by > get_mapped_args must be one, otherwise (as in the testcase) it must be > the same as the template depth of the constrained entity, which is the > depth of ARGS. > > How does the following look? Bootstrapped and regtested on > x86_64-pc-linux-gnu and also on cmcstl2 and range-v3. Ping. > > -- >8 -- > > Subject: [PATCH] c++: return-type-req in constraint using only outer tparms > [PR104527] > > Here the template context for the atomic constraint has two levels of > template parameters, but since it depends only on the innermost parameter > T we use a single-level argument vector (built by get_mapped_args) during > substitution into the atom. We eventually pass this vector to > do_auto_deduction as part of checking the return-type-requirement within > the atom, but do_auto_deduction expects outer_targs to be a full set of > arguments for sake of satisfaction. > > This patch fixes this by making get_mapped_args always return an > argument vector whose depth corresponds to the template depth of the > context in which the atomic constraint expression was written, instead > of the highest parameter level that the expression happens to use. > > PR c++/104527 > > gcc/cp/ChangeLog: > > * constraint.cc (normalize_atom): Set > ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P appropriately. > (get_mapped_args): Make static, adjust parameters. Always > return a vector whose depth corresponds to the template depth of > the context of the atomic constraint expression. Micro-optimize > by passing false as exact to safe_grow_cleared and by collapsing > a multi-level depth-one argument vector. > (satisfy_atom): Adjust call to get_mapped_args and > diagnose_atomic_constraint. > (diagnose_atomic_constraint): Replace map parameter with an args > parameter. > * cp-tree.h (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P): Define. > (get_mapped_args): Remove declaration. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/concepts-return-req4.C: New test. > --- > gcc/cp/constraint.cc | 64 +++++++++++-------- > gcc/cp/cp-tree.h | 7 +- > .../g++.dg/cpp2a/concepts-return-req4.C | 24 +++++++ > 3 files changed, 69 insertions(+), 26 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc > index 12db7e5cf14..306e28955c6 100644 > --- a/gcc/cp/constraint.cc > +++ b/gcc/cp/constraint.cc > @@ -764,6 +764,8 @@ normalize_atom (tree t, tree args, norm_info info) > tree ci = build_tree_list (t, info.context); > > tree atom = build1 (ATOMIC_CONSTR, ci, map); > + if (info.in_decl && concept_definition_p (info.in_decl)) > + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true; > if (!info.generate_diagnostics ()) > { > /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal > @@ -2826,33 +2828,37 @@ satisfaction_value (tree t) > return boolean_true_node; > } > > -/* Build a new template argument list with template arguments corresponding > - to the parameters used in an atomic constraint. */ > +/* Build a new template argument vector according to the parameter > + mapping of the atomic constraint T, using arguments from ARGS. */ > > -tree > -get_mapped_args (tree map) > +static tree > +get_mapped_args (tree t, tree args) > { > + tree map = ATOMIC_CONSTR_MAP (t); > + > /* No map, no arguments. */ > if (!map) > return NULL_TREE; > > - /* Find the mapped parameter with the highest level. */ > - int count = 0; > - for (tree p = map; p; p = TREE_CHAIN (p)) > - { > - int level; > - int index; > - template_parm_level_and_index (TREE_VALUE (p), &level, &index); > - if (level > count) > - count = level; > - } > + /* Determine the depth of the resulting argument vector. */ > + int depth; > + if (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (t)) > + /* The expression of this atomic constraint comes from a concept definition, > + whose template depth is always one, so the resulting argument vector > + will also have depth one. */ > + depth = 1; > + else > + /* Otherwise, the expression of this atomic constraint was written in > + the context of the constrained entity, whose template depth is that > + of ARGS. */ > + depth = TMPL_ARGS_DEPTH (args); > > /* Place each argument at its corresponding position in the argument > list. Note that the list will be sparse (not all arguments supplied), > but instantiation is guaranteed to only use the parameters in the > mapping, so null arguments would never be used. */ > - auto_vec< vec<tree> > lists (count); > - lists.quick_grow_cleared (count); > + auto_vec< vec<tree> > lists (depth); > + lists.quick_grow_cleared (depth); > for (tree p = map; p; p = TREE_CHAIN (p)) > { > int level; > @@ -2862,12 +2868,12 @@ get_mapped_args (tree map) > /* Insert the argument into its corresponding position. */ > vec<tree> &list = lists[level - 1]; > if (index >= (int)list.length ()) > - list.safe_grow_cleared (index + 1, true); > + list.safe_grow_cleared (index + 1, /*exact=*/false); > list[index] = TREE_PURPOSE (p); > } > > /* Build the new argument list. */ > - tree args = make_tree_vec (lists.length ()); > + args = make_tree_vec (lists.length ()); > for (unsigned i = 0; i != lists.length (); ++i) > { > vec<tree> &list = lists[i]; > @@ -2879,6 +2885,16 @@ get_mapped_args (tree map) > } > SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0); > > + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args) > + && TMPL_ARGS_DEPTH (args) == 1) > + { > + /* Micro-optimization: represent a depth-one argument vector > + using a single level. */ > + tree level = TMPL_ARGS_LEVEL (args, 1); > + ggc_free (args); > + args = level; > + } > + > return args; > } > > @@ -2933,7 +2949,7 @@ satisfy_atom (tree t, tree args, sat_info info) > } > > /* Rebuild the argument vector from the parameter mapping. */ > - args = get_mapped_args (map); > + args = get_mapped_args (t, args); > > /* Apply the parameter mapping (i.e., just substitute). */ > tree expr = ATOMIC_CONSTR_EXPR (t); > @@ -2955,7 +2971,7 @@ satisfy_atom (tree t, tree args, sat_info info) > if (!same_type_p (TREE_TYPE (result), boolean_type_node)) > { > if (info.noisy ()) > - diagnose_atomic_constraint (t, map, result, info); > + diagnose_atomic_constraint (t, args, result, info); > return cache.save (inst_cache.save (error_mark_node)); > } > > @@ -2974,7 +2990,7 @@ satisfy_atom (tree t, tree args, sat_info info) > } > result = satisfaction_value (result); > if (result == boolean_false_node && info.diagnose_unsatisfaction_p ()) > - diagnose_atomic_constraint (t, map, result, info); > + diagnose_atomic_constraint (t, args, result, info); > > return cache.save (inst_cache.save (result)); > } > @@ -3642,11 +3658,10 @@ diagnose_trait_expr (tree expr, tree args) > } > } > > -/* Diagnose a substitution failure in the atomic constraint T when applied > - with the instantiated parameter mapping MAP. */ > +/* Diagnose a substitution failure in the atomic constraint T using ARGS. */ > > static void > -diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info) > +diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info) > { > /* If the constraint is already ill-formed, we've previously diagnosed > the reason. We should still say why the constraints aren't satisfied. */ > @@ -3667,7 +3682,6 @@ diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info) > /* Generate better diagnostics for certain kinds of expressions. */ > tree expr = ATOMIC_CONSTR_EXPR (t); > STRIP_ANY_LOCATION_WRAPPER (expr); > - tree args = get_mapped_args (map); > switch (TREE_CODE (expr)) > { > case TRAIT_EXPR: > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index f253b32c3f2..dc2429a8406 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -466,6 +466,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; > IMPLICIT_CONV_EXPR_NONTYPE_ARG (in IMPLICIT_CONV_EXPR) > BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (in BASELINK) > BIND_EXPR_VEC_DTOR (in BIND_EXPR) > + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR) > 2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE) > ICS_THIS_FLAG (in _CONV) > DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) > @@ -1679,6 +1680,11 @@ check_constraint_info (tree t) > #define ATOMIC_CONSTR_MAP_INSTANTIATED_P(NODE) \ > TREE_LANG_FLAG_0 (ATOMIC_CONSTR_CHECK (NODE)) > > +/* Whether the expression for this atomic constraint belongs to a > + concept definition. */ > +#define ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P(NODE) \ > + TREE_LANG_FLAG_1 (ATOMIC_CONSTR_CHECK (NODE)) > + > /* The expression of an atomic constraint. */ > #define ATOMIC_CONSTR_EXPR(NODE) \ > CONSTR_EXPR (ATOMIC_CONSTR_CHECK (NODE)) > @@ -8306,7 +8312,6 @@ extern tree evaluate_requires_expr (tree); > extern tree tsubst_constraint (tree, tree, tsubst_flags_t, tree); > extern tree tsubst_constraint_info (tree, tree, tsubst_flags_t, tree); > extern tree tsubst_parameter_mapping (tree, tree, tsubst_flags_t, tree); > -extern tree get_mapped_args (tree); > > struct processing_constraint_expression_sentinel > { > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > new file mode 100644 > index 00000000000..471946bc8eb > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > @@ -0,0 +1,24 @@ > +// PR c++/104527 > +// { dg-do compile { target c++20 } } > + > +template<class T, class U> > +concept is_same = __is_same(T, U); > + > +template<class T> > +struct A { > + template<class...> > + requires requires { { 0 } -> is_same<T>; } > + struct B {}; > + > + template<class...> > + requires requires { { 1 } -> is_same<T>; } > + static void f(); > +}; > + > +A<int>::B<> a1; > +A<bool>::B<> a2; // { dg-error "constraint" } > + > +int main() { > + A<int>::f(); > + A<bool>::f(); // { dg-error "no match" } > +} > -- > 2.35.1.129.gb80121027d > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] 2022-02-16 19:56 ` Patrick Palka 2022-03-01 13:13 ` Patrick Palka @ 2022-03-10 19:43 ` Jason Merrill 2022-03-10 20:57 ` Patrick Palka 1 sibling, 1 reply; 8+ messages in thread From: Jason Merrill @ 2022-03-10 19:43 UTC (permalink / raw) To: Patrick Palka; +Cc: gcc-patches On 2/16/22 15:56, Patrick Palka wrote: > On Tue, 15 Feb 2022, Jason Merrill wrote: > >> On 2/14/22 11:32, Patrick Palka wrote: >>> Here the template context for the atomic constraint has two levels of >>> template arguments, but since it depends only on the innermost argument >>> T we use a single-level argument vector during substitution into the >>> constraint (built by get_mapped_args). We eventually pass this vector >>> to do_auto_deduction as part of checking the return-type-requirement >>> inside the atom, but do_auto_deduction expects outer_targs to be a full >>> set of arguments for sake of satisfaction. >> >> Could we note the current number of levels in the map and use that in >> get_mapped_args instead of the highest level parameter we happened to use? > > Ah yeah, that seems to work nicely. IIUC it should suffice to remember > whether the atomic constraint expression came from a concept definition. > If it did, then the depth of the argument vector returned by > get_mapped_args must be one, otherwise (as in the testcase) it must be > the same as the template depth of the constrained entity, which is the > depth of ARGS. > > How does the following look? Bootstrapped and regtested on > x86_64-pc-linux-gnu and also on cmcstl2 and range-v3. > > -- >8 -- > > Subject: [PATCH] c++: return-type-req in constraint using only outer tparms > [PR104527] > > Here the template context for the atomic constraint has two levels of > template parameters, but since it depends only on the innermost parameter > T we use a single-level argument vector (built by get_mapped_args) during > substitution into the atom. We eventually pass this vector to > do_auto_deduction as part of checking the return-type-requirement within > the atom, but do_auto_deduction expects outer_targs to be a full set of > arguments for sake of satisfaction. > > This patch fixes this by making get_mapped_args always return an > argument vector whose depth corresponds to the template depth of the > context in which the atomic constraint expression was written, instead > of the highest parameter level that the expression happens to use. > > PR c++/104527 > > gcc/cp/ChangeLog: > > * constraint.cc (normalize_atom): Set > ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P appropriately. > (get_mapped_args): Make static, adjust parameters. Always > return a vector whose depth corresponds to the template depth of > the context of the atomic constraint expression. Micro-optimize > by passing false as exact to safe_grow_cleared and by collapsing > a multi-level depth-one argument vector. > (satisfy_atom): Adjust call to get_mapped_args and > diagnose_atomic_constraint. > (diagnose_atomic_constraint): Replace map parameter with an args > parameter. > * cp-tree.h (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P): Define. > (get_mapped_args): Remove declaration. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/concepts-return-req4.C: New test. > --- > gcc/cp/constraint.cc | 64 +++++++++++-------- > gcc/cp/cp-tree.h | 7 +- > .../g++.dg/cpp2a/concepts-return-req4.C | 24 +++++++ > 3 files changed, 69 insertions(+), 26 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc > index 12db7e5cf14..306e28955c6 100644 > --- a/gcc/cp/constraint.cc > +++ b/gcc/cp/constraint.cc > @@ -764,6 +764,8 @@ normalize_atom (tree t, tree args, norm_info info) > tree ci = build_tree_list (t, info.context); > > tree atom = build1 (ATOMIC_CONSTR, ci, map); > + if (info.in_decl && concept_definition_p (info.in_decl)) > + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true; I'm a bit nervous about relying on in_decl, given that we support normalizing when it isn't set; I don't remember the circumstances for that. Maybe make the flag indicate that ctx_parms had depth 1? > if (!info.generate_diagnostics ()) > { > /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal > @@ -2826,33 +2828,37 @@ satisfaction_value (tree t) > return boolean_true_node; > } > > -/* Build a new template argument list with template arguments corresponding > - to the parameters used in an atomic constraint. */ > +/* Build a new template argument vector according to the parameter > + mapping of the atomic constraint T, using arguments from ARGS. */ > > -tree > -get_mapped_args (tree map) > +static tree > +get_mapped_args (tree t, tree args) > { > + tree map = ATOMIC_CONSTR_MAP (t); > + > /* No map, no arguments. */ > if (!map) > return NULL_TREE; > > - /* Find the mapped parameter with the highest level. */ > - int count = 0; > - for (tree p = map; p; p = TREE_CHAIN (p)) > - { > - int level; > - int index; > - template_parm_level_and_index (TREE_VALUE (p), &level, &index); > - if (level > count) > - count = level; > - } > + /* Determine the depth of the resulting argument vector. */ > + int depth; > + if (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (t)) > + /* The expression of this atomic constraint comes from a concept definition, > + whose template depth is always one, so the resulting argument vector > + will also have depth one. */ > + depth = 1; > + else > + /* Otherwise, the expression of this atomic constraint was written in > + the context of the constrained entity, whose template depth is that > + of ARGS. */ > + depth = TMPL_ARGS_DEPTH (args); > > /* Place each argument at its corresponding position in the argument > list. Note that the list will be sparse (not all arguments supplied), > but instantiation is guaranteed to only use the parameters in the > mapping, so null arguments would never be used. */ > - auto_vec< vec<tree> > lists (count); > - lists.quick_grow_cleared (count); > + auto_vec< vec<tree> > lists (depth); > + lists.quick_grow_cleared (depth); > for (tree p = map; p; p = TREE_CHAIN (p)) > { > int level; > @@ -2862,12 +2868,12 @@ get_mapped_args (tree map) > /* Insert the argument into its corresponding position. */ > vec<tree> &list = lists[level - 1]; > if (index >= (int)list.length ()) > - list.safe_grow_cleared (index + 1, true); > + list.safe_grow_cleared (index + 1, /*exact=*/false); > list[index] = TREE_PURPOSE (p); > } > > /* Build the new argument list. */ > - tree args = make_tree_vec (lists.length ()); > + args = make_tree_vec (lists.length ()); > for (unsigned i = 0; i != lists.length (); ++i) > { > vec<tree> &list = lists[i]; > @@ -2879,6 +2885,16 @@ get_mapped_args (tree map) > } > SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0); > > + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args) > + && TMPL_ARGS_DEPTH (args) == 1) > + { > + /* Micro-optimization: represent a depth-one argument vector > + using a single level. */ > + tree level = TMPL_ARGS_LEVEL (args, 1); > + ggc_free (args); > + args = level; > + } > + > return args; > } > > @@ -2933,7 +2949,7 @@ satisfy_atom (tree t, tree args, sat_info info) > } > > /* Rebuild the argument vector from the parameter mapping. */ > - args = get_mapped_args (map); > + args = get_mapped_args (t, args); > > /* Apply the parameter mapping (i.e., just substitute). */ > tree expr = ATOMIC_CONSTR_EXPR (t); > @@ -2955,7 +2971,7 @@ satisfy_atom (tree t, tree args, sat_info info) > if (!same_type_p (TREE_TYPE (result), boolean_type_node)) > { > if (info.noisy ()) > - diagnose_atomic_constraint (t, map, result, info); > + diagnose_atomic_constraint (t, args, result, info); > return cache.save (inst_cache.save (error_mark_node)); > } > > @@ -2974,7 +2990,7 @@ satisfy_atom (tree t, tree args, sat_info info) > } > result = satisfaction_value (result); > if (result == boolean_false_node && info.diagnose_unsatisfaction_p ()) > - diagnose_atomic_constraint (t, map, result, info); > + diagnose_atomic_constraint (t, args, result, info); > > return cache.save (inst_cache.save (result)); > } > @@ -3642,11 +3658,10 @@ diagnose_trait_expr (tree expr, tree args) > } > } > > -/* Diagnose a substitution failure in the atomic constraint T when applied > - with the instantiated parameter mapping MAP. */ > +/* Diagnose a substitution failure in the atomic constraint T using ARGS. */ > > static void > -diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info) > +diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info) > { > /* If the constraint is already ill-formed, we've previously diagnosed > the reason. We should still say why the constraints aren't satisfied. */ > @@ -3667,7 +3682,6 @@ diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info) > /* Generate better diagnostics for certain kinds of expressions. */ > tree expr = ATOMIC_CONSTR_EXPR (t); > STRIP_ANY_LOCATION_WRAPPER (expr); > - tree args = get_mapped_args (map); > switch (TREE_CODE (expr)) > { > case TRAIT_EXPR: > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index f253b32c3f2..dc2429a8406 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -466,6 +466,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; > IMPLICIT_CONV_EXPR_NONTYPE_ARG (in IMPLICIT_CONV_EXPR) > BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (in BASELINK) > BIND_EXPR_VEC_DTOR (in BIND_EXPR) > + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR) > 2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE) > ICS_THIS_FLAG (in _CONV) > DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) > @@ -1679,6 +1680,11 @@ check_constraint_info (tree t) > #define ATOMIC_CONSTR_MAP_INSTANTIATED_P(NODE) \ > TREE_LANG_FLAG_0 (ATOMIC_CONSTR_CHECK (NODE)) > > +/* Whether the expression for this atomic constraint belongs to a > + concept definition. */ > +#define ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P(NODE) \ > + TREE_LANG_FLAG_1 (ATOMIC_CONSTR_CHECK (NODE)) > + > /* The expression of an atomic constraint. */ > #define ATOMIC_CONSTR_EXPR(NODE) \ > CONSTR_EXPR (ATOMIC_CONSTR_CHECK (NODE)) > @@ -8306,7 +8312,6 @@ extern tree evaluate_requires_expr (tree); > extern tree tsubst_constraint (tree, tree, tsubst_flags_t, tree); > extern tree tsubst_constraint_info (tree, tree, tsubst_flags_t, tree); > extern tree tsubst_parameter_mapping (tree, tree, tsubst_flags_t, tree); > -extern tree get_mapped_args (tree); > > struct processing_constraint_expression_sentinel > { > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > new file mode 100644 > index 00000000000..471946bc8eb > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > @@ -0,0 +1,24 @@ > +// PR c++/104527 > +// { dg-do compile { target c++20 } } > + > +template<class T, class U> > +concept is_same = __is_same(T, U); > + > +template<class T> > +struct A { > + template<class...> > + requires requires { { 0 } -> is_same<T>; } > + struct B {}; > + > + template<class...> > + requires requires { { 1 } -> is_same<T>; } > + static void f(); > +}; > + > +A<int>::B<> a1; > +A<bool>::B<> a2; // { dg-error "constraint" } > + > +int main() { > + A<int>::f(); > + A<bool>::f(); // { dg-error "no match" } > +} ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] 2022-03-10 19:43 ` Jason Merrill @ 2022-03-10 20:57 ` Patrick Palka 2022-03-11 22:19 ` Jason Merrill 0 siblings, 1 reply; 8+ messages in thread From: Patrick Palka @ 2022-03-10 20:57 UTC (permalink / raw) To: Jason Merrill; +Cc: Patrick Palka, gcc-patches On Thu, 10 Mar 2022, Jason Merrill wrote: > On 2/16/22 15:56, Patrick Palka wrote: > > On Tue, 15 Feb 2022, Jason Merrill wrote: > > > > > On 2/14/22 11:32, Patrick Palka wrote: > > > > Here the template context for the atomic constraint has two levels of > > > > template arguments, but since it depends only on the innermost argument > > > > T we use a single-level argument vector during substitution into the > > > > constraint (built by get_mapped_args). We eventually pass this vector > > > > to do_auto_deduction as part of checking the return-type-requirement > > > > inside the atom, but do_auto_deduction expects outer_targs to be a full > > > > set of arguments for sake of satisfaction. > > > > > > Could we note the current number of levels in the map and use that in > > > get_mapped_args instead of the highest level parameter we happened to use? > > > > Ah yeah, that seems to work nicely. IIUC it should suffice to remember > > whether the atomic constraint expression came from a concept definition. > > If it did, then the depth of the argument vector returned by > > get_mapped_args must be one, otherwise (as in the testcase) it must be > > the same as the template depth of the constrained entity, which is the > > depth of ARGS. > > > > How does the following look? Bootstrapped and regtested on > > x86_64-pc-linux-gnu and also on cmcstl2 and range-v3. > > > > -- >8 -- > > > > Subject: [PATCH] c++: return-type-req in constraint using only outer tparms > > [PR104527] > > > > Here the template context for the atomic constraint has two levels of > > template parameters, but since it depends only on the innermost parameter > > T we use a single-level argument vector (built by get_mapped_args) during > > substitution into the atom. We eventually pass this vector to > > do_auto_deduction as part of checking the return-type-requirement within > > the atom, but do_auto_deduction expects outer_targs to be a full set of > > arguments for sake of satisfaction. > > > > This patch fixes this by making get_mapped_args always return an > > argument vector whose depth corresponds to the template depth of the > > context in which the atomic constraint expression was written, instead > > of the highest parameter level that the expression happens to use. > > > > PR c++/104527 > > > > gcc/cp/ChangeLog: > > > > * constraint.cc (normalize_atom): Set > > ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P appropriately. > > (get_mapped_args): Make static, adjust parameters. Always > > return a vector whose depth corresponds to the template depth of > > the context of the atomic constraint expression. Micro-optimize > > by passing false as exact to safe_grow_cleared and by collapsing > > a multi-level depth-one argument vector. > > (satisfy_atom): Adjust call to get_mapped_args and > > diagnose_atomic_constraint. > > (diagnose_atomic_constraint): Replace map parameter with an args > > parameter. > > * cp-tree.h (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P): Define. > > (get_mapped_args): Remove declaration. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/cpp2a/concepts-return-req4.C: New test. > > --- > > gcc/cp/constraint.cc | 64 +++++++++++-------- > > gcc/cp/cp-tree.h | 7 +- > > .../g++.dg/cpp2a/concepts-return-req4.C | 24 +++++++ > > 3 files changed, 69 insertions(+), 26 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > > > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc > > index 12db7e5cf14..306e28955c6 100644 > > --- a/gcc/cp/constraint.cc > > +++ b/gcc/cp/constraint.cc > > @@ -764,6 +764,8 @@ normalize_atom (tree t, tree args, norm_info info) > > tree ci = build_tree_list (t, info.context); > > tree atom = build1 (ATOMIC_CONSTR, ci, map); > > + if (info.in_decl && concept_definition_p (info.in_decl)) > > + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true; > > I'm a bit nervous about relying on in_decl, given that we support normalizing > when it isn't set; I don't remember the circumstances for that. Maybe make > the flag indicate that ctx_parms had depth 1? in_decl gets reliably updated by norm_info::update_context whenever we recurse inside a concept-id during normalization. And I think the only other situation we have to worry about is when starting out with a concept-id, which is handled by normalize_concept_definition where we also set in_decl appropriately. AFAICT, in_decl is not set (at the start) only when normalizing a placeholder type constraint or nested-requirement, and from some subsumption entrypoints. And we shouldn't see an atom that belongs to a concept in these cases unless we recurse into a concept-id, in which case norm_info::update_context will update in_decl appropriately. So IMHO it should be safe to rely on in_decl here to detect if the atom belongs to a concept, at least given the current entrypoints to subsumption/satisfaction.. > > > if (!info.generate_diagnostics ()) > > { > > /* Cache the ATOMIC_CONSTRs that we return, so that > > sat_hasher::equal > > @@ -2826,33 +2828,37 @@ satisfaction_value (tree t) > > return boolean_true_node; > > } > > -/* Build a new template argument list with template arguments > > corresponding > > - to the parameters used in an atomic constraint. */ > > +/* Build a new template argument vector according to the parameter > > + mapping of the atomic constraint T, using arguments from ARGS. */ > > -tree > > -get_mapped_args (tree map) > > +static tree > > +get_mapped_args (tree t, tree args) > > { > > + tree map = ATOMIC_CONSTR_MAP (t); > > + > > /* No map, no arguments. */ > > if (!map) > > return NULL_TREE; > > - /* Find the mapped parameter with the highest level. */ > > - int count = 0; > > - for (tree p = map; p; p = TREE_CHAIN (p)) > > - { > > - int level; > > - int index; > > - template_parm_level_and_index (TREE_VALUE (p), &level, &index); > > - if (level > count) > > - count = level; > > - } > > + /* Determine the depth of the resulting argument vector. */ > > + int depth; > > + if (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (t)) > > + /* The expression of this atomic constraint comes from a concept > > definition, > > + whose template depth is always one, so the resulting argument vector > > + will also have depth one. */ > > + depth = 1; > > + else > > + /* Otherwise, the expression of this atomic constraint was written in > > + the context of the constrained entity, whose template depth is that > > + of ARGS. */ > > + depth = TMPL_ARGS_DEPTH (args); > > /* Place each argument at its corresponding position in the argument > > list. Note that the list will be sparse (not all arguments supplied), > > but instantiation is guaranteed to only use the parameters in the > > mapping, so null arguments would never be used. */ > > - auto_vec< vec<tree> > lists (count); > > - lists.quick_grow_cleared (count); > > + auto_vec< vec<tree> > lists (depth); > > + lists.quick_grow_cleared (depth); > > for (tree p = map; p; p = TREE_CHAIN (p)) > > { > > int level; > > @@ -2862,12 +2868,12 @@ get_mapped_args (tree map) > > /* Insert the argument into its corresponding position. */ > > vec<tree> &list = lists[level - 1]; > > if (index >= (int)list.length ()) > > - list.safe_grow_cleared (index + 1, true); > > + list.safe_grow_cleared (index + 1, /*exact=*/false); > > list[index] = TREE_PURPOSE (p); > > } > > /* Build the new argument list. */ > > - tree args = make_tree_vec (lists.length ()); > > + args = make_tree_vec (lists.length ()); > > for (unsigned i = 0; i != lists.length (); ++i) > > { > > vec<tree> &list = lists[i]; > > @@ -2879,6 +2885,16 @@ get_mapped_args (tree map) > > } > > SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0); > > + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args) > > + && TMPL_ARGS_DEPTH (args) == 1) > > + { > > + /* Micro-optimization: represent a depth-one argument vector > > + using a single level. */ > > + tree level = TMPL_ARGS_LEVEL (args, 1); > > + ggc_free (args); > > + args = level; > > + } > > + > > return args; > > } > > @@ -2933,7 +2949,7 @@ satisfy_atom (tree t, tree args, sat_info info) > > } > > /* Rebuild the argument vector from the parameter mapping. */ > > - args = get_mapped_args (map); > > + args = get_mapped_args (t, args); > > /* Apply the parameter mapping (i.e., just substitute). */ > > tree expr = ATOMIC_CONSTR_EXPR (t); > > @@ -2955,7 +2971,7 @@ satisfy_atom (tree t, tree args, sat_info info) > > if (!same_type_p (TREE_TYPE (result), boolean_type_node)) > > { > > if (info.noisy ()) > > - diagnose_atomic_constraint (t, map, result, info); > > + diagnose_atomic_constraint (t, args, result, info); > > return cache.save (inst_cache.save (error_mark_node)); > > } > > @@ -2974,7 +2990,7 @@ satisfy_atom (tree t, tree args, sat_info info) > > } > > result = satisfaction_value (result); > > if (result == boolean_false_node && info.diagnose_unsatisfaction_p ()) > > - diagnose_atomic_constraint (t, map, result, info); > > + diagnose_atomic_constraint (t, args, result, info); > > return cache.save (inst_cache.save (result)); > > } > > @@ -3642,11 +3658,10 @@ diagnose_trait_expr (tree expr, tree args) > > } > > } > > -/* Diagnose a substitution failure in the atomic constraint T when > > applied > > - with the instantiated parameter mapping MAP. */ > > +/* Diagnose a substitution failure in the atomic constraint T using ARGS. > > */ > > static void > > -diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info) > > +diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info) > > { > > /* If the constraint is already ill-formed, we've previously diagnosed > > the reason. We should still say why the constraints aren't satisfied. > > */ > > @@ -3667,7 +3682,6 @@ diagnose_atomic_constraint (tree t, tree map, tree > > result, sat_info info) > > /* Generate better diagnostics for certain kinds of expressions. */ > > tree expr = ATOMIC_CONSTR_EXPR (t); > > STRIP_ANY_LOCATION_WRAPPER (expr); > > - tree args = get_mapped_args (map); > > switch (TREE_CODE (expr)) > > { > > case TRAIT_EXPR: > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > > index f253b32c3f2..dc2429a8406 100644 > > --- a/gcc/cp/cp-tree.h > > +++ b/gcc/cp/cp-tree.h > > @@ -466,6 +466,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; > > IMPLICIT_CONV_EXPR_NONTYPE_ARG (in IMPLICIT_CONV_EXPR) > > BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (in BASELINK) > > BIND_EXPR_VEC_DTOR (in BIND_EXPR) > > + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR) > > 2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE) > > ICS_THIS_FLAG (in _CONV) > > DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) > > @@ -1679,6 +1680,11 @@ check_constraint_info (tree t) > > #define ATOMIC_CONSTR_MAP_INSTANTIATED_P(NODE) \ > > TREE_LANG_FLAG_0 (ATOMIC_CONSTR_CHECK (NODE)) > > +/* Whether the expression for this atomic constraint belongs to a > > + concept definition. */ > > +#define ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P(NODE) \ > > + TREE_LANG_FLAG_1 (ATOMIC_CONSTR_CHECK (NODE)) > > + > > /* The expression of an atomic constraint. */ > > #define ATOMIC_CONSTR_EXPR(NODE) \ > > CONSTR_EXPR (ATOMIC_CONSTR_CHECK (NODE)) > > @@ -8306,7 +8312,6 @@ extern tree evaluate_requires_expr > > (tree); > > extern tree tsubst_constraint (tree, tree, > > tsubst_flags_t, tree); > > extern tree tsubst_constraint_info (tree, tree, > > tsubst_flags_t, tree); > > extern tree tsubst_parameter_mapping (tree, tree, > > tsubst_flags_t, tree); > > -extern tree get_mapped_args (tree); > > struct processing_constraint_expression_sentinel > > { > > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > > b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > > new file mode 100644 > > index 00000000000..471946bc8eb > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C > > @@ -0,0 +1,24 @@ > > +// PR c++/104527 > > +// { dg-do compile { target c++20 } } > > + > > +template<class T, class U> > > +concept is_same = __is_same(T, U); > > + > > +template<class T> > > +struct A { > > + template<class...> > > + requires requires { { 0 } -> is_same<T>; } > > + struct B {}; > > + > > + template<class...> > > + requires requires { { 1 } -> is_same<T>; } > > + static void f(); > > +}; > > + > > +A<int>::B<> a1; > > +A<bool>::B<> a2; // { dg-error "constraint" } > > + > > +int main() { > > + A<int>::f(); > > + A<bool>::f(); // { dg-error "no match" } > > +} > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] 2022-03-10 20:57 ` Patrick Palka @ 2022-03-11 22:19 ` Jason Merrill 0 siblings, 0 replies; 8+ messages in thread From: Jason Merrill @ 2022-03-11 22:19 UTC (permalink / raw) To: Patrick Palka; +Cc: gcc-patches On 3/10/22 16:57, Patrick Palka wrote: > > On Thu, 10 Mar 2022, Jason Merrill wrote: > >> On 2/16/22 15:56, Patrick Palka wrote: >>> On Tue, 15 Feb 2022, Jason Merrill wrote: >>> >>>> On 2/14/22 11:32, Patrick Palka wrote: >>>>> Here the template context for the atomic constraint has two levels of >>>>> template arguments, but since it depends only on the innermost argument >>>>> T we use a single-level argument vector during substitution into the >>>>> constraint (built by get_mapped_args). We eventually pass this vector >>>>> to do_auto_deduction as part of checking the return-type-requirement >>>>> inside the atom, but do_auto_deduction expects outer_targs to be a full >>>>> set of arguments for sake of satisfaction. >>>> >>>> Could we note the current number of levels in the map and use that in >>>> get_mapped_args instead of the highest level parameter we happened to use? >>> >>> Ah yeah, that seems to work nicely. IIUC it should suffice to remember >>> whether the atomic constraint expression came from a concept definition. >>> If it did, then the depth of the argument vector returned by >>> get_mapped_args must be one, otherwise (as in the testcase) it must be >>> the same as the template depth of the constrained entity, which is the >>> depth of ARGS. >>> >>> How does the following look? Bootstrapped and regtested on >>> x86_64-pc-linux-gnu and also on cmcstl2 and range-v3. >>> >>> -- >8 -- >>> >>> Subject: [PATCH] c++: return-type-req in constraint using only outer tparms >>> [PR104527] >>> >>> Here the template context for the atomic constraint has two levels of >>> template parameters, but since it depends only on the innermost parameter >>> T we use a single-level argument vector (built by get_mapped_args) during >>> substitution into the atom. We eventually pass this vector to >>> do_auto_deduction as part of checking the return-type-requirement within >>> the atom, but do_auto_deduction expects outer_targs to be a full set of >>> arguments for sake of satisfaction. >>> >>> This patch fixes this by making get_mapped_args always return an >>> argument vector whose depth corresponds to the template depth of the >>> context in which the atomic constraint expression was written, instead >>> of the highest parameter level that the expression happens to use. >>> >>> PR c++/104527 >>> >>> gcc/cp/ChangeLog: >>> >>> * constraint.cc (normalize_atom): Set >>> ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P appropriately. >>> (get_mapped_args): Make static, adjust parameters. Always >>> return a vector whose depth corresponds to the template depth of >>> the context of the atomic constraint expression. Micro-optimize >>> by passing false as exact to safe_grow_cleared and by collapsing >>> a multi-level depth-one argument vector. >>> (satisfy_atom): Adjust call to get_mapped_args and >>> diagnose_atomic_constraint. >>> (diagnose_atomic_constraint): Replace map parameter with an args >>> parameter. >>> * cp-tree.h (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P): Define. >>> (get_mapped_args): Remove declaration. >>> >>> gcc/testsuite/ChangeLog: >>> >>> * g++.dg/cpp2a/concepts-return-req4.C: New test. >>> --- >>> gcc/cp/constraint.cc | 64 +++++++++++-------- >>> gcc/cp/cp-tree.h | 7 +- >>> .../g++.dg/cpp2a/concepts-return-req4.C | 24 +++++++ >>> 3 files changed, 69 insertions(+), 26 deletions(-) >>> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C >>> >>> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc >>> index 12db7e5cf14..306e28955c6 100644 >>> --- a/gcc/cp/constraint.cc >>> +++ b/gcc/cp/constraint.cc >>> @@ -764,6 +764,8 @@ normalize_atom (tree t, tree args, norm_info info) >>> tree ci = build_tree_list (t, info.context); >>> tree atom = build1 (ATOMIC_CONSTR, ci, map); >>> + if (info.in_decl && concept_definition_p (info.in_decl)) >>> + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true; >> >> I'm a bit nervous about relying on in_decl, given that we support normalizing >> when it isn't set; I don't remember the circumstances for that. Maybe make >> the flag indicate that ctx_parms had depth 1? > > in_decl gets reliably updated by norm_info::update_context whenever we > recurse inside a concept-id during normalization. And I think the only > other situation we have to worry about is when starting out with a > concept-id, which is handled by normalize_concept_definition where we > also set in_decl appropriately. > > AFAICT, in_decl is not set (at the start) only when normalizing a > placeholder type constraint or nested-requirement, and from some > subsumption entrypoints. And we shouldn't see an atom that belongs to a > concept in these cases unless we recurse into a concept-id, in which > case norm_info::update_context will update in_decl appropriately. > > So IMHO it should be safe to rely on in_decl here to detect if the atom > belongs to a concept, at least given the current entrypoints to > subsumption/satisfaction.. Sounds good; please put a bit of that explanation in a comment where you set the flag. OK with that change. >> >>> if (!info.generate_diagnostics ()) >>> { >>> /* Cache the ATOMIC_CONSTRs that we return, so that >>> sat_hasher::equal >>> @@ -2826,33 +2828,37 @@ satisfaction_value (tree t) >>> return boolean_true_node; >>> } >>> -/* Build a new template argument list with template arguments >>> corresponding >>> - to the parameters used in an atomic constraint. */ >>> +/* Build a new template argument vector according to the parameter >>> + mapping of the atomic constraint T, using arguments from ARGS. */ >>> -tree >>> -get_mapped_args (tree map) >>> +static tree >>> +get_mapped_args (tree t, tree args) >>> { >>> + tree map = ATOMIC_CONSTR_MAP (t); >>> + >>> /* No map, no arguments. */ >>> if (!map) >>> return NULL_TREE; >>> - /* Find the mapped parameter with the highest level. */ >>> - int count = 0; >>> - for (tree p = map; p; p = TREE_CHAIN (p)) >>> - { >>> - int level; >>> - int index; >>> - template_parm_level_and_index (TREE_VALUE (p), &level, &index); >>> - if (level > count) >>> - count = level; >>> - } >>> + /* Determine the depth of the resulting argument vector. */ >>> + int depth; >>> + if (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (t)) >>> + /* The expression of this atomic constraint comes from a concept >>> definition, >>> + whose template depth is always one, so the resulting argument vector >>> + will also have depth one. */ >>> + depth = 1; >>> + else >>> + /* Otherwise, the expression of this atomic constraint was written in >>> + the context of the constrained entity, whose template depth is that >>> + of ARGS. */ >>> + depth = TMPL_ARGS_DEPTH (args); >>> /* Place each argument at its corresponding position in the argument >>> list. Note that the list will be sparse (not all arguments supplied), >>> but instantiation is guaranteed to only use the parameters in the >>> mapping, so null arguments would never be used. */ >>> - auto_vec< vec<tree> > lists (count); >>> - lists.quick_grow_cleared (count); >>> + auto_vec< vec<tree> > lists (depth); >>> + lists.quick_grow_cleared (depth); >>> for (tree p = map; p; p = TREE_CHAIN (p)) >>> { >>> int level; >>> @@ -2862,12 +2868,12 @@ get_mapped_args (tree map) >>> /* Insert the argument into its corresponding position. */ >>> vec<tree> &list = lists[level - 1]; >>> if (index >= (int)list.length ()) >>> - list.safe_grow_cleared (index + 1, true); >>> + list.safe_grow_cleared (index + 1, /*exact=*/false); >>> list[index] = TREE_PURPOSE (p); >>> } >>> /* Build the new argument list. */ >>> - tree args = make_tree_vec (lists.length ()); >>> + args = make_tree_vec (lists.length ()); >>> for (unsigned i = 0; i != lists.length (); ++i) >>> { >>> vec<tree> &list = lists[i]; >>> @@ -2879,6 +2885,16 @@ get_mapped_args (tree map) >>> } >>> SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0); >>> + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args) >>> + && TMPL_ARGS_DEPTH (args) == 1) >>> + { >>> + /* Micro-optimization: represent a depth-one argument vector >>> + using a single level. */ >>> + tree level = TMPL_ARGS_LEVEL (args, 1); >>> + ggc_free (args); >>> + args = level; >>> + } >>> + >>> return args; >>> } >>> @@ -2933,7 +2949,7 @@ satisfy_atom (tree t, tree args, sat_info info) >>> } >>> /* Rebuild the argument vector from the parameter mapping. */ >>> - args = get_mapped_args (map); >>> + args = get_mapped_args (t, args); >>> /* Apply the parameter mapping (i.e., just substitute). */ >>> tree expr = ATOMIC_CONSTR_EXPR (t); >>> @@ -2955,7 +2971,7 @@ satisfy_atom (tree t, tree args, sat_info info) >>> if (!same_type_p (TREE_TYPE (result), boolean_type_node)) >>> { >>> if (info.noisy ()) >>> - diagnose_atomic_constraint (t, map, result, info); >>> + diagnose_atomic_constraint (t, args, result, info); >>> return cache.save (inst_cache.save (error_mark_node)); >>> } >>> @@ -2974,7 +2990,7 @@ satisfy_atom (tree t, tree args, sat_info info) >>> } >>> result = satisfaction_value (result); >>> if (result == boolean_false_node && info.diagnose_unsatisfaction_p ()) >>> - diagnose_atomic_constraint (t, map, result, info); >>> + diagnose_atomic_constraint (t, args, result, info); >>> return cache.save (inst_cache.save (result)); >>> } >>> @@ -3642,11 +3658,10 @@ diagnose_trait_expr (tree expr, tree args) >>> } >>> } >>> -/* Diagnose a substitution failure in the atomic constraint T when >>> applied >>> - with the instantiated parameter mapping MAP. */ >>> +/* Diagnose a substitution failure in the atomic constraint T using ARGS. >>> */ >>> static void >>> -diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info) >>> +diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info) >>> { >>> /* If the constraint is already ill-formed, we've previously diagnosed >>> the reason. We should still say why the constraints aren't satisfied. >>> */ >>> @@ -3667,7 +3682,6 @@ diagnose_atomic_constraint (tree t, tree map, tree >>> result, sat_info info) >>> /* Generate better diagnostics for certain kinds of expressions. */ >>> tree expr = ATOMIC_CONSTR_EXPR (t); >>> STRIP_ANY_LOCATION_WRAPPER (expr); >>> - tree args = get_mapped_args (map); >>> switch (TREE_CODE (expr)) >>> { >>> case TRAIT_EXPR: >>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h >>> index f253b32c3f2..dc2429a8406 100644 >>> --- a/gcc/cp/cp-tree.h >>> +++ b/gcc/cp/cp-tree.h >>> @@ -466,6 +466,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; >>> IMPLICIT_CONV_EXPR_NONTYPE_ARG (in IMPLICIT_CONV_EXPR) >>> BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (in BASELINK) >>> BIND_EXPR_VEC_DTOR (in BIND_EXPR) >>> + ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR) >>> 2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE) >>> ICS_THIS_FLAG (in _CONV) >>> DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) >>> @@ -1679,6 +1680,11 @@ check_constraint_info (tree t) >>> #define ATOMIC_CONSTR_MAP_INSTANTIATED_P(NODE) \ >>> TREE_LANG_FLAG_0 (ATOMIC_CONSTR_CHECK (NODE)) >>> +/* Whether the expression for this atomic constraint belongs to a >>> + concept definition. */ >>> +#define ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P(NODE) \ >>> + TREE_LANG_FLAG_1 (ATOMIC_CONSTR_CHECK (NODE)) >>> + >>> /* The expression of an atomic constraint. */ >>> #define ATOMIC_CONSTR_EXPR(NODE) \ >>> CONSTR_EXPR (ATOMIC_CONSTR_CHECK (NODE)) >>> @@ -8306,7 +8312,6 @@ extern tree evaluate_requires_expr >>> (tree); >>> extern tree tsubst_constraint (tree, tree, >>> tsubst_flags_t, tree); >>> extern tree tsubst_constraint_info (tree, tree, >>> tsubst_flags_t, tree); >>> extern tree tsubst_parameter_mapping (tree, tree, >>> tsubst_flags_t, tree); >>> -extern tree get_mapped_args (tree); >>> struct processing_constraint_expression_sentinel >>> { >>> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C >>> b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C >>> new file mode 100644 >>> index 00000000000..471946bc8eb >>> --- /dev/null >>> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C >>> @@ -0,0 +1,24 @@ >>> +// PR c++/104527 >>> +// { dg-do compile { target c++20 } } >>> + >>> +template<class T, class U> >>> +concept is_same = __is_same(T, U); >>> + >>> +template<class T> >>> +struct A { >>> + template<class...> >>> + requires requires { { 0 } -> is_same<T>; } >>> + struct B {}; >>> + >>> + template<class...> >>> + requires requires { { 1 } -> is_same<T>; } >>> + static void f(); >>> +}; >>> + >>> +A<int>::B<> a1; >>> +A<bool>::B<> a2; // { dg-error "constraint" } >>> + >>> +int main() { >>> + A<int>::f(); >>> + A<bool>::f(); // { dg-error "no match" } >>> +} >> >> > ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2022-03-11 22:19 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2022-02-14 16:32 [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527] Patrick Palka 2022-02-14 16:37 ` Patrick Palka 2022-02-15 23:39 ` Jason Merrill 2022-02-16 19:56 ` Patrick Palka 2022-03-01 13:13 ` Patrick Palka 2022-03-10 19:43 ` Jason Merrill 2022-03-10 20:57 ` Patrick Palka 2022-03-11 22:19 ` Jason Merrill
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).