This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PR c++/14586
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 16 Mar 2004 14:23:20 -0800
- Subject: PR c++/14586
- Reply-to: mark at codesourcery dot com
This patch fixes PR c++/14586, which is another case where we
mistakenly treated a non-constant expression as being constant. The
PR is a tricky corner case: one might think that if the operands "x"
and "y" are integral constant expressions then "x op y" would also be
for choices of "op" like "+" -- but if "x" or "y" has enumeration type
then "op" might be an overloaded operator.
Tested on i686-pc-linux-gnu, applied on the mainline and on the 3.4
branch.
--
Mark Mitchell
CodeSourcery, LLC
(916) 791-8304
mark@codesourcery.com
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-16 Mark Mitchell <mark@codesourcery.com>
PR c++/14586
* g++.dg/parse/non-dependent3.C: New test.
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.452.2.12
diff -c -5 -p -r1.452.2.12 call.c
*** cp/call.c 9 Mar 2004 18:26:34 -0000 1.452.2.12
--- cp/call.c 16 Mar 2004 21:30:30 -0000
*************** add_candidates (tree fns, tree args,
*** 3369,3379 ****
fns = OVL_NEXT (fns);
}
}
tree
! build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
{
struct z_candidate *candidates = 0, *cand;
tree arglist, fnname;
tree args[3];
enum tree_code code2 = NOP_EXPR;
--- 3369,3380 ----
fns = OVL_NEXT (fns);
}
}
tree
! 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;
tree args[3];
enum tree_code code2 = NOP_EXPR;
*************** build_new_op (enum tree_code code, int f
*** 3512,3522 ****
operator_name_info[code].name);
if (code == POSTINCREMENT_EXPR)
code = PREINCREMENT_EXPR;
else
code = PREDECREMENT_EXPR;
! return build_new_op (code, flags, arg1, NULL_TREE, NULL_TREE);
/* The caller will deal with these. */
case ADDR_EXPR:
case COMPOUND_EXPR:
case COMPONENT_REF:
--- 3513,3524 ----
operator_name_info[code].name);
if (code == POSTINCREMENT_EXPR)
code = PREINCREMENT_EXPR;
else
code = PREDECREMENT_EXPR;
! return build_new_op (code, flags, arg1, NULL_TREE, NULL_TREE,
! overloaded_p);
/* The caller will deal with these. */
case ADDR_EXPR:
case COMPOUND_EXPR:
case COMPONENT_REF:
*************** build_new_op (enum tree_code code, int f
*** 3544,3553 ****
--- 3546,3558 ----
return error_mark_node;
}
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)
&& candidates->next
&& ! candidates->next->next)
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.946.4.9
diff -c -5 -p -r1.946.4.9 cp-tree.h
*** cp/cp-tree.h 10 Mar 2004 21:04:13 -0000 1.946.4.9
--- cp/cp-tree.h 16 Mar 2004 21:30:31 -0000
*************** extern tree type_decays_to (tree);
*** 3512,3522 ****
extern tree build_user_type_conversion (tree, tree, int);
extern tree build_new_function_call (tree, tree);
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_op_delete_call (enum tree_code, tree, tree, int, tree);
extern bool can_convert (tree, tree);
extern bool can_convert_arg (tree, tree, tree);
extern bool can_convert_arg_bad (tree, tree, tree);
extern bool enforce_access (tree, tree);
--- 3512,3522 ----
extern tree build_user_type_conversion (tree, tree, int);
extern tree build_new_function_call (tree, tree);
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, bool *);
extern tree build_op_delete_call (enum tree_code, tree, tree, int, tree);
extern bool can_convert (tree, tree);
extern bool can_convert_arg (tree, tree, tree);
extern bool can_convert_arg_bad (tree, tree, tree);
extern bool enforce_access (tree, tree);
*************** extern tree finish_class_member_access_e
*** 4200,4210 ****
extern tree build_x_indirect_ref (tree, const char *);
extern tree build_indirect_ref (tree, const char *);
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_unary_op (enum tree_code, tree);
extern tree unary_complex_lvalue (enum tree_code, tree);
extern tree build_x_conditional_expr (tree, tree, tree);
extern tree build_x_compound_expr_from_list (tree, const char *);
extern tree build_x_compound_expr (tree, tree);
--- 4200,4211 ----
extern tree build_x_indirect_ref (tree, const char *);
extern tree build_indirect_ref (tree, const char *);
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,
! 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);
extern tree build_x_compound_expr_from_list (tree, const char *);
extern tree build_x_compound_expr (tree, tree);
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.695.4.4
diff -c -5 -p -r1.695.4.4 decl2.c
*** cp/decl2.c 1 Mar 2004 06:21:39 -0000 1.695.4.4
--- cp/decl2.c 16 Mar 2004 21:30:38 -0000
*************** grok_array_decl (tree array_expr, tree i
*** 378,388 ****
type = non_reference (type);
/* 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);
else
{
tree p1, p2, i1, i2;
/* Otherwise, create an ARRAY_REF for a pointer or array type.
--- 378,389 ----
type = non_reference (type);
/* 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,
! /*overloaded_p=*/NULL);
else
{
tree p1, p2, i1, i2;
/* Otherwise, create an ARRAY_REF for a pointer or array type.
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.157.2.21
diff -c -5 -p -r1.157.2.21 parser.c
*** cp/parser.c 13 Mar 2004 16:44:12 -0000 1.157.2.21
--- cp/parser.c 16 Mar 2004 21:30:44 -0000
*************** cp_parser_binary_expression (cp_parser*
*** 13878,13893 ****
for (map_node = token_tree_map;
map_node->token_type != CPP_EOF;
++map_node)
if (map_node->token_type == token->type)
{
/* 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);
break;
}
/* If the token wasn't one of the ones we want, we're done. */
if (map_node->token_type == CPP_EOF)
--- 13878,13907 ----
for (map_node = token_tree_map;
map_node->token_type != CPP_EOF;
++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,
! &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;
}
/* If the token wasn't one of the ones we want, we're done. */
if (map_node->token_type == CPP_EOF)
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.816.2.18
diff -c -5 -p -r1.816.2.18 pt.c
*** cp/pt.c 9 Mar 2004 15:41:36 -0000 1.816.2.18
--- cp/pt.c 16 Mar 2004 21:30:48 -0000
*************** tsubst_copy_and_build (tree t,
*** 8266,8276 ****
case MEMBER_REF:
case DOTSTAR_EXPR:
return build_x_binary_op
(TREE_CODE (t),
RECUR (TREE_OPERAND (t, 0)),
! RECUR (TREE_OPERAND (t, 1)));
case SCOPE_REF:
return tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true,
/*address_p=*/false);
--- 8266,8277 ----
case MEMBER_REF:
case DOTSTAR_EXPR:
return build_x_binary_op
(TREE_CODE (t),
RECUR (TREE_OPERAND (t, 0)),
! RECUR (TREE_OPERAND (t, 1)),
! /*overloaded_p=*/NULL);
case SCOPE_REF:
return tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true,
/*address_p=*/false);
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.381.4.8
diff -c -5 -p -r1.381.4.8 semantics.c
*** cp/semantics.c 20 Feb 2004 09:03:29 -0000 1.381.4.8
--- cp/semantics.c 16 Mar 2004 21:30:50 -0000
*************** finish_call_expr (tree fn, tree args, bo
*** 1727,1737 ****
TREE_SIDE_EFFECTS (result) = 1;
}
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);
if (!result)
/* A call where the function is unknown. */
result = build_function_call (fn, args);
if (processing_template_decl)
--- 1727,1738 ----
TREE_SIDE_EFFECTS (result) = 1;
}
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,
! /*overloaded_p=*/NULL);
if (!result)
/* A call where the function is unknown. */
result = build_function_call (fn, args);
if (processing_template_decl)
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.519.2.9
diff -c -5 -p -r1.519.2.9 typeck.c
*** cp/typeck.c 2 Mar 2004 19:57:06 -0000 1.519.2.9
--- cp/typeck.c 16 Mar 2004 21:30:52 -0000
*************** rationalize_conditional_expr (enum tree_
*** 1491,1501 ****
{
return
build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
? LE_EXPR : GE_EXPR),
TREE_OPERAND (t, 0),
! TREE_OPERAND (t, 1)),
build_unary_op (code, TREE_OPERAND (t, 0), 0),
build_unary_op (code, TREE_OPERAND (t, 1), 0));
}
return
--- 1491,1502 ----
{
return
build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
? LE_EXPR : GE_EXPR),
TREE_OPERAND (t, 0),
! 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));
}
return
*************** build_x_indirect_ref (tree expr, const c
*** 2024,2034 ****
return build_min_nt (INDIRECT_REF, expr);
expr = build_non_dependent_expr (expr);
}
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
! NULL_TREE);
if (!rval)
rval = build_indirect_ref (expr, errorstring);
if (processing_template_decl && rval != error_mark_node)
return build_min_non_dep (INDIRECT_REF, rval, orig_expr);
--- 2025,2035 ----
return build_min_nt (INDIRECT_REF, expr);
expr = build_non_dependent_expr (expr);
}
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
! NULL_TREE, /*overloaded_p=*/NULL);
if (!rval)
rval = build_indirect_ref (expr, errorstring);
if (processing_template_decl && rval != error_mark_node)
return build_min_non_dep (INDIRECT_REF, rval, orig_expr);
*************** convert_arguments (tree typelist, tree v
*** 2652,2662 ****
/* Build a binary-operation expression, after performing default
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)
{
tree orig_arg1;
tree orig_arg2;
tree expr;
--- 2653,2664 ----
/* Build a binary-operation expression, after performing default
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,
! bool *overloaded_p)
{
tree orig_arg1;
tree orig_arg2;
tree expr;
*************** build_x_binary_op (enum tree_code code,
*** 2673,2683 ****
}
if (code == DOTSTAR_EXPR)
expr = build_m_component_ref (arg1, arg2);
else
! expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
return expr;
--- 2675,2686 ----
}
if (code == DOTSTAR_EXPR)
expr = build_m_component_ref (arg1, arg2);
else
! 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);
return expr;
*************** build_x_unary_op (enum tree_code code, t
*** 3530,3540 ****
&& ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
&& !COMPLETE_TYPE_P (TREE_TYPE (xarg)))
|| (TREE_CODE (xarg) == OFFSET_REF)))
/* Don't look for a function. */;
else
! exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE);
if (!exp && code == ADDR_EXPR)
{
/* A pointer to member-function can be formed only by saying
&X::mf. */
if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
--- 3533,3544 ----
&& ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
&& !COMPLETE_TYPE_P (TREE_TYPE (xarg)))
|| (TREE_CODE (xarg) == OFFSET_REF)))
/* Don't look for a function. */;
else
! 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
&X::mf. */
if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
*************** build_x_compound_expr (tree op1, tree op
*** 4370,4380 ****
return build_min_nt (COMPOUND_EXPR, op1, op2);
op1 = build_non_dependent_expr (op1);
op2 = build_non_dependent_expr (op2);
}
! result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE);
if (!result)
result = build_compound_expr (op1, op2);
if (processing_template_decl && result != error_mark_node)
return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2);
--- 4374,4385 ----
return build_min_nt (COMPOUND_EXPR, op1, op2);
op1 = build_non_dependent_expr (op1);
op2 = build_non_dependent_expr (op2);
}
! result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
! /*overloaded_p=*/NULL);
if (!result)
result = build_compound_expr (op1, op2);
if (processing_template_decl && result != error_mark_node)
return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2);
*************** build_modify_expr (tree lhs, enum tree_c
*** 5066,5076 ****
if (! IS_AGGR_TYPE (lhstype))
/* Do the default thing. */;
else
{
result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
! lhs, rhs, make_node (NOP_EXPR));
if (result == NULL_TREE)
return error_mark_node;
return result;
}
lhstype = olhstype;
--- 5071,5082 ----
if (! IS_AGGR_TYPE (lhstype))
/* Do the default thing. */;
else
{
result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
! lhs, rhs, make_node (NOP_EXPR),
! /*overloaded_p=*/NULL);
if (result == NULL_TREE)
return error_mark_node;
return result;
}
lhstype = olhstype;
*************** build_x_modify_expr (tree lhs, enum tree
*** 5278,5288 ****
build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
if (modifycode != NOP_EXPR)
{
tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
! make_node (modifycode));
if (rval)
return rval;
}
return build_modify_expr (lhs, modifycode, rhs);
}
--- 5284,5295 ----
build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
if (modifycode != NOP_EXPR)
{
tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
! make_node (modifycode),
! /*overloaded_p=*/NULL);
if (rval)
return rval;
}
return build_modify_expr (lhs, modifycode, rhs);
}
Index: cp/typeck2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck2.c,v
retrieving revision 1.153.4.1
diff -c -5 -p -r1.153.4.1 typeck2.c
*** cp/typeck2.c 25 Jan 2004 02:52:32 -0000 1.153.4.1
--- cp/typeck2.c 16 Mar 2004 21:30:53 -0000
*************** build_x_arrow (tree expr)
*** 1088,1098 ****
}
if (IS_AGGR_TYPE (type))
{
while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
! NULL_TREE, NULL_TREE)))
{
if (expr == error_mark_node)
return error_mark_node;
if (value_member (TREE_TYPE (expr), types_memoized))
--- 1088,1099 ----
}
if (IS_AGGR_TYPE (type))
{
while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
! NULL_TREE, NULL_TREE,
! /*overloaded_p=*/NULL)))
{
if (expr == error_mark_node)
return error_mark_node;
if (value_member (TREE_TYPE (expr), types_memoized))
Index: testsuite/g++.dg/parse/non-dependent3.C
===================================================================
RCS file: testsuite/g++.dg/parse/non-dependent3.C
diff -N testsuite/g++.dg/parse/non-dependent3.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/non-dependent3.C 16 Mar 2004 21:31:02 -0000
***************
*** 0 ****
--- 1,17 ----
+ // 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> ();