This patch adds checks for user-defined logical operators during
constraint normalization and ensures that all atomics can be converted
to bool.
2014-08-14 Andrew Sutton <[email protected]>
Implement normalization checks.
* gcc/cp/constraint.cc (normalize_expr): Delegate cast and
atomic nodes to a dedicated function.
(check_logical): Check that an && or || does not resolve to a
user-defined function.
(normalize_logical): Check operators and save the locaiton of
the new expression.
(normalize_call, normalize_var): Remove spurios error messages.
(normalize_cast): New, delegates to normalize atom.
(normalize_atom): Check that instantiated expressions can be
converted to bool
(tsubst_constraint_info): Re-normalize the associated constraints
to check for post-substitution restrictions.
* gcc/cp/cp-tree.h (xvalue_result_type): Add to header.
Andrew Sutton
Index: gcc/cp/constraint.cc
===================================================================
--- gcc/cp/constraint.cc (revision 213924)
+++ gcc/cp/constraint.cc (working copy)
@@ -264,6 +264,8 @@ tree normalize_nested_req (tree);
tree normalize_var (tree);
tree normalize_template_id (tree);
tree normalize_stmt_list (tree);
+tree normalize_cast (tree);
+tree normalize_atom (tree);
// Reduce the requirement T into a logical formula written in terms of
// atomic propositions.
@@ -328,7 +330,7 @@ normalize_expr (tree t)
return normalize_template_id (t);
case CAST_EXPR:
- return normalize_node (TREE_VALUE (TREE_OPERAND (t, 0)));
+ return normalize_cast (t);
case BIND_EXPR:
return normalize_node (BIND_EXPR_BODY (t));
@@ -339,7 +341,7 @@ normalize_expr (tree t)
// Everything else is atomic.
default:
- return t;
+ return normalize_atom (t);
}
}
@@ -402,6 +404,34 @@ normalize_misc (tree t)
return NULL_TREE;
}
+// Check that the logical expression is not a user-defined operator.
+bool
+check_logical (tree t)
+{
+ // We can't do much for type dependent expressions.
+ if (type_dependent_expression_p (t) || value_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;
+ tree arg1 = TREE_OPERAND (t, 0);
+ tree arg2 = TREE_OPERAND (t, 1);
+
+ tree ovl = NULL_TREE;
+ tree expr = build_new_op (input_location, TREE_CODE (t), LOOKUP_NORMAL,
+ arg1, arg2, /*arg3*/NULL_TREE,
+ &ovl, tf_none);
+ if (TREE_CODE (expr) != TREE_CODE (t))
+ {
+ error ("user-defined operator %qs in constraint %qE",
+ operator_name_info[TREE_CODE (t)].name, t);
+ ;
+ return false;
+ }
+ return true;
+}
+
// Reduction rules for the binary logical expression T (&& and ||).
//
// Generate a new expression from the reduced operands. If either operand
@@ -409,14 +439,18 @@ normalize_misc (tree t)
tree
normalize_logical (tree t)
{
+ if (!check_logical (t))
+ return NULL_TREE;
+
tree l = normalize_expr (TREE_OPERAND (t, 0));
tree r = normalize_expr (TREE_OPERAND (t, 1));
if (l && r)
{
- t = copy_node (t);
- TREE_OPERAND (t, 0) = l;
- TREE_OPERAND (t, 1) = r;
- return t;
+ tree result = copy_node (t);
+ SET_EXPR_LOCATION (result, EXPR_LOCATION (t));
+ TREE_OPERAND (result, 0) = l;
+ TREE_OPERAND (result, 1) = r;
+ return result;
}
else
return NULL_TREE;
@@ -440,18 +474,13 @@ normalize_call (tree t)
// Reduce the body of the function into the constriants language.
tree body = normalize_constraints (DECL_SAVED_TREE (fn));
if (!body)
- {
- error ("could not inline requirements from %qD", fn);
- return error_mark_node;
- }
+ return error_mark_node;
// Instantiate the reduced results using the deduced args.
tree result = tsubst_constraint_expr (body, args, false);
if (result == error_mark_node)
- {
- error ("could not instantiate requirements from %qD", fn);
- return error_mark_node;
- }
+ return error_mark_node;
+
return result;
}
@@ -469,18 +498,12 @@ normalize_var (tree t)
// Reduce the initializer of the variable into the constriants language.
tree body = normalize_constraints (DECL_INITIAL (decl));
if (!body)
- {
- error ("could not inline requirements from %qD", decl);
- return error_mark_node;
- }
+ return error_mark_node;
// Instantiate the reduced results.
tree result = tsubst_constraint_expr (body, TREE_OPERAND (t, 1), false);
if (result == error_mark_node)
- {
- error ("could not instantiate requirements from %qD", decl);
- return error_mark_node;
- }
+ return error_mark_node;
return result;
}
@@ -574,6 +597,29 @@ normalize_stmt_list (tree stmts)
return lhs;
}
+// Normalize a cast expression.
+tree
+normalize_cast (tree t)
+{
+ // return normalize_node (TREE_VALUE (TREE_OPERAND (t, 0)));
+ return normalize_atom (t);
+}
+
+// Normalize an atomic expression by performing some basic checks.
+// In particular, if the type is known, it must be convertible to
+// bool.
+tree
+normalize_atom (tree t)
+{
+ if (!type_dependent_expression_p (t))
+ if (!can_convert (boolean_type_node, TREE_TYPE (t), tf_none))
+ {
+ error ("atomic constraint %qE is not convertible to %<bool%>", t);
+ return NULL_TREE;
+ }
+ return t;
+}
+
// Reduce the requirement REQS into a logical formula written in terms of
// atomic propositions.
tree
@@ -1303,11 +1349,21 @@ tsubst_constraint_info (tree ci, tree ar
if (tree r = CI_TRAILING_REQS (ci))
result->trailing_reqs = tsubst_constraint_expr (r, args, true);
if (tree r = CI_ASSOCIATED_REQS (ci))
- result->associated_reqs = tsubst_constraint_expr (r, args, true);
+ result->associated_reqs = tsubst_constraint_expr (r, args, true);
+
+ // Re-normalize the constraints to ensure that we haven't picked
+ // any fatal errors when substituting.
+ if (!normalize_constraints (result->associated_reqs))
+ {
+ result->associated_reqs = error_mark_node;
+ result->assumptions = error_mark_node;
+ }
+ else
+ {
+ // Analyze the resulting constraints.
+ result->assumptions = decompose_assumptions (result->associated_reqs);
+ }
- // Analyze the resulting constraints.
- // TODO: Is this actually necessary if the constraints are non-dependent?
- result->assumptions = decompose_assumptions (result->associated_reqs);
return (tree)result;
}
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 213758)
+++ gcc/cp/cp-tree.h (working copy)
@@ -5957,6 +5957,7 @@ extern vec<tree> cx_error_context (void)
extern bool is_unary_trait (cp_trait_kind);
extern bool is_binary_trait (cp_trait_kind);
extern bool is_this_parameter (tree);
+extern tree xvalue_result_type (tree);
enum {
BCS_NO_SCOPE = 1,