aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/constraint.cc
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2021-09-13 19:49:49 +0200
committerThomas Koenig <tkoenig@gcc.gnu.org>2021-09-13 19:49:49 +0200
commitb18a97e5dd0935e1c4a626c230f21457d0aad3d5 (patch)
treec1818f41af6fe780deafb6cd6a183f32085fe654 /gcc/cp/constraint.cc
parente76a53644c9d70e998c0d050e9a456af388c6b61 (diff)
downloadgcc-b18a97e5dd0935e1c4a626c230f21457d0aad3d5.zip
gcc-b18a97e5dd0935e1c4a626c230f21457d0aad3d5.tar.gz
gcc-b18a97e5dd0935e1c4a626c230f21457d0aad3d5.tar.bz2
Merged current trunk to branch.
Diffstat (limited to 'gcc/cp/constraint.cc')
-rw-r--r--gcc/cp/constraint.cc1046
1 files changed, 450 insertions, 596 deletions
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 24fcbaa..1aaf1e2 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1,5 +1,5 @@
/* Processing rules for constraints.
- Copyright (C) 2013-2020 Free Software Foundation, Inc.
+ Copyright (C) 2013-2021 Free Software Foundation, Inc.
Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
This file is part of GCC.
@@ -100,18 +100,31 @@ struct 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). */
+ During 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 additionally
+ explain why a constraint is not satisfied.
+ - We enter satisfaction with noisy+unsat from diagnose_constraints.
+ - We enter satisfaction with noisy-unsat from the replay inside
+ constraint_satisfaction_value.
+ - We enter satisfaction quietly (both flags cleared) from
+ constraints_satisfied_p.
+
+ During evaluation of a requires-expression:
+ - The flag noisy() controls whether to diagnose ill-formed types and
+ expressions inside its requirements.
+ - The flag diagnose_unsatisfaction_p() controls whether to additionally
+ explain why the requires-expression evaluates to false.
+ - We enter tsubst_requires_expr with noisy+unsat from
+ diagnose_atomic_constraint and potentially from
+ satisfy_nondeclaration_constraints.
+ - We enter tsubst_requires_expr with noisy-unsat from
+ cp_parser_requires_expression when processing a requires-expression that
+ appears outside a template.
+ - We enter tsubst_requires_expr quietly (both flags cleared) when
+ substituting through a requires-expression as part of template
+ instantiation. */
struct sat_info : subst_info
{
@@ -133,7 +146,7 @@ struct sat_info : subst_info
bool diagnose_unsatisfaction;
};
-static tree satisfy_constraint (tree, tree, sat_info);
+static tree constraint_satisfaction_value (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. */
@@ -265,21 +278,6 @@ get_concept_check_template (tree t)
return tmpl;
}
-/* Returns true if any of the arguments in the template argument list is
- a wildcard or wildcard pack. */
-
-bool
-contains_wildcard_p (tree args)
-{
- for (int i = 0; i < TREE_VEC_LENGTH (args); ++i)
- {
- tree arg = TREE_VEC_ELT (args, i);
- if (TREE_CODE (arg) == WILDCARD_DECL)
- return true;
- }
- return false;
-}
-
/*---------------------------------------------------------------------------
Resolution of qualified concept names
---------------------------------------------------------------------------*/
@@ -594,26 +592,12 @@ map_arguments (tree parms, tree args)
return parms;
}
-/* Build the parameter mapping for EXPR using ARGS. */
+/* Build the parameter mapping for EXPR using ARGS, where CTX_PARMS
+ are the template parameters in scope for EXPR. */
static tree
-build_parameter_mapping (tree expr, tree args, tree decl)
+build_parameter_mapping (tree expr, tree args, tree ctx_parms)
{
- tree ctx_parms = NULL_TREE;
- if (decl)
- {
- gcc_assert (TREE_CODE (decl) == TEMPLATE_DECL);
- ctx_parms = DECL_TEMPLATE_PARMS (decl);
- }
- else if (current_template_parms)
- {
- /* TODO: This should probably be the only case, but because the
- point of declaration of concepts is currently set after the
- initializer, the template parameter lists are not available
- when normalizing concept definitions, hence the case above. */
- ctx_parms = current_template_parms;
- }
-
tree parms = find_template_parameters (expr, ctx_parms);
tree map = map_arguments (parms, args);
return map;
@@ -645,53 +629,63 @@ parameter_mapping_equivalent_p (tree t1, tree t2)
struct norm_info : subst_info
{
- explicit norm_info (tsubst_flags_t complain)
- : subst_info (tf_warning_or_error | complain, NULL_TREE),
- context()
+ explicit norm_info (tsubst_flags_t cmp)
+ : norm_info (NULL_TREE, cmp)
{}
/* Construct a top-level context for DECL. */
norm_info (tree in_decl, tsubst_flags_t complain)
- : subst_info (tf_warning_or_error | complain, in_decl),
- context (make_context (in_decl)),
- orig_decl (in_decl)
- {}
-
- bool generate_diagnostics() const
+ : subst_info (tf_warning_or_error | complain, in_decl)
{
- return complain & tf_norm;
+ if (in_decl)
+ {
+ initial_parms = DECL_TEMPLATE_PARMS (in_decl);
+ if (generate_diagnostics ())
+ context = build_tree_list (NULL_TREE, in_decl);
+ }
+ else
+ initial_parms = current_template_parms;
}
- tree make_context(tree in_decl)
+ bool generate_diagnostics() const
{
- if (generate_diagnostics ())
- return build_tree_list (NULL_TREE, in_decl);
- return NULL_TREE;
+ return complain & tf_norm;
}
void update_context(tree expr, tree args)
{
if (generate_diagnostics ())
{
- tree map = build_parameter_mapping (expr, args, in_decl);
+ tree map = build_parameter_mapping (expr, args, ctx_parms ());
context = tree_cons (map, expr, context);
}
in_decl = get_concept_check_template (expr);
}
+ /* Returns the template parameters that are in scope for the current
+ normalization context. */
+
+ tree ctx_parms()
+ {
+ if (in_decl)
+ return DECL_TEMPLATE_PARMS (in_decl);
+ else
+ return initial_parms;
+ }
+
/* Provides information about the source of a constraint. This is a
TREE_LIST whose VALUE is either a concept check or a constrained
declaration. The PURPOSE, for concept checks is a parameter mapping
for that check. */
- tree context;
+ tree context = NULL_TREE;
/* The declaration whose constraints we're normalizing. The targets
of the parameter mapping of each atom will be in terms of the
template parameters of ORIG_DECL. */
- tree orig_decl = NULL_TREE;
+ tree initial_parms = NULL_TREE;
};
static tree normalize_expression (tree, tree, norm_info);
@@ -773,7 +767,7 @@ normalize_atom (tree t, tree args, norm_info info)
return normalize_concept_check (t, args, info);
/* Build the parameter mapping for the atom. */
- tree map = build_parameter_mapping (t, args, info.in_decl);
+ tree map = build_parameter_mapping (t, args, info.ctx_parms ());
/* Build a new info object for the atom. */
tree ci = build_tree_list (t, info.context);
@@ -803,10 +797,8 @@ normalize_atom (tree t, tree args, norm_info info)
tree target = TREE_PURPOSE (node);
TREE_VEC_ELT (targets, i++) = target;
}
- tree ctx_parms = (info.orig_decl
- ? DECL_TEMPLATE_PARMS (info.orig_decl)
- : current_template_parms);
- tree target_parms = find_template_parameters (targets, ctx_parms);
+ tree target_parms = find_template_parameters (targets,
+ info.initial_parms);
TREE_TYPE (map) = target_parms;
}
@@ -879,6 +871,16 @@ get_normalized_constraints_from_decl (tree d, bool diag = false)
it has the correct template information attached. */
d = strip_inheriting_ctors (d);
+ if (regenerated_lambda_fn_p (d))
+ {
+ /* If this lambda was regenerated, DECL_TEMPLATE_PARMS doesn't contain
+ all in-scope template parameters, but the lambda from which it was
+ ultimately regenerated does, so use that instead. */
+ tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (d));
+ lambda = most_general_lambda (lambda);
+ d = lambda_function (lambda);
+ }
+
if (TREE_CODE (d) == TEMPLATE_DECL)
{
tmpl = d;
@@ -924,12 +926,7 @@ get_normalized_constraints_from_decl (tree d, bool diag = false)
tree norm = NULL_TREE;
if (tree ci = get_constraints (decl))
{
- push_nested_class_guard pncs (DECL_CONTEXT (d));
-
- temp_override<tree> ovr (current_function_decl);
- if (TREE_CODE (decl) == FUNCTION_DECL)
- current_function_decl = decl;
-
+ push_access_scope_guard pas (decl);
norm = get_normalized_constraints_from_info (ci, tmpl, diag);
}
@@ -964,33 +961,25 @@ normalize_concept_definition (tree tmpl, bool diag = false)
return norm;
}
-/* Returns the normal form of TMPL's requirements. */
-
-static tree
-normalize_template_requirements (tree tmpl, bool diag = false)
-{
- return get_normalized_constraints_from_decl (tmpl, diag);
-}
-
-/* Returns the normal form of TMPL's requirements. */
-
-static tree
-normalize_nontemplate_requirements (tree decl, bool diag = false)
-{
- return get_normalized_constraints_from_decl (decl, diag);
-}
-
/* Normalize an EXPR as a constraint. */
static tree
-normalize_constraint_expression (tree expr, bool diag)
+normalize_constraint_expression (tree expr, norm_info info)
{
if (!expr || expr == error_mark_node)
return expr;
+
+ if (!info.generate_diagnostics ())
+ if (tree *p = hash_map_safe_get (normalized_map, expr))
+ return *p;
+
++processing_template_decl;
- norm_info info (diag ? tf_norm : tf_none);
tree norm = get_normalized_constraints (expr, info);
--processing_template_decl;
+
+ if (!info.generate_diagnostics ())
+ hash_map_safe_put<hm_ggc> (normalized_map, expr, norm);
+
return norm;
}
@@ -1301,18 +1290,6 @@ maybe_substitute_reqs_for (tree reqs, const_tree decl_)
return reqs;
}
-/* Returns the template-head requires clause for the template
- declaration T or NULL_TREE if none. */
-
-tree
-get_template_head_requirements (tree t)
-{
- tree ci = get_constraints (t);
- if (!ci)
- return NULL_TREE;
- return CI_TEMPLATE_REQS (ci);
-}
-
/* Returns the trailing requires clause of the declarator of
a template declaration T or NULL_TREE if none. */
@@ -1345,7 +1322,6 @@ build_concept_check_arguments (tree arg, tree rest)
}
else
{
- gcc_assert (rest != NULL_TREE);
args = rest;
}
return args;
@@ -1444,13 +1420,6 @@ build_concept_check (tree target, tree args, tsubst_flags_t complain)
tree
build_concept_check (tree decl, tree arg, tree rest, tsubst_flags_t complain)
{
- if (arg == NULL_TREE && rest == NULL_TREE)
- {
- tree id = build_nt (TEMPLATE_ID_EXPR, decl, rest);
- error ("invalid use concept %qE", id);
- return error_mark_node;
- }
-
tree args = build_concept_check_arguments (arg, rest);
if (standard_concept_p (decl))
@@ -1949,40 +1918,90 @@ hash_placeholder_constraint (tree c)
return val;
}
-/* Substitute through the simple requirement. */
+/* Substitute through the expression of a simple requirement or
+ compound requirement. */
static tree
-tsubst_valid_expression_requirement (tree t, tree args, subst_info info)
+tsubst_valid_expression_requirement (tree t, tree args, sat_info info)
{
- tree r = tsubst_expr (t, args, info.complain, info.in_decl, false);
- if (convert_to_void (r, ICV_STATEMENT, info.complain) == error_mark_node)
- return error_mark_node;
- return r;
+ tree r = tsubst_expr (t, args, tf_none, info.in_decl, false);
+ if (convert_to_void (r, ICV_STATEMENT, tf_none) != error_mark_node)
+ return r;
+
+ if (info.diagnose_unsatisfaction_p ())
+ {
+ location_t loc = cp_expr_loc_or_input_loc (t);
+ if (diagnosing_failed_constraint::replay_errors_p ())
+ {
+ inform (loc, "the required expression %qE is invalid, because", t);
+ if (r == error_mark_node)
+ tsubst_expr (t, args, info.complain, info.in_decl, false);
+ else
+ convert_to_void (r, ICV_STATEMENT, info.complain);
+ }
+ else
+ inform (loc, "the required expression %qE is invalid", t);
+ }
+ else if (info.noisy ())
+ {
+ r = tsubst_expr (t, args, info.complain, info.in_decl, false);
+ convert_to_void (r, ICV_STATEMENT, info.complain);
+ }
+
+ return error_mark_node;
}
/* Substitute through the simple requirement. */
static tree
-tsubst_simple_requirement (tree t, tree args, subst_info info)
+tsubst_simple_requirement (tree t, tree args, sat_info info)
{
tree t0 = TREE_OPERAND (t, 0);
tree expr = tsubst_valid_expression_requirement (t0, args, info);
if (expr == error_mark_node)
return error_mark_node;
- return finish_simple_requirement (EXPR_LOCATION (t), expr);
+ return boolean_true_node;
+}
+
+/* Subroutine of tsubst_type_requirement that performs the actual substitution
+ and diagnosing. Also used by tsubst_compound_requirement. */
+
+static tree
+tsubst_type_requirement_1 (tree t, tree args, sat_info info, location_t loc)
+{
+ tree r = tsubst (t, args, tf_none, info.in_decl);
+ if (r != error_mark_node)
+ return r;
+
+ if (info.diagnose_unsatisfaction_p ())
+ {
+ if (diagnosing_failed_constraint::replay_errors_p ())
+ {
+ /* Replay the substitution error. */
+ inform (loc, "the required type %qT is invalid, because", t);
+ tsubst (t, args, info.complain, info.in_decl);
+ }
+ else
+ inform (loc, "the required type %qT is invalid", t);
+ }
+ else if (info.noisy ())
+ tsubst (t, args, info.complain, info.in_decl);
+
+ return error_mark_node;
}
+
/* Substitute through the type requirement. */
static tree
-tsubst_type_requirement (tree t, tree args, subst_info info)
+tsubst_type_requirement (tree t, tree args, sat_info info)
{
tree t0 = TREE_OPERAND (t, 0);
- tree type = tsubst (t0, args, info.complain, info.in_decl);
+ tree type = tsubst_type_requirement_1 (t0, args, info, EXPR_LOCATION (t));
if (type == error_mark_node)
return error_mark_node;
- return finish_type_requirement (EXPR_LOCATION (t), type);
+ return boolean_true_node;
}
/* True if TYPE can be deduced from EXPR. */
@@ -1995,39 +2014,19 @@ type_deducible_p (tree expr, tree type, tree placeholder, tree args,
references are preserved in the result. */
expr = force_paren_expr_uneval (expr);
- /* Replace the constraints with the instantiated constraints. This
- substitutes args into any template parameters in the trailing
- result type. */
- tree saved_constr = PLACEHOLDER_TYPE_CONSTRAINTS (placeholder);
- tree subst_constr
- = tsubst_constraint (saved_constr,
- args,
- info.complain | tf_partial,
- info.in_decl);
-
- if (subst_constr == error_mark_node)
- return false;
-
- PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) = subst_constr;
-
- /* Temporarily unlink the canonical type. */
- tree saved_type = TYPE_CANONICAL (placeholder);
- TYPE_CANONICAL (placeholder) = NULL_TREE;
-
- tree deduced_type
- = do_auto_deduction (type,
- expr,
- placeholder,
- info.complain,
- adc_requirement);
-
- PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) = saved_constr;
- TYPE_CANONICAL (placeholder) = saved_type;
+ /* When args is NULL, we're evaluating a non-templated requires expression,
+ but even those are parsed under processing_template_decl == 1, and so the
+ placeholder 'auto' inside this return-type-requirement has level 2. In
+ order to have all parms and arguments match up for satisfaction, we need
+ to pass an empty level of OUTER_TARGS in this case. */
+ if (!args)
+ args = make_tree_vec (0);
- if (deduced_type == error_mark_node)
- return false;
+ tree deduced_type = do_auto_deduction (type, expr, placeholder,
+ info.complain, adc_requirement,
+ /*outer_targs=*/args);
- return true;
+ return deduced_type != error_mark_node;
}
/* True if EXPR can not be converted to TYPE. */
@@ -2056,7 +2055,7 @@ expression_convertible_p (tree expr, tree type, subst_info info)
/* Substitute through the compound requirement. */
static tree
-tsubst_compound_requirement (tree t, tree args, subst_info info)
+tsubst_compound_requirement (tree t, tree args, sat_info info)
{
tree t0 = TREE_OPERAND (t, 0);
tree t1 = TREE_OPERAND (t, 1);
@@ -2064,13 +2063,20 @@ tsubst_compound_requirement (tree t, tree args, subst_info info)
if (expr == error_mark_node)
return error_mark_node;
+ location_t loc = cp_expr_loc_or_input_loc (expr);
+
/* Check the noexcept condition. */
bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t);
if (noexcept_p && !expr_noexcept_p (expr, tf_none))
- return error_mark_node;
+ {
+ if (info.diagnose_unsatisfaction_p ())
+ inform (loc, "%qE is not %<noexcept%>", expr);
+ else
+ return error_mark_node;
+ }
/* Substitute through the type expression, if any. */
- tree type = tsubst (t1, args, info.complain, info.in_decl);
+ tree type = tsubst_type_requirement_1 (t1, args, info, EXPR_LOCATION (t));
if (type == error_mark_node)
return error_mark_node;
@@ -2082,39 +2088,76 @@ tsubst_compound_requirement (tree t, tree args, subst_info info)
if (tree placeholder = type_uses_auto (type))
{
if (!type_deducible_p (expr, type, placeholder, args, quiet))
- return error_mark_node;
+ {
+ if (info.diagnose_unsatisfaction_p ())
+ {
+ if (diagnosing_failed_constraint::replay_errors_p ())
+ {
+ inform (loc,
+ "%qE does not satisfy return-type-requirement, "
+ "because", t0);
+ /* Further explain the reason for the error. */
+ type_deducible_p (expr, type, placeholder, args, info);
+ }
+ else
+ inform (loc,
+ "%qE does not satisfy return-type-requirement", t0);
+ }
+ return error_mark_node;
+ }
}
else if (!expression_convertible_p (expr, type, quiet))
- return error_mark_node;
+ {
+ if (info.diagnose_unsatisfaction_p ())
+ {
+ if (diagnosing_failed_constraint::replay_errors_p ())
+ {
+ inform (loc, "cannot convert %qE to %qT because", t0, type);
+ /* Further explain the reason for the error. */
+ expression_convertible_p (expr, type, info);
+ }
+ else
+ inform (loc, "cannot convert %qE to %qT", t0, type);
+ }
+ return error_mark_node;
+ }
}
- return finish_compound_requirement (EXPR_LOCATION (t),
- expr, type, noexcept_p);
+ return boolean_true_node;
}
+/* Substitute through the nested requirement. */
+
static tree
-tsubst_nested_requirement (tree t, tree args, subst_info info)
+tsubst_nested_requirement (tree t, tree args, sat_info info)
{
- /* Perform satisfaction quietly with the regular normal form. */
sat_info quiet (tf_none, info.in_decl);
- tree norm = TREE_VALUE (TREE_TYPE (t));
- tree diag_norm = TREE_PURPOSE (TREE_TYPE (t));
- tree result = satisfy_constraint (norm, args, quiet);
- if (result == error_mark_node)
+ tree result = constraint_satisfaction_value (t, args, quiet);
+ if (result == boolean_true_node)
+ return boolean_true_node;
+
+ if (result == boolean_false_node
+ && info.diagnose_unsatisfaction_p ())
{
- /* Replay the error using the diagnostic normal form. */
- sat_info noisy (tf_warning_or_error, info.in_decl);
- satisfy_constraint (diag_norm, args, noisy);
+ tree expr = TREE_OPERAND (t, 0);
+ location_t loc = cp_expr_location (t);
+ if (diagnosing_failed_constraint::replay_errors_p ())
+ {
+ /* Replay the substitution error. */
+ inform (loc, "nested requirement %qE is not satisfied, because", expr);
+ constraint_satisfaction_value (t, args, info);
+ }
+ else
+ inform (loc, "nested requirement %qE is not satisfied", expr);
}
- if (result != boolean_true_node)
- return error_mark_node;
- return result;
+
+ return error_mark_node;
}
/* Substitute ARGS into the requirement T. */
static tree
-tsubst_requirement (tree t, tree args, subst_info info)
+tsubst_requirement (tree t, tree args, sat_info info)
{
iloc_sentinel loc_s (cp_expr_location (t));
switch (TREE_CODE (t))
@@ -2133,24 +2176,6 @@ tsubst_requirement (tree t, tree args, subst_info info)
gcc_unreachable ();
}
-/* Substitute ARGS into the list of requirements T. Note that
- substitution failures here result in ill-formed programs. */
-
-static tree
-tsubst_requirement_body (tree t, tree args, subst_info info)
-{
- tree result = NULL_TREE;
- while (t)
- {
- tree req = tsubst_requirement (TREE_VALUE (t), args, info);
- if (req == error_mark_node)
- return error_mark_node;
- result = tree_cons (NULL_TREE, req, result);
- t = TREE_CHAIN (t);
- }
- return nreverse (result);
-}
-
static tree
declare_constraint_vars (tree parms, tree vars)
{
@@ -2176,7 +2201,7 @@ declare_constraint_vars (tree parms, tree vars)
if an error occurred. */
static tree
-check_constaint_variables (tree t, tree args, subst_info info)
+check_constraint_variables (tree t, tree args, subst_info info)
{
tree types = NULL_TREE;
tree p = t;
@@ -2201,7 +2226,7 @@ static tree
tsubst_constraint_variables (tree t, tree args, subst_info info)
{
/* Perform a trial substitution to check for type errors. */
- tree parms = check_constaint_variables (t, args, info);
+ tree parms = check_constraint_variables (t, args, info);
if (parms == error_mark_node)
return error_mark_node;
@@ -2222,34 +2247,27 @@ tsubst_constraint_variables (tree t, tree args, subst_info info)
in its requirements ... In such cases, the expression evaluates
to false; it does not cause the program to be ill-formed.
- However, there are cases where substitution must produce a
- new requires-expression, that is not a template constraint.
- For example:
+ When substituting through a REQUIRES_EXPR as part of template
+ instantiation, we call this routine with info.quiet() true.
- template<typename T>
- class X {
- template<typename U>
- static constexpr bool var = requires (U u) { T::fn(u); };
- };
+ When evaluating a REQUIRES_EXPR that appears outside a template in
+ cp_parser_requires_expression, we call this routine with
+ info.noisy() true.
- In the instantiation of X<Y> (assuming Y defines fn), then the
- instantiated requires-expression would include Y::fn(u). If any
- substitution in the requires-expression fails, we can immediately
- fold the expression to false, as would be the case e.g., when
- instantiation X<int>. */
+ Finally, when diagnosing unsatisfaction from diagnose_atomic_constraint
+ and when diagnosing a false REQUIRES_EXPR via diagnose_constraints,
+ we call this routine with info.diagnose_unsatisfaction_p() true. */
-tree
-tsubst_requires_expr (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+static tree
+tsubst_requires_expr (tree t, tree args, sat_info info)
{
local_specialization_stack stack (lss_copy);
- subst_info info (complain, in_decl);
-
/* A requires-expression is an unevaluated context. */
cp_unevaluated u;
- args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args);
+ args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args,
+ info.complain, info.in_decl);
if (processing_template_decl)
{
/* We're partially instantiating a generic lambda. Substituting into
@@ -2257,24 +2275,41 @@ tsubst_requires_expr (tree t, tree args,
checked out of order, so instead just remember the template
arguments and wait until we can substitute them all at once. */
t = copy_node (t);
- REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, complain);
+ REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain);
return t;
}
- tree parms = REQUIRES_EXPR_PARMS (t);
- if (parms)
+ if (tree parms = REQUIRES_EXPR_PARMS (t))
{
parms = tsubst_constraint_variables (parms, args, info);
if (parms == error_mark_node)
return boolean_false_node;
}
- tree reqs = REQUIRES_EXPR_REQS (t);
- reqs = tsubst_requirement_body (reqs, args, info);
- if (reqs == error_mark_node)
- return boolean_false_node;
+ tree result = boolean_true_node;
+ for (tree reqs = REQUIRES_EXPR_REQS (t); reqs; reqs = TREE_CHAIN (reqs))
+ {
+ tree req = TREE_VALUE (reqs);
+ if (tsubst_requirement (req, args, info) == error_mark_node)
+ {
+ result = boolean_false_node;
+ if (info.diagnose_unsatisfaction_p ())
+ /* Keep going so that we diagnose all failed requirements. */;
+ else
+ break;
+ }
+ }
+ return result;
+}
- return boolean_true_node;
+/* Public wrapper for the above. */
+
+tree
+tsubst_requires_expr (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ sat_info info (complain, in_decl);
+ return tsubst_requires_expr (t, args, info);
}
/* Substitute ARGS into the constraint information CI, producing a new
@@ -2312,48 +2347,23 @@ tsubst_parameter_mapping (tree map, tree args, subst_info info)
return error_mark_node;
tree parm = TREE_VALUE (p);
tree arg = TREE_PURPOSE (p);
- tree new_arg = NULL_TREE;
- if (TYPE_P (arg))
- {
- /* If a template parameter is declared with a placeholder, we can
- get those in the argument list if decltype is applied to the
- placeholder. For example:
-
- template<auto T>
- requires C<decltype(T)>
- void f() { }
-
- The normalized argument for C will be an auto type, so we'll
- need to deduce the actual argument from the corresponding
- initializer (whatever argument is provided for T), and use
- that result in the instantiated parameter mapping. */
- if (tree auto_node = type_uses_auto (arg))
- {
- int level;
- int index;
- template_parm_level_and_index (parm, &level, &index);
- tree init = TMPL_ARG (args, level, index);
- new_arg = do_auto_deduction (arg, init, auto_node,
- complain, adc_variable_type,
- make_tree_vec (0));
- }
- }
- else if (ARGUMENT_PACK_P (arg))
+ tree new_arg;
+ if (ARGUMENT_PACK_P (arg))
new_arg = tsubst_argument_pack (arg, args, complain, in_decl);
- if (!new_arg)
+ else
{
new_arg = tsubst_template_arg (arg, args, complain, in_decl);
if (TYPE_P (new_arg))
new_arg = canonicalize_type_argument (new_arg, complain);
- if (TREE_CODE (new_arg) == TYPE_ARGUMENT_PACK)
+ }
+ if (TREE_CODE (new_arg) == TYPE_ARGUMENT_PACK)
+ {
+ tree pack_args = ARGUMENT_PACK_ARGS (new_arg);
+ for (int i = 0; i < TREE_VEC_LENGTH (pack_args); i++)
{
- tree pack_args = ARGUMENT_PACK_ARGS (new_arg);
- for (int i = 0; i < TREE_VEC_LENGTH (pack_args); i++)
- {
- tree& pack_arg = TREE_VEC_ELT (pack_args, i);
- if (TYPE_P (pack_arg))
- pack_arg = canonicalize_type_argument (pack_arg, complain);
- }
+ tree& pack_arg = TREE_VEC_ELT (pack_args, i);
+ if (TYPE_P (pack_arg))
+ pack_arg = canonicalize_type_argument (pack_arg, complain);
}
}
if (new_arg == error_mark_node)
@@ -2530,7 +2540,7 @@ 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 constraint_satisfaction_value. */
+/* Cache the result of satisfy_declaration_constraints. */
static GTY((deletable)) hash_map<tree, tree> *decl_satisfied_cache;
/* A tool used by satisfy_atom to help manage satisfaction caching and to
@@ -2706,6 +2716,7 @@ tsubst_constraint (tree t, tree args, tsubst_flags_t complain, tree in_decl)
/* We also don't want to evaluate concept-checks when substituting the
constraint-expressions of a declaration. */
processing_constraint_expression_sentinel s;
+ cp_unevaluated u;
tree expr = tsubst_expr (t, args, complain, in_decl, false);
return expr;
}
@@ -2885,7 +2896,7 @@ get_mapped_args (tree map)
return args;
}
-static void diagnose_atomic_constraint (tree, tree, tree, subst_info);
+static void diagnose_atomic_constraint (tree, tree, tree, sat_info);
/* Compute the satisfaction of an atomic constraint. */
@@ -2964,7 +2975,10 @@ satisfy_atom (tree t, tree args, sat_info info)
/* Compute the value of the constraint. */
if (info.noisy ())
- result = cxx_constant_value (result);
+ {
+ iloc_sentinel ils (EXPR_LOCATION (result));
+ result = cxx_constant_value (result);
+ }
else
{
result = maybe_constant_value (result, NULL_TREE,
@@ -3012,7 +3026,7 @@ satisfy_constraint_r (tree t, tree args, sat_info info)
/* Check that the normalized constraint T is satisfied for ARGS. */
static tree
-satisfy_constraint (tree t, tree args, sat_info info)
+satisfy_normalized_constraints (tree t, tree args, sat_info info)
{
auto_timevar time (TV_CONSTRAINT_SAT);
@@ -3025,68 +3039,109 @@ satisfy_constraint (tree t, tree args, sat_info info)
/* We need to check access during satisfaction. */
deferring_access_check_sentinel acs (dk_no_deferred);
+ /* Constraints are unevaluated operands. */
+ cp_unevaluated u;
+
return satisfy_constraint_r (t, args, info);
}
-/* Check the normalized constraints T against ARGS, returning a satisfaction
- value (either true, false, or error). */
+/* Return the normal form of the constraints on the placeholder 'auto'
+ type T. */
static tree
-satisfy_associated_constraints (tree t, tree args, sat_info info)
+normalize_placeholder_type_constraints (tree t, bool diag)
{
- /* If there are no constraints then this is trivially satisfied. */
- if (!t)
- return boolean_true_node;
+ gcc_assert (is_auto (t));
+ tree ci = PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t);
+ if (!ci)
+ return NULL_TREE;
- /* If any arguments depend on template parameters, we can't
- check constraints. Pretend they're satisfied for now. */
- if (args && uses_template_parms (args))
- return boolean_true_node;
+ tree constr = TREE_VALUE (ci);
+ /* The TREE_PURPOSE contains the set of template parameters that were in
+ scope for this placeholder type; use them as the initial template
+ parameters for normalization. */
+ tree initial_parms = TREE_PURPOSE (ci);
+
+ if (!initial_parms && TEMPLATE_TYPE_LEVEL (t) == 2)
+ /* This is a return-type-requirement of a non-templated requires-expression,
+ which are parsed under processing_template_decl == 1 and empty
+ current_template_parms; hence the 'auto' has level 2 and initial_parms
+ is empty. Fix up initial_parms to be consistent with the value of
+ processing_template_decl whence the 'auto' was created. */
+ initial_parms = build_tree_list (size_int (1), make_tree_vec (0));
+
+ /* The 'auto' itself is used as the first argument in its own constraints,
+ and its level is one greater than its template depth. So in order to
+ capture all used template parameters, we need to add an extra level of
+ template parameters to the context; a dummy level suffices. */
+ initial_parms
+ = tree_cons (size_int (initial_parms
+ ? TMPL_PARMS_DEPTH (initial_parms) + 1 : 1),
+ make_tree_vec (0), initial_parms);
- return satisfy_constraint (t, args, info);
+ norm_info info (diag ? tf_norm : tf_none);
+ info.initial_parms = initial_parms;
+ return normalize_constraint_expression (constr, info);
}
-/* Evaluate EXPR as a constraint expression using ARGS, returning a
- satisfaction value. */
+/* Evaluate the constraints of T using ARGS, returning a satisfaction value.
+ Here, T can be a concept-id, nested-requirement, placeholder 'auto', or
+ requires-expression. */
static tree
-satisfy_constraint_expression (tree t, tree args, sat_info info)
+satisfy_nondeclaration_constraints (tree t, tree args, sat_info info)
{
if (t == error_mark_node)
return error_mark_node;
- gcc_assert (EXPR_P (t));
+ /* Handle REQUIRES_EXPR directly, bypassing satisfaction. */
+ if (TREE_CODE (t) == REQUIRES_EXPR)
+ {
+ auto ovr = make_temp_override (current_constraint_diagnosis_depth);
+ if (info.noisy ())
+ ++current_constraint_diagnosis_depth;
+ return tsubst_requires_expr (t, args, info);
+ }
/* Get the normalized constraints. */
tree norm;
- if (args == NULL_TREE && concept_check_p (t))
+ if (concept_check_p (t))
{
+ gcc_assert (!args);
tree id = unpack_concept_check (t);
args = TREE_OPERAND (id, 1);
tree tmpl = get_concept_check_template (id);
norm = normalize_concept_definition (tmpl, info.noisy ());
}
+ else if (TREE_CODE (t) == NESTED_REQ)
+ {
+ norm_info ninfo (info.noisy () ? tf_norm : tf_none);
+ /* The TREE_TYPE contains the set of template parameters that were in
+ scope for this nested requirement; use them as the initial template
+ parameters for normalization. */
+ ninfo.initial_parms = TREE_TYPE (t);
+ norm = normalize_constraint_expression (TREE_OPERAND (t, 0), ninfo);
+ }
+ else if (is_auto (t))
+ {
+ norm = normalize_placeholder_type_constraints (t, info.noisy ());
+ if (!norm)
+ return boolean_true_node;
+ }
else
- norm = normalize_constraint_expression (t, info.noisy ());
+ gcc_unreachable ();
/* Perform satisfaction. */
- return satisfy_constraint (norm, args, info);
+ return satisfy_normalized_constraints (norm, args, info);
}
-/* Used only to evaluate requires-expressions during constant expression
- evaluation. */
-
-tree
-satisfy_constraint_expression (tree expr)
-{
- sat_info info (tf_none, NULL_TREE);
- return satisfy_constraint_expression (expr, NULL_TREE, info);
-}
+/* Evaluate the associated constraints of the template specialization T
+ according to INFO, returning a satisfaction value. */
static tree
satisfy_declaration_constraints (tree t, sat_info info)
{
- gcc_assert (DECL_P (t));
+ gcc_assert (DECL_P (t) && TREE_CODE (t) != TEMPLATE_DECL);
const tree saved_t = t;
/* For inherited constructors, consider the original declaration;
@@ -3106,26 +3161,38 @@ satisfy_declaration_constraints (tree t, sat_info info)
if (tree *result = hash_map_safe_get (decl_satisfied_cache, saved_t))
return *result;
- /* Get the normalized constraints. */
- tree norm = NULL_TREE;
tree args = NULL_TREE;
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. */
args = TI_ARGS (ti);
if (inh_ctor_targs)
args = add_outermost_template_args (args, inh_ctor_targs);
}
- else
+
+ if (regenerated_lambda_fn_p (t))
{
- /* These should be empty until we allow constraints on non-templates. */
- norm = normalize_nontemplate_requirements (t, info.noisy ());
+ /* The TI_ARGS of a regenerated lambda contains only the innermost
+ set of template arguments. Augment this with the outer template
+ arguments that were used to regenerate the lambda. */
+ gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1);
+ tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
+ tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
+ if (args)
+ args = add_to_template_args (outer_args, args);
+ else
+ args = outer_args;
}
+ /* If any arguments depend on template parameters, we can't
+ check constraints. Pretend they're satisfied for now. */
+ if (uses_template_parms (args))
+ return boolean_true_node;
+
+ /* Get the normalized constraints. */
+ tree norm = get_normalized_constraints_from_decl (t, info.noisy ());
+
unsigned ftc_count = vec_safe_length (failed_type_completions);
tree result = boolean_true_node;
@@ -3134,7 +3201,7 @@ satisfy_declaration_constraints (tree t, sat_info info)
if (!push_tinst_level (t))
return result;
push_access_scope (t);
- result = satisfy_associated_constraints (norm, args, info);
+ result = satisfy_normalized_constraints (norm, args, info);
pop_access_scope (t);
pop_tinst_level ();
}
@@ -3157,6 +3224,10 @@ satisfy_declaration_constraints (tree t, sat_info info)
return result;
}
+/* Evaluate the associated constraints of the template T using ARGS as the
+ innermost set of template arguments and according to INFO, returning a
+ satisfaction value. */
+
static tree
satisfy_declaration_constraints (tree t, tree args, sat_info info)
{
@@ -3165,16 +3236,30 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info)
gcc_assert (TREE_CODE (t) == TEMPLATE_DECL);
- args = add_outermost_template_args (t, args);
+ if (regenerated_lambda_fn_p (t))
+ {
+ /* As in the two-parameter version of this function. */
+ gcc_assert (TMPL_ARGS_DEPTH (args) == 1);
+ tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
+ tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
+ args = add_to_template_args (outer_args, args);
+ }
+ else
+ args = add_outermost_template_args (t, args);
+
+ /* If any arguments depend on template parameters, we can't
+ check constraints. Pretend they're satisfied for now. */
+ if (uses_template_parms (args))
+ return boolean_true_node;
tree result = boolean_true_node;
- if (tree norm = normalize_template_requirements (t, info.noisy ()))
+ if (tree norm = get_normalized_constraints_from_decl (t, info.noisy ()))
{
if (!push_tinst_level (t, args))
return result;
tree pattern = DECL_TEMPLATE_RESULT (t);
push_access_scope (pattern);
- result = satisfy_associated_constraints (norm, args, info);
+ result = satisfy_normalized_constraints (norm, args, info);
pop_access_scope (pattern);
pop_tinst_level ();
}
@@ -3182,62 +3267,50 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info)
return result;
}
-static tree
-constraint_satisfaction_value (tree t, sat_info info)
-{
- tree r;
- if (DECL_P (t))
- r = satisfy_declaration_constraints (t, info);
- else
- r = satisfy_constraint_expression (t, NULL_TREE, info);
- if (r == error_mark_node && info.quiet ()
- && !(DECL_P (t) && TREE_NO_WARNING (t)))
- {
- /* 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;
-}
+/* A wrapper around satisfy_declaration_constraints and
+ satisfy_nondeclaration_constraints which additionally replays
+ quiet ill-formed satisfaction noisily, so that ill-formed
+ satisfaction always gets diagnosed. */
static tree
constraint_satisfaction_value (tree t, tree args, sat_info info)
{
tree r;
if (DECL_P (t))
- r = satisfy_declaration_constraints (t, args, info);
+ {
+ if (args)
+ r = satisfy_declaration_constraints (t, args, info);
+ else
+ r = satisfy_declaration_constraints (t, info);
+ }
else
- r = satisfy_constraint_expression (t, args, info);
- if (r == error_mark_node && info.quiet ())
+ r = satisfy_nondeclaration_constraints (t, args, info);
+ if (r == error_mark_node && info.quiet ()
+ && !(DECL_P (t) && warning_suppressed_p (t)))
{
- /* Replay the error with re-normalized requirements. */
+ /* Replay the error noisily. */
sat_info noisy (tf_warning_or_error, info.in_decl);
constraint_satisfaction_value (t, args, noisy);
+ if (DECL_P (t) && !args)
+ /* Avoid giving these errors again. */
+ suppress_warning (t);
}
return r;
}
-/* True iff the result of satisfying T is BOOLEAN_TRUE_NODE and false
- otherwise, even in the case of errors. */
+/* True iff the result of satisfying T using ARGS is BOOLEAN_TRUE_NODE
+ and false otherwise, even in the case of errors.
-bool
-constraints_satisfied_p (tree t)
-{
- if (!flag_concepts)
- return true;
-
- 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
- and false otherwise, even in the case of errors. */
+ Here, T can be:
+ - a template declaration
+ - a template specialization (in which case ARGS must be empty)
+ - a concept-id (in which case ARGS must be empty)
+ - a nested-requirement
+ - a placeholder 'auto'
+ - a requires-expression. */
bool
-constraints_satisfied_p (tree t, tree args)
+constraints_satisfied_p (tree t, tree args/*= NULL_TREE */)
{
if (!flag_concepts)
return true;
@@ -3250,7 +3323,7 @@ constraints_satisfied_p (tree t, tree args)
evaluation of template-ids as id-expressions. */
tree
-evaluate_concept_check (tree check, tsubst_flags_t complain)
+evaluate_concept_check (tree check)
{
if (check == error_mark_node)
return error_mark_node;
@@ -3259,14 +3332,19 @@ evaluate_concept_check (tree check, tsubst_flags_t complain)
/* Check for satisfaction without diagnostics. */
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. */
- sat_info noisy (tf_warning_or_error, NULL_TREE);
- satisfy_constraint_expression (check, NULL_TREE, noisy);
- }
- return result;
+ return constraint_satisfaction_value (check, /*args=*/NULL_TREE, quiet);
+}
+
+/* Evaluate the requires-expression T, returning either boolean_true_node
+ or boolean_false_node. This is used during folding and constexpr
+ evaluation. */
+
+tree
+evaluate_requires_expr (tree t)
+{
+ gcc_assert (TREE_CODE (t) == REQUIRES_EXPR);
+ sat_info quiet (tf_none, NULL_TREE);
+ return constraint_satisfaction_value (t, /*args=*/NULL_TREE, quiet);
}
/*---------------------------------------------------------------------------
@@ -3279,15 +3357,6 @@ evaluate_concept_check (tree check, tsubst_flags_t complain)
tree
finish_requires_expr (location_t loc, tree parms, tree reqs)
{
- /* Modify the declared parameters by removing their context
- so they don't refer to the enclosing scope and explicitly
- indicating that they are constraint variables. */
- for (tree parm = parms; parm; parm = DECL_CHAIN (parm))
- {
- DECL_CONTEXT (parm) = NULL_TREE;
- CONSTRAINT_VAR_P (parm) = true;
- }
-
/* Build the node. */
tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs, NULL_TREE);
TREE_SIDE_EFFECTS (r) = false;
@@ -3336,15 +3405,9 @@ finish_compound_requirement (location_t loc, tree expr, tree type, bool noexcept
tree
finish_nested_requirement (location_t loc, tree expr)
{
- /* We need to normalize the constraints now, at parse time, while
- we have the necessary template context. We normalize twice,
- once without diagnostic information and once with, which we'll
- later use for quiet and noisy satisfaction respectively. */
- tree norm = normalize_constraint_expression (expr, /*diag=*/false);
- tree diag_norm = normalize_constraint_expression (expr, /*diag=*/true);
-
- /* Build the constraint, saving its two normalizations as its type. */
- tree r = build1 (NESTED_REQ, build_tree_list (diag_norm, norm), expr);
+ /* Build the requirement, saving the set of in-scope template
+ parameters as its type. */
+ tree r = build1 (NESTED_REQ, current_template_parms, expr);
SET_EXPR_LOCATION (r, loc);
return r;
}
@@ -3384,31 +3447,6 @@ check_function_concept (tree fn)
return NULL_TREE;
}
-
-// Check that a constrained friend declaration function declaration,
-// FN, is admissible. This is the case only when the declaration depends
-// on template parameters and does not declare a specialization.
-void
-check_constrained_friend (tree fn, tree reqs)
-{
- if (fn == error_mark_node)
- return;
- gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
-
- // If there are not constraints, this cannot be an error.
- if (!reqs)
- return;
-
- // Constrained friend functions that don't depend on template
- // arguments are effectively meaningless.
- if (!uses_template_parms (TREE_TYPE (fn)))
- {
- error_at (location_of (fn),
- "constrained friend does not depend on template parameters");
- return;
- }
-}
-
/*---------------------------------------------------------------------------
Equivalence of constraints
---------------------------------------------------------------------------*/
@@ -3436,16 +3474,6 @@ equivalently_constrained (tree d1, tree d2)
Partial ordering of constraints
---------------------------------------------------------------------------*/
-/* Returns true when the constraints in A subsume those in B. */
-
-bool
-subsumes_constraints (tree a, tree b)
-{
- gcc_assert (!a || TREE_CODE (a) == CONSTRAINT_INFO);
- gcc_assert (!b || TREE_CODE (b) == CONSTRAINT_INFO);
- return subsumes (a, b);
-}
-
/* Returns true when the constraints in CI strictly subsume
the associated constraints of TMPL. */
@@ -3543,11 +3571,10 @@ get_constraint_error_location (tree t)
/* Emit a diagnostic for a failed trait. */
-void
-diagnose_trait_expr (tree expr, tree map)
+static void
+diagnose_trait_expr (tree expr, tree args)
{
location_t loc = cp_expr_location (expr);
- tree args = get_mapped_args (map);
/* Build a "fake" version of the instantiated trait, so we can
get the instantiated types from result. */
@@ -3601,9 +3628,16 @@ diagnose_trait_expr (tree expr, tree map)
case CPTK_IS_FINAL:
inform (loc, " %qT is not a final class", t1);
break;
+ case CPTK_IS_LAYOUT_COMPATIBLE:
+ inform (loc, " %qT is not layout compatible with %qT", t1, t2);
+ break;
case CPTK_IS_LITERAL_TYPE:
inform (loc, " %qT is not a literal type", t1);
break;
+ case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
+ inform (loc, " %qT is not pointer-interconvertible base of %qT",
+ t1, t2);
+ break;
case CPTK_IS_POD:
inform (loc, " %qT is not a POD type", t1);
break;
@@ -3627,194 +3661,11 @@ diagnose_trait_expr (tree expr, tree map)
}
}
-static tree
-diagnose_valid_expression (tree expr, tree args, tree in_decl)
-{
- tree result = tsubst_expr (expr, args, tf_none, in_decl, false);
- if (result != error_mark_node
- && convert_to_void (result, ICV_STATEMENT, tf_none) != error_mark_node)
- return result;
-
- location_t loc = cp_expr_loc_or_input_loc (expr);
- if (diagnosing_failed_constraint::replay_errors_p ())
- {
- /* Replay the substitution error. */
- inform (loc, "the required expression %qE is invalid, because", expr);
- if (result == error_mark_node)
- tsubst_expr (expr, args, tf_error, in_decl, false);
- else
- convert_to_void (result, ICV_STATEMENT, tf_error);
- }
- else
- inform (loc, "the required expression %qE is invalid", expr);
-
- return error_mark_node;
-}
-
-static tree
-diagnose_valid_type (tree type, tree args, tree in_decl)
-{
- tree result = tsubst (type, args, tf_none, in_decl);
- if (result != error_mark_node)
- return result;
-
- location_t loc = cp_expr_loc_or_input_loc (type);
- if (diagnosing_failed_constraint::replay_errors_p ())
- {
- /* Replay the substitution error. */
- inform (loc, "the required type %qT is invalid, because", type);
- tsubst (type, args, tf_error, in_decl);
- }
- else
- inform (loc, "the required type %qT is invalid", type);
-
- return error_mark_node;
-}
-
-static void
-diagnose_simple_requirement (tree req, tree args, tree in_decl)
-{
- diagnose_valid_expression (TREE_OPERAND (req, 0), args, in_decl);
-}
-
-static void
-diagnose_compound_requirement (tree req, tree args, tree in_decl)
-{
- tree expr = TREE_OPERAND (req, 0);
- expr = diagnose_valid_expression (expr, args, in_decl);
- if (expr == error_mark_node)
- return;
-
- location_t loc = cp_expr_loc_or_input_loc (expr);
-
- /* Check the noexcept condition. */
- if (COMPOUND_REQ_NOEXCEPT_P (req) && !expr_noexcept_p (expr, tf_none))
- inform (loc, "%qE is not %<noexcept%>", expr);
-
- tree type = TREE_OPERAND (req, 1);
- type = diagnose_valid_type (type, args, in_decl);
- if (type == error_mark_node)
- return;
-
- if (type)
- {
- subst_info quiet (tf_none, in_decl);
- subst_info noisy (tf_error, in_decl);
-
- /* Check the expression against the result type. */
- if (tree placeholder = type_uses_auto (type))
- {
- if (!type_deducible_p (expr, type, placeholder, args, quiet))
- {
- tree orig_expr = TREE_OPERAND (req, 0);
- if (diagnosing_failed_constraint::replay_errors_p ())
- {
- inform (loc,
- "%qE does not satisfy return-type-requirement, "
- "because", orig_expr);
- /* Further explain the reason for the error. */
- type_deducible_p (expr, type, placeholder, args, noisy);
- }
- else
- inform (loc, "%qE does not satisfy return-type-requirement",
- orig_expr);
- }
- }
- else if (!expression_convertible_p (expr, type, quiet))
- {
- tree orig_expr = TREE_OPERAND (req, 0);
- if (diagnosing_failed_constraint::replay_errors_p ())
- {
- inform (loc, "cannot convert %qE to %qT because", orig_expr, type);
- /* Further explain the reason for the error. */
- expression_convertible_p (expr, type, noisy);
- }
- else
- inform (loc, "cannot convert %qE to %qT", orig_expr, type);
- }
- }
-}
-
-static void
-diagnose_type_requirement (tree req, tree args, tree in_decl)
-{
- tree type = TREE_OPERAND (req, 0);
- diagnose_valid_type (type, args, in_decl);
-}
-
-static void
-diagnose_nested_requirement (tree req, tree args)
-{
- /* Quietly check for satisfaction first using the regular normal form.
- We can elaborate details later if needed. */
- tree norm = TREE_VALUE (TREE_TYPE (req));
- tree diag_norm = TREE_PURPOSE (TREE_TYPE (req));
- sat_info info (tf_none, NULL_TREE);
- tree result = satisfy_constraint (norm, args, info);
- if (result == boolean_true_node)
- return;
-
- tree expr = TREE_OPERAND (req, 0);
- location_t loc = cp_expr_location (expr);
- if (diagnosing_failed_constraint::replay_errors_p ())
- {
- /* Replay the substitution error using the diagnostic normal form. */
- inform (loc, "nested requirement %qE is not satisfied, because", expr);
- sat_info noisy (tf_warning_or_error, NULL_TREE, /*diag_unsat=*/true);
- satisfy_constraint (diag_norm, args, noisy);
- }
- else
- inform (loc, "nested requirement %qE is not satisfied", expr);
-
-}
-
-static void
-diagnose_requirement (tree req, tree args, tree in_decl)
-{
- iloc_sentinel loc_s (cp_expr_location (req));
- switch (TREE_CODE (req))
- {
- case SIMPLE_REQ:
- return diagnose_simple_requirement (req, args, in_decl);
- case COMPOUND_REQ:
- return diagnose_compound_requirement (req, args, in_decl);
- case TYPE_REQ:
- return diagnose_type_requirement (req, args, in_decl);
- case NESTED_REQ:
- return diagnose_nested_requirement (req, args);
- default:
- gcc_unreachable ();
- }
-}
-
-static void
-diagnose_requires_expr (tree expr, tree map, tree in_decl)
-{
- local_specialization_stack stack (lss_copy);
- tree parms = TREE_OPERAND (expr, 0);
- tree body = TREE_OPERAND (expr, 1);
- tree args = get_mapped_args (map);
-
- cp_unevaluated u;
- subst_info info (tf_warning_or_error, NULL_TREE);
- tree vars = tsubst_constraint_variables (parms, args, info);
- if (vars == error_mark_node)
- return;
-
- tree p = body;
- while (p)
- {
- tree req = TREE_VALUE (p);
- diagnose_requirement (req, args, in_decl);
- p = TREE_CHAIN (p);
- }
-}
-
/* Diagnose a substitution failure in the atomic constraint T when applied
with the instantiated parameter mapping MAP. */
static void
-diagnose_atomic_constraint (tree t, tree map, tree result, subst_info info)
+diagnose_atomic_constraint (tree t, tree map, tree result, sat_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. */
@@ -3835,13 +3686,19 @@ diagnose_atomic_constraint (tree t, tree map, tree result, subst_info info)
/* Generate better diagnostics for certain kinds of expressions. */
tree expr = ATOMIC_CONSTR_EXPR (t);
STRIP_ANY_LOCATION_WRAPPER (expr);
+ tree args = get_mapped_args (map);
switch (TREE_CODE (expr))
{
case TRAIT_EXPR:
- diagnose_trait_expr (expr, map);
+ diagnose_trait_expr (expr, args);
break;
case REQUIRES_EXPR:
- diagnose_requires_expr (expr, map, info.in_decl);
+ gcc_checking_assert (info.diagnose_unsatisfaction_p ());
+ /* Clear in_decl before replaying the substitution to avoid emitting
+ seemingly unhelpful "in declaration ..." notes that follow some
+ substitution failure error messages. */
+ info.in_decl = NULL_TREE;
+ tsubst_requires_expr (expr, args, info);
break;
default:
if (!same_type_p (TREE_TYPE (result), boolean_type_node))
@@ -3894,7 +3751,7 @@ diagnosing_failed_constraint::replay_errors_p ()
}
/* Emit diagnostics detailing the failure ARGS to satisfy the constraints
- of T. Here, T can be either a constraint or a declaration. */
+ of T. Here, T and ARGS are as in constraints_satisfied_p. */
void
diagnose_constraints (location_t loc, tree t, tree args)
@@ -3906,10 +3763,7 @@ diagnose_constraints (location_t loc, tree t, tree args)
/* Replay satisfaction, but diagnose unsatisfaction. */
sat_info noisy (tf_warning_or_error, NULL_TREE, /*diag_unsat=*/true);
- if (!args)
- constraint_satisfaction_value (t, noisy);
- else
- constraint_satisfaction_value (t, args, noisy);
+ constraint_satisfaction_value (t, args, noisy);
static bool suggested_p;
if (concepts_diagnostics_max_depth_exceeded_p