Index: error.c
===================================================================
--- error.c (revision 201240)
+++ error.c (working copy)
@@ -57,6 +57,7 @@ static const char *expr_to_string (tree)
static const char *fndecl_to_string (tree, int);
static const char *op_to_string (enum tree_code);
static const char *parm_to_string (int);
+static const char *parms_to_string (tree);
static const char *type_to_string (tree, int);
static void dump_alias_template_specialization (tree, int);
@@ -2589,6 +2590,17 @@ dump_expr (tree t, int flags)
pp_cxx_nested_requirement (cxx_pp, t);
break;
+ case VALIDEXPR_EXPR:
+ pp_cxx_validexpr_expr (cxx_pp, t);
+ break;
+
+ case VALIDTYPE_EXPR:
+ pp_cxx_validtype_expr (cxx_pp, t);
+ break;
+
+ case CONSTEXPR_EXPR:
+ pp_cxx_constexpr_expr (cxx_pp, t);
+
/* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
@@ -2908,7 +2920,7 @@ args_to_string (tree p, int verbose)
int flags = 0;
if (verbose)
flags |= TFF_CLASS_KEY_OR_ENUM;
-
+
if (p == NULL_TREE)
return "";
@@ -2968,6 +2980,14 @@ cv_to_string (tree p, int v)
return pp_formatted_text (cxx_pp);
}
+static const char*
+parms_to_string (tree p)
+{
+ reinit_cxx_pp ();
+ pp_cxx_parameter_declaration_clause (cxx_pp, p);
+ return pp_formatted_text (cxx_pp);
+}
+
/* Langhook for print_error_function. */
void
@@ -3400,6 +3420,7 @@ cp_printer (pretty_printer *pp, text_inf
case 'K':
percent_K_format (text);
return true;
+ case 'Z': result = parms_to_string (next_tree); break;
default:
return false;
Index: logic.cc
===================================================================
--- logic.cc (revision 201240)
+++ logic.cc (working copy)
@@ -1,4 +1,4 @@
-/* Process declarations and variables for C++ compiler.
+/* Derivation and subsumption rules for constraints.
Copyright (C) 2013 Free Software Foundation, Inc.
Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
@@ -18,8 +18,7 @@ You should have received a copy of the G
along with GCC; see the file COPYING3. If not see
. */
-// Algorithms and data structures for the decomposition and validation
-// of logical formulas.
+//
#include "config.h"
#include "system.h"
Index: cxx-pretty-print.c
===================================================================
--- cxx-pretty-print.c (revision 201240)
+++ cxx-pretty-print.c (working copy)
@@ -42,7 +42,6 @@ static void pp_cxx_ptr_operator (cxx_pre
static void pp_cxx_type_id (cxx_pretty_printer *, tree);
static void pp_cxx_direct_abstract_declarator (cxx_pretty_printer *, tree);
static void pp_cxx_declarator (cxx_pretty_printer *, tree);
-static void pp_cxx_parameter_declaration_clause (cxx_pretty_printer *, tree);
static void pp_cxx_abstract_declarator (cxx_pretty_printer *, tree);
static void pp_cxx_statement (cxx_pretty_printer *, tree);
static void pp_cxx_template_parameter (cxx_pretty_printer *, tree);
@@ -480,6 +479,18 @@ pp_cxx_primary_expression (cxx_pretty_pr
pp_cxx_nested_requirement (pp, t);
break;
+ case VALIDEXPR_EXPR:
+ pp_cxx_validexpr_expr (pp, t);
+ break;
+
+ case VALIDTYPE_EXPR:
+ pp_cxx_validtype_expr (pp, t);
+ break;
+
+ case CONSTEXPR_EXPR:
+ pp_cxx_constexpr_expr (pp, t);
+ break;
+
default:
pp_c_primary_expression (pp_c_base (pp), t);
break;
@@ -1450,14 +1461,29 @@ pp_cxx_parameter_declaration (cxx_pretty
parameter-declaration
parameter-declaration-list , parameter-declaration */
-static void
+void
pp_cxx_parameter_declaration_clause (cxx_pretty_printer *pp, tree t)
{
- tree args = TYPE_P (t) ? NULL : FUNCTION_FIRST_USER_PARM (t);
- tree types =
- TYPE_P (t) ? TYPE_ARG_TYPES (t) : FUNCTION_FIRST_USER_PARMTYPE (t);
- const bool abstract = args == NULL
- || pp_c_base (pp)->flags & pp_c_flag_abstract;
+ tree args;
+ tree types;
+ bool abstract;
+
+ // For a requires clause or the explicit printing of a parameter list
+ // we expect T to be a TREE_LIST of PARM_DECLs. Otherwise, the list of
+ // args and types are taken from the function decl T.
+ if (TREE_CODE (t) == TREE_LIST)
+ {
+ args = TREE_VALUE (t);
+ types = TREE_VALUE (t);
+ abstract = false;
+ }
+ else
+ {
+ bool type_p = TYPE_P (t);
+ args = type_p ? NULL : FUNCTION_FIRST_USER_PARM (t);
+ types = type_p ? TYPE_ARG_TYPES (t) : FUNCTION_FIRST_USER_PARMTYPE (t);
+ abstract = args == NULL || pp_c_base (pp)->flags & pp_c_flag_abstract;
+ }
bool first = true;
/* Skip artificial parameter for nonstatic member functions. */
@@ -2486,30 +2512,10 @@ static void
pp_cxx_requirement_body (cxx_pretty_printer *pp, tree t)
{
pp_cxx_left_brace (pp);
- pp_cxx_requirement_list (pp, TREE_OPERAND (t, 1));
+ pp_cxx_requirement_list (pp, t);
pp_cxx_right_brace (pp);
}
-// requirement-parameter-list:
-// '(' parameter-declaration-clause ')'
-static void
-pp_cxx_requirement_parameter_list (cxx_pretty_printer *pp, tree t)
-{
- tree p = TREE_OPERAND (t, 0);
- pp_left_paren (pp);
- while (p)
- {
- tree parm = TREE_VALUE (p);
- pp_cxx_parameter_declaration (pp, parm);
- if (!VOID_TYPE_P (TREE_VALUE (TREE_CHAIN (p))))
- pp_separate_with (pp, ',');
- else
- break;
- p = TREE_CHAIN (p);
- }
- pp_right_paren (pp);
-}
-
// requires-expression:
// 'requires' requirement-parameter-list requirement-body
void
@@ -2517,9 +2523,9 @@ pp_cxx_requires_expr (cxx_pretty_printer
{
pp_cxx_ws_string (pp, "requires");
pp_space (pp);
- pp_cxx_requirement_parameter_list (pp, t);
+ pp_cxx_parameter_declaration_clause(pp, TREE_OPERAND (t, 0));
pp_space (pp);
- pp_cxx_requirement_body (pp, t);
+ pp_cxx_requirement_body (pp, TREE_OPERAND (t, 1));
}
// constraint-specifier:
@@ -2627,6 +2633,33 @@ pp_cxx_nested_requirement (cxx_pretty_pr
pp_cxx_semicolon (pp);
}
+void
+pp_cxx_validexpr_expr (cxx_pretty_printer *pp, tree t)
+{
+ pp_cxx_ws_string (pp, "__is_valid_expr");
+ pp_cxx_left_paren (pp);
+ pp_cxx_expression (pp, TREE_OPERAND (t, 0));
+ pp_cxx_right_paren (pp);
+}
+
+void
+pp_cxx_validtype_expr (cxx_pretty_printer *pp, tree t)
+{
+ pp_cxx_ws_string (pp, "__is_valid_expr");
+ pp_cxx_left_paren (pp);
+ pp_cxx_type_id (pp, TREE_OPERAND (t, 0));
+ pp_cxx_right_paren (pp);
+}
+
+void
+pp_cxx_constexpr_expr (cxx_pretty_printer *pp, tree t)
+{
+ pp_cxx_ws_string (pp, "__is_valid_expr");
+ pp_cxx_left_paren (pp);
+ pp_cxx_expression (pp, TREE_OPERAND (t, 0));
+ pp_cxx_right_paren (pp);
+}
+
typedef c_pretty_print_fn pp_fun;
Index: pt.c
===================================================================
--- pt.c (revision 201240)
+++ pt.c (working copy)
@@ -168,8 +168,6 @@ static tree expand_template_argument_pac
static tree build_template_parm_index (int, int, int, tree, tree);
static bool inline_needs_template_parms (tree);
static void push_inline_template_parms_recursive (tree, int);
-static tree retrieve_local_specialization (tree);
-static void register_local_specialization (tree, tree);
static hashval_t hash_specialization (const void *p);
static tree reduce_template_parm_level (tree, tree, int, tree, tsubst_flags_t);
static int mark_template_parm (tree, void *);
@@ -209,7 +207,6 @@ static int invalid_nontype_parm_type_p (
static bool dependent_template_arg_p (tree);
static bool any_template_arguments_need_structural_equality_p (tree);
static bool dependent_type_p_r (tree);
-static tree tsubst_expr (tree, tree, tsubst_flags_t, tree, bool);
static tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
static tree tsubst_decl (tree, tree, tsubst_flags_t);
@@ -1100,7 +1097,7 @@ retrieve_specialization (tree tmpl, tree
/* Like retrieve_specialization, but for local declarations. */
-static tree
+tree
retrieve_local_specialization (tree tmpl)
{
void **slot;
@@ -1711,7 +1708,7 @@ reregister_specialization (tree spec, tr
/* Like register_specialization, but for local declarations. We are
registering SPEC, an instantiation of TMPL. */
-static void
+void
register_local_specialization (tree spec, tree tmpl)
{
void **slot;
@@ -3908,7 +3905,7 @@ template_parms_to_args (tree parms)
/* Within the declaration of a template, return the currently active
template parameters as an argument TREE_VEC. */
-tree
+static tree
current_template_args (void)
{
return template_parms_to_args (current_template_parms);
@@ -9265,7 +9262,7 @@ tsubst_template_arg (tree t, tree args,
instantiated from it at *SPEC_P, return a NONTYPE_ARGUMENT_PACK of them
and set *SPEC_P to point at the next point in the list. */
-static tree
+tree
extract_fnparm_pack (tree tmpl_parm, tree *spec_p)
{
/* Collect all of the extra "packed" parameters into an
@@ -13012,7 +13009,7 @@ tsubst_omp_for_iterator (tree t, int i,
/* Like tsubst_copy for expressions, etc. but also does semantic
processing. */
-static tree
+tree
tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
bool integral_constant_expression_p)
{
@@ -14788,6 +14785,31 @@ tsubst_copy_and_build (tree t,
RECUR (TREE_OPERAND (t, 2)),
complain));
+ case REQUIRES_EXPR:
+ RETURN (tsubst_requires_expr (t, args, complain, in_decl));
+
+ case VALIDEXPR_EXPR:
+ RETURN (tsubst_validexpr_expr (t, args, in_decl));
+
+ case VALIDTYPE_EXPR:
+ RETURN (tsubst_validtype_expr (t, args, in_decl));
+
+ case CONSTEXPR_EXPR:
+ RETURN (tsubst_constexpr_expr (t, args, in_decl));
+
+ // Normally, *_REQ are reduced out of requiremetns when used
+ // as constraints. If a concept is checked directly via e.g.,
+ // a static_assert, however, these appear in the input tree.
+
+ case EXPR_REQ:
+ RETURN (tsubst_expr_req (t, args, in_decl));
+
+ case TYPE_REQ:
+ RETURN (tsubst_type_req (t, args, in_decl));
+
+ case NESTED_REQ:
+ RETURN (tsubst_nested_req (t, args, in_decl));
+
default:
/* Handle Objective-C++ constructs, if appropriate. */
{
@@ -15394,7 +15416,7 @@ fn_type_unification (tree fn,
if (!check_template_constraints (fn, targs))
{
if (explain_p)
- diagnose_constraint_failure (DECL_SOURCE_LOCATION (fn), fn, targs);
+ diagnose_constraints (DECL_SOURCE_LOCATION (fn), fn, targs);
return error_mark_node;
}
@@ -21360,26 +21382,4 @@ print_template_statistics (void)
htab_collisions (type_specializations));
}
-// Substitute the template arguments ARGS into the requirement
-// expression REQS. Errors resulting from substitution are not
-// diagnosed.
-tree
-instantiate_requirements (tree reqs, tree args)
-{
- return tsubst_expr (reqs, args, tf_none, NULL_TREE, true);
-}
-
-// Create a new constraint info block by substituting ARGS into
-// the requirements of CONS.
-//
-// Note that this does not require evaluation.
-tree
-tsubst_constraint (tree cons, tree args)
-{
- if (!cons)
- return NULL_TREE;
- tree reqs = instantiate_requirements (CI_REQUIREMENTS (cons), args);
- return make_constraints (reqs);
-}
-
#include "gt-cp-pt.h"
Index: cxx-pretty-print.h
===================================================================
--- cxx-pretty-print.h (revision 201240)
+++ cxx-pretty-print.h (working copy)
@@ -76,10 +76,14 @@ void pp_cxx_trait_expression (cxx_pretty
void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
void pp_cxx_userdef_literal (cxx_pretty_printer *, tree);
+void pp_cxx_parameter_declaration_clause (cxx_pretty_printer *, tree);
void pp_cxx_requires_expr (cxx_pretty_printer *, tree);
void pp_cxx_expr_requirement (cxx_pretty_printer *, tree);
void pp_cxx_type_requirement (cxx_pretty_printer *, tree);
void pp_cxx_nested_requirement (cxx_pretty_printer *, tree);
+void pp_cxx_validexpr_expr (cxx_pretty_printer *, tree);
+void pp_cxx_validtype_expr (cxx_pretty_printer *, tree);
+void pp_cxx_constexpr_expr (cxx_pretty_printer *, tree);
#endif /* GCC_CXX_PRETTY_PRINT_H */
Index: semantics.c
===================================================================
--- semantics.c (revision 201240)
+++ semantics.c (working copy)
@@ -8461,6 +8461,13 @@ potential_constant_expression_1 (tree t,
case FIELD_DECL:
case PARM_DECL:
case USING_DECL:
+ case REQUIRES_EXPR:
+ case EXPR_REQ:
+ case TYPE_REQ:
+ case NESTED_REQ:
+ case VALIDEXPR_EXPR:
+ case VALIDTYPE_EXPR:
+ case CONSTEXPR_EXPR:
return true;
case AGGR_INIT_EXPR:
@@ -9118,195 +9125,4 @@ capture_decltype (tree decl)
}
-// Semantics for constraints.
-
-// Finish the template requirement, EXPR, by translating it into
-// a constraint information record.
-tree
-finish_template_requirements (tree expr)
-{
- if (expr == error_mark_node)
- return NULL_TREE;
- else
- return make_constraints (expr);
-}
-
-// Finish a requires expression, returning a node wrapping the parameters,
-// PARMS, and the list of requirements REQS.
-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 marking them constant (so
- // we can actually check constexpr properties).
- for (tree p = parms; p && !VOID_TYPE_P (TREE_VALUE (p)); p = TREE_CHAIN (p))
- {
- tree parm = TREE_VALUE (p);
- DECL_CONTEXT (parm) = NULL_TREE;
- TREE_CONSTANT (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 unary expression that evaluates properties of the
-// expression or type T, and has a boolean result type.
-static inline tree
-build_check_expr (tree_code c, tree t)
-{
- tree r = build_min (c, boolean_type_node, t);
- TREE_SIDE_EFFECTS (r) = false;
- TREE_READONLY (r) = true;
- TREE_CONSTANT (r) = true;
- return r;
-}
-
-// Finish a syntax requirement, constructing a list embodying a sequence
-// of checks for the validity of EXPR and TYPE, the convertibility of
-// EXPR to TYPE, and the expression properties specified in SPECS.
-tree
-finish_expr_requirement (tree expr, tree type, tree specs)
-{
- gcc_assert (processing_template_decl);
-
- // Build a list of checks, starting with the valid expression.
- tree result = tree_cons (NULL_TREE, finish_validexpr_expr (expr), NULL_TREE);
-
- // If a type requirement was provided, build the result type checks.
- if (type)
- {
- // If the type is dependent, ensure that it can be validly
- // instantiated.
- //
- // NOTE: We can also disregard checks that result in the template
- // parameter.
- if (dependent_type_p (type))
- {
- tree treq = finish_type_requirement (type);
- result = tree_cons (NULL_TREE, treq, result);
- }
-
- // Ensure that the result of the expression can be converted to
- // the result type.
- tree decl_type = finish_decltype_type (expr, false, tf_none);
- tree creq = finish_trait_expr (CPTK_IS_CONVERTIBLE_TO, decl_type, type);
- result = tree_cons (NULL_TREE, creq, result);
- }
-
- // If constraint specifiers are present, make them part of the
- // list of constraints.
- if (specs)
- {
- TREE_CHAIN (tree_last (specs)) = result;
- result = specs;
- }
-
- // Finally, construct the syntactic requirement.
- return build_check_expr (EXPR_REQ, nreverse (result));
-}
-
-// Finish a simple syntax requirement, returning a node representing
-// a check that EXPR is a valid expression.
-tree
-finish_expr_requirement (tree expr)
-{
- gcc_assert (processing_template_decl);
- tree req = finish_validexpr_expr (expr);
- return build_check_expr (EXPR_REQ, req);
-}
-
-// Finish a type requirement, returning a node representing a check
-// that TYPE will result in a valid type when instantiated.
-tree
-finish_type_requirement (tree type)
-{
- gcc_assert (processing_template_decl);
- tree req = finish_validtype_epxr (type);
- return build_check_expr (TYPE_REQ, req);
-}
-
-tree
-finish_nested_requirement (tree expr)
-{
- gcc_assert (processing_template_decl);
- return build_check_expr (NESTED_REQ, expr);
-}
-
-// Finish a constexpr requirement, returning a node representing a
-// check that EXPR, when instantiated, may be evaluated at compile time.
-tree
-finish_constexpr_requirement (tree expr)
-{
- gcc_assert (processing_template_decl);
- return finish_constexpr_expr (expr);
-}
-
-// Finish the noexcept requirement by constructing a noexcept
-// expression evaluating EXPR.
-tree
-finish_noexcept_requirement (tree expr)
-{
- gcc_assert (processing_template_decl);
- return finish_noexcept_expr (expr, tf_none);
-}
-
-// Returns the true or false node depending on the truth value of B.
-static inline tree
-truth_node (bool b)
-{
- return b ? boolean_true_node : boolean_false_node;
-}
-
-// Returns a finished validexpr-expr. Returns the true or false node
-// depending on whether EXPR denotes a valid expression. This is the case
-// when the expression has been successfully type checked.
-//
-// When processing a template declaration, the result is an expression
-// representing the check.
-tree
-finish_validexpr_expr (tree expr)
-{
- if (processing_template_decl)
- return build_check_expr (VALIDEXPR_EXPR, expr);
- return truth_node (expr && expr != error_mark_node);
-}
-
-// Returns a finished validtype-expr. Returns the true or false node
-// depending on whether T denotes a valid type name.
-//
-// When processing a template declaration, the result is an expression
-// representing the check.
-tree
-finish_validtype_epxr (tree type)
-{
- if (processing_template_decl)
- return build_check_expr (VALIDTYPE_EXPR, type);
- return truth_node (type && TYPE_P (type));
-}
-
-// Returns a finished constexpr-expr. Returns the true or false node
-// depending on whether the expression T may be evaluated at compile
-// time.
-//
-// When processing a template declaration, the result is an expression
-// representing the check.
-tree
-finish_constexpr_expr (tree expr)
-{
- if (processing_template_decl)
- return build_check_expr (CONSTEXPR_EXPR, expr);
-
- // TODO: Actually check that the expression can be constexpr
- // evaluatd.
- //
- // return truth_node (potential_constant_expression (expr));
- sorry ("constexpr requirement");
- return NULL_TREE;
-}
-
-
#include "gt-cp-semantics.h"
Index: constraint.cc
===================================================================
--- constraint.cc (revision 201240)
+++ constraint.cc (working copy)
@@ -1,4 +1,4 @@
-/* Process declarations and variables for C++ compiler.
+/* Processing rules for constraints.
Copyright (C) 2013 Free Software Foundation, Inc.
Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
@@ -18,8 +18,6 @@ You should have received a copy of the G
along with GCC; see the file COPYING3. If not see
. */
-// Components for processing constraints and evaluating constraints.
-
#include "config.h"
#include "system.h"
#include "coretypes.h"
@@ -188,6 +186,10 @@ static tree reduce_misc (tree);
static tree reduce_logical (tree);
static tree reduce_call (tree);
+static tree reduce_requires (tree);
+static tree reduce_expr_req (tree);
+static tree reduce_type_req (tree);
+static tree reduce_nested_req (tree);
static tree reduce_template_id (tree);
static tree reduce_stmt_list (tree);
@@ -238,6 +240,18 @@ reduce_expr (tree t)
case CALL_EXPR:
return reduce_call (t);
+ case REQUIRES_EXPR:
+ return reduce_requires (t);
+
+ case EXPR_REQ:
+ return reduce_expr_req (t);
+
+ case TYPE_REQ:
+ return reduce_type_req (t);
+
+ case NESTED_REQ:
+ return reduce_nested_req (t);
+
case TEMPLATE_ID_EXPR:
return reduce_template_id (t);
@@ -389,6 +403,43 @@ reduce_template_id (tree t)
return NULL_TREE;
}
+
+// Reduce an expression requirement as a conjunction of its
+// individual constraints.
+tree
+reduce_expr_req (tree t)
+{
+ tree r = NULL_TREE;
+ for (tree l = TREE_OPERAND (t, 0); l; l = TREE_CHAIN (l))
+ r = conjoin_requirements (r, reduce_expr (TREE_VALUE (l)));
+ return r;
+}
+
+// Reduce a type requirement by returing its underlying
+// constraint.
+tree
+reduce_type_req (tree t)
+{
+ return TREE_OPERAND (t, 0);
+}
+
+// Reduce a nested requireemnt by returing its only operand.
+tree
+reduce_nested_req (tree t)
+{
+ return TREE_OPERAND (t, 0);
+}
+
+// Reduce a requires expr by reducing each requirement in turn,
+// rewriting the list of requirements.
+tree
+reduce_requires (tree t)
+{
+ for (tree l = TREE_OPERAND (t, 1); l; l = TREE_CHAIN (l))
+ TREE_VALUE (l) = reduce_expr (TREE_VALUE (l));
+ return t;
+}
+
// Reduction rules for the statement list STMTS.
//
// Recursively reduce each statement in the list, concatenating each
@@ -405,12 +456,7 @@ reduce_stmt_list (tree stmts)
while (!tsi_end_p (i))
{
if (tree rhs = reduce_node (tsi_stmt (i)))
- {
- if (!lhs)
- lhs = rhs;
- else
- lhs = conjoin_requirements (lhs, rhs);
- }
+ lhs = conjoin_requirements (lhs, rhs);
tsi_next (&i);
}
return lhs;
@@ -418,7 +464,6 @@ reduce_stmt_list (tree stmts)
} // end namespace
-
// Reduce the requirement REQS into a logical formula written in terms of
// atomic propositions.
tree
@@ -427,6 +472,12 @@ reduce_requirements (tree reqs)
return reduce_node (reqs);
}
+// -------------------------------------------------------------------------- //
+// Constraint Semantic Processing
+//
+// The following functions are called by the parser and substitution rules
+// to create and evaluate constraint-related nodes.
+
// Create a constraint-info node from the specified requirements.
tree
make_constraints (tree reqs)
@@ -451,10 +502,6 @@ make_constraints (tree reqs)
return (tree)cinfo;
}
-
-// -------------------------------------------------------------------------- //
-// Get Constraints
-
// Returns the template constraints of declaration T. If T is not a
// template, this return NULL_TREE. Note that T must be non-null.
tree
@@ -471,19 +518,392 @@ get_constraints (tree t)
return DECL_CONSTRAINTS (t);
}
+// Finish the template requirement, EXPR, by translating it into
+// a constraint information record.
+tree
+finish_template_requirements (tree expr)
+{
+ if (expr == error_mark_node)
+ return NULL_TREE;
+ else
+ return make_constraints (expr);
+}
+
+tree
+build_requires_expr (tree parms, tree reqs)
+{
+ // Modify the declared parameters by removing their context (so they
+ // don't refer to the enclosing scope), and marking them constant (so
+ // we can actually check constexpr properties).
+ for (tree p = parms; p && !VOID_TYPE_P (TREE_VALUE (p)); p = TREE_CHAIN (p))
+ {
+ tree parm = TREE_VALUE (p);
+ DECL_CONTEXT (parm) = NULL_TREE;
+ TREE_CONSTANT (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;
+}
+
+// Evaluate an instantiatd requires expr, returning the truth node
+// only when all sub-requirements have evaluated to true.
+tree
+eval_requires_expr (tree reqs)
+{
+ for (tree t = reqs ; t; t = TREE_CHAIN (t)) {
+ tree r = TREE_VALUE (t);
+ r = fold_non_dependent_expr (r);
+ r = maybe_constant_value (r);
+ if (r != boolean_true_node)
+ return boolean_false_node;
+ }
+ return boolean_true_node;
+}
+
+// Finish a requires expression, returning a node wrapping the parameters,
+// PARMS, and the list of requirements REQS.
+tree
+finish_requires_expr (tree parms, tree reqs)
+{
+ if (processing_template_decl)
+ return build_requires_expr (parms, reqs);
+ else
+ return eval_requires_expr (reqs);
+}
+
+// Construct a unary expression that evaluates properties of the
+// expression or type T, and has a boolean result type.
+static inline tree
+build_check_expr (tree_code c, tree t)
+{
+ tree r = build_min (c, boolean_type_node, t);
+ TREE_SIDE_EFFECTS (r) = false;
+ TREE_READONLY (r) = true;
+ TREE_CONSTANT (r) = true;
+ return r;
+}
+
+// Finish a syntax requirement, constructing a list embodying a sequence
+// of checks for the validity of EXPR and TYPE, the convertibility of
+// EXPR to TYPE, and the expression properties specified in SPECS.
+tree
+finish_expr_requirement (tree expr, tree type, tree specs)
+{
+ gcc_assert (processing_template_decl);
+
+ // Build a list of checks, starting with the valid expression.
+ tree result = tree_cons (NULL_TREE, finish_validexpr_expr (expr), NULL_TREE);
+
+ // If a type requirement was provided, build the result type checks.
+ if (type)
+ {
+ // If the type is dependent, ensure that it can be validly
+ // instantiated.
+ //
+ // NOTE: We can also disregard checks that result in the template
+ // parameter.
+ if (dependent_type_p (type))
+ {
+ tree treq = finish_type_requirement (type);
+ result = tree_cons (NULL_TREE, treq, result);
+ }
+
+ // Ensure that the result of the expression can be converted to
+ // the result type.
+ tree decl_type = finish_decltype_type (expr, false, tf_none);
+ tree creq = finish_trait_expr (CPTK_IS_CONVERTIBLE_TO, decl_type, type);
+ result = tree_cons (NULL_TREE, creq, result);
+ }
+
+ // If constraint specifiers are present, make them part of the
+ // list of constraints.
+ if (specs)
+ {
+ TREE_CHAIN (tree_last (specs)) = result;
+ result = specs;
+ }
+
+ // Finally, construct the syntactic requirement.
+ return build_check_expr (EXPR_REQ, nreverse (result));
+}
+
+// Finish a simple syntax requirement, returning a node representing
+// a check that EXPR is a valid expression.
+tree
+finish_expr_requirement (tree expr)
+{
+ gcc_assert (processing_template_decl);
+ tree req = finish_validexpr_expr (expr);
+ tree reqs = tree_cons (NULL_TREE, req, NULL_TREE);
+ return build_check_expr (EXPR_REQ, reqs);
+}
+
+// Finish a type requirement, returning a node representing a check
+// that TYPE will result in a valid type when instantiated.
+tree
+finish_type_requirement (tree type)
+{
+ gcc_assert (processing_template_decl);
+ tree req = finish_validtype_expr (type);
+ return build_check_expr (TYPE_REQ, req);
+}
+
+tree
+finish_nested_requirement (tree expr)
+{
+ gcc_assert (processing_template_decl);
+ return build_check_expr (NESTED_REQ, expr);
+}
+
+// Finish a constexpr requirement, returning a node representing a
+// check that EXPR, when instantiated, may be evaluated at compile time.
+tree
+finish_constexpr_requirement (tree expr)
+{
+ gcc_assert (processing_template_decl);
+ return finish_constexpr_expr (expr);
+}
+
+// Finish the noexcept requirement by constructing a noexcept
+// expression evaluating EXPR.
+tree
+finish_noexcept_requirement (tree expr)
+{
+ gcc_assert (processing_template_decl);
+ return finish_noexcept_expr (expr, tf_none);
+}
+
+// Returns the true or false node depending on the truth value of B.
+static inline tree
+truth_node (bool b)
+{
+ return b ? boolean_true_node : boolean_false_node;
+}
+
+// Returns a finished validexpr-expr. Returns the true or false node
+// depending on whether EXPR denotes a valid expression. This is the case
+// when the expression has been successfully type checked.
+//
+// When processing a template declaration, the result is an expression
+// representing the check.
+tree
+finish_validexpr_expr (tree expr)
+{
+ if (processing_template_decl)
+ return build_check_expr (VALIDEXPR_EXPR, expr);
+ return truth_node (expr && expr != error_mark_node);
+}
+
+// Returns a finished validtype-expr. Returns the true or false node
+// depending on whether T denotes a valid type name.
+//
+// When processing a template declaration, the result is an expression
+// representing the check.
+tree
+finish_validtype_expr (tree type)
+{
+ if (processing_template_decl)
+ return build_check_expr (VALIDTYPE_EXPR, type);
+ return truth_node (type && TYPE_P (type));
+}
+
+// Returns a finished constexpr-expr. Returns the true or false node
+// depending on whether the expression T may be evaluated at compile
+// time.
+//
+// When processing a template declaration, the result is an expression
+// representing the check.
+tree
+finish_constexpr_expr (tree expr)
+{
+ if (processing_template_decl)
+ return build_check_expr (CONSTEXPR_EXPR, expr);
+
+ // TODO: Actually check that the expression can be constexpr
+ // evaluatd.
+ //
+ // return truth_node (potential_constant_expression (expr));
+ sorry ("constexpr requirement");
+ return NULL_TREE;
+}
// -------------------------------------------------------------------------- //
-// Check Constraints
+// Substitution Rules
+//
+// The following functions implement substitution rules for constraints.
+
+namespace {
+// In an unevaluated context, the substitution of parm decls are not
+// properly chained during substitution. Do that here.
+tree
+fix_local_parms (tree sparms)
+{
+ if (!sparms)
+ return sparms;
+ tree p = TREE_CHAIN (sparms);
+ tree q = sparms;
+ while (p && TREE_VALUE (p) != void_type_node)
+ {
+ DECL_CHAIN (TREE_VALUE (q)) = TREE_VALUE (p);
+ q = p;
+ p = TREE_CHAIN (p);
+ }
+ return sparms;
+}
+
+// Register local specializations for each of tparm and the corresponding
+// sparm. This is a helper function for tsubst_requires_expr.
+void
+declare_local_parms (tree tparms, tree sparms)
+{
+ tree s = TREE_VALUE (sparms);
+ for (tree p = tparms; p && !VOID_TYPE_P (TREE_VALUE (p)); p = TREE_CHAIN (p))
+ {
+ tree t = TREE_VALUE (p);
+ if (FUNCTION_PARAMETER_PACK_P (t))
+ {
+ tree pack = extract_fnparm_pack (t, &s);
+ register_local_specialization (pack, t);
+ }
+ else
+ {
+ register_local_specialization (s, t);
+ s = TREE_CHAIN (s);
+ }
+ }
+}
+
+// Substitute ARGS into the parameter list T, producing a sequence of
+// local parameters (variables) in the current scope.
+tree
+tsubst_local_parms (tree t,
+ tree args,
+ tsubst_flags_t complain,
+ tree in_decl)
+{
+ tree r = fix_local_parms (tsubst (t, args, complain, in_decl));
+ if (r == error_mark_node)
+ return error_mark_node;
+
+ // Register the instantiated args as local parameters.
+ if (t)
+ declare_local_parms (t, r);
+
+ return r;
+}
+
+// Substitute ARGS into the requirement body (list of requirements), T.
+tree
+tsubst_requirement_body (tree t, tree args, tree in_decl)
+{
+ cp_unevaluated guard;
+ tree r = NULL_TREE;
+ while (t)
+ {
+ // If any substitutions fail, then this is equivalent to
+ // returning false.
+ tree e = tsubst_expr (TREE_VALUE (t), args, tf_none, in_decl, false);
+ if (e == error_mark_node)
+ e = boolean_false_node;
+ r = tree_cons (NULL_TREE, e, r);
+ t = TREE_CHAIN (t);
+ }
+ return r;
+}
+} // namespace
+
+// Substitute ARGS into the requires expression T.
+tree
+tsubst_requires_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ local_specialization_stack stack;
+ tree p = tsubst_local_parms (TREE_OPERAND (t, 0), args, complain, in_decl);
+ tree r = tsubst_requirement_body (TREE_OPERAND (t, 1), args, in_decl);
+ return finish_requires_expr (p, r);
+}
+
+// Substitute ARGS into the valid-expr expression T.
+tree
+tsubst_validexpr_expr (tree t, tree args, tree in_decl)
+{
+ tree r = tsubst_expr (TREE_OPERAND (t, 0), args, tf_none, in_decl, false);
+ return finish_validexpr_expr (r);
+}
+
+// Substitute ARGS into the valid-type expression T.
+tree
+tsubst_validtype_expr (tree t, tree args, tree in_decl)
+{
+ tree r = tsubst (TREE_OPERAND (t, 0), args, tf_none, in_decl);
+ return finish_validtype_expr (r);
+}
+
+// Substitute ARGS into the constexpr expression T.
+tree
+tsubst_constexpr_expr (tree t, tree args, tree in_decl)
+{
+ tree r = tsubst_expr (TREE_OPERAND (t, 0), args, tf_none, in_decl, false);
+ return finish_constexpr_expr (r);
+}
+
+// Substitute ARGS into the expr requirement T. Note that a requirement
+// node is instantiated from a non-reduced context (e.g., static_assert).
+tree
+tsubst_expr_req (tree t, tree args, tree in_decl)
+{
+ tree r = NULL_TREE;
+ for (tree l = TREE_OPERAND (t, 0); l; l = TREE_CHAIN (l))
+ {
+ tree e = tsubst_expr (TREE_VALUE (l), args, tf_none, in_decl, false);
+ r = conjoin_requirements (r, e);
+ }
+ return r;
+}
+
+// Substitute ARGS into the type requirement T. Note that a requirement
+// node is instantiated from a non-reduced context (e.g., static_assert).
+tree
+tsubst_type_req (tree t, tree args, tree in_decl)
+{
+ return tsubst_expr (TREE_OPERAND (t, 0), args, tf_none, in_decl, false);
+}
+
+// Substitute ARGS into the nested requirement T. Note that a requirement
+// node is instantiated from a non-reduced context (e.g., static_assert).
+tree
+tsubst_nested_req (tree t, tree args, tree in_decl)
+{
+ return tsubst_expr (TREE_OPERAND (t, 0), args, tf_none, in_decl, false);
+}
+
+// Substitute the template arguments ARGS into the requirement
+// expression REQS. Errors resulting from substitution are not
+// diagnosed.
+tree
+instantiate_requirements (tree reqs, tree args)
+{
+ return tsubst_expr (reqs, args, tf_none, NULL_TREE, false);
+}
+
+// -------------------------------------------------------------------------- //
+// Constraint Satisfaction
+//
+// The following functions are responsible for the instantiation and
+// evaluation of constraints.
+
+namespace {
// Returns true if the requirements expression REQS is satisfied
// and false otherwise. The requirements are checked by simply
// evaluating REQS as a constant expression.
static inline bool
check_requirements (tree reqs)
{
- // Simplify the expression before evaluating it. This will
- // cause TRAIT_EXPR nodes to be reduced before constexpr
- // evaluation.
+ // Reduce any remaining TRAIT_EXPR nodes before evaluating.
reqs = fold_non_dependent_expr (reqs);
// Requirements are satisfied when REQS evaluates to true.
@@ -501,6 +921,7 @@ check_requirements (tree reqs, tree args
return false;
return check_requirements (reqs);
}
+} // namespace
// Check the instantiated declaration constraints.
bool
@@ -531,6 +952,11 @@ check_template_constraints (tree t, tree
return check_constraints (DECL_CONSTRAINTS (t), args);
}
+// -------------------------------------------------------------------------- //
+// Constraint Relations
+//
+// Interfaces for determining equivalency and ordering of constraints.
+
// Returns true when A and B are equivalent constraints.
bool
equivalent_constraints (tree a, tree b)
@@ -702,6 +1128,78 @@ diagnose_call (location_t loc, tree t, t
inform (loc, " %qE evaluated to false", t);
}
+// Diagnose specific constraint failures.
+void
+diagnose_requires (location_t loc, tree t, tree args)
+{
+ if (check_requirements (t, args))
+ return;
+
+ ++processing_template_decl;
+ tree subst = instantiate_requirements (t, args);
+ --processing_template_decl;
+
+ // Print the header for the requires expression.
+ tree parms = TREE_OPERAND (subst, 0);
+ if (!VOID_TYPE_P (TREE_VALUE (parms)))
+ inform (loc, " requiring syntax with values %Z", TREE_OPERAND (subst, 0));
+
+ // Create a new local specialization binding for the arguments.
+ // This lets us instantiate sub-expressions separately from the
+ // requires clause.
+ local_specialization_stack locals;
+ declare_local_parms (TREE_OPERAND (t, 0), TREE_OPERAND (subst, 0));
+
+ // Iterate over the sub-requirements and try instantiating each.
+ for (tree l = TREE_OPERAND (t, 1); l; l = TREE_CHAIN (l))
+ diagnose_node (loc, TREE_VALUE (l), args);
+}
+
+static void
+diagnose_validexpr (location_t loc, tree t, tree args)
+{
+ if (check_requirements (t, args))
+ return;
+ inform (loc, " %qE is not a valid expression", TREE_OPERAND (t, 0));
+}
+
+static void
+diagnose_validtype (location_t loc, tree t, tree args)
+{
+ if (check_requirements (t, args))
+ return;
+
+ // Substitute into the qualified name.
+ tree name = TREE_OPERAND (t, 0);
+ if (tree cxt = TYPE_CONTEXT (name))
+ {
+ tree id = TYPE_IDENTIFIER (name);
+ cxt = tsubst (cxt, args, tf_none, NULL_TREE);
+ name = build_qualified_name (NULL_TREE, cxt, id, false);
+ inform (loc, " %qE does not name a valid type", name);
+ }
+ else
+ {
+ inform (loc, " %qT does not name a valid type", name);
+ }
+}
+
+static void
+diagnose_constexpr (location_t loc, tree t, tree args)
+{
+ if (check_requirements (t, args))
+ return;
+ inform (loc, " %qE is not a constant expression", TREE_OPERAND (t, 0));
+}
+
+static void
+diagnose_noexcept (location_t loc, tree t, tree args)
+{
+ if (check_requirements (t, args))
+ return;
+ inform (loc, " %qE propagates exceptions", TREE_OPERAND (t, 0));
+}
+
// Diagnose a constraint failure in the expression T.
void
diagnose_other (location_t loc, tree t, tree args)
@@ -730,9 +1228,31 @@ diagnose_node (location_t loc, tree t, t
case TRAIT_EXPR:
diagnose_trait (loc, t, args);
break;
+
case CALL_EXPR:
diagnose_call (loc, t, args);
break;
+
+ case REQUIRES_EXPR:
+ diagnose_requires (loc, t, args);
+ break;
+
+ case VALIDEXPR_EXPR:
+ diagnose_validexpr (loc, t, args);
+ break;
+
+ case VALIDTYPE_EXPR:
+ diagnose_validtype (loc, t, args);
+ break;
+
+ case CONSTEXPR_EXPR:
+ diagnose_constexpr (loc, t, args);
+ break;
+
+ case NOEXCEPT_EXPR:
+ diagnose_noexcept (loc, t, args);
+ break;
+
default:
diagnose_other (loc, t, args);
break;
@@ -757,12 +1277,12 @@ make_subst (tree tmpl, tree args)
return subst;
}
-} // namesapce
+} // namespace
// Emit diagnostics detailing the failure ARGS to satisfy the constraints
// of the template declaration, TMPL.
void
-diagnose_constraint_failure (location_t loc, tree tmpl, tree args)
+diagnose_constraints (location_t loc, tree tmpl, tree args)
{
inform (loc, " constraints not satisfied %S", make_subst (tmpl, args));
Index: call.c
===================================================================
--- call.c (revision 201240)
+++ call.c (working copy)
@@ -3294,7 +3294,7 @@ print_z_candidate (location_t loc, const
{
tree tmpl = r->u.template_instantiation.tmpl;
tree args = r->u.template_instantiation.targs;
- diagnose_constraint_failure (cloc, tmpl, args);
+ diagnose_constraints (cloc, tmpl, args);
}
break;
case rr_none:
Index: cp-tree.h
===================================================================
--- cp-tree.h (revision 201240)
+++ cp-tree.h (working copy)
@@ -5602,6 +5602,8 @@ extern tree tsubst_default_argument (tr
extern tree tsubst (tree, tree, tsubst_flags_t, tree);
extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t,
tree, bool, bool);
+extern tree tsubst_expr (tree, tree, tsubst_flags_t,
+ tree, bool);
extern tree most_general_template (tree);
extern tree get_mostly_instantiated_function_type (tree);
extern int problematic_instantiation_changed (void);
@@ -5648,9 +5650,10 @@ extern tree get_function_template_decl
extern tree resolve_nondeduced_context (tree);
extern hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
extern tree coerce_template_parms (tree, tree, tree);
-extern tree instantiate_requirements (tree, tree);
-extern tree tsubst_constraint (tree, tree);
-extern tree current_template_args ();
+extern void register_local_specialization (tree, tree);
+extern tree retrieve_local_specialization (tree);
+extern tree extract_fnparm_pack (tree, tree *);
+
/* in repo.c */
extern void init_repo (void);
@@ -5804,16 +5807,6 @@ extern void explain_invalid_constexpr_fn
extern vec cx_error_context (void);
extern bool is_unary_trait (cp_trait_kind);
extern bool is_binary_trait (cp_trait_kind);
-extern tree finish_requires_expr (tree, tree);
-extern tree finish_expr_requirement (tree, tree, tree);
-extern tree finish_expr_requirement (tree);
-extern tree finish_type_requirement (tree);
-extern tree finish_nested_requirement (tree);
-extern tree finish_constexpr_requirement (tree);
-extern tree finish_noexcept_requirement (tree);
-extern tree finish_validexpr_expr (tree);
-extern tree finish_validtype_epxr (tree);
-extern tree finish_constexpr_expr (tree);
enum {
BCS_NO_SCOPE = 1,
@@ -6257,10 +6250,30 @@ extern tree strip_using_decl
/* in constraint.cc */
extern tree conjoin_requirements (tree, tree);
-extern tree disjoin_requirements (tree, tree);
extern tree reduce_requirements (tree);
extern tree make_constraints (tree);
extern tree get_constraints (tree);
+
+extern tree finish_requires_expr (tree, tree);
+extern tree finish_expr_requirement (tree, tree, tree);
+extern tree finish_expr_requirement (tree);
+extern tree finish_type_requirement (tree);
+extern tree finish_nested_requirement (tree);
+extern tree finish_constexpr_requirement (tree);
+extern tree finish_noexcept_requirement (tree);
+extern tree finish_validexpr_expr (tree);
+extern tree finish_validtype_expr (tree);
+extern tree finish_constexpr_expr (tree);
+
+extern tree tsubst_requires_expr (tree, tree, tsubst_flags_t, tree);
+extern tree tsubst_validexpr_expr (tree, tree, tree);
+extern tree tsubst_validtype_expr (tree, tree, tree);
+extern tree tsubst_constexpr_expr (tree, tree, tree);
+extern tree tsubst_expr_req (tree, tree, tree);
+extern tree tsubst_type_req (tree, tree, tree);
+extern tree tsubst_nested_req (tree, tree, tree);
+extern tree instantiate_requirements (tree, tree);
+
extern bool check_constraints (tree);
extern bool check_constraints (tree, tree);
extern bool check_template_constraints (tree, tree);
@@ -6269,7 +6282,8 @@ extern bool equivalent_constraints
extern bool equivalently_constrained (tree, tree);
extern bool more_constraints (tree, tree);
extern bool more_constrained (tree, tree);
-extern void diagnose_constraint_failure (location_t, tree, tree);
+
+extern void diagnose_constraints (location_t, tree, tree);
/* in logic.cc */
extern tree decompose_assumptions (tree);