public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/marxin/heads/marxin-gcc-benchmark-branch)] c++: Improve handling of ill-formed constraints [PR94186].
@ 2020-03-30 11:05 Martin Liska
0 siblings, 0 replies; only message in thread
From: Martin Liska @ 2020-03-30 11:05 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:fddfd3ce555965864b6116cf541f6355d2057d3d
commit fddfd3ce555965864b6116cf541f6355d2057d3d
Author: Jason Merrill <jason@redhat.com>
Date: Tue Mar 24 18:25:17 2020 -0400
c++: Improve handling of ill-formed constraints [PR94186].
It would have been trivial to make the error for non-bool constraint in
satisfy_atom unconditional, but that didn't give context for the error or
printing with the dependent form and template arguments. So I changed a
couple of places so that, when a hard error is encountered during quiet
substitution/satisfaction, we go through again noisily; this builds up the
necessary context.
The similar change to tsubst_nested_requirement does not build up the
necessary context; rather than try to fix that now I changed
get_constraint_error_location to give up and use input_location if there's
no CONSTR_CONTEXT. In the case of concepts-pr67697.C, we still have a good
source location because the NESTED_REQ has a correct EXPR_LOCATION, but this
patch doesn't improve context printing for this case as it does for the
above.
gcc/cp/ChangeLog
2020-03-24 Jason Merrill <jason@redhat.com>
PR c++/94186
* constraint.cc (constraint_satisfaction_value): Repeat noisily on
error.
(tsubst_nested_requirement): Likewise.
(get_constraint_error_location): Allow missing context.
(diagnose_atomic_constraint): Diagnose non-bool constraint here.
(satisfy_atom): Not here. Only diagnose non-constant when noisy.
Diff:
---
gcc/cp/ChangeLog | 10 ++++
gcc/cp/constraint.cc | 79 ++++++++++++++++++-------
gcc/testsuite/g++.dg/concepts/pr84330.C | 2 +-
gcc/testsuite/g++.dg/cpp2a/concepts-nonbool1.C | 20 +++++++
gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C | 4 +-
gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C | 12 ++--
6 files changed, 96 insertions(+), 31 deletions(-)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a4b132d6961..f867d0e4e1a 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,13 @@
+2020-03-24 Jason Merrill <jason@redhat.com>
+
+ PR c++/94186
+ * constraint.cc (constraint_satisfaction_value): Repeat noisily on
+ error.
+ (tsubst_nested_requirement): Likewise.
+ (get_constraint_error_location): Allow missing context.
+ (diagnose_atomic_constraint): Diagnose non-bool constraint here.
+ (satisfy_atom): Not here. Only diagnose non-constant when noisy.
+
2020-03-24 Jason Merrill <jason@redhat.com>
* pt.c (any_template_parm_r): Look into the type of a non-type
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e434be815f..a86bcdf603a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2004,6 +2004,11 @@ tsubst_nested_requirement (tree t, tree args, subst_info info)
/* Ensure that we're in an evaluation context prior to satisfaction. */
tree norm = TREE_VALUE (TREE_TYPE (t));
tree result = satisfy_constraint (norm, args, info);
+ if (result == error_mark_node && info.quiet ())
+ {
+ subst_info noisy (tf_warning_or_error, info.in_decl);
+ satisfy_constraint (norm, args, noisy);
+ }
if (result != boolean_true_node)
return error_mark_node;
return result;
@@ -2489,7 +2494,7 @@ get_mapped_args (tree map)
return args;
}
-static void diagnose_atomic_constraint (tree, tree, subst_info);
+static void diagnose_atomic_constraint (tree, tree, tree, subst_info);
/* Compute the satisfaction of an atomic constraint. */
@@ -2534,8 +2539,6 @@ satisfy_atom (tree t, tree args, subst_info info)
return cache.save (boolean_false_node);
}
- location_t loc = cp_expr_loc_or_input_loc (expr);
-
/* [17.4.1.2] ... lvalue-to-rvalue conversion is performed as necessary,
and EXPR shall be a constant expression of type bool. */
result = force_rvalue (result, info.complain);
@@ -2544,14 +2547,22 @@ satisfy_atom (tree t, tree args, subst_info info)
if (!same_type_p (TREE_TYPE (result), boolean_type_node))
{
if (info.noisy ())
- error_at (loc, "constraint does not have type %<bool%>");
+ diagnose_atomic_constraint (t, map, result, info);
return cache.save (error_mark_node);
}
/* Compute the value of the constraint. */
- result = satisfaction_value (cxx_constant_value (result));
+ if (info.noisy ())
+ result = cxx_constant_value (result);
+ else
+ {
+ result = maybe_constant_value (result);
+ if (!TREE_CONSTANT (result))
+ result = error_mark_node;
+ }
+ result = satisfaction_value (result);
if (result == boolean_false_node && info.noisy ())
- diagnose_atomic_constraint (t, map, info);
+ diagnose_atomic_constraint (t, map, result, info);
return cache.save (result);
}
@@ -2733,20 +2744,34 @@ static tree
constraint_satisfaction_value (tree t, tsubst_flags_t complain)
{
subst_info info (complain, NULL_TREE);
+ tree r;
if (DECL_P (t))
- return satisfy_declaration_constraints (t, info);
+ r = satisfy_declaration_constraints (t, info);
else
- return satisfy_constraint_expression (t, NULL_TREE, 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;
+ }
+ return r;
}
static tree
constraint_satisfaction_value (tree t, tree args, tsubst_flags_t complain)
{
subst_info info (complain, NULL_TREE);
+ tree r;
if (DECL_P (t))
- return satisfy_declaration_constraints (t, args, info);
+ r = satisfy_declaration_constraints (t, args, info);
else
- return satisfy_constraint_expression (t, args, info);
+ r = satisfy_constraint_expression (t, args, info);
+ if (r == error_mark_node && info.quiet ())
+ constraint_satisfaction_value (t, args, tf_warning_or_error);
+ return r;
}
/* True iff the result of satisfying T is BOOLEAN_TRUE_NODE and false
@@ -3033,6 +3058,9 @@ at_least_as_constrained (tree d1, tree d2)
static location_t
get_constraint_error_location (tree t)
{
+ if (location_t loc = cp_expr_location (t))
+ return loc;
+
/* If we have a specific location give it. */
tree expr = CONSTR_EXPR (t);
if (location_t loc = cp_expr_location (expr))
@@ -3041,20 +3069,23 @@ get_constraint_error_location (tree t)
/* If the constraint is normalized from a requires-clause, give
the location as that of the constrained declaration. */
tree cxt = CONSTR_CONTEXT (t);
- tree src = TREE_VALUE (cxt);
+ tree src = cxt ? TREE_VALUE (cxt) : NULL_TREE;
if (!src)
/* TODO: This only happens for constrained non-template declarations. */
- return input_location;
- if (DECL_P (src))
+ ;
+ else if (DECL_P (src))
return DECL_SOURCE_LOCATION (src);
-
/* Otherwise, give the location as the defining concept. */
- gcc_assert (concept_check_p (src));
- tree id = unpack_concept_check (src);
- tree tmpl = TREE_OPERAND (id, 0);
- if (OVL_P (tmpl))
- tmpl = OVL_FIRST (tmpl);
- return DECL_SOURCE_LOCATION (tmpl);
+ else if (concept_check_p (src))
+ {
+ tree id = unpack_concept_check (src);
+ tree tmpl = TREE_OPERAND (id, 0);
+ if (OVL_P (tmpl))
+ tmpl = OVL_FIRST (tmpl);
+ return DECL_SOURCE_LOCATION (tmpl);
+ }
+
+ return input_location;
}
/* Emit a diagnostic for a failed trait. */
@@ -3302,7 +3333,7 @@ diagnose_requires_expr (tree expr, tree map, tree in_decl)
with the instantiated parameter mapping MAP. */
static void
-diagnose_atomic_constraint (tree t, tree map, subst_info info)
+diagnose_atomic_constraint (tree t, tree map, tree result, subst_info info)
{
/* If the constraint is already ill-formed, we've previously diagnosed
the reason. We should still say why the constraints aren't satisfied. */
@@ -3338,7 +3369,11 @@ diagnose_atomic_constraint (tree t, tree map, subst_info info)
default:
tree a = copy_node (t);
ATOMIC_CONSTR_MAP (a) = map;
- inform (loc, "the expression %qE evaluated to %<false%>", a);
+ if (!same_type_p (TREE_TYPE (result), boolean_type_node))
+ error_at (loc, "constraint %qE has type %qT, not %<bool%>",
+ a, TREE_TYPE (result));
+ else
+ inform (loc, "the expression %qE evaluated to %<false%>", a);
ggc_free (a);
}
}
diff --git a/gcc/testsuite/g++.dg/concepts/pr84330.C b/gcc/testsuite/g++.dg/concepts/pr84330.C
index ba035d02555..3f5b1f405a1 100644
--- a/gcc/testsuite/g++.dg/concepts/pr84330.C
+++ b/gcc/testsuite/g++.dg/concepts/pr84330.C
@@ -5,7 +5,7 @@
struct A
{
template<typename T>
- requires (sizeof(T) >> 0) // { dg-error "constraint does not have type 'bool'" }
+ requires (sizeof(T) >> 0) // { dg-error "bool" }
void foo(T);
void bar()
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-nonbool1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-nonbool1.C
new file mode 100644
index 00000000000..8be365dfa97
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-nonbool1.C
@@ -0,0 +1,20 @@
+// PR c++/94186
+// { dg-do compile { target concepts } }
+
+template <typename T>
+struct is_small
+{
+ enum { value = sizeof(T) <= 4 };
+};
+
+template <typename T>
+ requires is_small<T>::value // { dg-error "bool" }
+void fun(T) {}
+
+template <typename T>
+void fun(T) {}
+
+int main()
+{
+ fun(1); // { dg-message "" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C
index 62cc21dd7e1..7afd34d11fd 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C
@@ -41,8 +41,8 @@ template<int N> requires N == 0 struct S2 { }; // { dg-error "does not have type
template<int N> requires (N == 0) struct S3 { }; // OK
-template<typename T, T X> requires X struct S4 { }; // OK
-S4<int, 0> x1; // { dg-error "template constraint failure|does not have type" }
+template<typename T, T X> requires X struct S4 { }; // { dg-error "bool" }
+S4<int, 0> x1; // { dg-error "template constraint failure" }
S4<bool, true> x2; // OK
S4<bool, false> x3; // { dg-error "template constraint failure" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
index 8643f46a16d..282dba63e29 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
@@ -12,13 +12,13 @@ template<typename T> constexpr fool p1() { return {}; }
template<typename T> constexpr fool p2() { return {}; }
template<typename T>
-concept Bad = p1<T>() && p2<T>(); // { dg-error "does not have type 'bool'" }
+concept Bad = p1<T>() && p2<T>(); // { dg-error "bool" }
template<typename T> requires Bad<T> void bad(T x) { }
void driver_2()
{
- bad(0); // { dg-error "" }
+ bad(0); // { dg-message "" }
}
// req6.C
@@ -26,10 +26,10 @@ struct X { };
int operator==(X, X) { return 0; }
template<typename T>
-concept C1 = (X()); // { dg-error "does not have type 'bool'" }
+concept C1 = (X()); // { dg-error "bool" }
template<typename T>
-concept C2 = (X() == X()); // { dg-error "does not have type 'bool'" }
+concept C2 = (X() == X()); // { dg-error "bool" }
template<typename T>
requires C1<T>
@@ -41,8 +41,8 @@ void h2(T);
void driver_3()
{
- h1(0); // { dg-error "" }
- h2(0); // { dg-error "" }
+ h1(0); // { dg-message "" }
+ h2(0); // { dg-message "" }
}
// req7.C
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2020-03-30 11:05 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-30 11:05 [gcc(refs/users/marxin/heads/marxin-gcc-benchmark-branch)] c++: Improve handling of ill-formed constraints [PR94186] Martin Liska
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).