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 <andrew.n.sut...@gmail.com> 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,