summaryrefslogtreecommitdiff
path: root/gcc/cp/constraint.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/constraint.cc')
-rw-r--r--gcc/cp/constraint.cc2617
1 files changed, 2617 insertions, 0 deletions
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
new file mode 100644
index 00000000000..cf57cc010a4
--- /dev/null
+++ b/gcc/cp/constraint.cc
@@ -0,0 +1,2617 @@
+/* Processing rules for constraints.
+ Copyright (C) 2013-2015 Free Software Foundation, Inc.
+ Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "intl.h"
+#include "flags.h"
+#include "cp-tree.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
+#include "cp-objcp-common.h"
+#include "tree-inline.h"
+#include "decl.h"
+#include "toplev.h"
+#include "type-utils.h"
+
+/*---------------------------------------------------------------------------
+ Operations on constraints
+---------------------------------------------------------------------------*/
+
+/* Returns true if C is a constraint tree code. Note that ERROR_MARK
+ is a valid constraint. */
+
+static inline bool
+constraint_p (tree_code c)
+{
+ return (PRED_CONSTR <= c && c <= DISJ_CONSTR) || c == ERROR_MARK;
+}
+
+/* Returns true if T is a constraint. Note that error_mark_node
+ is a valid constraint. */
+
+bool
+constraint_p (tree t)
+{
+ return constraint_p (TREE_CODE (t));
+}
+
+/* Make a predicate constraint from the given expression. */
+
+tree
+make_predicate_constraint (tree expr)
+{
+ return build_nt (PRED_CONSTR, expr);
+}
+
+/* Returns the conjunction of two constraints A and B. Note that
+ conjoining a non-null constraint with NULL_TREE is an identity
+ operation. That is, for non-null A,
+
+ conjoin_constraints(a, NULL_TREE) == a
+
+ and
+
+ conjoin_constraints (NULL_TREE, a) == a
+
+ If both A and B are NULL_TREE, the result is also NULL_TREE. */
+
+tree
+conjoin_constraints (tree a, tree b)
+{
+ gcc_assert (a ? constraint_p (a) : true);
+ gcc_assert (b ? constraint_p (b) : true);
+ if (a)
+ return b ? build_nt (CONJ_CONSTR, a, b) : a;
+ else if (b)
+ return b;
+ else
+ return NULL_TREE;
+}
+
+/* Transform the vector of expressions in the T into a conjunction
+ of requirements. T must be a TREE_VEC. */
+
+tree
+conjoin_constraints (tree t)
+{
+ gcc_assert (TREE_CODE (t) == TREE_VEC);
+ tree r = NULL_TREE;
+ for (int i = 0; i < TREE_VEC_LENGTH (t); ++i)
+ r = conjoin_constraints (r, TREE_VEC_ELT (t, i));
+ return r;
+}
+
+/* Returns true if T is a call expression to a function
+ concept. */
+
+bool
+function_concept_check_p (tree t)
+{
+ gcc_assert (TREE_CODE (t) == CALL_EXPR);
+ tree fn = CALL_EXPR_FN (t);
+ if (TREE_CODE (fn) == TEMPLATE_ID_EXPR
+ && TREE_CODE (TREE_OPERAND (fn, 0)) == OVERLOAD)
+ {
+ tree f1 = get_first_fn (fn);
+ if (TREE_CODE (f1) == TEMPLATE_DECL
+ && DECL_DECLARED_CONCEPT_P (DECL_TEMPLATE_RESULT (f1)))
+ return true;
+ }
+ return false;
+}
+
+/*---------------------------------------------------------------------------
+ Resolution of qualified concept names
+---------------------------------------------------------------------------*/
+
+/* This facility is used to resolve constraint checks from
+ requirement expressions. A constraint check is a call to
+ a function template declared with the keyword 'concept'.
+
+ The result of resolution is a pair (a TREE_LIST) whose value
+ is the matched declaration, and whose purpose contains the
+ coerced template arguments that can be substituted into the
+ call. */
+
+// Given an overload set OVL, try to find a unique definition that can be
+// instantiated by the template arguments ARGS.
+//
+// This function is not called for arbitrary call expressions. In particular,
+// the call expression must be written with explicit template arguments
+// and no function arguments. For example:
+//
+// f<T, U>()
+//
+// If a single match is found, this returns a TREE_LIST whose VALUE
+// is the constraint function (not the template), and its PURPOSE is
+// the complete set of arguments substituted into the parameter list.
+static tree
+resolve_constraint_check (tree ovl, tree args)
+{
+ tree cands = NULL_TREE;
+ for (tree p = ovl; p != NULL_TREE; p = OVL_NEXT (p))
+ {
+ // Get the next template overload.
+ tree tmpl = OVL_CURRENT (p);
+ if (TREE_CODE (tmpl) != TEMPLATE_DECL)
+ continue;
+
+ // Don't try to deduce checks for non-concepts. We often
+ // end up trying to resolve constraints in functional casts
+ // as part of a postfix-expression. We can save time and
+ // headaches by not instantiating those declarations.
+ //
+ // NOTE: This masks a potential error, caused by instantiating
+ // non-deduced contexts using placeholder arguments.
+ tree fn = DECL_TEMPLATE_RESULT (tmpl);
+ if (DECL_ARGUMENTS (fn))
+ continue;
+ if (!DECL_DECLARED_CONCEPT_P (fn))
+ continue;
+
+ // Remember the candidate if we can deduce a substitution.
+ ++processing_template_decl;
+ tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (tmpl));
+ if (tree subst = coerce_template_parms (parms, args, tmpl))
+ if (subst != error_mark_node)
+ cands = tree_cons (subst, fn, cands);
+ --processing_template_decl;
+ }
+
+ // If we didn't find a unique candidate, then this is
+ // not a constraint check.
+ if (!cands || TREE_CHAIN (cands))
+ return NULL_TREE;
+
+ return cands;
+}
+
+// Determine if the the call expression CALL is a constraint check, and
+// return the concept declaration and arguments being checked. If CALL
+// does not denote a constraint check, return NULL.
+tree
+resolve_constraint_check (tree call)
+{
+ gcc_assert (TREE_CODE (call) == CALL_EXPR);
+
+ // A constraint check must be only a template-id expression. If
+ // it's a call to a base-link, its function(s) should be a
+ // template-id expression. If this is not a template-id, then it
+ // cannot be a concept-check.
+ tree target = CALL_EXPR_FN (call);
+ if (BASELINK_P (target))
+ target = BASELINK_FUNCTIONS (target);
+ if (TREE_CODE (target) != TEMPLATE_ID_EXPR)
+ return NULL_TREE;
+
+ // Get the overload set and template arguments and try to
+ // resolve the target.
+ tree ovl = TREE_OPERAND (target, 0);
+
+ /* This is a function call of a variable concept... ill-formed. */
+ if (TREE_CODE (ovl) == TEMPLATE_DECL)
+ {
+ error_at (location_of (call),
+ "function call of variable concept %qE", call);
+ return error_mark_node;
+ }
+
+ tree args = TREE_OPERAND (target, 1);
+ return resolve_constraint_check (ovl, args);
+}
+
+/* Returns a pair containing the checked variable concept
+ and its associated prototype parameter. The result
+ is a TREE_LIST whose TREE_VALUE is the variable concept
+ and whose TREE_PURPOSE is the prototype parameter. */
+
+tree
+resolve_variable_concept_check (tree id)
+{
+ tree tmpl = TREE_OPERAND (id, 0);
+ tree args = TREE_OPERAND (id, 1);
+
+ if (!variable_concept_p (tmpl))
+ return NULL_TREE;
+
+ /* Make sure that we have the right parameters before
+ assuming that it works. Note that failing to deduce
+ will result in diagnostics. */
+ tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
+ tree result = coerce_template_parms (parms, args, tmpl);
+ if (result != error_mark_node)
+ {
+ tree decl = DECL_TEMPLATE_RESULT (tmpl);
+ return build_tree_list (result, decl);
+ }
+ else
+ return NULL_TREE;
+}
+
+
+/* Given a call expression or template-id expression to
+ a concept EXPR possibly including a wildcard, deduce
+ the concept being checked and the prototype parameter.
+ Returns true if the constraint and prototype can be
+ deduced and false otherwise. Note that the CHECK and
+ PROTO arguments are set to NULL_TREE if this returns
+ false. */
+
+bool
+deduce_constrained_parameter (tree expr, tree& check, tree& proto)
+{
+ tree info = NULL_TREE;
+ if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
+ info = resolve_variable_concept_check (expr);
+ else if (TREE_CODE (expr) == CALL_EXPR)
+ info = resolve_constraint_check (expr);
+ else
+ gcc_unreachable ();
+
+ if (info && info != error_mark_node)
+ {
+ check = TREE_VALUE (info);
+ tree arg = TREE_VEC_ELT (TREE_PURPOSE (info), 0);
+ if (ARGUMENT_PACK_P (arg))
+ arg = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg), 0);
+ proto = TREE_TYPE (arg);
+ return true;
+ }
+ check = proto = NULL_TREE;
+ return false;
+}
+
+// Given a call expression or template-id expression to a concept, EXPR,
+// deduce the concept being checked and return the template arguments.
+// Returns NULL_TREE if deduction fails.
+static tree
+deduce_concept_introduction (tree expr)
+{
+ tree info = NULL_TREE;
+ if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
+ info = resolve_variable_concept_check (expr);
+ else if (TREE_CODE (expr) == CALL_EXPR)
+ info = resolve_constraint_check (expr);
+ else
+ gcc_unreachable ();
+
+ if (info && info != error_mark_node)
+ return TREE_PURPOSE (info);
+ return NULL_TREE;
+}
+
+namespace {
+
+/*---------------------------------------------------------------------------
+ Lifting of concept definitions
+---------------------------------------------------------------------------*/
+
+/* Part of constraint normalization. Whenever we find a reference to
+ a variable concept or a call to a function concept, we lift or
+ inline that concept's definition into the constraint. This ensures
+ that constraints are always checked in the immediate instantiation
+ context. */
+
+tree lift_expression (tree);
+
+/* If the tree T has operands, then lift any concepts out of them. */
+tree
+lift_operands (tree t)
+{
+ if (int n = tree_operand_length (t))
+ {
+ t = copy_node (t);
+ for (int i = 0; i < n; ++i)
+ TREE_OPERAND (t, i) = lift_expression (TREE_OPERAND (t, i));
+ }
+ return t;
+}
+
+/* Recursively lift all operands of the function call. Also, check
+ that the call target is not accidentally a variable concept
+ since that's ill-formed. */
+tree
+lift_function_call (tree t)
+{
+ gcc_assert (TREE_CODE (t) == CALL_EXPR);
+ gcc_assert (!VAR_P (CALL_EXPR_FN (t)));
+ return lift_operands (t);
+}
+
+/* Inline a function (concept) definition by substituting
+ ARGS into its body. */
+tree
+lift_function_definition (tree fn, tree args)
+{
+ /* Extract the body of the function minus the return expression. */
+ tree body = DECL_SAVED_TREE (fn);
+ if (!body)
+ return error_mark_node;
+ if (TREE_CODE (body) == BIND_EXPR)
+ body = BIND_EXPR_BODY (body);
+ if (TREE_CODE (body) != RETURN_EXPR)
+ return error_mark_node;
+
+ body = TREE_OPERAND (body, 0);
+
+ /* Substitute template arguments to produce our inline expression. */
+ tree result = tsubst_expr (body, args, tf_none, NULL_TREE, false);
+ if (result == error_mark_node)
+ return error_mark_node;
+
+ return lift_expression (result);
+}
+
+/* Inline a reference to a function concept. */
+tree
+lift_call_expression (tree t)
+{
+ /* Try to resolve this function call as a concept. If not, then
+ it can be returned as-is. */
+ tree check = resolve_constraint_check (t);
+ if (!check)
+ return lift_function_call (t);
+ if (check == error_mark_node)
+ return error_mark_node;
+
+ tree fn = TREE_VALUE (check);
+ tree args = TREE_PURPOSE (check);
+ return lift_function_definition (fn, args);
+}
+
+tree
+lift_variable_initializer (tree var, tree args)
+{
+ /* Extract the body from the variable initializer. */
+ tree init = DECL_INITIAL (var);
+ if (!init)
+ return error_mark_node;
+
+ /* Substitute the arguments to form our new inline expression. */
+ tree result = tsubst_expr (init, args, tf_none, NULL_TREE, false);
+ if (result == error_mark_node)
+ return error_mark_node;
+
+ return lift_expression (result);
+}
+
+/* Determine if a template-id is a variable concept and inline. */
+
+tree
+lift_template_id (tree t)
+{
+ if (tree info = resolve_variable_concept_check (t))
+ {
+ tree decl = TREE_VALUE (info);
+ tree args = TREE_PURPOSE (info);
+ return lift_variable_initializer (decl, args);
+ }
+
+ /* Check that we didn't refer to a function concept like
+ a variable.
+
+ TODO: Add a note on how to fix this. */
+ tree tmpl = TREE_OPERAND (t, 0);
+ if (TREE_CODE (tmpl) == OVERLOAD)
+ {
+ tree fn = OVL_FUNCTION (tmpl);
+ if (TREE_CODE (fn) == TEMPLATE_DECL
+ && DECL_DECLARED_CONCEPT_P (DECL_TEMPLATE_RESULT (fn)))
+ {
+ error_at (location_of (t),
+ "invalid reference to function concept %qD", fn);
+ return error_mark_node;
+ }
+ }
+
+ return t;
+}
+
+/* Lift any constraints appearing in a nested requirement of
+ a requires-expression. */
+tree
+lift_requires_expression (tree t)
+{
+ tree parms = TREE_OPERAND (t, 0);
+ tree reqs = TREE_OPERAND (t, 1);
+ tree result = NULL_TREE;
+ for (; reqs != NULL_TREE; reqs = TREE_CHAIN (reqs))
+ {
+ tree req = TREE_VALUE (reqs);
+ if (TREE_CODE (req) == NESTED_REQ)
+ {
+ tree expr = lift_expression (TREE_OPERAND (req, 0));
+ req = finish_nested_requirement (expr);
+ }
+ result = tree_cons (NULL_TREE, req, result);
+ }
+ return finish_requires_expr (parms, result);
+}
+
+/* Inline references to specializations of concepts. */
+tree
+lift_expression (tree t)
+{
+ if (t == NULL_TREE)
+ return NULL_TREE;
+
+ if (t == error_mark_node)
+ return error_mark_node;
+
+ /* Concepts can be referred to by call or variable. All other
+ nodes are preserved. */
+ switch (TREE_CODE (t))
+ {
+ case CALL_EXPR:
+ return lift_call_expression (t);
+
+ case TEMPLATE_ID_EXPR:
+ return lift_template_id (t);
+
+ case REQUIRES_EXPR:
+ return lift_requires_expression (t);
+
+ case EXPR_PACK_EXPANSION:
+ /* Use copy_node rather than make_pack_expansion so that
+ PACK_EXPANSION_PARAMETER_PACKS stays the same. */
+ t = copy_node (t);
+ SET_PACK_EXPANSION_PATTERN
+ (t, lift_expression (PACK_EXPANSION_PATTERN (t)));
+ return t;
+
+ case TREE_LIST:
+ {
+ t = copy_node (t);
+ TREE_VALUE (t) = lift_expression (TREE_VALUE (t));
+ TREE_CHAIN (t) = lift_expression (TREE_CHAIN (t));
+ return t;
+ }
+
+ default:
+ return lift_operands (t);
+ }
+}
+
+/*---------------------------------------------------------------------------
+ Transformation of expressions into constraints
+---------------------------------------------------------------------------*/
+
+/* Part of constraint normalization. The following functions rewrite
+ expressions as constraints. */
+
+tree transform_expression (tree);
+
+/* Check that the logical-or or logical-and expression does
+ not result in a call to a user-defined user-defined operator
+ (temp.constr.op). Returns true if the logical operator is
+ admissible and false otherwise. */
+
+bool
+check_logical_expr (tree t)
+{
+ /* We can't do much for type dependent expressions. */
+ if (type_dependent_expression_p (t))
+ return true;
+
+ /* Resolve the logical operator. Note that template processing is
+ disabled so we get the actual call or target expression back.
+ not_processing_template_sentinel sentinel.
+
+ TODO: This check is actually subsumed by the requirement that
+ constraint operands have type bool. I'm not sure we need it
+ unless we allow conversions. */
+ tree arg1 = TREE_OPERAND (t, 0);
+ tree arg2 = TREE_OPERAND (t, 1);
+ tree ovl = NULL_TREE;
+ tree expr = build_x_binary_op (EXPR_LOC_OR_LOC (arg2, input_location),
+ TREE_CODE (t),
+ arg1, TREE_CODE (arg1),
+ arg2, TREE_CODE (arg2),
+ &ovl,
+ tf_none);
+ if (TREE_CODE (expr) != TREE_CODE (t))
+ {
+ error ("user-defined operator %qs in constraint %q+E",
+ operator_name_info[TREE_CODE (t)].name, t);
+ return false;
+ }
+ return true;
+}
+
+/* Transform a logical-or or logical-and expression into either
+ a conjunction or disjunction. */
+
+tree
+xform_logical (tree t, tree_code c)
+{
+ if (!check_logical_expr (t))
+ return error_mark_node;
+ tree t0 = transform_expression (TREE_OPERAND (t, 0));
+ tree t1 = transform_expression (TREE_OPERAND (t, 1));
+ return build_nt (c, t0, t1);
+}
+
+/* A simple requirement T introduces an expression constraint
+ for its expression. */
+
+inline tree
+xform_simple_requirement (tree t)
+{
+ return build_nt (EXPR_CONSTR, TREE_OPERAND (t, 0));
+}
+
+/* A type requirement T introduce a type constraint for its type. */
+
+inline tree
+xform_type_requirement (tree t)
+{
+ return build_nt (TYPE_CONSTR, TREE_OPERAND (t, 0));
+}
+
+/* A compound requirement T introduces a conjunction of constraints
+ depending on its form. The conjunction always includes an
+ expression constraint for the expression of the requirement.
+ If a trailing return type was specified, the conjunction includes
+ either an implicit conversion constraint or an argument deduction
+ constraint. If the noexcept specifier is present, the conjunction
+ includes an exception constraint. */
+
+tree
+xform_compound_requirement (tree t)
+{
+ tree expr = TREE_OPERAND (t, 0);
+ tree constr = build_nt (EXPR_CONSTR, TREE_OPERAND (t, 0));
+
+ /* If a type is given, append an implicit conversion or
+ argument deduction constraint. */
+ if (tree type = TREE_OPERAND (t, 1))
+ {
+ tree type_constr;
+ /* TODO: We should be extracting a list of auto nodes
+ from type_uses_auto, not a single node */
+ if (tree placeholder = type_uses_auto (type))
+ type_constr = build_nt (DEDUCT_CONSTR, expr, type, placeholder);
+ else
+ type_constr = build_nt (ICONV_CONSTR, expr, type);
+ constr = conjoin_constraints (constr, type_constr);
+ }
+
+ /* If noexcept is present, append an exception constraint. */
+ if (COMPOUND_REQ_NOEXCEPT_P (t))
+ {
+ tree except = build_nt (EXCEPT_CONSTR, expr);
+ constr = conjoin_constraints (constr, except);
+ }
+
+ return constr;
+}
+
+/* A nested requirement T introduces a conjunction of constraints
+ corresponding to its constraint-expression.
+
+ If the result of transforming T is error_mark_node, the resulting
+ constraint is a predicate constraint whose operand is also
+ error_mark_node. This preserves the constraint structure, but
+ will guarantee that the constraint is never satisfied. */
+
+inline tree
+xform_nested_requirement (tree t)
+{
+ return transform_expression (TREE_OPERAND (t, 0));
+}
+
+/* Transform a requirement T into one or more constraints. */
+
+tree
+xform_requirement (tree t)
+{
+ switch (TREE_CODE (t))
+ {
+ case SIMPLE_REQ:
+ return xform_simple_requirement (t);
+
+ case TYPE_REQ:
+ return xform_type_requirement (t);
+
+ case COMPOUND_REQ:
+ return xform_compound_requirement (t);
+
+ case NESTED_REQ:
+ return xform_nested_requirement (t);
+
+ default:
+ gcc_unreachable ();
+ }
+ return error_mark_node;
+}
+
+/* Transform a sequence of requirements into a conjunction of
+ constraints. */
+
+tree
+xform_requirements (tree t)
+{
+ tree result = NULL_TREE;
+ for (; t; t = TREE_CHAIN (t))
+ {
+ tree constr = xform_requirement (TREE_VALUE (t));
+ result = conjoin_constraints (result, constr);
+ }
+ return result;
+}
+
+/* Transform a requires-expression into a parameterized constraint. */
+
+tree
+xform_requires_expr (tree t)
+{
+ tree operand = xform_requirements (TREE_OPERAND (t, 1));
+ if (tree parms = TREE_OPERAND (t, 0))
+ return build_nt (PARM_CONSTR, parms, operand);
+ else
+ return operand;
+}
+
+/* Transform an expression into an atomic predicate constraint.
+ After substitution, the expression of a predicate constraint
+ shall have type bool (temp.constr.pred). For non-type-dependent
+ expressions, we can check that now. */
+
+tree
+xform_atomic (tree t)
+{
+ if (TREE_TYPE (t) && !type_dependent_expression_p (t))
+ {
+ tree type = cv_unqualified (TREE_TYPE (t));
+ if (!same_type_p (type, boolean_type_node))
+ {
+ error ("predicate constraint %q+E does not have type %<bool%>", t);
+ return error_mark_node;
+ }
+ }
+ return build_nt (PRED_CONSTR, t);
+}
+
+/* Push down the pack expansion EXP into the leaves of the constraint PAT. */
+
+tree
+push_down_pack_expansion (tree exp, tree pat)
+{
+ switch (TREE_CODE (pat))
+ {
+ case CONJ_CONSTR:
+ case DISJ_CONSTR:
+ {
+ pat = copy_node (pat);
+ TREE_OPERAND (pat, 0)
+ = push_down_pack_expansion (exp, TREE_OPERAND (pat, 0));
+ TREE_OPERAND (pat, 1)
+ = push_down_pack_expansion (exp, TREE_OPERAND (pat, 1));
+ return pat;
+ }
+ default:
+ {
+ exp = copy_node (exp);
+ SET_PACK_EXPANSION_PATTERN (exp, pat);
+ return exp;
+ }
+ }
+}
+
+/* Transform a pack expansion into a constraint. First we transform the
+ pattern of the pack expansion, then we push the pack expansion down into the
+ leaves of the constraint so that partial ordering will work. */
+
+tree
+xform_pack_expansion (tree t)
+{
+ tree pat = transform_expression (PACK_EXPANSION_PATTERN (t));
+ return push_down_pack_expansion (t, pat);
+}
+
+/* Transform an expression into a constraint. */
+
+tree
+xform_expr (tree t)
+{
+ switch (TREE_CODE (t))
+ {
+ case TRUTH_ANDIF_EXPR:
+ return xform_logical (t, CONJ_CONSTR);
+
+ case TRUTH_ORIF_EXPR:
+ return xform_logical (t, DISJ_CONSTR);
+
+ case REQUIRES_EXPR:
+ return xform_requires_expr (t);
+
+ case BIND_EXPR:
+ return transform_expression (BIND_EXPR_BODY (t));
+
+ case EXPR_PACK_EXPANSION:
+ return xform_pack_expansion (t);
+
+ default:
+ /* All other constraints are atomic. */
+ return xform_atomic (t);
+ }
+}
+
+/* Transform a statement into an expression. */
+
+tree
+xform_stmt (tree t)
+{
+ switch (TREE_CODE (t))
+ {
+ case RETURN_EXPR:
+ return transform_expression (TREE_OPERAND (t, 0));
+ default:
+ gcc_unreachable ();
+ }
+ return error_mark_node;
+}
+
+/* Reduction rules for the declaration T. */
+
+tree
+xform_decl (tree t)
+{
+ switch (TREE_CODE (t))
+ {
+ case VAR_DECL:
+ return xform_atomic (t);
+ default:
+ gcc_unreachable ();
+ }
+ return error_mark_node;
+}
+
+/* Transform a lifted expression into a constraint. This either
+ returns a constraint, or it returns error_mark_node when
+ a constraint cannot be formed. */
+
+tree
+transform_expression (tree t)
+{
+ if (!t)
+ return NULL_TREE;
+
+ if (t == error_mark_node)
+ return error_mark_node;
+
+ switch (TREE_CODE_CLASS (TREE_CODE (t)))
+ {
+ case tcc_unary:
+ case tcc_binary:
+ case tcc_expression:
+ case tcc_vl_exp:
+ return xform_expr (t);
+
+ case tcc_statement:
+ return xform_stmt (t);
+
+ case tcc_declaration:
+ return xform_decl (t);
+
+ case tcc_exceptional:
+ case tcc_constant:
+ case tcc_reference:
+ case tcc_comparison:
+ /* These are all atomic predicate constraints. */
+ return xform_atomic (t);
+
+ default:
+ /* Unhandled node kind. */
+ gcc_unreachable ();
+ }
+ return error_mark_node;
+}
+
+/*---------------------------------------------------------------------------
+ Constraint normalization
+---------------------------------------------------------------------------*/
+
+tree normalize_constraint (tree);
+
+/* The normal form of the disjunction T0 /\ T1 is the conjunction
+ of the normal form of T0 and the normal form of T1. */
+
+inline tree
+normalize_conjunction (tree t)
+{
+ tree t0 = normalize_constraint (TREE_OPERAND (t, 0));
+ tree t1 = normalize_constraint (TREE_OPERAND (t, 1));
+ return build_nt (CONJ_CONSTR, t0, t1);
+}
+
+/* The normal form of the disjunction T0 \/ T1 is the disjunction
+ of the normal form of T0 and the normal form of T1. */
+
+inline tree
+normalize_disjunction (tree t)
+{
+ tree t0 = normalize_constraint (TREE_OPERAND (t, 0));
+ tree t1 = normalize_constraint (TREE_OPERAND (t, 1));
+ return build_nt (DISJ_CONSTR, t0, t1);
+}
+
+/* A predicate constraint is normalized in two stages. First all
+ references specializations of concepts are replaced by their
+ substituted definitions. Then, the resulting expression is
+ transformed into a constraint by transforming && expressions
+ into conjunctions and || into disjunctions. */
+
+tree
+normalize_predicate_constraint (tree t)
+{
+ ++processing_template_decl;
+ tree expr = PRED_CONSTR_EXPR (t);
+ tree lifted = lift_expression (expr);
+ tree constr = transform_expression (lifted);
+ --processing_template_decl;
+ return constr;
+}
+
+/* The normal form of a parameterized constraint is the normal
+ form of its operand. */
+
+tree
+normalize_parameterized_constraint (tree t)
+{
+ tree parms = PARM_CONSTR_PARMS (t);
+ tree operand = normalize_constraint (PARM_CONSTR_OPERAND (t));
+ return build_nt (PARM_CONSTR, parms, operand);
+}
+
+/* Normalize the constraint T by reducing it so that it is
+ comprised of only conjunctions and disjunctions of atomic
+ constraints. */
+
+tree
+normalize_constraint (tree t)
+{
+ if (!t)
+ return NULL_TREE;
+
+ if (t == error_mark_node)
+ return t;
+
+ switch (TREE_CODE (t))
+ {
+ case CONJ_CONSTR:
+ return normalize_conjunction (t);
+
+ case DISJ_CONSTR:
+ return normalize_disjunction (t);
+
+ case PRED_CONSTR:
+ return normalize_predicate_constraint (t);
+
+ case PARM_CONSTR:
+ return normalize_parameterized_constraint (t);
+
+ case EXPR_CONSTR:
+ case TYPE_CONSTR:
+ case ICONV_CONSTR:
+ case DEDUCT_CONSTR:
+ case EXCEPT_CONSTR:
+ /* These constraints are defined to be atomic. */
+ return t;
+
+ default:
+ /* CONSTR was not a constraint. */
+ gcc_unreachable();
+ }
+ return error_mark_node;
+}
+
+} /* namespace */
+
+
+// -------------------------------------------------------------------------- //
+// Constraint Semantic Processing
+//
+// The following functions are called by the parser and substitution rules
+// to create and evaluate constraint-related nodes.
+
+// The constraints associated with the current template parameters.
+tree
+current_template_constraints (void)
+{
+ if (!current_template_parms)
+ return NULL_TREE;
+ tree tmpl_constr = TEMPLATE_PARM_CONSTRAINTS (current_template_parms);
+ return build_constraints (tmpl_constr, NULL_TREE);
+}
+
+// If the recently parsed TYPE declares or defines a template or template
+// specialization, get its corresponding constraints from the current
+// template parameters and bind them to TYPE's declaration.
+tree
+associate_classtype_constraints (tree type)
+{
+ if (!type || type == error_mark_node || TREE_CODE (type) != RECORD_TYPE)
+ return type;
+
+ // An explicit class template specialization has no template
+ // parameters.
+ if (!current_template_parms)
+ return type;
+
+ if (CLASSTYPE_IS_TEMPLATE (type) || CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
+ {
+ tree decl = TYPE_STUB_DECL (type);
+ tree ci = current_template_constraints ();
+
+ // An implicitly instantiated member template declaration already
+ // has associated constraints. If it is defined outside of its
+ // class, then we need match these constraints against those of
+ // original declaration.
+ if (tree orig_ci = get_constraints (decl))
+ {
+ if (!equivalent_constraints (ci, orig_ci))
+ {
+ // FIXME: Improve diagnostics.
+ error ("%qT does not match any declaration", type);
+ return error_mark_node;
+ }
+ return type;
+ }
+ set_constraints (decl, ci);
+ }
+ return type;
+}
+
+namespace {
+
+// Create an empty constraint info block.
+inline tree_constraint_info*
+build_constraint_info ()
+{
+ return (tree_constraint_info *)make_node (CONSTRAINT_INFO);
+}
+
+} // namespace
+
+/* Build a constraint-info object that contains the associated constraints
+ of a declaration. This also includes the declaration's template
+ requirements (TREQS) and any trailing requirements for a function
+ declarator (DREQS). Note that both TREQS and DREQS must be constraints.
+
+ If the declaration has neither template nor declaration requirements
+ this returns NULL_TREE, indicating an unconstrained declaration. */
+
+tree
+build_constraints (tree tmpl_reqs, tree decl_reqs)
+{
+ gcc_assert (tmpl_reqs ? constraint_p (tmpl_reqs) : true);
+ gcc_assert (decl_reqs ? constraint_p (decl_reqs) : true);
+
+ if (!tmpl_reqs && !decl_reqs)
+ return NULL_TREE;
+
+ tree_constraint_info* ci = build_constraint_info ();
+ ci->template_reqs = tmpl_reqs;
+ ci->declarator_reqs = decl_reqs;
+ ci->associated_constr = conjoin_constraints (tmpl_reqs, decl_reqs);
+
+ ++processing_template_decl;
+ ci->normalized_constr = normalize_constraint (ci->associated_constr);
+ --processing_template_decl;
+
+ ci->assumptions = decompose_assumptions (ci->normalized_constr);
+ return (tree)ci;
+}
+
+namespace {
+
+/* 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;
+}
+
+/* Build a new call expression, but don't actually generate
+ a new function call. We just want the tree, not the
+ semantics. */
+inline tree
+build_call_check (tree id)
+{
+ ++processing_template_decl;
+ vec<tree, va_gc> *fargs = make_tree_vector();
+ tree call = finish_call_expr (id, &fargs, false, false, tf_none);
+ release_tree_vector (fargs);
+ --processing_template_decl;
+ return call;
+}
+
+/* Build an expression that will check a variable concept. If any
+ argument contains a wildcard, don't try to finish the variable
+ template because we can't substitute into a non-existent
+ declaration. */
+tree
+build_variable_check (tree id)
+{
+ gcc_assert (TREE_CODE (id) == TEMPLATE_ID_EXPR);
+ if (contains_wildcard_p (TREE_OPERAND (id, 1)))
+ return id;
+
+ ++processing_template_decl;
+ tree var = finish_template_variable (id);
+ --processing_template_decl;
+ return var;
+}
+
+/* Construct a sequence of template arguments by prepending
+ ARG to REST. Either ARG or REST may be null. */
+tree
+build_concept_check_arguments (tree arg, tree rest)
+{
+ gcc_assert (rest ? TREE_CODE (rest) == TREE_VEC : true);
+ tree args;
+ if (arg)
+ {
+ int n = rest ? TREE_VEC_LENGTH (rest) : 0;
+ args = make_tree_vec (n + 1);
+ TREE_VEC_ELT (args, 0) = arg;
+ if (rest)
+ for (int i = 0; i < n; ++i)
+ TREE_VEC_ELT (args, i + 1) = TREE_VEC_ELT (rest, i);
+ int def = rest ? GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (rest) : 0;
+ SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, def + 1);
+ }
+ else
+ {
+ gcc_assert (rest != NULL_TREE);
+ args = rest;
+ }
+ return args;
+}
+
+} // namespace
+
+/* Construct an expression that checks the concept given by
+ TARGET. The TARGET must be:
+
+ - an OVERLOAD referring to one or more function concepts
+ - a BASELINK referring to an overload set of the above, or
+ - a TEMPLTATE_DECL referring to a variable concept.
+
+ ARG and REST are the explicit template arguments for the
+ eventual concept check. */
+tree
+build_concept_check (tree target, tree arg, tree rest)
+{
+ tree args = build_concept_check_arguments (arg, rest);
+ if (variable_template_p (target))
+ return build_variable_check (lookup_template_variable (target, args));
+ else
+ return build_call_check (lookup_template_function (target, args));
+}
+
+
+/* Returns a TYPE_DECL that contains sufficient information to
+ build a template parameter of the same kind as PROTO and
+ constrained by the concept declaration CNC. Note that PROTO
+ is the first template parameter of CNC.
+
+ If specified, ARGS provides additional arguments to the
+ constraint check. */
+tree
+build_constrained_parameter (tree cnc, tree proto, tree args)
+{
+ tree name = DECL_NAME (cnc);
+ tree type = TREE_TYPE (proto);
+ tree decl = build_decl (input_location, TYPE_DECL, name, type);
+ CONSTRAINED_PARM_PROTOTYPE (decl) = proto;
+ CONSTRAINED_PARM_CONCEPT (decl) = cnc;
+ CONSTRAINED_PARM_EXTRA_ARGS (decl) = args;
+ return decl;
+}
+
+/* Create a constraint expression for the given DECL that
+ evaluates the requirements specified by CONSTR, a TYPE_DECL
+ that contains all the information necessary to build the
+ requirements (see finish_concept_name for the layout of
+ that TYPE_DECL).
+
+ Note that the constraints are neither reduced nor decomposed.
+ That is done only after the requires clause has been parsed
+ (or not). */
+tree
+finish_shorthand_constraint (tree decl, tree constr)
+{
+ /* No requirements means no constraints. */
+ if (!constr)
+ return NULL_TREE;
+
+ tree proto = CONSTRAINED_PARM_PROTOTYPE (constr);
+ tree con = CONSTRAINED_PARM_CONCEPT (constr);
+ tree args = CONSTRAINED_PARM_EXTRA_ARGS (constr);
+
+ /* If the parameter declaration is variadic, but the concept
+ is not then we need to apply the concept to every element
+ in the pack. */
+ bool is_proto_pack = template_parameter_pack_p (proto);
+ bool is_decl_pack = template_parameter_pack_p (decl);
+ bool apply_to_all_p = is_decl_pack && !is_proto_pack;
+
+ /* Get the argument and overload used for the requirement
+ and adjust it if we're going to expand later. */
+ tree arg = template_parm_to_arg (build_tree_list (NULL_TREE, decl));
+ if (apply_to_all_p)
+ arg = PACK_EXPANSION_PATTERN (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg), 0));
+
+ /* Build the concept check. If it the constraint needs to be
+ applied to all elements of the parameter pack, then make
+ the constraint an expansion. */
+ tree check;
+ tree tmpl = DECL_TI_TEMPLATE (con);
+ if (TREE_CODE (con) == VAR_DECL)
+ {
+ check = build_concept_check (tmpl, arg, args);
+ }
+ else
+ {
+ tree ovl = build_overload (tmpl, NULL_TREE);
+ check = build_concept_check (ovl, arg, args);
+ }
+
+ /* Make the check a pack expansion if needed.
+
+ FIXME: We should be making a fold expression. */
+ if (apply_to_all_p)
+ {
+ check = make_pack_expansion (check);
+ TREE_TYPE (check) = boolean_type_node;
+ }
+
+ return make_predicate_constraint (check);
+}
+
+/* Returns a conjunction of shorthand requirements for the template
+ parameter list PARMS. Note that the requirements are stored in
+ the TYPE of each tree node. */
+tree
+get_shorthand_constraints (tree parms)
+{
+ tree result = NULL_TREE;
+ parms = INNERMOST_TEMPLATE_PARMS (parms);
+ for (int i = 0; i < TREE_VEC_LENGTH (parms); ++i)
+ {
+ tree parm = TREE_VEC_ELT (parms, i);
+ tree constr = TEMPLATE_PARM_CONSTRAINTS (parm);
+ result = conjoin_constraints (result, constr);
+ }
+ return result;
+}
+
+// Returns and chains a new parameter for PARAMETER_LIST which will conform
+// to the prototype given by SRC_PARM. The new parameter will have its
+// identifier and location set according to IDENT and PARM_LOC respectively.
+static tree
+process_introduction_parm (tree parameter_list, tree src_parm)
+{
+ // If we have a pack, we should have a single pack argument which is the
+ // placeholder we want to look at.
+ bool is_parameter_pack = ARGUMENT_PACK_P (src_parm);
+ if (is_parameter_pack)
+ src_parm = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (src_parm), 0);
+
+ // At this point we should have a wildcard, but we want to
+ // grab the associated decl from it. Also grab the stored
+ // identifier and location that should be chained to it in
+ // a PARM_DECL.
+ gcc_assert (TREE_CODE (src_parm) == WILDCARD_DECL);
+
+ tree ident = DECL_NAME (src_parm);
+ location_t parm_loc = DECL_SOURCE_LOCATION (src_parm);
+
+ // If we expect a pack and the deduced template is not a pack, or if the
+ // template is using a pack and we didn't declare a pack, throw an error.
+ if (is_parameter_pack != WILDCARD_PACK_P (src_parm))
+ {
+ error_at (parm_loc, "cannot match pack for introduced parameter");
+ tree err_parm = build_tree_list (error_mark_node, error_mark_node);
+ return chainon (parameter_list, err_parm);
+ }
+
+ src_parm = TREE_TYPE (src_parm);
+
+ tree parm;
+ bool is_non_type;
+ if (TREE_CODE (src_parm) == TYPE_DECL)
+ {
+ is_non_type = false;
+ parm = finish_template_type_parm (class_type_node, ident);
+ }
+ else if (TREE_CODE (src_parm) == TEMPLATE_DECL)
+ {
+ is_non_type = false;
+ begin_template_parm_list ();
+ current_template_parms = DECL_TEMPLATE_PARMS (src_parm);
+ end_template_parm_list ();
+ parm = finish_template_template_parm (class_type_node, ident);
+ }
+ else
+ {
+ is_non_type = true;
+
+ // Since we don't have a declarator, so we can copy the source
+ // parameter and change the name and eventually the location.
+ parm = copy_decl (src_parm);
+ DECL_NAME (parm) = ident;
+ }
+
+ // Wrap in a TREE_LIST for process_template_parm. Introductions do not
+ // retain the defaults from the source template.
+ parm = build_tree_list (NULL_TREE, parm);
+
+ return process_template_parm (parameter_list, parm_loc, parm,
+ is_non_type, is_parameter_pack);
+}
+
+/* Associates a constraint check to the current template based
+ on the introduction parameters. INTRO_LIST must be a TREE_VEC
+ of WILDCARD_DECLs containing a chained PARM_DECL which
+ contains the identifier as well as the source location.
+ TMPL_DECL is the decl for the concept being used. If we
+ take a concept, C, this will form a check in the form of
+ C<INTRO_LIST> filling in any extra arguments needed by the
+ defaults deduced.
+
+ Returns NULL_TREE if no concept could be matched and
+ error_mark_node if an error occurred when matching. */
+tree
+finish_template_introduction (tree tmpl_decl, tree intro_list)
+{
+ /* Deduce the concept check. */
+ tree expr = build_concept_check (tmpl_decl, NULL_TREE, intro_list);
+ if (expr == error_mark_node)
+ return NULL_TREE;
+
+ tree parms = deduce_concept_introduction (expr);
+ if (!parms)
+ return NULL_TREE;
+
+ /* Build template parameter scope for introduction. */
+ tree parm_list = NULL_TREE;
+ begin_template_parm_list ();
+ int nargs = MIN (TREE_VEC_LENGTH (parms), TREE_VEC_LENGTH (intro_list));
+ for (int n = 0; n < nargs; ++n)
+ parm_list = process_introduction_parm (parm_list, TREE_VEC_ELT (parms, n));
+ parm_list = end_template_parm_list (parm_list);
+ for (int i = 0; i < TREE_VEC_LENGTH (parm_list); ++i)
+ if (TREE_VALUE (TREE_VEC_ELT (parm_list, i)) == error_mark_node)
+ {
+ end_template_decl ();
+ return error_mark_node;
+ }
+
+ /* Build a concept check for our constraint. */
+ tree check_args = make_tree_vec (TREE_VEC_LENGTH (parms));
+ int n = 0;
+ for (; n < TREE_VEC_LENGTH (parm_list); ++n)
+ {
+ tree parm = TREE_VEC_ELT (parm_list, n);
+ TREE_VEC_ELT (check_args, n) = template_parm_to_arg (parm);
+ }
+
+ /* If the template expects more parameters we should be able
+ to use the defaults from our deduced concept. */
+ for (; n < TREE_VEC_LENGTH (parms); ++n)
+ TREE_VEC_ELT (check_args, n) = TREE_VEC_ELT (parms, n);
+
+ /* Associate the constraint. */
+ tree check = build_concept_check (tmpl_decl, NULL_TREE, check_args);
+ tree constr = make_predicate_constraint (check);
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = constr;
+
+ return parm_list;
+}
+
+
+/* Make a "constrained auto" type-specifier. This is an
+ auto type with constraints that must be associated after
+ deduction. The constraint is formed from the given
+ CONC and its optional sequence of arguments, which are
+ non-null if written as partial-concept-id. */
+tree
+make_constrained_auto (tree con, tree args)
+{
+ tree type = make_auto();
+
+ /* Build the constraint. */
+ tree tmpl = DECL_TI_TEMPLATE (con);
+ tree expr;
+ if (VAR_P (con))
+ expr = build_concept_check (tmpl, type, args);
+ else
+ expr = build_concept_check (build_overload (tmpl, NULL_TREE), type, args);
+
+ tree constr = make_predicate_constraint (expr);
+ PLACEHOLDER_TYPE_CONSTRAINTS (type) = constr;
+
+ /* Attach the constraint to the type declaration. */
+ tree decl = TYPE_NAME (type);
+ return decl;
+}
+
+
+/*---------------------------------------------------------------------------
+ Constraint substitution
+---------------------------------------------------------------------------*/
+
+/* The following functions implement substitution rules for constraints.
+ Substitution without checking constraints happens only in the
+ instantiation of class templates. For example:
+
+ template<C1 T> struct S {
+ void f(T) requires C2<T>;
+ void g(T) requires T::value;
+ };
+
+ S<int> s; // error instantiating S<int>::g(T)
+
+ When we instantiate S, we substitute into its member declarations,
+ including their constraints. However, those constraints are not
+ checked. Substituting int into C2<T> yields C2<int>, and substituting
+ into T::value yields a substitution failure, making the program
+ ill-formed.
+
+ Note that we only ever substitute into the associated constraints
+ of a declaration. That is, substitution is defined only for predicate
+ constraints and conjunctions. */
+
+/* Substitute into the predicate constraints. Returns error_mark_node
+ if the substitution into the expression fails. */
+tree
+tsubst_predicate_constraint (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ tree expr = PRED_CONSTR_EXPR (t);
+ ++processing_template_decl;
+ tree result = tsubst_expr (expr, args, complain, in_decl, false);
+ --processing_template_decl;
+ return build_nt (PRED_CONSTR, result);
+}
+
+/* Substitute into the conjunction of constraints. Returns
+ error_mark_node if substitution into either operand fails. */
+tree
+tsubst_conjunction (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ tree t0 = TREE_OPERAND (t, 0);
+ tree r0 = tsubst_constraint (t0, args, complain, in_decl);
+ tree t1 = TREE_OPERAND (t, 1);
+ tree r1 = tsubst_constraint (t1, args, complain, in_decl);
+ return build_nt (CONJ_CONSTR, r0, r1);
+}
+
+/* Substitute ARGS into the constraint T. */
+tree
+tsubst_constraint (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ if (t == NULL_TREE)
+ return t;
+ if (TREE_CODE (t) == CONJ_CONSTR)
+ return tsubst_conjunction (t, args, complain, in_decl);
+ else if (TREE_CODE (t) == PRED_CONSTR)
+ return tsubst_predicate_constraint (t, args, complain, in_decl);
+ else
+ gcc_unreachable ();
+ return error_mark_node;
+}
+
+namespace {
+
+/* A subroutine of tsubst_constraint_variables. Register local
+ specializations for each of parameter in PARMS and its
+ corresponding substituted constraint variable in VARS.
+ Returns VARS. */
+tree
+declare_constraint_vars (tree parms, tree vars)
+{
+ tree s = vars;
+ for (tree t = parms; t; t = DECL_CHAIN (t))
+ {
+ if (DECL_PACK_P (t))
+ {
+ tree pack = extract_fnparm_pack (t, &s);
+ register_local_specialization (pack, t);
+ }
+ else
+ {
+ register_local_specialization (s, t);
+ s = DECL_CHAIN (s);
+ }
+ }
+ return vars;
+}
+
+/* A subroutine of tsubst_parameterized_constraint. Substitute ARGS
+ into the parameter list T, producing a sequence of constraint
+ variables, declared in the current scope.
+
+ Note that the caller must establish a local specialization stack
+ prior to calling this function since this substitution will
+ declare the substituted parameters. */
+tree
+tsubst_constraint_variables (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ /* Clear cp_unevaluated_operand across tsubst so that we get a proper chain
+ of PARM_DECLs. */
+ int saved_unevaluated_operand = cp_unevaluated_operand;
+ cp_unevaluated_operand = 0;
+ tree vars = tsubst (t, args, complain, in_decl);
+ cp_unevaluated_operand = saved_unevaluated_operand;
+ if (vars == error_mark_node)
+ return error_mark_node;
+ return declare_constraint_vars (t, vars);
+}
+
+/* Substitute ARGS into the simple requirement T. Note that
+ substitution may result in an ill-formed expression without
+ causing the program to be ill-formed. In such cases, the
+ requirement wraps an error_mark_node. */
+inline tree
+tsubst_simple_requirement (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ ++processing_template_decl;
+ tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
+ --processing_template_decl;
+ return finish_simple_requirement (expr);
+}
+
+/* Substitute ARGS into the type requirement T. Note that
+ substitution may result in an ill-formed type without
+ causing the program to be ill-formed. In such cases, the
+ requirement wraps an error_mark_node. */
+
+inline tree
+tsubst_type_requirement (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ ++processing_template_decl;
+ tree type = tsubst (TREE_OPERAND (t, 0), args, complain, in_decl);
+ --processing_template_decl;
+ return finish_type_requirement (type);
+}
+
+/* Substitute args into the compound requirement T. If substituting
+ into either the expression or the type fails, the corresponding
+ operands in the resulting node will be error_mark_node. This
+ preserves a requirement for the purpose of partial ordering, but
+ it will never be satisfied. */
+
+tree
+tsubst_compound_requirement (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ ++processing_template_decl;
+ tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
+ tree type = tsubst (TREE_OPERAND (t, 1), args, complain, in_decl);
+ --processing_template_decl;
+ bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t);
+ return finish_compound_requirement (expr, type, noexcept_p);
+}
+
+/* Substitute ARGS into the nested requirement T. */
+
+tree
+tsubst_nested_requirement (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ ++processing_template_decl;
+ tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
+ --processing_template_decl;
+ return finish_nested_requirement (expr);
+}
+
+inline tree
+tsubst_requirement (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ switch (TREE_CODE (t))
+ {
+ case SIMPLE_REQ:
+ return tsubst_simple_requirement (t, args, complain, in_decl);
+ case TYPE_REQ:
+ return tsubst_type_requirement (t, args, complain, in_decl);
+ case COMPOUND_REQ:
+ return tsubst_compound_requirement (t, args, complain, in_decl);
+ case NESTED_REQ:
+ return tsubst_nested_requirement (t, args, complain, in_decl);
+ default:
+ gcc_unreachable ();
+ }
+ return error_mark_node;
+}
+
+/* Substitute ARGS into the list of requirements T. Note that
+ substitution failures here result in ill-formed programs. */
+
+tree
+tsubst_requirement_body (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ tree r = NULL_TREE;
+ while (t)
+ {
+ tree e = tsubst_requirement (TREE_VALUE (t), args, complain, in_decl);
+ if (e == error_mark_node)
+ return error_mark_node;
+ r = tree_cons (NULL_TREE, e, r);
+ t = TREE_CHAIN (t);
+ }
+ return r;
+}
+
+} /* namespace */
+
+/* Substitute ARGS into the requires expression T. Note that this
+ results in the re-declaration of local parameters when
+ substituting through the parameter list. If either substitution
+ fails, the program is ill-formed. */
+
+tree
+tsubst_requires_expr (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ local_specialization_stack stack;
+
+ tree parms = TREE_OPERAND (t, 0);
+ if (parms)
+ {
+ parms = tsubst_constraint_variables (parms, args, complain, in_decl);
+ if (parms == error_mark_node)
+ return error_mark_node;
+ }
+
+ tree reqs = TREE_OPERAND (t, 1);
+ reqs = tsubst_requirement_body (reqs, args, complain, in_decl);
+ if (reqs == error_mark_node)
+ return error_mark_node;
+
+ return finish_requires_expr (parms, reqs);
+}
+
+/* Substitute ARGS into the constraint information CI, producing a new
+ constraint record. */
+tree
+tsubst_constraint_info (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ if (!t || t == error_mark_node || !check_constraint_info (t))
+ return NULL_TREE;
+
+ tree tmpl_constr = NULL_TREE;
+ if (tree r = CI_TEMPLATE_REQS (t))
+ tmpl_constr = tsubst_constraint (r, args, complain, in_decl);
+
+ tree decl_constr = NULL_TREE;
+ if (tree r = CI_DECLARATOR_REQS (t))
+ decl_constr = tsubst_constraint (r, args, complain, in_decl);
+
+ return build_constraints (tmpl_constr, decl_constr);
+}
+
+
+/*---------------------------------------------------------------------------
+ Constraint satisfaction
+---------------------------------------------------------------------------*/
+
+/* The following functions determine if a constraint, when
+ substituting template arguments, is satisfied. For convenience,
+ satisfaction reduces a constraint to either true or false (and
+ nothing else). */
+
+namespace {
+
+tree satisfy_constraint_1 (tree, tree, tsubst_flags_t, tree);
+
+/* Check the constraint pack expansion. */
+
+tree
+satisfy_pack_expansion (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ /* Get the vector of satisfaction results.
+ gen_elem_of_pack_expansion_instantiation will check that each element of
+ the expansion is satisfied. */
+ tree exprs = tsubst_pack_expansion (t, args, complain, in_decl);
+ if (exprs == error_mark_node)
+ return boolean_false_node;
+ int n = TREE_VEC_LENGTH (exprs);
+
+ for (int i = 0; i < n; ++i)
+ if (TREE_VEC_ELT (exprs, i) != boolean_true_node)
+ return boolean_false_node;
+ return boolean_true_node;
+}
+
+/* A predicate constraint is satisfied if its expression evaluates
+ to true. If substitution into that node fails, the constraint
+ is not satisfied ([temp.constr.pred]).
+
+ Note that a predicate constraint is a constraint expression
+ of type bool. If neither of those are true, the program is
+ ill-formed; they are not SFINAE'able errors. */
+
+tree
+satisfy_predicate_constraint (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ tree original = TREE_OPERAND (t, 0);
+
+ /* We should never have a naked pack expansion in a predicate constraint. */
+ gcc_assert (TREE_CODE (original) != EXPR_PACK_EXPANSION);
+
+ tree expr = tsubst_expr (original, args, complain, in_decl, false);
+ if (expr == error_mark_node)
+ return boolean_false_node;
+
+ /* A predicate constraint shall have type bool. In some
+ cases, substitution gives us const-qualified bool, which
+ is also acceptable. */
+ tree type = cv_unqualified (TREE_TYPE (expr));
+ if (!same_type_p (type, boolean_type_node))
+ {
+ error_at (EXPR_LOC_OR_LOC (expr, input_location),
+ "constraint %qE does not have type %qT",
+ expr, boolean_type_node);
+ return boolean_false_node;
+ }
+
+ tree value = cxx_constant_value (expr);
+ return value;
+}
+
+/* Check an expression constraint. The constraint is satisfied if
+ substitution succeeds ([temp.constr.expr]).
+
+ Note that the expression is unevaluated. */
+
+tree
+satisfy_expression_constraint (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ cp_unevaluated guard;
+ deferring_access_check_sentinel deferring;
+
+ tree expr = EXPR_CONSTR_EXPR (t);
+ tree check = tsubst_expr (expr, args, complain, in_decl, false);
+ if (check == error_mark_node)
+ return boolean_false_node;
+ if (!perform_deferred_access_checks (tf_none))
+ return boolean_false_node;
+
+ return boolean_true_node;
+}
+
+/* Check a type constraint. The constraint is satisfied if
+ substitution succeeds. */
+
+inline tree
+satisfy_type_constraint (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ deferring_access_check_sentinel deferring;
+ tree type = TYPE_CONSTR_TYPE (t);
+ gcc_assert (TYPE_P (type) || type == error_mark_node);
+ tree check = tsubst (type, args, complain, in_decl);
+ if (error_operand_p (check))
+ return boolean_false_node;
+ if (!perform_deferred_access_checks (complain))
+ return boolean_false_node;
+
+ return boolean_true_node;
+}
+
+/* Check an implicit conversion constraint. */
+
+tree
+satisfy_implicit_conversion_constraint (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ /* Don't tsubst as if we're processing a template. If we try
+ to we can end up generating template-like expressions
+ (e.g., modop-exprs) that aren't properly typed. */
+ tree expr =
+ tsubst_expr (ICONV_CONSTR_EXPR (t), args, complain, in_decl, false);
+ if (expr == error_mark_node)
+ return boolean_false_node;
+
+ /* Get the transformed target type. */
+ tree type = tsubst (ICONV_CONSTR_TYPE (t), args, complain, in_decl);
+ if (type == error_mark_node)
+ return boolean_false_node;
+
+ /* Attempt the conversion as a direct initialization
+ of the form TYPE <unspecified> = EXPR. */
+ tree conv =
+ perform_direct_initialization_if_possible (type, expr, false, complain);
+ if (conv == error_mark_node)
+ return boolean_false_node;
+ else
+ return boolean_true_node;
+}
+
+/* Check an argument deduction constraint. */
+
+tree
+satisfy_argument_deduction_constraint (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ /* Substitute through the expression. */
+ tree expr = DEDUCT_CONSTR_EXPR (t);
+ tree init = tsubst_expr (expr, args, complain, in_decl, false);
+ if (expr == error_mark_node)
+ return boolean_false_node;
+
+ /* Perform auto or decltype(auto) deduction to get the result. */
+ tree pattern = DEDUCT_CONSTR_PATTERN (t);
+ tree placeholder = DEDUCT_CONSTR_PLACEHOLDER (t);
+ tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (placeholder);
+ PLACEHOLDER_TYPE_CONSTRAINTS (placeholder)
+ = tsubst_constraint (constr, args, complain|tf_partial, in_decl);
+ tree type = do_auto_deduction (pattern, init, placeholder,
+ complain, adc_requirement);
+ PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) = constr;
+ if (type == error_mark_node)
+ return boolean_false_node;
+
+ return boolean_true_node;
+}
+
+/* Check an exception constraint. An exception constraint for an
+ expression e is satisfied when noexcept(e) is true. */
+
+tree
+satisfy_exception_constraint (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ tree expr = EXCEPT_CONSTR_EXPR (t);
+ tree check = tsubst_expr (expr, args, complain, in_decl, false);
+ if (check == error_mark_node)
+ return boolean_false_node;
+
+ if (expr_noexcept_p (check, complain))
+ return boolean_true_node;
+ else
+ return boolean_false_node;
+}
+
+/* Check a parameterized constraint. */
+
+tree
+satisfy_parameterized_constraint (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ local_specialization_stack stack;
+ tree parms = PARM_CONSTR_PARMS (t);
+ tree vars = tsubst_constraint_variables (parms, args, complain, in_decl);
+ if (vars == error_mark_node)
+ return boolean_false_node;
+ tree constr = PARM_CONSTR_OPERAND (t);
+ return satisfy_constraint_1 (constr, args, complain, in_decl);
+}
+
+/* Check that the conjunction of constraints is satisfied. Note
+ that if left operand is not satisfied, the right operand
+ is not checked.
+
+ FIXME: Check that this wouldn't result in a user-defined
+ operator. Note that this error is partially diagnosed in
+ satisfy_predicate_constraint. It would be nice to diagnose
+ the overload, but I don't think it's strictly necessary. */
+
+tree
+satisfy_conjunction (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ tree t0 = satisfy_constraint_1 (TREE_OPERAND (t, 0), args, complain, in_decl);
+ if (t0 == boolean_false_node)
+ return t0;
+ tree t1 = satisfy_constraint_1 (TREE_OPERAND (t, 1), args, complain, in_decl);
+ if (t1 == boolean_false_node)
+ return t1;
+ return boolean_true_node;
+}
+
+/* Check that the disjunction of constraints is satisfied. Note
+ that if the left operand is satisfied, the right operand is not
+ checked. */
+
+tree
+satisfy_disjunction (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ tree t0 = satisfy_constraint_1 (TREE_OPERAND (t, 0), args, complain, in_decl);
+ if (t0 == boolean_true_node)
+ return boolean_true_node;
+ tree t1 = satisfy_constraint_1 (TREE_OPERAND (t, 1), args, complain, in_decl);
+ if (t1 == boolean_true_node)
+ return boolean_true_node;
+ return boolean_false_node;
+}
+
+/* Dispatch to an appropriate satisfaction routine depending on the
+ tree code of T. */
+
+tree
+satisfy_constraint_1 (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ gcc_assert (!processing_template_decl);
+
+ if (!t)
+ return boolean_false_node;
+
+ if (t == error_mark_node)
+ return boolean_false_node;
+
+ switch (TREE_CODE (t))
+ {
+ case PRED_CONSTR:
+ return satisfy_predicate_constraint (t, args, complain, in_decl);
+
+ case EXPR_CONSTR:
+ return satisfy_expression_constraint (t, args, complain, in_decl);
+
+ case TYPE_CONSTR:
+ return satisfy_type_constraint (t, args, complain, in_decl);
+
+ case ICONV_CONSTR:
+ return satisfy_implicit_conversion_constraint (t, args, complain, in_decl);
+
+ case DEDUCT_CONSTR:
+ return satisfy_argument_deduction_constraint (t, args, complain, in_decl);
+
+ case EXCEPT_CONSTR:
+ return satisfy_exception_constraint (t, args, complain, in_decl);
+
+ case PARM_CONSTR:
+ return satisfy_parameterized_constraint (t, args, complain, in_decl);
+
+ case CONJ_CONSTR:
+ return satisfy_conjunction (t, args, complain, in_decl);
+
+ case DISJ_CONSTR:
+ return satisfy_disjunction (t, args, complain, in_decl);
+
+ case EXPR_PACK_EXPANSION:
+ return satisfy_pack_expansion (t, args, complain, in_decl);
+
+ default:
+ gcc_unreachable ();
+ }
+ return boolean_false_node;
+}
+
+/* Check that the constraint is satisfied, according to the rules
+ for that constraint. Note that each satisfy_* function returns
+ true or false, depending on whether it is satisfied or not. */
+
+tree
+satisfy_constraint (tree t, tree args)
+{
+ /* Turn off template processing. Constraint satisfaction only applies
+ to non-dependent terms, so we want full checking here. */
+ processing_template_decl_sentinel sentinel (true);
+ /* Avoid early exit in tsubst and tsubst_copy from null args; since earlier
+ substitution was done with processing_template_decl forced on, there will
+ be expressions that still need semantic processing, possibly buried in
+ decltype or a template argument. */
+ if (args == NULL_TREE)
+ args = make_tree_vec (1);
+ return satisfy_constraint_1 (t, args, tf_none, NULL_TREE);
+}
+
+/* Check the associated constraints in CI against the given
+ ARGS, returning true when the constraints are satisfied
+ and false otherwise. */
+
+tree
+satisfy_associated_constraints (tree ci, tree args)
+{
+ /* If there are no constraints then this is trivially satisfied. */
+ if (!ci)
+ return boolean_true_node;
+
+ /* If any arguments depend on template parameters, we can't
+ check constraints. */
+ if (args && uses_template_parms (args))
+ return boolean_true_node;
+
+ /* Invalid requirements cannot be satisfied. */
+ if (!valid_constraints_p (ci))
+ return boolean_false_node;
+
+ return satisfy_constraint (CI_NORMALIZED_CONSTRAINTS (ci), args);
+}
+
+} /* namespace */
+
+/* Evaluate the given constraint, returning boolean_true_node
+ if the constraint is satisfied and boolean_false_node
+ otherwise. */
+
+tree
+evaluate_constraints (tree constr, tree args)
+{
+ gcc_assert (constraint_p (constr));
+ return satisfy_constraint (normalize_constraint (constr), args);
+}
+
+/* Evaluate the function concept FN by substituting its own args
+ into its definition and evaluating that as the result. Returns
+ boolean_true_node if the constraints are satisfied and
+ boolean_false_node otherwise. */
+
+tree
+evaluate_function_concept (tree fn, tree args)
+{
+ ++processing_template_decl;
+ /* We lift using DECL_TI_ARGS because we want to delay producing
+ non-dependent expressions until we're doing satisfaction. We can't just
+ go without any substitution because we need to lower the level of 'auto's
+ in type deduction constraints. */
+ tree constr = transform_expression (lift_function_definition
+ (fn, DECL_TI_ARGS (fn)));
+ --processing_template_decl;
+ return satisfy_constraint (constr, args);
+}
+
+/* Evaluate the variable concept VAR by substituting its own args into
+ its initializer and checking the resulting constraint. Returns
+ boolean_true_node if the constraints are satisfied and
+ boolean_false_node otherwise. */
+
+tree
+evaluate_variable_concept (tree decl, tree args)
+{
+ ++processing_template_decl;
+ tree constr = transform_expression (lift_variable_initializer
+ (decl, DECL_TI_ARGS (decl)));
+ --processing_template_decl;
+ return satisfy_constraint (constr, args);
+}
+
+/* Evaluate the given expression as if it were a predicate
+ constraint. Returns boolean_true_node if the constraint
+ is satisfied and boolean_false_node otherwise. */
+
+tree
+evaluate_constraint_expression (tree expr, tree args)
+{
+ ++processing_template_decl;
+ tree constr = transform_expression (lift_expression (expr));
+ --processing_template_decl;
+ return satisfy_constraint (constr, args);
+}
+
+/* Returns true if the DECL's constraints are satisfied.
+ This is used in cases where a declaration is formed but
+ before it is used (e.g., overload resolution). */
+
+bool
+constraints_satisfied_p (tree decl)
+{
+ /* Get the constraints to check for satisfaction. This depends
+ on whether we're looking at a template specialization or not. */
+ tree ci;
+ tree args = NULL_TREE;
+ if (tree ti = DECL_TEMPLATE_INFO (decl))
+ {
+ ci = get_constraints (TI_TEMPLATE (ti));
+ args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti));
+ }
+ else
+ {
+ ci = get_constraints (decl);
+ }
+
+ tree eval = satisfy_associated_constraints (ci, args);
+ return eval == boolean_true_node;
+}
+
+/* Returns true if the constraints are satisfied by ARGS.
+ Here, T can be either a constraint or a constrained
+ declaration. */
+
+bool
+constraints_satisfied_p (tree t, tree args)
+{
+ tree eval;
+ if (constraint_p (t))
+ eval = evaluate_constraints (t, args);
+ else
+ eval = satisfy_associated_constraints (get_constraints (t), args);
+ return eval == boolean_true_node;
+}
+
+namespace
+{
+
+/* Normalize EXPR and determine if the resulting constraint is
+ satisfied by ARGS. Returns true if and only if the constraint
+ is satisfied. This is used extensively by diagnostics to
+ determine causes for failure. */
+
+inline bool
+constraint_expression_satisfied_p (tree expr, tree args)
+{
+ return evaluate_constraint_expression (expr, args) == boolean_true_node;
+}
+
+} /* namespace */
+
+
+/*---------------------------------------------------------------------------
+ Semantic analysis of requires-expressions
+---------------------------------------------------------------------------*/
+
+/* Finish a requires expression for the given PARMS (possibly
+ null) and the non-empty sequence of requirements. */
+tree
+finish_requires_expr (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);
+ TREE_SIDE_EFFECTS (r) = false;
+ TREE_CONSTANT (r) = true;
+ return r;
+}
+
+/* Construct a requirement for the validity of EXPR. */
+tree
+finish_simple_requirement (tree expr)
+{
+ return build_nt (SIMPLE_REQ, expr);
+}
+
+/* Construct a requirement for the validity of TYPE. */
+tree
+finish_type_requirement (tree type)
+{
+ return build_nt (TYPE_REQ, type);
+}
+
+/* Construct a requirement for the validity of EXPR, along with
+ its properties. if TYPE is non-null, then it specifies either
+ an implicit conversion or argument deduction constraint,
+ depending on whether any placeholders occur in the type name.
+ NOEXCEPT_P is true iff the noexcept keyword was specified. */
+tree
+finish_compound_requirement (tree expr, tree type, bool noexcept_p)
+{
+ tree req = build_nt (COMPOUND_REQ, expr, type);
+ COMPOUND_REQ_NOEXCEPT_P (req) = noexcept_p;
+ return req;
+}
+
+/* Finish a nested requirement. */
+tree
+finish_nested_requirement (tree expr)
+{
+ return build_nt (NESTED_REQ, expr);
+}
+
+// Check that FN satisfies the structural requirements of a
+// function concept definition.
+tree
+check_function_concept (tree fn)
+{
+ // Check that the function is comprised of only a single
+ // return statement.
+ tree body = DECL_SAVED_TREE (fn);
+ if (TREE_CODE (body) == BIND_EXPR)
+ body = BIND_EXPR_BODY (body);
+
+ // Sometimes a function call results in the creation of clean up
+ // points. Allow these to be preserved in the body of the
+ // constraint, as we might actually need them for some constexpr
+ // evaluations.
+ if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
+ body = TREE_OPERAND (body, 0);
+
+ /* Check that the definition is written correctly. */
+ if (TREE_CODE (body) != RETURN_EXPR)
+ {
+ location_t loc = DECL_SOURCE_LOCATION (fn);
+ if (TREE_CODE (body) == STATEMENT_LIST && !STATEMENT_LIST_HEAD (body))
+ error_at (loc, "definition of concept %qD is empty", fn);
+ else
+ error_at (loc, "definition of concept %qD has multiple statements", 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
+---------------------------------------------------------------------------*/
+
+/* Returns true when A and B are equivalent constraints. */
+bool
+equivalent_constraints (tree a, tree b)
+{
+ gcc_assert (!a || TREE_CODE (a) == CONSTRAINT_INFO);
+ gcc_assert (!b || TREE_CODE (b) == CONSTRAINT_INFO);
+ return cp_tree_equal (a, b);
+}
+
+/* Returns true if the template declarations A and B have equivalent
+ constraints. This is the case when A's constraints subsume B's and
+ when B's also constrain A's. */
+bool
+equivalently_constrained (tree d1, tree d2)
+{
+ gcc_assert (TREE_CODE (d1) == TREE_CODE (d2));
+ return equivalent_constraints (get_constraints (d1), get_constraints (d2));
+}
+
+/*---------------------------------------------------------------------------
+ Partial ordering of constraints
+---------------------------------------------------------------------------*/
+
+/* Returns true when the 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);
+}
+
+/* Determines which of the declarations, A or B, is more constrained.
+ That is, which declaration's constraints subsume but are not subsumed
+ by the other's?
+
+ Returns 1 if A is more constrained than B, -1 if B is more constrained
+ than A, and 0 otherwise. */
+int
+more_constrained (tree d1, tree d2)
+{
+ tree c1 = get_constraints (d1);
+ tree c2 = get_constraints (d2);
+ int winner = 0;
+ if (subsumes_constraints (c1, c2))
+ ++winner;
+ if (subsumes_constraints (c2, c1))
+ --winner;
+ return winner;
+}
+
+/* Returns true if D1 is at least as constrained as D2. That is, the
+ associated constraints of D1 subsume those of D2, or both declarations
+ are unconstrained. */
+bool
+at_least_as_constrained (tree d1, tree d2)
+{
+ tree c1 = get_constraints (d1);
+ tree c2 = get_constraints (d2);
+ return subsumes_constraints (c1, c2);
+}
+
+
+/*---------------------------------------------------------------------------
+ Constraint diagnostics
+---------------------------------------------------------------------------*/
+
+/* The diagnosis of constraints performs a combination of
+ normalization and satisfaction testing. We recursively
+ walk through the conjunction (or disjunctions) of associated
+ constraints, testing each sub-expression in turn.
+
+ We currently restrict diagnostics to just the top-level
+ conjunctions within the associated constraints. A fully
+ recursive walk is possible, but it can generate a lot
+ of errors. */
+
+
+namespace {
+
+void diagnose_expression (location_t, tree, tree);
+void diagnose_constraint (location_t, tree, tree);
+
+/* Diagnose a conjunction of constraints. */
+void
+diagnose_logical_operation (location_t loc, tree t, tree args)
+{
+ diagnose_expression (loc, TREE_OPERAND (t, 0), args);
+ diagnose_expression (loc, TREE_OPERAND (t, 0), args);
+}
+
+/* Determine if the trait expression T is satisfied by ARGS.
+ Emit a precise diagnostic if it is not. */
+void
+diagnose_trait_expression (location_t loc, tree t, tree args)
+{
+ if (constraint_expression_satisfied_p (t, args))
+ return;
+
+ /* Rebuild the trait expression so we can diagnose the
+ specific failure. */
+ ++processing_template_decl;
+ tree expr = tsubst_expr (t, args, tf_none, NULL_TREE, false);
+ --processing_template_decl;
+
+ tree t1 = TRAIT_EXPR_TYPE1 (expr);
+ tree t2 = TRAIT_EXPR_TYPE2 (expr);
+ switch (TRAIT_EXPR_KIND (t))
+ {
+ case CPTK_HAS_NOTHROW_ASSIGN:
+ inform (loc, " %qT is not nothrow copy assignable", t1);
+ break;
+ case CPTK_HAS_NOTHROW_CONSTRUCTOR:
+ inform (loc, " %qT is not nothrow default constructible", t1);
+ break;
+ case CPTK_HAS_NOTHROW_COPY:
+ inform (loc, " %qT is not nothrow copy constructible", t1);
+ break;
+ case CPTK_HAS_TRIVIAL_ASSIGN:
+ inform (loc, " %qT is not trivially copy assignable", t1);
+ break;
+ case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+ inform (loc, " %qT is not trivially default constructible", t1);
+ break;
+ case CPTK_HAS_TRIVIAL_COPY:
+ inform (loc, " %qT is not trivially copy constructible", t1);
+ break;
+ case CPTK_HAS_TRIVIAL_DESTRUCTOR:
+ inform (loc, " %qT is not trivially destructible", t1);
+ break;
+ case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+ inform (loc, " %qT does not have a virtual destructor", t1);
+ break;
+ case CPTK_IS_ABSTRACT:
+ inform (loc, " %qT is not an abstract class", t1);
+ break;
+ case CPTK_IS_BASE_OF:
+ inform (loc, " %qT is not a base of %qT", t1, t2);
+ break;
+ case CPTK_IS_CLASS:
+ inform (loc, " %qT is not a class", t1);
+ break;
+ case CPTK_IS_EMPTY:
+ inform (loc, " %qT is not an empty class", t1);
+ break;
+ case CPTK_IS_ENUM:
+ inform (loc, " %qT is not an enum", t1);
+ break;
+ case CPTK_IS_FINAL:
+ inform (loc, " %qT is not a final class", t1);
+ break;
+ case CPTK_IS_LITERAL_TYPE:
+ inform (loc, " %qT is not a literal type", t1);
+ break;
+ case CPTK_IS_POD:
+ inform (loc, " %qT is not a POD type", t1);
+ break;
+ case CPTK_IS_POLYMORPHIC:
+ inform (loc, " %qT is not a polymorphic type", t1);
+ break;
+ case CPTK_IS_SAME_AS:
+ inform (loc, " %qT is not the same as %qT", t1, t2);
+ break;
+ case CPTK_IS_STD_LAYOUT:
+ inform (loc, " %qT is not an standard layout type", t1);
+ break;
+ case CPTK_IS_TRIVIAL:
+ inform (loc, " %qT is not a trivial type", t1);
+ break;
+ case CPTK_IS_UNION:
+ inform (loc, " %qT is not a union", t1);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Determine if the call expression T, when normalized as a constraint,
+ is satisfied by ARGS.
+
+ TODO: If T is refers to a concept, We could recursively analyze
+ its definition to identify the exact failure, but that could
+ emit a *lot* of error messages (defeating the purpose of
+ improved diagnostics). Consider adding a flag to control the
+ depth of diagnostics. */
+void
+diagnose_call_expression (location_t loc, tree t, tree args)
+{
+ if (constraint_expression_satisfied_p (t, args))
+ return;
+
+ /* Rebuild the expression for the purpose of diagnostics. */
+ ++processing_template_decl;
+ tree expr = tsubst_expr (t, args, tf_none, NULL_TREE, false);
+ --processing_template_decl;
+
+ /* If the function call is known to be a concept check, then
+ diagnose it differently (i.e., we may recurse). */
+ if (resolve_constraint_check (t))
+ inform (loc, " concept %qE was not satisfied", expr);
+ else
+ inform (loc, " %qE evaluated to false", expr);
+}
+
+/* Determine if the template-id T, when normalized as a constraint
+ is satisfied by ARGS. */
+void
+diagnose_template_id (location_t loc, tree t, tree args)
+{
+ /* Check for invalid template-ids. */
+ if (!variable_template_p (TREE_OPERAND (t, 0)))
+ {
+ inform (loc, " invalid constraint %qE", t);
+ return;
+ }
+
+ if (constraint_expression_satisfied_p (t, args))
+ return;
+
+ /* Rebuild the expression for the purpose of diagnostics. */
+ ++processing_template_decl;
+ tree expr = tsubst_expr (t, args, tf_none, NULL_TREE, false);
+ --processing_template_decl;
+
+ tree var = DECL_TEMPLATE_RESULT (TREE_OPERAND (t, 0));
+ if (DECL_DECLARED_CONCEPT_P (var))
+ inform (loc, " concept %qE was not satisfied", expr);
+ else
+ inform (loc, " %qE evaluated to false", expr);
+}
+
+/* Determine if the requires-expression, when normalized as a
+ constraint is satisfied by ARGS.
+
+ TODO: Build sets of expressions, types, and constraints
+ based on the requirements in T and emit specific diagnostics
+ for those. */
+void
+diagnose_requires_expression (location_t loc, tree t, tree args)
+{
+ if (constraint_expression_satisfied_p (t, args))
+ return;
+ inform (loc, "requirements not satisfied");
+}
+
+void
+diagnose_pack_expansion (location_t loc, tree t, tree args)
+{
+ if (constraint_expression_satisfied_p (t, args))
+ return;
+
+ /* Make sure that we don't have naked packs that we don't expect. */
+ if (!same_type_p (TREE_TYPE (t), boolean_type_node))
+ {
+ inform (loc, "invalid pack expansion in constraint %qE", t);
+ return;
+ }
+
+ inform (loc, " in the expansion of %qE", t);
+
+ /* Get the vector of expanded arguments. Note that n must not
+ be 0 since this constraint is not satisfied. */
+ ++processing_template_decl;
+ tree exprs = tsubst_pack_expansion (t, args, tf_none, NULL_TREE);
+ --processing_template_decl;
+ if (exprs == error_mark_node)
+ {
+ /* TODO: This error message could be better. */
+ inform (loc, " substitution failure occurred during expansion");
+ return;
+ }
+
+ /* Check each expanded constraint separately. */
+ int n = TREE_VEC_LENGTH (exprs);
+ for (int i = 0; i < n; ++i)
+ {
+ tree expr = TREE_VEC_ELT (exprs, i);
+ if (!constraint_expression_satisfied_p (expr, args))
+ inform (loc, " %qE was not satisfied", expr);
+ }
+}
+
+/* Diagnose an expression that would be characterized as
+ a predicate constraint. */
+void
+diagnose_other_expression (location_t loc, tree t, tree args)
+{
+ if (constraint_expression_satisfied_p (t, args))
+ return;
+ inform (loc, " %qE evaluated to false", t);
+}
+
+void
+diagnose_expression (location_t loc, tree t, tree args)
+{
+ switch (TREE_CODE (t))
+ {
+ case TRUTH_ANDIF_EXPR:
+ diagnose_logical_operation (loc, t, args);
+ break;
+
+ case TRUTH_ORIF_EXPR:
+ diagnose_logical_operation (loc, t, args);
+ break;
+
+ case CALL_EXPR:
+ diagnose_call_expression (loc, t, args);
+ break;
+
+ case TEMPLATE_ID_EXPR:
+ diagnose_template_id (loc, t, args);
+ break;
+
+ case REQUIRES_EXPR:
+ diagnose_requires_expression (loc, t, args);
+ break;
+
+ case TRAIT_EXPR:
+ diagnose_trait_expression (loc, t, args);
+ break;
+
+ case EXPR_PACK_EXPANSION:
+ diagnose_pack_expansion (loc, t, args);
+ break;
+
+ default:
+ diagnose_other_expression (loc, t, args);
+ break;
+ }
+}
+
+inline void
+diagnose_predicate_constraint (location_t loc, tree t, tree args)
+{
+ diagnose_expression (loc, PRED_CONSTR_EXPR (t), args);
+}
+
+inline void
+diagnose_conjunction (location_t loc, tree t, tree args)
+{
+ diagnose_constraint (loc, TREE_OPERAND (t, 0), args);
+ diagnose_constraint (loc, TREE_OPERAND (t, 1), args);
+}
+
+/* Diagnose the constraint T for the given ARGS. This is only
+ ever invoked on the associated constraints, so we can
+ only have conjunctions of predicate constraints. */
+void
+diagnose_constraint (location_t loc, tree t, tree args)
+{
+ switch (TREE_CODE (t))
+ {
+ case CONJ_CONSTR:
+ diagnose_conjunction (loc, t, args);
+ break;
+
+ case PRED_CONSTR:
+ diagnose_predicate_constraint (loc, t, args);
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
+}
+
+/* Diagnose the reason(s) why ARGS do not satisfy the constraints
+ of declaration DECL. */
+
+void
+diagnose_declaration_constraints (location_t loc, tree decl, tree args)
+{
+ inform (loc, " constraints not satisfied");
+
+ /* Constraints are attached to the template. */
+ if (tree ti = DECL_TEMPLATE_INFO (decl))
+ {
+ decl = TI_TEMPLATE (ti);
+ if (!args)
+ args = TI_ARGS (ti);
+ }
+
+ /* Check that the constraints are actually valid. */
+ tree ci = get_constraints (decl);
+ if (!valid_constraints_p (ci))
+ {
+ inform (loc, " invalid constraints");
+ return;
+ }
+
+ /* Recursively diagnose the associated constraints. */
+ diagnose_constraint (loc, CI_ASSOCIATED_CONSTRAINTS (ci), args);
+}
+
+} // namespace
+
+/* Emit diagnostics detailing the failure ARGS to satisfy the
+ constraints of T. Here, T can be either a constraint
+ or a declaration. */
+
+void
+diagnose_constraints (location_t loc, tree t, tree args)
+{
+ if (constraint_p (t))
+ diagnose_constraint (loc, t, args);
+ else
+ diagnose_declaration_constraints (loc, t, args);
+}