tree in_decl;
};
-static tree satisfy_constraint (tree, tree, subst_info);
+/* Provides additional context for satisfaction.
+
+ The flag noisy() controls whether to diagnose ill-formed satisfaction,
+ such as the satisfaction value of an atom being non-bool or non-constant.
+
+ The flag diagnose_unsatisfaction_p() controls whether to explain why
+ 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
+ cleared). */
+
+struct sat_info : subst_info
+{
+ sat_info (tsubst_flags_t cmp, tree in, bool diag_unsat = false)
+ : subst_info (cmp, in), diagnose_unsatisfaction (diag_unsat)
+ {
+ if (diagnose_unsatisfaction_p ())
+ gcc_checking_assert (noisy ());
+ }
+
+ /* True if we should diagnose the cause of satisfaction failure.
+ Implies noisy(). */
+ bool
+ diagnose_unsatisfaction_p () const
+ {
+ return diagnose_unsatisfaction;
+ }
+
+ bool diagnose_unsatisfaction;
+};
+
+static tree satisfy_constraint (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. */
{
/* Ensure that we're in an evaluation context prior to satisfaction. */
tree norm = TREE_TYPE (t);
- tree result = satisfy_constraint (norm, args, info);
+ tree result = satisfy_constraint (norm, args,
+ sat_info (info.complain, info.in_decl));
if (result == error_mark_node && info.quiet ())
{
- subst_info noisy (tf_warning_or_error, info.in_decl);
+ sat_info noisy (tf_warning_or_error, info.in_decl);
satisfy_constraint (norm, args, noisy);
}
if (result != boolean_true_node)
return expr;
}
-static tree satisfy_constraint_r (tree, tree, subst_info info);
+static tree satisfy_constraint_r (tree, tree, sat_info info);
/* Compute the satisfaction of a conjunction. */
static tree
-satisfy_conjunction (tree t, tree args, subst_info info)
+satisfy_conjunction (tree t, tree args, sat_info info)
{
tree lhs = satisfy_constraint_r (TREE_OPERAND (t, 0), args, info);
if (lhs == error_mark_node || lhs == boolean_false_node)
/* Compute the satisfaction of a disjunction. */
static tree
-satisfy_disjunction (tree t, tree args, subst_info info)
+satisfy_disjunction (tree t, tree args, sat_info info)
{
- /* Evaluate the operands quietly. */
- subst_info quiet (tf_none, NULL_TREE);
+ /* Evaluate each operand with unsatisfaction diagnostics disabled. */
+ sat_info sub = info;
+ sub.diagnose_unsatisfaction = false;
- /* Register the constraint for diagnostics, if needed. */
- diagnosing_failed_constraint failure (t, args, info.noisy ());
+ tree lhs = satisfy_constraint_r (TREE_OPERAND (t, 0), args, sub);
+ if (lhs == boolean_true_node || lhs == error_mark_node)
+ return lhs;
- tree lhs = satisfy_constraint_r (TREE_OPERAND (t, 0), args, quiet);
- if (lhs == boolean_true_node)
- return boolean_true_node;
- tree rhs = satisfy_constraint_r (TREE_OPERAND (t, 1), args, quiet);
- if (rhs != boolean_true_node && info.noisy ())
+ tree rhs = satisfy_constraint_r (TREE_OPERAND (t, 1), args, sub);
+ if (rhs == boolean_true_node || rhs == error_mark_node)
+ return rhs;
+
+ /* Both branches evaluated to false. Explain the satisfaction failure in
+ each branch. */
+ if (info.diagnose_unsatisfaction_p ())
{
+ diagnosing_failed_constraint failure (t, args, info.noisy ());
cp_expr disj_expr = CONSTR_EXPR (t);
inform (disj_expr.get_location (),
"no operand of the disjunction is satisfied");
}
}
}
- return rhs;
+
+ return boolean_false_node;
}
/* Ensures that T is a truth value and not (accidentally, as sometimes
/* Compute the satisfaction of an atomic constraint. */
static tree
-satisfy_atom (tree t, tree args, subst_info info)
+satisfy_atom (tree t, tree args, sat_info info)
{
satisfaction_cache cache (t, args, info.complain);
if (tree r = cache.get ())
tree map = tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, quiet);
if (map == error_mark_node)
{
- /* If instantiation of the parameter mapping fails, the program
- is ill-formed. */
- if (info.noisy())
+ /* If instantiation of the parameter mapping fails, the constraint is
+ not satisfied. Replay the substitution. */
+ if (info.diagnose_unsatisfaction_p ())
tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, info);
return cache.save (boolean_false_node);
}
{
/* If substitution results in an invalid type or expression, the constraint
is not satisfied. Replay the substitution. */
- if (info.noisy ())
+ if (info.diagnose_unsatisfaction_p ())
tsubst_expr (expr, args, info.complain, info.in_decl, false);
return cache.save (inst_cache.save (boolean_false_node));
}
result = error_mark_node;
}
result = satisfaction_value (result);
- if (result == boolean_false_node && info.noisy ())
+ if (result == boolean_false_node && info.diagnose_unsatisfaction_p ())
diagnose_atomic_constraint (t, map, result, info);
return cache.save (inst_cache.save (result));
constraint only matters for subsumption. */
static tree
-satisfy_constraint_r (tree t, tree args, subst_info info)
+satisfy_constraint_r (tree t, tree args, sat_info info)
{
if (t == error_mark_node)
return error_mark_node;
/* Check that the normalized constraint T is satisfied for ARGS. */
static tree
-satisfy_constraint (tree t, tree args, subst_info info)
+satisfy_constraint (tree t, tree args, sat_info info)
{
auto_timevar time (TV_CONSTRAINT_SAT);
value (either true, false, or error). */
static tree
-satisfy_associated_constraints (tree t, tree args, subst_info info)
+satisfy_associated_constraints (tree t, tree args, sat_info info)
{
/* If there are no constraints then this is trivially satisfied. */
if (!t)
satisfaction value. */
static tree
-satisfy_constraint_expression (tree t, tree args, subst_info info)
+satisfy_constraint_expression (tree t, tree args, sat_info info)
{
if (t == error_mark_node)
return error_mark_node;
tree
satisfy_constraint_expression (tree expr)
{
- subst_info info (tf_none, NULL_TREE);
+ sat_info info (tf_none, NULL_TREE);
return satisfy_constraint_expression (expr, NULL_TREE, info);
}
static tree
-satisfy_declaration_constraints (tree t, subst_info info)
+satisfy_declaration_constraints (tree t, sat_info info)
{
gcc_assert (DECL_P (t));
const tree saved_t = t;
}
static tree
-satisfy_declaration_constraints (tree t, tree args, subst_info info)
+satisfy_declaration_constraints (tree t, tree args, sat_info info)
{
/* Update the declaration for diagnostics. */
info.in_decl = t;
}
static tree
-constraint_satisfaction_value (tree t, tsubst_flags_t complain)
+constraint_satisfaction_value (tree t, sat_info info)
{
- subst_info info (complain, NULL_TREE);
tree r;
if (DECL_P (t))
r = satisfy_declaration_constraints (t, info);
r = satisfy_constraint_expression (t, NULL_TREE, info);
if (r == error_mark_node && info.quiet ()
&& !(DECL_P (t) && TREE_NO_WARNING (t)))
- {
- constraint_satisfaction_value (t, tf_warning_or_error);
- if (DECL_P (t))
- /* Avoid giving these errors again. */
- TREE_NO_WARNING (t) = true;
- }
+ {
+ /* Replay the error with re-normalized requirements. */
+ sat_info noisy (tf_warning_or_error, info.in_decl);
+ constraint_satisfaction_value (t, noisy);
+ if (DECL_P (t))
+ /* Avoid giving these errors again. */
+ TREE_NO_WARNING (t) = true;
+ }
return r;
}
static tree
-constraint_satisfaction_value (tree t, tree args, tsubst_flags_t complain)
+constraint_satisfaction_value (tree t, tree args, sat_info info)
{
- subst_info info (complain, NULL_TREE);
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 ())
- constraint_satisfaction_value (t, args, tf_warning_or_error);
+ {
+ /* 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;
}
if (!flag_concepts)
return true;
- return constraint_satisfaction_value (t, tf_none) == boolean_true_node;
+ sat_info quiet (tf_none, NULL_TREE);
+ return constraint_satisfaction_value (t, quiet) == boolean_true_node;
}
/* True iff the result of satisfying T with ARGS is BOOLEAN_TRUE_NODE
if (!flag_concepts)
return true;
- return constraint_satisfaction_value (t, args, tf_none) == boolean_true_node;
+ sat_info quiet (tf_none, NULL_TREE);
+ return constraint_satisfaction_value (t, args, quiet) == boolean_true_node;
}
/* Evaluate a concept check of the form C<ARGS>. This is only used for the
gcc_assert (concept_check_p (check));
/* Check for satisfaction without diagnostics. */
- subst_info quiet (tf_none, NULL_TREE);
+ 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. */
- subst_info noisy (tf_warning_or_error, NULL_TREE);
- satisfy_constraint_expression (check, NULL_TREE, noisy);
- }
+ {
+ /* 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;
}
/* Quietly check for satisfaction first. We can elaborate details
later if needed. */
tree norm = TREE_TYPE (req);
- subst_info info (tf_none, NULL_TREE);
+ sat_info info (tf_none, NULL_TREE);
tree result = satisfy_constraint (norm, args, info);
if (result == boolean_true_node)
return;
{
/* Replay the substitution error. */
inform (loc, "nested requirement %qE is not satisfied, because", expr);
- subst_info noisy (tf_warning_or_error, NULL_TREE);
+ sat_info noisy (tf_warning_or_error, NULL_TREE, /*diag_unsat=*/true);
satisfy_constraint_expression (expr, args, noisy);
}
else
if (concepts_diagnostics_max_depth == 0)
return;
- /* Replay satisfaction, but diagnose errors. */
+ /* Replay satisfaction, but diagnose unsatisfaction. */
+ sat_info noisy (tf_warning_or_error, NULL_TREE, /*diag_unsat=*/true);
if (!args)
- constraint_satisfaction_value (t, tf_warning_or_error);
+ constraint_satisfaction_value (t, noisy);
else
- constraint_satisfaction_value (t, args, tf_warning_or_error);
+ constraint_satisfaction_value (t, args, noisy);
static bool suggested_p;
if (concepts_diagnostics_max_depth_exceeded_p