On Mon, 1 Mar 2021, Jason Merrill wrote: > On 2/28/21 12:40 PM, Patrick Palka wrote: > > On Fri, 12 Feb 2021, Jason Merrill wrote: > > > > > On 2/10/21 9:41 AM, Patrick Palka wrote: > > > > On Tue, 9 Feb 2021, Jason Merrill wrote: > > > > > > > > > On 2/8/21 2:03 PM, Patrick Palka wrote: > > > > > > This sets up the functionality for controlling the initial set of > > > > > > template parameters to pass to normalization when dealing with a > > > > > > constraint-expression that is not associated with some constrained > > > > > > declaration, for instance when normalizing a nested requirement of a > > > > > > requires expression, or the constraints on a placeholder type. > > > > > > > > > > > > The main new ingredient here is the data member > > > > > > norm_info::initial_parms > > > > > > which can be set by callers of the normalization routines to > > > > > > communicate > > > > > > the in-scope template parameters for the supplied > > > > > > constraint-expression, > > > > > > rather than always falling back to using current_template_parms. > > > > > > > > > > > > This patch then uses this functionality in our handling of nested > > > > > > requirements so that we can delay normalizing them until needed for > > > > > > satisfaction. We currently immediately normalize nested > > > > > > requirements at > > > > > > parse time, where we have the necessary template context, and cache > > > > > > the > > > > > > normal form in their TREE_TYPE node. With this patch, we now delay > > > > > > normalization until needed (as with other constraint expressions), > > > > > > and > > > > > > instead store the current value of current_template_parms in their > > > > > > TREE_TYPE node (which we use to restore the template context at > > > > > > normalization time). > > > > > > > > > > > > In the subsequent patch, this functionality will also be used to > > > > > > normalize placeholder type constraints during auto deduction. > > > > > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > > > > > * constraint.cc (build_parameter_mapping): Rely on the caller > > > > > > to > > > > > > determine the in-scope template parameters. > > > > > > (norm_info::norm_info): Delegate the one-parameter constructor > > > > > > to the two-parameter constructor. In the two-parameter > > > > > > constructor, fold in the definition of make_context, set > > > > > > initial_parms appropriately, and don't set the now-removed > > > > > > orig_decl member. > > > > > > (norm_info::make_context): Remove, now that its only use is > > > > > > inlined into the caller. > > > > > > (norm_info::update_context): Adjust call to > > > > > > build_parameter_mapping to pass in the relevant set of > > > > > > in-scope > > > > > > template parameters. > > > > > > (norm_info::ctx_parms): Define this member function. > > > > > > (norm_info::context): Initialize to NULL_TREE. > > > > > > (norm_info::orig_decl): Remove this data member. > > > > > > (norm_info::initial_parms): Define this data member. > > > > > > (normalize_atom): Adjust call to build_parameter_mapping to > > > > > > pass > > > > > > in the relevant set of in-scope template parameters. Use > > > > > > info.initial_parms instead of info.orig_decl. > > > > > > (normalize_constraint_expression): Define an overload that > > > > > > takes > > > > > > a norm_info object. Cache the result of normalization. > > > > > > Define > > > > > > the other overload in terms of this one, and handle a > > > > > > NESTED_REQ > > > > > > argument by setting info.initial_parms appropriately. > > > > > > (tsubst_nested_requirement): Go through > > > > > > satisfy_constraint_expression so that we normalize on demand. > > > > > > (finish_nested_requirement): Set the TREE_TYPE of the > > > > > > NESTED_REQ > > > > > > to current_template_parms. > > > > > > (diagnose_nested_requirements): Go through > > > > > > satisfy_constraint_expression, as with > > > > > > tsubst_nested_requirement. > > > > > > --- > > > > > > gcc/cp/constraint.cc | 140 > > > > > > +++++++++++++++++++++++-------------------- > > > > > > gcc/cp/cp-tree.h | 4 +- > > > > > > 2 files changed, 78 insertions(+), 66 deletions(-) > > > > > > > > > > > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc > > > > > > index 39c97986082..56134f8b2bf 100644 > > > > > > --- a/gcc/cp/constraint.cc > > > > > > +++ b/gcc/cp/constraint.cc > > > > > > @@ -133,7 +133,7 @@ struct sat_info : subst_info > > > > > > bool diagnose_unsatisfaction; > > > > > > }; > > > > > > -static tree satisfy_constraint (tree, tree, sat_info); > > > > > > +static tree satisfy_constraint_expression (tree, tree, sat_info); > > > > > > /* True if T is known to be some type other than bool. Note > > > > > > that > > > > > > this > > > > > > is false for dependent types and errors. */ > > > > > > @@ -594,26 +594,12 @@ map_arguments (tree parms, tree args) > > > > > > return parms; > > > > > > } > > > > > > -/* Build the parameter mapping for EXPR using ARGS. */ > > > > > > +/* Build the parameter mapping for EXPR using ARGS, where CTX_PARMS > > > > > > + are the template parameters in scope for EXPR. */ > > > > > > static tree > > > > > > -build_parameter_mapping (tree expr, tree args, tree decl) > > > > > > +build_parameter_mapping (tree expr, tree args, tree ctx_parms) > > > > > > { > > > > > > - tree ctx_parms = NULL_TREE; > > > > > > - if (decl) > > > > > > - { > > > > > > - gcc_assert (TREE_CODE (decl) == TEMPLATE_DECL); > > > > > > - ctx_parms = DECL_TEMPLATE_PARMS (decl); > > > > > > - } > > > > > > - else if (current_template_parms) > > > > > > - { > > > > > > - /* TODO: This should probably be the only case, but because > > > > > > the > > > > > > - point of declaration of concepts is currently set after the > > > > > > - initializer, the template parameter lists are not available > > > > > > - when normalizing concept definitions, hence the case above. > > > > > > */ > > > > > > - ctx_parms = current_template_parms; > > > > > > - } > > > > > > - > > > > > > tree parms = find_template_parameters (expr, ctx_parms); > > > > > > tree map = map_arguments (parms, args); > > > > > > return map; > > > > > > @@ -645,53 +631,63 @@ parameter_mapping_equivalent_p (tree t1, tree > > > > > > t2) > > > > > > struct norm_info : subst_info > > > > > > { > > > > > > - explicit norm_info (tsubst_flags_t complain) > > > > > > - : subst_info (tf_warning_or_error | complain, NULL_TREE), > > > > > > - context() > > > > > > + explicit norm_info (tsubst_flags_t cmp) > > > > > > + : norm_info (NULL_TREE, cmp) > > > > > > {} > > > > > > /* Construct a top-level context for DECL. */ > > > > > > norm_info (tree in_decl, tsubst_flags_t complain) > > > > > > - : subst_info (tf_warning_or_error | complain, in_decl), > > > > > > - context (make_context (in_decl)), > > > > > > - orig_decl (in_decl) > > > > > > - {} > > > > > > - > > > > > > - bool generate_diagnostics() const > > > > > > + : subst_info (tf_warning_or_error | complain, in_decl) > > > > > > { > > > > > > - return complain & tf_norm; > > > > > > + if (in_decl) > > > > > > + { > > > > > > + initial_parms = DECL_TEMPLATE_PARMS (in_decl); > > > > > > + if (generate_diagnostics ()) > > > > > > + context = build_tree_list (NULL_TREE, in_decl); > > > > > > + } > > > > > > + else > > > > > > + initial_parms = current_template_parms; > > > > > > } > > > > > > - tree make_context(tree in_decl) > > > > > > + bool generate_diagnostics() const > > > > > > { > > > > > > - if (generate_diagnostics ()) > > > > > > - return build_tree_list (NULL_TREE, in_decl); > > > > > > - return NULL_TREE; > > > > > > + return complain & tf_norm; > > > > > > } > > > > > > void update_context(tree expr, tree args) > > > > > > { > > > > > > if (generate_diagnostics ()) > > > > > > { > > > > > > - tree map = build_parameter_mapping (expr, args, in_decl); > > > > > > + tree map = build_parameter_mapping (expr, args, ctx_parms ()); > > > > > > context = tree_cons (map, expr, context); > > > > > > } > > > > > > in_decl = get_concept_check_template (expr); > > > > > > } > > > > > > + /* Returns the template parameters that are in scope for the > > > > > > current > > > > > > + normalization context. */ > > > > > > + > > > > > > + tree ctx_parms() > > > > > > + { > > > > > > + if (in_decl) > > > > > > + return DECL_TEMPLATE_PARMS (in_decl); > > > > > > + else > > > > > > + return initial_parms; > > > > > > + } > > > > > > + > > > > > > /* Provides information about the source of a constraint. This > > > > > > is a > > > > > > TREE_LIST whose VALUE is either a concept check or a > > > > > > constrained > > > > > > declaration. The PURPOSE, for concept checks is a parameter > > > > > > mapping > > > > > > for that check. */ > > > > > > - tree context; > > > > > > + tree context = NULL_TREE; > > > > > > /* The declaration whose constraints we're normalizing. The > > > > > > targets > > > > > > of the parameter mapping of each atom will be in terms of > > > > > > the > > > > > > template parameters of ORIG_DECL. */ > > > > > > - tree orig_decl = NULL_TREE; > > > > > > + tree initial_parms = NULL_TREE; > > > > > > }; > > > > > > static tree normalize_expression (tree, tree, norm_info); > > > > > > @@ -773,7 +769,7 @@ normalize_atom (tree t, tree args, norm_info > > > > > > info) > > > > > > return normalize_concept_check (t, args, info); > > > > > > /* Build the parameter mapping for the atom. */ > > > > > > - tree map = build_parameter_mapping (t, args, info.in_decl); > > > > > > + tree map = build_parameter_mapping (t, args, info.ctx_parms ()); > > > > > > /* Build a new info object for the atom. */ > > > > > > tree ci = build_tree_list (t, info.context); > > > > > > @@ -803,10 +799,8 @@ normalize_atom (tree t, tree args, norm_info > > > > > > info) > > > > > > tree target = TREE_PURPOSE (node); > > > > > > TREE_VEC_ELT (targets, i++) = target; > > > > > > } > > > > > > - tree ctx_parms = (info.orig_decl > > > > > > - ? DECL_TEMPLATE_PARMS (info.orig_decl) > > > > > > - : current_template_parms); > > > > > > - tree target_parms = find_template_parameters (targets, > > > > > > ctx_parms); > > > > > > + tree target_parms = find_template_parameters (targets, > > > > > > + > > > > > > info.initial_parms); > > > > > > TREE_TYPE (map) = target_parms; > > > > > > } > > > > > > @@ -983,17 +977,43 @@ normalize_nontemplate_requirements (tree > > > > > > decl, > > > > > > bool > > > > > > diag = false) > > > > > > /* Normalize an EXPR as a constraint. */ > > > > > > static tree > > > > > > -normalize_constraint_expression (tree expr, bool diag) > > > > > > +normalize_constraint_expression (tree expr, norm_info info) > > > > > > { > > > > > > if (!expr || expr == error_mark_node) > > > > > > return expr; > > > > > > + > > > > > > + if (!info.generate_diagnostics ()) > > > > > > + if (tree *p = hash_map_safe_get (normalized_map, expr)) > > > > > > + return *p; > > > > > > > > > > It seems like we only want this for NESTED_REQ. > > > > > > > > I figured it'd also be beneficial to cache the normal form of a > > > > placeholder type constraint, which will also goes through this overload. > > > > > > True. And if we change REQUIRES_EXPR handling to not go through here, it > > > should be just the two. OK, let's leave this alone. > > > > > > > > > ++processing_template_decl; > > > > > > - norm_info info (diag ? tf_norm : tf_none); > > > > > > tree norm = get_normalized_constraints (expr, info); > > > > > > --processing_template_decl; > > > > > > + > > > > > > + if (!info.generate_diagnostics ()) > > > > > > + hash_map_safe_put<hm_ggc> (normalized_map, expr, norm); > > > > > > + > > > > > > return norm; > > > > > > } > > > > > > +/* High-level wrapper for the above. */ > > > > > > + > > > > > > +static tree > > > > > > +normalize_constraint_expression (tree expr, bool diag) > > > > > > +{ > > > > > > + norm_info info (diag ? tf_norm : tf_none); > > > > > > > > > > I wonder if we want to add a norm_info constructor taking a sat_info > > > > > so we > > > > > don't need to mediate passing from one into the other with bool "diag" > > > > > parameters in various functions. That doesn't need to happen in this > > > > > patch. > > > > > > > > Sounds good. I think such a constructor would let us eliminate the > > > > bool-taking overload of normalize_constraint_expression altogether, if > > > > we move the special handling of NESTED_REQ to the norm_info-taking > > > > overload or to satisfy_constraint_expression. > > > > Here's v2 of this patch, which refrains from adding a second overload of > > normalize_constraint_expression. Handling of NESTED_REQs now happens in > > satisfy_constraint_expression. > > > > The rest of the cleanups mentioned here will be performed in another > > patch. > > > > (For now, I didn't add a norm_info(sat_info) constructor since it wasn't > > clear to me if this constructor should propagate in_decl or not. For > > > sat_info, in_decl is used purely for diagnostics, whereas for norm_info, > > in_decl keeps track of the current normalization context, so carrying > > over the value of in_decl might not always make sense. > > > Perhaps it might be better to add a norm_info(bool diag) constructor > > instead? > > I was thinking the norm_info(sat_info) constructor would do the equivalent of > > + norm_info ninfo (info.noisy () ? tf_norm : tf_none);
Ah, sounds good. Shall I do that (and the tf_norm removal) in a followup patch, or update this one? > > > While we're at it, I think we could remove the tf_norm flag.) > > Sure. > > > -- >8 -- > > > > Subject: [PATCH 3/6] c++: Delay normalizing nested requirements until > > satisfaction > > > > This sets up the functionality for controlling the initial set of > > template parameters to pass to normalization when dealing with a > > constraint-expression that is not associated with some constrained > > declaration, for instance when normalizing a nested requirement of a > > requires expression, or the constraints on a placeholder type. > > > > The main new ingredient here is the data member norm_info::initial_parms > > which can be set by callers of the normalization routines to communicate > > the in-scope template parameters for the supplied constraint-expression, > > rather than always falling back to using current_template_parms. > > > > This patch then uses this functionality in our handling of nested > > requirements so that we can delay normalizing them until needed for > > satisfaction. We currently immediately normalize nested requirements at > > parse time, where we have the necessary template context, and cache the > > normal form in their TREE_TYPE node. With this patch, we now delay > > normalization until needed (as with other constraint expressions), and > > instead store the current value of current_template_parms in their > > TREE_TYPE node (which we use to restore the template context at > > normalization time). > > > > In the subsequent patch, this functionality will also be used to > > normalize placeholder type constraints during auto deduction. > > > > gcc/cp/ChangeLog: > > > > * constraint.cc (build_parameter_mapping): Rely on the caller to > > determine the in-scope template parameters. > > (norm_info::norm_info): Delegate the tsubst_flags_t constructor > > to the two-parameter constructor. In the two-parameter > > constructor, fold in the definition of make_context, set > > initial_parms appropriately, and don't set the now-removed > > orig_decl member. > > (norm_info::make_context): Remove, now that its only use is > > inlined into the caller. > > (norm_info::update_context): Adjust call to > > build_parameter_mapping to pass in the relevant set of in-scope > > template parameters. > > (norm_info::ctx_parms): Define this member function. > > (norm_info::context): Initialize to NULL_TREE. > > (norm_info::orig_decl): Remove this data member. > > (norm_info::initial_parms): Define this data member. > > (normalize_atom): Adjust call to build_parameter_mapping to pass > > in the relevant set of in-scope template parameters. Use > > info.initial_parms instead of info.orig_decl. > > (normalize_constraint_expression): Take a norm_info object > > instead of a bool. Cache the result of normalization. > > (tsubst_nested_requirement): Call satisfy_constraint_expression > > instead of satisfy_constraint, so that we normalize on demand. > > (satisfy_constraint_expression): Handle a NESTED_REQ argument. > > Adjust call to normalize_constraint_expression. > > (finish_nested_requirement): Set the TREE_TYPE of the NESTED_REQ > > to current_template_parms. > > (diagnose_nested_requirements): Go through > > satisfy_constraint_expression, as with tsubst_nested_requirement. > > --- > > gcc/cp/constraint.cc | 138 ++++++++++++++++++++++--------------------- > > 1 file changed, 72 insertions(+), 66 deletions(-) > > > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc > > index 39c97986082..fcb249a642f 100644 > > --- a/gcc/cp/constraint.cc > > +++ b/gcc/cp/constraint.cc > > @@ -133,7 +133,7 @@ struct sat_info : subst_info > > bool diagnose_unsatisfaction; > > }; > > -static tree satisfy_constraint (tree, tree, sat_info); > > +static tree satisfy_constraint_expression (tree, tree, sat_info); > > /* True if T is known to be some type other than bool. Note that this > > is false for dependent types and errors. */ > > @@ -594,26 +594,12 @@ map_arguments (tree parms, tree args) > > return parms; > > } > > -/* Build the parameter mapping for EXPR using ARGS. */ > > +/* Build the parameter mapping for EXPR using ARGS, where CTX_PARMS > > + are the template parameters in scope for EXPR. */ > > static tree > > -build_parameter_mapping (tree expr, tree args, tree decl) > > +build_parameter_mapping (tree expr, tree args, tree ctx_parms) > > { > > - tree ctx_parms = NULL_TREE; > > - if (decl) > > - { > > - gcc_assert (TREE_CODE (decl) == TEMPLATE_DECL); > > - ctx_parms = DECL_TEMPLATE_PARMS (decl); > > - } > > - else if (current_template_parms) > > - { > > - /* TODO: This should probably be the only case, but because the > > - point of declaration of concepts is currently set after the > > - initializer, the template parameter lists are not available > > - when normalizing concept definitions, hence the case above. */ > > - ctx_parms = current_template_parms; > > - } > > - > > tree parms = find_template_parameters (expr, ctx_parms); > > tree map = map_arguments (parms, args); > > return map; > > @@ -645,53 +631,63 @@ parameter_mapping_equivalent_p (tree t1, tree t2) > > struct norm_info : subst_info > > { > > - explicit norm_info (tsubst_flags_t complain) > > - : subst_info (tf_warning_or_error | complain, NULL_TREE), > > - context() > > + explicit norm_info (tsubst_flags_t cmp) > > + : norm_info (NULL_TREE, cmp) > > {} > > /* Construct a top-level context for DECL. */ > > norm_info (tree in_decl, tsubst_flags_t complain) > > - : subst_info (tf_warning_or_error | complain, in_decl), > > - context (make_context (in_decl)), > > - orig_decl (in_decl) > > - {} > > - > > - bool generate_diagnostics() const > > + : subst_info (tf_warning_or_error | complain, in_decl) > > { > > - return complain & tf_norm; > > + if (in_decl) > > + { > > + initial_parms = DECL_TEMPLATE_PARMS (in_decl); > > + if (generate_diagnostics ()) > > + context = build_tree_list (NULL_TREE, in_decl); > > + } > > + else > > + initial_parms = current_template_parms; > > } > > - tree make_context(tree in_decl) > > + bool generate_diagnostics() const > > { > > - if (generate_diagnostics ()) > > - return build_tree_list (NULL_TREE, in_decl); > > - return NULL_TREE; > > + return complain & tf_norm; > > } > > void update_context(tree expr, tree args) > > { > > if (generate_diagnostics ()) > > { > > - tree map = build_parameter_mapping (expr, args, in_decl); > > + tree map = build_parameter_mapping (expr, args, ctx_parms ()); > > context = tree_cons (map, expr, context); > > } > > in_decl = get_concept_check_template (expr); > > } > > + /* Returns the template parameters that are in scope for the current > > + normalization context. */ > > + > > + tree ctx_parms() > > + { > > + if (in_decl) > > + return DECL_TEMPLATE_PARMS (in_decl); > > + else > > + return initial_parms; > > + } > > Why prefer in_decl to initial_parms? In fact, why look at in_decl here at > all, when we already used it to set initial_parms in the constructor? IIUC, that's true at the start of normalization, but in_decl gets continuously updated as we recurse into a concept-id and normalize the concept's definition (in normalize_concept_check via norm_info::update_context), whereas initial_parms gets set at the start of normalization (upon construction) and remains unchanged. > > > /* Provides information about the source of a constraint. This is a > > TREE_LIST whose VALUE is either a concept check or a constrained > > declaration. The PURPOSE, for concept checks is a parameter mapping > > for that check. */ > > - tree context; > > + tree context = NULL_TREE; > > /* The declaration whose constraints we're normalizing. The targets > > of the parameter mapping of each atom will be in terms of the > > template parameters of ORIG_DECL. */ > > - tree orig_decl = NULL_TREE; > > + tree initial_parms = NULL_TREE; > > }; > > static tree normalize_expression (tree, tree, norm_info); > > @@ -773,7 +769,7 @@ normalize_atom (tree t, tree args, norm_info info) > > return normalize_concept_check (t, args, info); > > /* Build the parameter mapping for the atom. */ > > - tree map = build_parameter_mapping (t, args, info.in_decl); > > + tree map = build_parameter_mapping (t, args, info.ctx_parms ()); > > /* Build a new info object for the atom. */ > > tree ci = build_tree_list (t, info.context); > > @@ -803,10 +799,8 @@ normalize_atom (tree t, tree args, norm_info info) > > tree target = TREE_PURPOSE (node); > > TREE_VEC_ELT (targets, i++) = target; > > } > > - tree ctx_parms = (info.orig_decl > > - ? DECL_TEMPLATE_PARMS (info.orig_decl) > > - : current_template_parms); > > - tree target_parms = find_template_parameters (targets, ctx_parms); > > + tree target_parms = find_template_parameters (targets, > > + info.initial_parms); > > TREE_TYPE (map) = target_parms; > > } > > @@ -983,14 +977,22 @@ normalize_nontemplate_requirements (tree decl, bool > > diag = false) > > /* Normalize an EXPR as a constraint. */ > > static tree > > -normalize_constraint_expression (tree expr, bool diag) > > +normalize_constraint_expression (tree expr, norm_info info) > > { > > if (!expr || expr == error_mark_node) > > return expr; > > + > > + if (!info.generate_diagnostics ()) > > + if (tree *p = hash_map_safe_get (normalized_map, expr)) > > + return *p; > > + > > ++processing_template_decl; > > - norm_info info (diag ? tf_norm : tf_none); > > tree norm = get_normalized_constraints (expr, info); > > --processing_template_decl; > > + > > + if (!info.generate_diagnostics ()) > > + hash_map_safe_put<hm_ggc> (normalized_map, expr, norm); > > + > > return norm; > > } > > @@ -2086,16 +2088,14 @@ tsubst_compound_requirement (tree t, tree args, > > subst_info info) > > static tree > > tsubst_nested_requirement (tree t, tree args, subst_info info) > > { > > - /* Perform satisfaction quietly with the regular normal form. */ > > + /* Perform satisfaction quietly first. */ > > sat_info quiet (tf_none, info.in_decl); > > - tree norm = TREE_VALUE (TREE_TYPE (t)); > > - tree diag_norm = TREE_PURPOSE (TREE_TYPE (t)); > > - tree result = satisfy_constraint (norm, args, quiet); > > + tree result = satisfy_constraint_expression (t, args, quiet); > > if (result == error_mark_node) > > { > > - /* Replay the error using the diagnostic normal form. */ > > + /* Replay the error. */ > > sat_info noisy (tf_warning_or_error, info.in_decl); > > - satisfy_constraint (diag_norm, args, noisy); > > + satisfy_constraint_expression (t, args, noisy); > > } > > if (result != boolean_true_node) > > return error_mark_node; > > @@ -3040,8 +3040,22 @@ satisfy_constraint_expression (tree t, tree args, > > sat_info info) > > tree tmpl = get_concept_check_template (id); > > norm = normalize_concept_definition (tmpl, info.noisy ()); > > } > > + else if (TREE_CODE (t) == NESTED_REQ) > > + { > > + norm_info ninfo (info.noisy () ? tf_norm : tf_none); > > + /* The TREE_TYPE contains the set of template parameters that were in > > + scope for this nested requirement; use them as the initial template > > + parameters for normalization. */ > > + ninfo.initial_parms = TREE_TYPE (t); > > + norm = normalize_constraint_expression (TREE_OPERAND (t, 0), ninfo); > > + } > > + else if (EXPR_P (t)) > > + { > > + norm_info ninfo (info.noisy () ? tf_norm : tf_none); > > + norm = normalize_constraint_expression (t, ninfo); > > + } > > else > > - norm = normalize_constraint_expression (t, info.noisy ()); > > + gcc_unreachable (); > > /* Perform satisfaction. */ > > return satisfy_constraint (norm, args, info); > > @@ -3301,15 +3315,9 @@ finish_compound_requirement (location_t loc, tree > > expr, tree type, bool noexcept > > tree > > finish_nested_requirement (location_t loc, tree expr) > > { > > - /* We need to normalize the constraints now, at parse time, while > > - we have the necessary template context. We normalize twice, > > - once without diagnostic information and once with, which we'll > > - later use for quiet and noisy satisfaction respectively. */ > > - tree norm = normalize_constraint_expression (expr, /*diag=*/false); > > - tree diag_norm = normalize_constraint_expression (expr, /*diag=*/true); > > - > > - /* Build the constraint, saving its two normalizations as its type. */ > > - tree r = build1 (NESTED_REQ, build_tree_list (diag_norm, norm), expr); > > + /* Build the requirement, saving the set of in-scope template > > + parameters as its type. */ > > + tree r = build1 (NESTED_REQ, current_template_parms, expr); > > SET_EXPR_LOCATION (r, loc); > > return r; > > } > > @@ -3710,12 +3718,9 @@ diagnose_type_requirement (tree req, tree args, tree > > in_decl) > > static void > > diagnose_nested_requirement (tree req, tree args) > > { > > - /* Quietly check for satisfaction first using the regular normal form. > > - We can elaborate details later if needed. */ > > - tree norm = TREE_VALUE (TREE_TYPE (req)); > > - tree diag_norm = TREE_PURPOSE (TREE_TYPE (req)); > > - sat_info info (tf_none, NULL_TREE); > > - tree result = satisfy_constraint (norm, args, info); > > + /* Quietly check for satisfaction first. */ > > + sat_info quiet (tf_none, NULL_TREE); > > + tree result = satisfy_constraint_expression (req, args, quiet); > > if (result == boolean_true_node) > > return; > > @@ -3723,10 +3728,11 @@ diagnose_nested_requirement (tree req, tree args) > > location_t loc = cp_expr_location (expr); > > if (diagnosing_failed_constraint::replay_errors_p ()) > > { > > - /* Replay the substitution error using the diagnostic normal form. > > */ > > + /* Replay the substitution error with re-normalized requirements. */ > > inform (loc, "nested requirement %qE is not satisfied, because", > > expr); > > + > > sat_info noisy (tf_warning_or_error, NULL_TREE, > > /*diag_unsat=*/true); > > - satisfy_constraint (diag_norm, args, noisy); > > + satisfy_constraint_expression (req, args, noisy); > > } > > else > > inform (loc, "nested requirement %qE is not satisfied", expr); > > > >