+2004-03-16 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/14586
+ * cp-tree.h (build_new_op): Change prototype.
+ (build_x_binary_op): Likewise.
+ * call.c (build_new_op): Add overloaded_p parameter.
+ * decl2.c (grok_array_decl): Adjust call to build_new_op.
+ * parser.c (cp_parser_binary_expression): Note that uses of
+ overloaded operators prevents an expression from being considered
+ an integral constant.
+ * pt.c (tsubst_copy_and_build): Adjust calls to build_new_op and/or
+ build_x_binary_op.
+ * semantics.c (finish_call_expr): Likewise.
+ * typeck.c (rationalize_conditional_expr): Likewise.
+ (build_x_indirect_ref): Likewise.
+ (build_x_binary_op): Likewise.
+ (build_x_unary_op): Likewise.
+ (build_x_compound_expr): Likewise.
+ (build_modify_expr): Likewise.
+ * typeck2.c (build_x_arrow): Likewise.
+
2004-03-15 Kazu Hirata <kazu@cs.umass.edu>
* cp-lang.c, ptree.c: Update copyright.
}
tree
-build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
+build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
+ bool *overloaded_p)
{
struct z_candidate *candidates = 0, *cand;
tree arglist, fnname;
code = PREINCREMENT_EXPR;
else
code = PREDECREMENT_EXPR;
- result = build_new_op (code, flags, arg1, NULL_TREE, NULL_TREE);
+ result = build_new_op (code, flags, arg1, NULL_TREE, NULL_TREE,
+ overloaded_p);
break;
/* The caller will deal with these. */
}
else if (TREE_CODE (cand->fn) == FUNCTION_DECL)
{
+ if (overloaded_p)
+ *overloaded_p = true;
+
if (warn_synth
&& fnname == ansi_assopname (NOP_EXPR)
&& DECL_ARTIFICIAL (cand->fn)
extern tree build_operator_new_call (tree, tree, tree *, tree *);
extern tree build_new_method_call (tree, tree, tree, tree, int);
extern tree build_special_member_call (tree, tree, tree, tree, int);
-extern tree build_new_op (enum tree_code, int, tree, tree, tree);
+extern tree build_new_op (enum tree_code, int, tree, tree, tree, bool *);
extern tree build_op_delete_call (enum tree_code, tree, tree, bool, tree);
extern bool can_convert (tree, tree);
extern bool can_convert_arg (tree, tree, tree);
extern tree build_array_ref (tree, tree);
extern tree get_member_function_from_ptrfunc (tree *, tree);
extern tree convert_arguments (tree, tree, tree, int);
-extern tree build_x_binary_op (enum tree_code, tree, tree);
+extern tree build_x_binary_op (enum tree_code, tree, tree,
+ bool *);
extern tree build_x_unary_op (enum tree_code, tree);
extern tree unary_complex_lvalue (enum tree_code, tree);
extern tree build_x_conditional_expr (tree, tree, tree);
/* If they have an `operator[]', use that. */
if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL,
- array_expr, index_exp, NULL_TREE);
+ array_expr, index_exp, NULL_TREE,
+ /*overloaded_p=*/NULL);
else
{
tree p1, p2, i1, i2;
++map_node)
if (map_node->token_type == token->type)
{
+ /* Assume that an overloaded operator will not be used. */
+ bool overloaded_p = false;
+
/* Consume the operator token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the right-hand side of the expression. */
rhs = (*fn) (parser);
/* Build the binary tree node. */
- lhs = build_x_binary_op (map_node->tree_type, lhs, rhs);
+ lhs = build_x_binary_op (map_node->tree_type, lhs, rhs,
+ &overloaded_p);
+ /* If the binary operator required the use of an
+ overloaded operator, then this expression cannot be an
+ integral constant-expression. An overloaded operator
+ can be used even if both operands are otherwise
+ permissible in an integral constant-expression if at
+ least one of the operands is of enumeration type. */
+ if (overloaded_p
+ && (cp_parser_non_integral_constant_expression
+ (parser, "calls to overloaded operators")))
+ lhs = error_mark_node;
break;
}
return build_x_binary_op
(TREE_CODE (t),
RECUR (TREE_OPERAND (t, 0)),
- RECUR (TREE_OPERAND (t, 1)));
+ RECUR (TREE_OPERAND (t, 1)),
+ /*overloaded_p=*/NULL);
case SCOPE_REF:
return tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true,
else if (CLASS_TYPE_P (TREE_TYPE (fn)))
/* If the "function" is really an object of class type, it might
have an overloaded `operator ()'. */
- result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
+ result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE,
+ /*overloaded_p=*/NULL);
if (!result)
/* A call where the function is unknown. */
result = build_function_call (fn, args);
build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
? LE_EXPR : GE_EXPR),
TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1)),
+ TREE_OPERAND (t, 1),
+ /*overloaded_p=*/NULL),
build_unary_op (code, TREE_OPERAND (t, 0), 0),
build_unary_op (code, TREE_OPERAND (t, 1), 0));
}
}
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
- NULL_TREE);
+ NULL_TREE, /*overloaded_p=*/NULL);
if (!rval)
rval = build_indirect_ref (expr, errorstring);
conversions on the operands. CODE is the kind of expression to build. */
tree
-build_x_binary_op (enum tree_code code, tree arg1, tree arg2)
+build_x_binary_op (enum tree_code code, tree arg1, tree arg2,
+ bool *overloaded_p)
{
tree orig_arg1;
tree orig_arg2;
if (code == DOTSTAR_EXPR)
expr = build_m_component_ref (arg1, arg2);
else
- expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
+ expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
+ overloaded_p);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
|| (TREE_CODE (xarg) == OFFSET_REF)))
/* Don't look for a function. */;
else
- exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE);
+ exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE,
+ /*overloaded_p=*/NULL);
if (!exp && code == ADDR_EXPR)
{
/* A pointer to member-function can be formed only by saying
op2 = build_non_dependent_expr (op2);
}
- result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE);
+ result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
+ /*overloaded_p=*/NULL);
if (!result)
result = build_compound_expr (op1, op2);
else
{
result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
+ lhs, rhs, make_node (NOP_EXPR),
+ /*overloaded_p=*/NULL);
if (result == NULL_TREE)
return error_mark_node;
return result;
if (modifycode != NOP_EXPR)
{
tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
- make_node (modifycode));
+ make_node (modifycode),
+ /*overloaded_p=*/NULL);
if (rval)
return rval;
}
if (IS_AGGR_TYPE (type))
{
while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
- NULL_TREE, NULL_TREE)))
+ NULL_TREE, NULL_TREE,
+ /*overloaded_p=*/NULL)))
{
if (expr == error_mark_node)
return error_mark_node;
+2004-03-16 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/14586
+ * g++.dg/parse/non-dependent3.C: New test.
+
2004-03-16 Paolo Bonzini <bonzini@gnu.org>
* g++.dg/eh/simd-1.C: Use vector_size attribute, not mode.
--- /dev/null
+// PR c++/14586
+
+enum E { e };
+
+E & operator |= (E &f1, const E &f2);
+
+E operator | (const E &f1, const E &f2) {
+ E result = f1;
+ result |= f2;
+ return result;
+}
+
+template <typename> void foo () {
+ const E flags = e | e;
+}
+
+template void foo<double> ();