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;