Hi! For MULT_EXPR and TRUNC_DIV_EXPR, both sides of COMPLEX_EXPR contain a copy of the non-complex operand, which means its side-effects can be evaluated twice. For PLUS_EXPR/MINUS_EXPR they appear just in one of the operands and thus it works fine as is.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/4.6? 2011-07-07 Jakub Jelinek <ja...@redhat.com> PR c/49644 * c-typeck.c (build_binary_op): For MULT_EXPR and TRUNC_DIV_EXPR with one non-complex and one complex argument, call c_save_expr on both operands. * gcc.c-torture/execute/pr49644.c: New test. --- gcc/c-typeck.c.jj 2011-05-31 08:03:10.000000000 +0200 +++ gcc/c-typeck.c 2011-07-07 11:47:31.000000000 +0200 @@ -10032,6 +10032,8 @@ build_binary_op (location_t location, en if (first_complex) { op0 = c_save_expr (op0); + if (code == MULT_EXPR || code == TRUNC_DIV_EXPR) + op1 = c_save_expr (op1); real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR, op0, 1); imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR, @@ -10052,6 +10054,8 @@ build_binary_op (location_t location, en } else { + if (code == MULT_EXPR) + op0 = c_save_expr (op0); op1 = c_save_expr (op1); real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR, op1, 1); --- gcc/testsuite/gcc.c-torture/execute/pr49644.c.jj 2011-07-07 11:48:34.000000000 +0200 +++ gcc/testsuite/gcc.c-torture/execute/pr49644.c 2011-07-07 11:35:52.000000000 +0200 @@ -0,0 +1,16 @@ +/* PR c/49644 */ + +extern void abort (void); + +int +main (void) +{ + _Complex double a[12], *c = a, s = 3.0 + 1.0i; + double b[12] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }, *d = b; + int i; + for (i = 0; i < 6; i++) + *c++ = *d++ * s; + if (c != a + 6 || d != b + 6) + abort (); + return 0; +} Jakub