aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/constraint.cc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2021-03-03 12:01:13 -0500
committerPatrick Palka <ppalka@redhat.com>2021-03-03 12:01:13 -0500
commit662ef5b54de8f77080a19e03f31b162c04ba273f (patch)
tree719af4f3e7349cf7da230988be93761b19817c04 /gcc/cp/constraint.cc
parent39d7eb8a73d5f8c09db20926a98181181d9dd2c2 (diff)
downloadgcc-662ef5b54de8f77080a19e03f31b162c04ba273f.zip
gcc-662ef5b54de8f77080a19e03f31b162c04ba273f.tar.gz
gcc-662ef5b54de8f77080a19e03f31b162c04ba273f.tar.bz2
c++: Clean up normalization and satisfaction routines
This patch mostly performs some straightforward refactoring: - Renamed satisfy_constraint to satisfy_normalized_constraints - Renamed the three-parameter version of satisfy_constraint_expression to satisfy_nondeclaration_constraints - Removed normalize_(non)?template_requirements - Removed satisfy_associated_constraints (and made its callers check for dependent template args sooner, before normalization) - Removed the tsubst_flags_t parameter of evaluate_concept_check - Combined the two versions of constraint_satisfaction_value - Combined the two versions of constraint_satisfied_p Additionally, this patch removes the handling of general constraint-expressions from satisfy_nondeclaration_constraints, and hence constraints_satisfied_p and constraint_satisfaction_value now take only things that carry their own template information needed for normalization, and, as a special case, REQUIRES_EXPRs. But the latter now get evaluated directly via tsubst_requires_expr rather than going through satisfaction. (That we used to evaluate REQUIRES_EXPR via satisfaction might even be a correctness issue: since we cache satisfaction in special ways that don't apply to regular evaluation, going through satisfaction could in theory cause us to reuse a cached value for a REQUIRES_EXPR when we shouldn't have.) gcc/cp/ChangeLog: * constexpr.c (cxx_eval_call_expression): Adjust call to evaluate_concept_check. (cxx_eval_constant_expression) <case REQUIRES_EXPR>: Use evaluate_requires_expression instead of satisfy_constraint_expression. <case TEMPLATE_ID_EXPR>: Adjust call to evaluate_concept_check. * constraint.cc (struct sat_info): Adjust comment about which satisfaction entrypoints use noisy-unsat. (normalize_template_requirements): Remove (and adjust callers appropriately). (normalize_nontemplate_requirements): Likewise. (tsubst_nested_requirement): Use constraint_satisfaction_value instead of satisfy_constraint_expression, which'll do the noisy replaying of ill-formed quiet satisfaction for us. (decl_satisfied_cache): Adjust comment. (satisfy_constraint): Rename to ... (satisfy_normalized_constraints): ... this. (satisfy_associated_constraints): Remove (and make its callers check for dependent arguments). (satisfy_constraint_expression): Rename to ... (satisfy_nondeclaration_constraints): ... this. Assert that 'args' is empty when 't' is a concept-id. Removing handling bare constraint-expressions, and handle REQUIRES_EXPRs specially. Adjust comment accordingly. (satisfy_declaration_constraints): Assert in the two-parameter version that 't' is not a TEMPLATE_DECL. Adjust following removal of normalize_(non)?template_requirements and satisfy_asociated_constraints. (constraint_satisfaction_value): Combine the two- and three-parameter versions in the natural way. (constraints_satisfied_p): Combine the one- and two-parameter versions in the natural way. Improve documentation. (evaluate_requires_expr): Define. (evaluate_concept_check): Remove 'complain' parameter. Use constraint_satisfaction_value instead of satisfy_constraint_expression. (diagnose_nested_requirement): Adjust following renaming of satisfy_constraint_expression. (diagnose_constraints): Handle REQUIRES_EXPR by going through diagnose_requires_expr directly instead of treating it as a constraint-expression. Improve documentation. * cp-gimplify.c (cp_genericize_r) <case CALL_EXPR>: Adjust call to evaluate_concept_check. <case REQUIRES_EXPR>: Use evaluate_requires_expr instead of constraints_satisfied_p. <case TEMPLATE_ID_EXPR>: Adjust call to evaluate_concept_check. * cp-tree.h (evaluate_requires_expr): Declare. (evaluate_concept_check): Remove tsubst_flag_t parameter. (satisfy_constraint_expression): Remove declaration. (constraints_satisfied_p): Remove one-parameter declaration. Add a default argument to the two-parameter declaration. * cvt.c (convert_to_void): Adjust call to evaluate_concept_check.
Diffstat (limited to 'gcc/cp/constraint.cc')
-rw-r--r--gcc/cp/constraint.cc234
1 files changed, 100 insertions, 134 deletions
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3332e60..0949788 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -107,10 +107,9 @@ struct subst_info
a constraint is not satisfied.
The entrypoints to satisfaction for which we set noisy+unsat are
- diagnose_constraints and diagnose_nested_requirement. The entrypoints for
- which we set noisy-unsat are the replays inside constraint_satisfaction_value,
- evaluate_concept_check and tsubst_nested_requirement. In other entrypoints,
- e.g. constraints_satisfied_p, we enter satisfaction quietly (both flags
+ diagnose_constraints and diagnose_nested_requirement. The entrypoint for
+ which we set noisy-unsat is the replay inside constraint_satisfaction_value.
+ From constraints_satisfied_p, we enter satisfaction quietly (both flags
cleared). */
struct sat_info : subst_info
@@ -133,7 +132,7 @@ struct sat_info : subst_info
bool diagnose_unsatisfaction;
};
-static tree satisfy_constraint_expression (tree, tree, sat_info);
+static tree constraint_satisfaction_value (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. */
@@ -958,22 +957,6 @@ normalize_concept_definition (tree tmpl, bool diag = false)
return norm;
}
-/* Returns the normal form of TMPL's requirements. */
-
-static tree
-normalize_template_requirements (tree tmpl, bool diag = false)
-{
- return get_normalized_constraints_from_decl (tmpl, diag);
-}
-
-/* Returns the normal form of TMPL's requirements. */
-
-static tree
-normalize_nontemplate_requirements (tree decl, bool diag = false)
-{
- return get_normalized_constraints_from_decl (decl, diag);
-}
-
/* Normalize an EXPR as a constraint. */
static tree
@@ -2068,15 +2051,8 @@ 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 first. */
sat_info quiet (tf_none, info.in_decl);
- tree result = satisfy_constraint_expression (t, args, quiet);
- if (result == error_mark_node)
- {
- /* Replay the error. */
- sat_info noisy (tf_warning_or_error, info.in_decl);
- satisfy_constraint_expression (t, args, noisy);
- }
+ tree result = constraint_satisfaction_value (t, args, quiet);
if (result != boolean_true_node)
return error_mark_node;
return boolean_true_node;
@@ -2459,7 +2435,7 @@ struct sat_hasher : ggc_ptr_hash<sat_entry>
/* Cache the result of satisfy_atom. */
static GTY((deletable)) hash_table<sat_hasher> *sat_cache;
-/* Cache the result of constraint_satisfaction_value. */
+/* Cache the result of satisfy_declaration_constraints. */
static GTY((deletable)) hash_map<tree, tree> *decl_satisfied_cache;
/* A tool used by satisfy_atom to help manage satisfaction caching and to
@@ -2941,7 +2917,7 @@ satisfy_constraint_r (tree t, tree args, sat_info info)
/* Check that the normalized constraint T is satisfied for ARGS. */
static tree
-satisfy_constraint (tree t, tree args, sat_info info)
+satisfy_normalized_constraints (tree t, tree args, sat_info info)
{
auto_timevar time (TV_CONSTRAINT_SAT);
@@ -2957,24 +2933,6 @@ satisfy_constraint (tree t, tree args, sat_info info)
return satisfy_constraint_r (t, args, info);
}
-/* Check the normalized constraints T against ARGS, returning a satisfaction
- value (either true, false, or error). */
-
-static tree
-satisfy_associated_constraints (tree t, tree args, sat_info info)
-{
- /* If there are no constraints then this is trivially satisfied. */
- if (!t)
- return boolean_true_node;
-
- /* If any arguments depend on template parameters, we can't
- check constraints. Pretend they're satisfied for now. */
- if (args && uses_template_parms (args))
- return boolean_true_node;
-
- return satisfy_constraint (t, args, info);
-}
-
/* Return the normal form of the constraints on the placeholder 'auto'
type T. */
@@ -3005,19 +2963,34 @@ normalize_placeholder_type_constraints (tree t, bool diag)
return normalize_constraint_expression (constr, info);
}
-/* Evaluate EXPR as a constraint expression using ARGS, returning a
- satisfaction value. */
+/* Evaluate the constraints of T using ARGS, returning a satisfaction value.
+ Here, T can be a concept-id, nested-requirement, placeholder 'auto', or
+ requires-expression. */
static tree
-satisfy_constraint_expression (tree t, tree args, sat_info info)
+satisfy_nondeclaration_constraints (tree t, tree args, sat_info info)
{
if (t == error_mark_node)
return error_mark_node;
+ /* Handle REQUIRES_EXPR directly, bypassing satisfaction. */
+ if (TREE_CODE (t) == REQUIRES_EXPR)
+ {
+ /* TODO: Remove this assert and the special casing of REQUIRES_EXPRs
+ from diagnose_constraints once we merge tsubst_requires_expr and
+ diagnose_requires_expr. */
+ gcc_assert (!info.diagnose_unsatisfaction_p ());
+ auto ovr = make_temp_override (current_constraint_diagnosis_depth);
+ if (info.noisy ())
+ ++current_constraint_diagnosis_depth;
+ return tsubst_requires_expr (t, args, info.complain, info.in_decl);
+ }
+
/* Get the normalized constraints. */
tree norm;
- if (args == NULL_TREE && concept_check_p (t))
+ if (concept_check_p (t))
{
+ gcc_assert (!args);
tree id = unpack_concept_check (t);
args = TREE_OPERAND (id, 1);
tree tmpl = get_concept_check_template (id);
@@ -3032,11 +3005,6 @@ satisfy_constraint_expression (tree t, tree args, sat_info info)
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 if (is_auto (t))
{
norm = normalize_placeholder_type_constraints (t, info.noisy ());
@@ -3047,23 +3015,16 @@ satisfy_constraint_expression (tree t, tree args, sat_info info)
gcc_unreachable ();
/* Perform satisfaction. */
- return satisfy_constraint (norm, args, info);
+ return satisfy_normalized_constraints (norm, args, info);
}
-/* Used only to evaluate requires-expressions during constant expression
- evaluation. */
-
-tree
-satisfy_constraint_expression (tree expr)
-{
- sat_info info (tf_none, NULL_TREE);
- return satisfy_constraint_expression (expr, NULL_TREE, info);
-}
+/* Evaluate the associated constraints of the template specialization T
+ according to INFO, returning a satisfaction value. */
static tree
satisfy_declaration_constraints (tree t, sat_info info)
{
- gcc_assert (DECL_P (t));
+ gcc_assert (DECL_P (t) && TREE_CODE (t) != TEMPLATE_DECL);
const tree saved_t = t;
/* For inherited constructors, consider the original declaration;
@@ -3083,26 +3044,24 @@ satisfy_declaration_constraints (tree t, sat_info info)
if (tree *result = hash_map_safe_get (decl_satisfied_cache, saved_t))
return *result;
- /* Get the normalized constraints. */
- tree norm = NULL_TREE;
tree args = NULL_TREE;
if (tree ti = DECL_TEMPLATE_INFO (t))
{
- tree tmpl = TI_TEMPLATE (ti);
- norm = normalize_template_requirements (tmpl, info.noisy ());
-
/* The initial parameter mapping is the complete set of
template arguments substituted into the declaration. */
args = TI_ARGS (ti);
if (inh_ctor_targs)
args = add_outermost_template_args (args, inh_ctor_targs);
- }
- else
- {
- /* These should be empty until we allow constraints on non-templates. */
- norm = normalize_nontemplate_requirements (t, info.noisy ());
+
+ /* If any arguments depend on template parameters, we can't
+ check constraints. Pretend they're satisfied for now. */
+ if (uses_template_parms (args))
+ return boolean_true_node;
}
+ /* Get the normalized constraints. */
+ tree norm = get_normalized_constraints_from_decl (t, info.noisy ());
+
unsigned ftc_count = vec_safe_length (failed_type_completions);
tree result = boolean_true_node;
@@ -3111,7 +3070,7 @@ satisfy_declaration_constraints (tree t, sat_info info)
if (!push_tinst_level (t))
return result;
push_access_scope (t);
- result = satisfy_associated_constraints (norm, args, info);
+ result = satisfy_normalized_constraints (norm, args, info);
pop_access_scope (t);
pop_tinst_level ();
}
@@ -3134,6 +3093,10 @@ satisfy_declaration_constraints (tree t, sat_info info)
return result;
}
+/* Evaluate the associated constraints of the template T using ARGS as the
+ innermost set of template arguments and according to INFO, returning a
+ satisfaction value. */
+
static tree
satisfy_declaration_constraints (tree t, tree args, sat_info info)
{
@@ -3144,14 +3107,19 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info)
args = add_outermost_template_args (t, args);
+ /* If any arguments depend on template parameters, we can't
+ check constraints. Pretend they're satisfied for now. */
+ if (uses_template_parms (args))
+ return boolean_true_node;
+
tree result = boolean_true_node;
- if (tree norm = normalize_template_requirements (t, info.noisy ()))
+ if (tree norm = get_normalized_constraints_from_decl (t, info.noisy ()))
{
if (!push_tinst_level (t, args))
return result;
tree pattern = DECL_TEMPLATE_RESULT (t);
push_access_scope (pattern);
- result = satisfy_associated_constraints (norm, args, info);
+ result = satisfy_normalized_constraints (norm, args, info);
pop_access_scope (pattern);
pop_tinst_level ();
}
@@ -3159,62 +3127,50 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info)
return result;
}
+/* A wrapper around satisfy_declaration_constraints and
+ satisfy_nondeclaration_constraints which additionally replays
+ quiet ill-formed satisfaction noisily, so that ill-formed
+ satisfaction always gets diagnosed. */
+
static tree
-constraint_satisfaction_value (tree t, sat_info info)
+constraint_satisfaction_value (tree t, tree args, sat_info info)
{
tree r;
if (DECL_P (t))
- r = satisfy_declaration_constraints (t, info);
+ {
+ if (args)
+ r = satisfy_declaration_constraints (t, args, info);
+ else
+ r = satisfy_declaration_constraints (t, info);
+ }
else
- r = satisfy_constraint_expression (t, NULL_TREE, info);
+ r = satisfy_nondeclaration_constraints (t, args, info);
if (r == error_mark_node && info.quiet ()
&& !(DECL_P (t) && TREE_NO_WARNING (t)))
{
- /* Replay the error with re-normalized requirements. */
+ /* Replay the error noisily. */
sat_info noisy (tf_warning_or_error, info.in_decl);
- constraint_satisfaction_value (t, noisy);
- if (DECL_P (t))
+ constraint_satisfaction_value (t, args, noisy);
+ if (DECL_P (t) && !args)
/* Avoid giving these errors again. */
TREE_NO_WARNING (t) = true;
}
return r;
}
-static tree
-constraint_satisfaction_value (tree t, tree args, sat_info info)
-{
- tree r;
- if (DECL_P (t))
- r = satisfy_declaration_constraints (t, args, info);
- else
- r = satisfy_constraint_expression (t, args, info);
- if (r == error_mark_node && info.quiet ())
- {
- /* Replay the error with re-normalized requirements. */
- sat_info noisy (tf_warning_or_error, info.in_decl);
- constraint_satisfaction_value (t, args, noisy);
- }
- return r;
-}
-
-/* True iff the result of satisfying T is BOOLEAN_TRUE_NODE and false
- otherwise, even in the case of errors. */
-
-bool
-constraints_satisfied_p (tree t)
-{
- if (!flag_concepts)
- return true;
-
- sat_info quiet (tf_none, NULL_TREE);
- return constraint_satisfaction_value (t, quiet) == boolean_true_node;
-}
+/* True iff the result of satisfying T using ARGS is BOOLEAN_TRUE_NODE
+ and false otherwise, even in the case of errors.
-/* True iff the result of satisfying T with ARGS is BOOLEAN_TRUE_NODE
- and false otherwise, even in the case of errors. */
+ Here, T can be:
+ - a template declaration
+ - a template specialization (in which case ARGS must be empty)
+ - a concept-id (in which case ARGS must be empty)
+ - a nested-requirement
+ - a placeholder 'auto'
+ - a requires-expression. */
bool
-constraints_satisfied_p (tree t, tree args)
+constraints_satisfied_p (tree t, tree args/*= NULL_TREE */)
{
if (!flag_concepts)
return true;
@@ -3227,7 +3183,7 @@ constraints_satisfied_p (tree t, tree args)
evaluation of template-ids as id-expressions. */
tree
-evaluate_concept_check (tree check, tsubst_flags_t complain)
+evaluate_concept_check (tree check)
{
if (check == error_mark_node)
return error_mark_node;
@@ -3236,14 +3192,19 @@ evaluate_concept_check (tree check, tsubst_flags_t complain)
/* Check for satisfaction without diagnostics. */
sat_info quiet (tf_none, NULL_TREE);
- tree result = satisfy_constraint_expression (check, NULL_TREE, quiet);
- if (result == error_mark_node && (complain & tf_error))
- {
- /* Replay the error with re-normalized requirements. */
- sat_info noisy (tf_warning_or_error, NULL_TREE);
- satisfy_constraint_expression (check, NULL_TREE, noisy);
- }
- return result;
+ return constraint_satisfaction_value (check, /*args=*/NULL_TREE, quiet);
+}
+
+/* Evaluate the requires-expression T, returning either boolean_true_node
+ or boolean_false_node. This is used during gimplification and constexpr
+ evaluation. */
+
+tree
+evaluate_requires_expr (tree t)
+{
+ gcc_assert (TREE_CODE (t) == REQUIRES_EXPR);
+ sat_info quiet (tf_none, NULL_TREE);
+ return constraint_satisfaction_value (t, /*args=*/NULL_TREE, quiet);
}
/*---------------------------------------------------------------------------
@@ -3709,7 +3670,7 @@ diagnose_nested_requirement (tree req, tree args)
{
/* Quietly check for satisfaction first. */
sat_info quiet (tf_none, NULL_TREE);
- tree result = satisfy_constraint_expression (req, args, quiet);
+ tree result = satisfy_nondeclaration_constraints (req, args, quiet);
if (result == boolean_true_node)
return;
@@ -3721,7 +3682,7 @@ diagnose_nested_requirement (tree req, tree args)
inform (loc, "nested requirement %qE is not satisfied, because", expr);
sat_info noisy (tf_warning_or_error, NULL_TREE, /*diag_unsat=*/true);
- satisfy_constraint_expression (req, args, noisy);
+ satisfy_nondeclaration_constraints (req, args, noisy);
}
else
inform (loc, "nested requirement %qE is not satisfied", expr);
@@ -3854,7 +3815,7 @@ diagnosing_failed_constraint::replay_errors_p ()
}
/* Emit diagnostics detailing the failure ARGS to satisfy the constraints
- of T. Here, T can be either a constraint or a declaration. */
+ of T. Here, T and ARGS are as in constraints_satisfied_p. */
void
diagnose_constraints (location_t loc, tree t, tree args)
@@ -3866,8 +3827,13 @@ diagnose_constraints (location_t loc, tree t, tree args)
/* Replay satisfaction, but diagnose unsatisfaction. */
sat_info noisy (tf_warning_or_error, NULL_TREE, /*diag_unsat=*/true);
- if (!args)
- constraint_satisfaction_value (t, noisy);
+ if (TREE_CODE (t) == REQUIRES_EXPR)
+ {
+ gcc_assert (!args);
+ ++current_constraint_diagnosis_depth;
+ diagnose_requires_expr (t, /*map=*/NULL_TREE, /*in_decl=*/NULL_TREE);
+ --current_constraint_diagnosis_depth;
+ }
else
constraint_satisfaction_value (t, args, noisy);