aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Sutton <asutton@lock3software.com>2019-11-27 14:02:49 +0000
committerAndrew Sutton <asutton@gcc.gnu.org>2019-11-27 14:02:49 +0000
commit1906392b2c9a02da82d1739386219ec0f13bcc33 (patch)
treea7fc0e30e92fb6d419ec84c49136bf5c86cd753d
parent45a454883eef8acbdad75c0f376aaf22ec7416ff (diff)
downloadgcc-1906392b2c9a02da82d1739386219ec0f13bcc33.zip
gcc-1906392b2c9a02da82d1739386219ec0f13bcc33.tar.gz
gcc-1906392b2c9a02da82d1739386219ec0f13bcc33.tar.bz2
Diagnose certain constraint errors as hard errors, but otherwise treat them the same as normal SFINAE-type errors.
2019-11-27 Andrew Sutton <asutton@lock3software.com> Diagnose certain constraint errors as hard errors, but otherwise treat them the same as normal SFINAE-type errors. Also, generally clean up the satisfaction functions. gcc/cp/ * constexpr.c (cxx_eval_constant_expression): Use evaluate_concept_check. * constraint.cc (normalize_concept_definition): Accept a diagnostic flag and only cache when not diagnosing errors. (decl_satisfied_cache): Map to trees instead of bools. (satisfy_atom): Guarantee a location for the errors, propagate complain flags to force_rvalue, and emit errors for non-boolean constraints. (get_normalized_constraints_and_args): New overloads. Factored out of satisfy_constraint_expression and satisfy_declaration_constraints. (satisfy_constraint_expression): Propagate diagnostic info to normalization. (satisfy_declaration_constraints): New. Factored out of constraints_satisfied_p. (constraint_satisfaction_value): New. Calls satisfy_constraint_expression or satisfy_declaration_constraints. (constraints_satisfied_p): Call constraint_satisfaction_value. (evaluate_concept_check): Don't take tsubst_falgs_t. Replay satisfaction if an error is encountered. (current_failed_constraint): Moved from pt.c. (diagnose_constraints): Call constraint_satisfaction_value. * cp-tree.h: Update declarations. * pt.c (current_failed_constraint): Moved to constraint.cc. * semantics.c (finish_id_expression_1): Remove a duplicate case. gcc/testsuite/ * g++.dg/concepts/pr84330.C: Update diagnostics. * g++.dg/cpp2a/concepts-requires2.C: Likewise. From-SVN: r278768
-rw-r--r--gcc/cp/ChangeLog30
-rw-r--r--gcc/cp/constexpr.c2
-rw-r--r--gcc/cp/constraint.cc190
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/error.c3
-rw-r--r--gcc/cp/pt.c2
-rw-r--r--gcc/cp/semantics.c10
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr84330.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C12
10 files changed, 145 insertions, 116 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4cbdb43..5f770e9 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,33 @@
+2019-11-27 Andrew Sutton <asutton@lock3software.com>
+
+ Diagnose certain constraint errors as hard errors, but otherwise treat
+ them the same as normal SFINAE-type errors. Also, generally clean up
+ the satisfaction functions.
+
+ * constexpr.c (cxx_eval_constant_expression): Use
+ evaluate_concept_check.
+ * constraint.cc (normalize_concept_definition): Accept a diagnostic
+ flag and only cache when not diagnosing errors.
+ (decl_satisfied_cache): Map to trees instead of bools.
+ (satisfy_atom): Guarantee a location for the errors, propagate complain
+ flags to force_rvalue, and emit errors for non-boolean constraints.
+ (get_normalized_constraints_and_args): New overloads. Factored out of
+ satisfy_constraint_expression and satisfy_declaration_constraints.
+ (satisfy_constraint_expression): Propagate diagnostic info to
+ normalization.
+ (satisfy_declaration_constraints): New. Factored out of
+ constraints_satisfied_p.
+ (constraint_satisfaction_value): New. Calls
+ satisfy_constraint_expression or satisfy_declaration_constraints.
+ (constraints_satisfied_p): Call constraint_satisfaction_value.
+ (evaluate_concept_check): Don't take tsubst_falgs_t. Replay
+ satisfaction if an error is encountered.
+ (current_failed_constraint): Moved from pt.c.
+ (diagnose_constraints): Call constraint_satisfaction_value.
+ * cp-tree.h: Update declarations.
+ * pt.c (current_failed_constraint): Moved to constraint.cc.
+ * semantics.c (finish_id_expression_1): Remove a duplicate case.
+
2019-11-27 Jakub Jelinek <jakub@redhat.com>
PR c++/92524
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index f648b1d..32d929b 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5649,7 +5649,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
internal_error ("unexpected template-id %qE", t);
if (!processing_template_decl)
- return satisfy_constraint_expression (t);
+ return evaluate_concept_check (t, tf_warning_or_error);
else
*non_constant_p = true;
return t;
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 171ca4e..d29c33a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -849,10 +849,12 @@ get_normalized_constraints_from_decl (tree d, bool diag = false)
/* Returns the normal form of TMPL's definition. */
static tree
-normalize_concept_definition (tree tmpl)
+normalize_concept_definition (tree tmpl, bool diag = false)
{
- if (tree *p = hash_map_safe_get (normalized_map, tmpl))
- return *p;
+ if (!diag)
+ if (tree *p = hash_map_safe_get (normalized_map, tmpl))
+ return *p;
+
gcc_assert (concept_definition_p (tmpl));
if (OVL_P (tmpl))
tmpl = OVL_FIRST (tmpl);
@@ -860,10 +862,13 @@ normalize_concept_definition (tree tmpl)
tree args = generic_targs_for (tmpl);
tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
++processing_template_decl;
- norm_info info (tmpl, tf_none);
+ norm_info info (tmpl, diag ? tf_norm : tf_none);
tree norm = get_normalized_constraints (def, args, info);
--processing_template_decl;
- hash_map_safe_put<hm_ggc> (normalized_map, tmpl, norm);
+
+ if (!diag)
+ hash_map_safe_put<hm_ggc> (normalized_map, tmpl, norm);
+
return norm;
}
@@ -2231,8 +2236,8 @@ 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 constraints_satisfied_p. */
-static GTY((deletable)) hash_map<tree,bool> *decl_satisfied_cache;
+/* Cache the result of constraint_satisfaction_value. */
+static GTY((deletable)) hash_map<tree, tree> *decl_satisfied_cache;
static tree
get_satisfaction (tree constr, tree args)
@@ -2481,21 +2486,17 @@ satisfy_atom (tree t, tree args, subst_info info)
return cache.save (boolean_false_node);
}
- location_t loc = cp_expr_location (expr);
+ location_t loc = cp_expr_loc_or_input_loc (expr);
/* [17.4.1.2] ... lvalue-to-value conversion is performed as necessary,
and EXPR shall be a constant expression of type bool. */
- result = force_rvalue (result, tf_error);
+ result = force_rvalue (result, info.complain);
if (result == error_mark_node)
- {
- if (info.noisy ())
- inform (loc, "cannot convert constraint to rvalue");
- return cache.save (error_mark_node);
- }
+ return cache.save (error_mark_node);
if (!same_type_p (TREE_TYPE (result), boolean_type_node))
{
if (info.noisy ())
- inform (loc, "constraint does not have type %<bool%>");
+ error_at (loc, "constraint does not have type %<bool%>");
return cache.save (error_mark_node);
}
@@ -2560,7 +2561,7 @@ satisfy_constraint (tree t, tree args, subst_info info)
static tree
satisfy_associated_constraints (tree t, tree args, subst_info info)
{
- /* If there are no constraints then this is trivially satisfied. */
+ /* If there are no constraints then this is trivially satisfied. */
if (!t)
return boolean_true_node;
@@ -2576,24 +2577,31 @@ satisfy_associated_constraints (tree t, tree args, subst_info info)
satisfaction value. */
static tree
-satisfy_constraint_expression (tree expr, tree args, subst_info info)
+satisfy_constraint_expression (tree t, tree args, subst_info info)
{
- /* Normalize the expression before satisfaction testing. */
+ if (t == error_mark_node)
+ return error_mark_node;
+
+ gcc_assert (EXPR_P (t));
+
+ /* Get the normalized constraints. */
tree norm;
- if (args == NULL_TREE && concept_check_p (expr))
+ if (args == NULL_TREE && concept_check_p (t))
{
- tree id = unpack_concept_check (expr);
+ tree id = unpack_concept_check (t);
args = TREE_OPERAND (id, 1);
tree tmpl = get_concept_check_template (id);
- norm = normalize_concept_definition (tmpl);
+ norm = normalize_concept_definition (tmpl, info.noisy ());
}
else
- norm = normalize_constraint_expression (expr);
+ norm = normalize_constraint_expression (t, info.noisy ());
+
+ /* Perform satisfaction. */
return satisfy_constraint (norm, args, info);
}
-/* Used to evaluate concept checks and requires-expressions during
- constant expression evaluation. */
+/* Used only to evaluate requires-expressions during constant expression
+ evaluation. */
tree
satisfy_constraint_expression (tree expr)
@@ -2602,20 +2610,10 @@ satisfy_constraint_expression (tree expr)
return satisfy_constraint_expression (expr, NULL_TREE, info);
}
-/* True if T is satisfied for ARGS. */
-
-static bool
-constraint_expression_satisfied_p (tree t, tree args, subst_info info)
-{
- tree r = satisfy_constraint_expression (t, args, info);
- return r == boolean_true_node;
-}
-
-static bool
-constraints_satisfied_p (tree t, subst_info info)
+static tree
+satisfy_declaration_constraints (tree t, subst_info info)
{
- if (!DECL_P (t))
- return constraint_expression_satisfied_p (t, NULL_TREE, info);
+ gcc_assert (DECL_P (t));
/* For inherited constructors, consider the original declaration;
it has the correct template information attached. */
@@ -2626,21 +2624,19 @@ constraints_satisfied_p (tree t, subst_info info)
info.in_decl = t;
if (info.quiet ())
- if (bool *p = hash_map_safe_get (decl_satisfied_cache, t))
- return *p;
+ if (tree *result = hash_map_safe_get (decl_satisfied_cache, t))
+ return *result;
- /* Get the constraints to check for satisfaction. This depends
- on whether we're looking at a template specialization or not. */
+ /* Get the normalized constraints. */
tree norm = NULL_TREE;
tree args = NULL_TREE;
- tree ti = DECL_TEMPLATE_INFO (t);
- if (ti)
+ 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. */
+ template arguments substituted into the declaration. */
args = TI_ARGS (ti);
}
else
@@ -2649,44 +2645,23 @@ constraints_satisfied_p (tree t, subst_info info)
norm = normalize_nontemplate_requirements (t, info.noisy ());
}
- bool r = true;
+ tree result = boolean_true_node;
if (norm)
{
push_access_scope (t);
- tree eval = satisfy_associated_constraints (norm, args, info);
+ result = satisfy_associated_constraints (norm, args, info);
pop_access_scope (t);
- r = (eval == boolean_true_node);
}
if (info.quiet ())
- hash_map_safe_put<hm_ggc> (decl_satisfied_cache, t, r);
-
- return r;
-}
+ hash_map_safe_put<hm_ggc> (decl_satisfied_cache, t, result);
-/* Returns true if the T's constraints are satisfied, of if T is an expression,
- if T is satisfied. This is used in cases where the arguments can be
- determined from the declaration or expression.
-
- Note that T is typically a template specialization. */
-
-bool
-constraints_satisfied_p (tree t)
-{
- subst_info info (tf_none, NULL_TREE);
- return constraints_satisfied_p (t, info);
+ return result;
}
-/* Returns true if the expression or constrained declaration T is
- satisfied by ARGS. In this case, we don't have a specialization
- where we can cache the results (e.g., alias templates). */
-
-static bool
-constraints_satisfied_p (tree t, tree args, subst_info info)
+static tree
+satisfy_declaration_constraints (tree t, tree args, subst_info info)
{
- if (!DECL_P (t))
- return constraint_expression_satisfied_p (t, args, info);
-
/* Update the declaration for diagnostics. */
info.in_decl = t;
@@ -2695,46 +2670,72 @@ constraints_satisfied_p (tree t, tree args, subst_info info)
{
tree pattern = DECL_TEMPLATE_RESULT (t);
push_access_scope (pattern);
- tree eval = satisfy_associated_constraints (norm, args, info);
+ tree result = satisfy_associated_constraints (norm, args, info);
pop_access_scope (pattern);
- return eval == boolean_true_node;
+ return result;
}
- return true;
+ return boolean_true_node;
}
+static tree
+constraint_satisfaction_value (tree t, tsubst_flags_t complain)
+{
+ subst_info info (complain, NULL_TREE);
+ if (DECL_P (t))
+ return satisfy_declaration_constraints (t, info);
+ else
+ return satisfy_constraint_expression (t, NULL_TREE, info);
+}
+
+static tree
+constraint_satisfaction_value (tree t, tree args, tsubst_flags_t complain)
+{
+ subst_info info (complain, NULL_TREE);
+ if (DECL_P (t))
+ return satisfy_declaration_constraints (t, args, info);
+ else
+ return satisfy_constraint_expression (t, args, info);
+}
+
+/* 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)
+{
+ return constraint_satisfaction_value (t, tf_none) == boolean_true_node;
+}
+
+/* True iff the result of satisfying T with ARGS is BOOLEAN_TRUE_NODE
+ and false otherwise, even in the case of errors. */
+
bool
constraints_satisfied_p (tree t, tree args)
{
- subst_info info (tf_none, NULL);
- return constraints_satisfied_p (t, args, info);
+ return constraint_satisfaction_value (t, args, tf_none) == boolean_true_node;
}
-/* Evaluate a concept check of the form C<ARGS>, returning either TRUE
- or FALSE. If ARGS contains any template parameters, this returns the
- check. If satisfaction yields a hard error, diagnose the error. */
+/* Evaluate a concept check of the form C<ARGS>. This is only used for the
+ evaluation of template-ids as id-expressions. */
tree
evaluate_concept_check (tree check, tsubst_flags_t complain)
{
- /* FIXME we ought to be able to pass complain into subst_info rather
- than repeat satisfaction, but currently that will complain about
- non-satisfaction as well as errors. */
if (check == error_mark_node)
return error_mark_node;
gcc_assert (concept_check_p (check));
- subst_info info (tf_none, NULL_TREE);
- tree result = satisfy_constraint_expression (check, NULL_TREE, info);
+ /* Check for satisfaction without diagnostics. */
+ subst_info quiet (tf_none, NULL_TREE);
+ tree result = satisfy_constraint_expression (check, NULL_TREE, quiet);
if (result == error_mark_node && (complain & tf_error))
- {
- location_t loc = cp_expr_loc_or_input_loc (check);
- error_at (loc, "concept satisfaction failed");
- info.complain = complain;
- satisfy_constraint_expression (check, NULL_TREE, info);
- }
-
+ {
+ /* Replay the error with re-normalized requirements. */
+ subst_info noisy (tf_warning_or_error, NULL_TREE);
+ satisfy_constraint_expression (check, NULL_TREE, noisy);
+ }
return result;
}
@@ -3275,6 +3276,8 @@ diagnose_atomic_constraint (tree t, tree args, subst_info info)
}
}
+GTY(()) tree current_failed_constraint;
+
diagnosing_failed_constraint::
diagnosing_failed_constraint (tree t, tree args, bool diag)
: diagnosing_error (diag)
@@ -3299,11 +3302,10 @@ diagnose_constraints (location_t loc, tree t, tree args)
inform (loc, "constraints not satisfied");
/* Replay satisfaction, but diagnose errors. */
- subst_info info (tf_warning_or_error, NULL_TREE);
if (!args)
- constraints_satisfied_p (t, info);
+ constraint_satisfaction_value (t, tf_warning_or_error);
else
- constraints_satisfied_p (t, args, info);
+ constraint_satisfaction_value (t, args, tf_warning_or_error);
}
#include "gt-cp-constraint.h"
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0da1ed4..4b4bc24 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7821,8 +7821,8 @@ extern bool processing_constraint_expression_p ();
extern tree unpack_concept_check (tree);
extern tree evaluate_concept_check (tree, tsubst_flags_t);
extern tree satisfy_constraint_expression (tree);
-extern bool constraints_satisfied_p (tree);
-extern bool constraints_satisfied_p (tree, tree);
+extern bool constraints_satisfied_p (tree);
+extern bool constraints_satisfied_p (tree, tree);
extern void clear_satisfaction_cache ();
extern bool* lookup_subsumption_result (tree, tree);
extern bool save_subsumption_result (tree, tree, bool);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index c06776f..4261d3c 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -3358,6 +3358,9 @@ cp_print_error_function (diagnostic_context *context,
to be wrong, so just rely on print_instantiation_full_context. */
if (current_instantiation ())
return;
+ /* The above is true for constraint satisfaction also. */
+ if (current_failed_constraint)
+ return;
if (diagnostic_last_function_changed (context, diagnostic))
{
char *old_prefix = pp_take_prefix (context->printer);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a11718e..eb907c5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -28736,8 +28736,6 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
return tsubst (parm, replacement, tf_none, NULL_TREE);
}
-GTY(()) tree current_failed_constraint;
-
/* __integer_pack(N) in a pack expansion expands to a sequence of numbers from
0..N-1. */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 16180f5..6c4785c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3970,16 +3970,6 @@ finish_id_expression_1 (tree id_expression,
decl = baselink_for_fns (decl);
}
- else if (concept_check_p (decl))
- {
- /* If this is a standard or variable concept check, potentially
- evaluate it. Function concepts need to be called as functions,
- so don't try evaluating them here. */
- tree tmpl = TREE_OPERAND (decl, 0);
- tree args = TREE_OPERAND (decl, 1);
- if (!function_concept_p (tmpl) && !uses_template_parms (args))
- decl = evaluate_concept_check (decl, tf_warning_or_error);
- }
else
{
if (DECL_P (decl) && DECL_NONLOCAL (decl)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2fd0ae7..4c01d14 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2019-11-27 Andrew Sutton <asutton@lock3software.com>
+
+ Emit hard errors for certain satisfaction errors.
+ * g++.dg/concepts/pr84330.C: Update diagnostics.
+ * g++.dg/cpp2a/concepts-requires2.C: Likewise.
+
2019-11-27 Richard Biener <rguenther@suse.de>
PR tree-optimization/92690
diff --git a/gcc/testsuite/g++.dg/concepts/pr84330.C b/gcc/testsuite/g++.dg/concepts/pr84330.C
index 0c2f456..ba035d0 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)
+ requires (sizeof(T) >> 0) // { dg-error "constraint does not have type 'bool'" }
void foo(T);
void bar()
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
index 73cee22..8643f46 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
@@ -12,7 +12,7 @@ template<typename T> constexpr fool p1() { return {}; }
template<typename T> constexpr fool p2() { return {}; }
template<typename T>
-concept Bad = p1<T>() && p2<T>();
+concept Bad = p1<T>() && p2<T>(); // { dg-error "does not have type 'bool'" }
template<typename T> requires Bad<T> void bad(T x) { }
@@ -26,14 +26,14 @@ struct X { };
int operator==(X, X) { return 0; }
template<typename T>
-concept C1 = (X());
+concept C1 = (X()); // { dg-error "does not have type 'bool'" }
template<typename T>
-concept C2 = (X() == X());
+concept C2 = (X() == X()); // { dg-error "does not have type 'bool'" }
template<typename T>
requires C1<T>
-void h1(T) { }
+void h1(T) { }
template<typename T>
requires C2<T>
@@ -42,12 +42,12 @@ void h2(T);
void driver_3()
{
h1(0); // { dg-error "" }
- h2(0); // { dg-error "" }
+ h2(0); // { dg-error "" }
}
// req7.C
template<bool B>
-struct boolean_constant
+struct boolean_constant
{
constexpr operator bool() const { return B; }
};