diff options
author | Andrew Sutton <asutton@lock3software.com> | 2019-11-27 14:02:49 +0000 |
---|---|---|
committer | Andrew Sutton <asutton@gcc.gnu.org> | 2019-11-27 14:02:49 +0000 |
commit | 1906392b2c9a02da82d1739386219ec0f13bcc33 (patch) | |
tree | a7fc0e30e92fb6d419ec84c49136bf5c86cd753d /gcc/cp/constraint.cc | |
parent | 45a454883eef8acbdad75c0f376aaf22ec7416ff (diff) | |
download | gcc-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
Diffstat (limited to 'gcc/cp/constraint.cc')
-rw-r--r-- | gcc/cp/constraint.cc | 190 |
1 files changed, 96 insertions, 94 deletions
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" |