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)
@@ -2508,12 +2537,12 @@ tsubst_constraint (tree t, tree args, tsubst_flags_t
complain, tree in_decl)
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)
@@ -2567,20 +2596,25 @@ collect_operands_of_disjunction (tree t,
auto_vec<tree_pair> *operands)
/* 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");
@@ -2601,7 +2635,8 @@ satisfy_disjunction (tree t, tree args, subst_info info)
}
}
}
- return rhs;
+
+ return boolean_false_node;
}
/* Ensures that T is a truth value and not (accidentally, as sometimes
@@ -2682,7 +2717,7 @@ static void diagnose_atomic_constraint (tree, tree, tree,
subst_info);
/* 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 ())
@@ -2700,9 +2735,9 @@ satisfy_atom (tree t, tree args, subst_info info)
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);
}
@@ -2729,7 +2764,7 @@ satisfy_atom (tree t, tree args, subst_info info)
{
/* 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));
}
@@ -2757,7 +2792,7 @@ satisfy_atom (tree t, tree args, subst_info info)
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));
@@ -2775,7 +2810,7 @@ satisfy_atom (tree t, tree args, subst_info info)
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;
@@ -2796,7 +2831,7 @@ satisfy_constraint_r (tree t, tree args, subst_info info)
/* 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);
@@ -2814,7 +2849,7 @@ satisfy_constraint (tree t, tree args, subst_info info)
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)
@@ -2832,7 +2867,7 @@ satisfy_associated_constraints (tree t, tree args,
subst_info info)
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;
@@ -2861,12 +2896,12 @@ satisfy_constraint_expression (tree t, tree args,
subst_info info)
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;
@@ -2926,7 +2961,7 @@ satisfy_declaration_constraints (tree t, subst_info info)
}
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;
@@ -2951,9 +2986,8 @@ satisfy_declaration_constraints (tree t, tree args,
subst_info info)
}
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);
@@ -2961,26 +2995,31 @@ constraint_satisfaction_value (tree t, tsubst_flags_t
complain)
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;
}
@@ -2993,7 +3032,8 @@ constraints_satisfied_p (tree t)
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
@@ -3005,7 +3045,8 @@ constraints_satisfied_p (tree t, tree args)
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
@@ -3020,14 +3061,14 @@ evaluate_concept_check (tree check, tsubst_flags_t
complain)
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;
}
@@ -3505,7 +3546,7 @@ diagnose_nested_requirement (tree req, tree args)
/* 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;
@@ -3516,7 +3557,8 @@ diagnose_nested_requirement (tree req, tree args)
{
/* 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);
+ noisy.diagnose_unsatisfaction = true;
satisfy_constraint_expression (expr, args, noisy);
}
else
@@ -3660,11 +3702,12 @@ diagnose_constraints (location_t loc, tree t, tree args)
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, /*diagnose_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
diff --git a/gcc/testsuite/g++.dg/concepts/pr94252.C
b/gcc/testsuite/g++.dg/concepts/pr94252.C
index 56ce5f88bad..b0457037ede 100644
--- a/gcc/testsuite/g++.dg/concepts/pr94252.C
+++ b/gcc/testsuite/g++.dg/concepts/pr94252.C
@@ -16,6 +16,7 @@ static_assert(requires(S o, int i) {
template<typename T>
concept c = requires (T t) { requires (T)5; }; // { dg-error "has type
.int." }
+// { dg-bogus "not satisfied" "" { target *-*-* } .-1 }
int
foo()
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-nonbool3.C
b/gcc/testsuite/g++.dg/cpp2a/concepts-nonbool3.C
new file mode 100644
index 00000000000..2a2af54847b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-nonbool3.C
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++20 } }
+
+template <auto V> concept C = false || V || false; // { dg-error "has type
'int'" }
+template <auto V> int f() requires C<V>;
+int a = f<0>(); // { dg-error "no match" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires18.C
b/gcc/testsuite/g++.dg/cpp2a/concepts-requires18.C
index a9b7720cc6c..9e45c586917 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-requires18.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires18.C
@@ -4,7 +4,7 @@ template<typename T>
concept integer = __is_same_as(T, int);
template<typename T>
-concept subst = requires (T x) { requires true; }; // { dg-error "parameter type
.void." }
+concept subst = requires (T x) { requires true; };
template<typename T>
concept c1 = requires { requires integer<T> || subst<T&>; }; // { dg-message "in
requirements" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires21.C
b/gcc/testsuite/g++.dg/cpp2a/concepts-requires21.C
index bc38b893c68..8aead2fe2c5 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-requires21.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires21.C
@@ -5,3 +5,4 @@ template<typename T, typename U>
constexpr bool is_same_v = __is_same (T, U);
static_assert(is_same_v<bool, decltype(requires { requires false; })>);
+// { dg-bogus "evaluated to 'false" "" { target *-*-* } .-1 }