Hi! For EXPAND_NORMAL we shouldn't be returning (plus (reg) (const_int)), that should be limited to EXPAND_SUM and higher modifiers. But with -fsection-anchors we sometimes do.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, tested with cross to powerpc64-linux on the testcase. Ok for trunk? 2012-02-01 Jakub Jelinek <ja...@redhat.com> PR middle-end/52074 * expr.c (expand_expr_addr_expr_1): For CONSTANT_CLASS_P or CONST_DECL if modifier < EXPAND_SUM call force_operand on the result. * gcc.c-torture/compile/pr52074.c: New test. --- gcc/expr.c.jj 2012-01-30 00:10:01.000000000 +0100 +++ gcc/expr.c 2012-02-01 13:00:03.468835769 +0100 @@ -7414,7 +7414,12 @@ expand_expr_addr_expr_1 (tree exp, rtx t generating ADDR_EXPR of something that isn't an LVALUE. The only exception here is STRING_CST. */ if (CONSTANT_CLASS_P (exp)) - return XEXP (expand_expr_constant (exp, 0, modifier), 0); + { + result = XEXP (expand_expr_constant (exp, 0, modifier), 0); + if (modifier < EXPAND_SUM) + result = force_operand (result, target); + return result; + } /* Everything must be something allowed by is_gimple_addressable. */ switch (TREE_CODE (exp)) @@ -7433,7 +7438,11 @@ expand_expr_addr_expr_1 (tree exp, rtx t case CONST_DECL: /* Expand the initializer like constants above. */ - return XEXP (expand_expr_constant (DECL_INITIAL (exp), 0, modifier), 0); + result = XEXP (expand_expr_constant (DECL_INITIAL (exp), + 0, modifier), 0); + if (modifier < EXPAND_SUM) + result = force_operand (result, target); + return result; case REALPART_EXPR: /* The real part of the complex number is always first, therefore --- gcc/testsuite/gcc.c-torture/compile/pr52074.c.jj 2012-02-01 13:03:26.236788697 +0100 +++ gcc/testsuite/gcc.c-torture/compile/pr52074.c 2012-02-01 13:03:07.000000000 +0100 @@ -0,0 +1,10 @@ +/* PR middle-end/52074 */ + +struct S { const char *d, *e; } __attribute__((packed)); + +void +foo (const char **p, struct S *q) +{ + *p = "abcdef"; + q->d = "ghijk"; +} Jakub