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);
> > 
> 
> 

Reply via email to