Hi! The following (invalid) testcase ICEs, because we try to store into CONST_DECL's FIELD. Normally in GIMPLE we have MEM_REF[&C.1234] and writes to that expand gracefully into a MEM, but as soon as we use get_inner_reference in expand_assignment (even if the MEM is just reverse order, or we just want to store to a part of it etc.), get_inner_reference looks through even that MEM_REF. Instead of hacking that around in expand_assignment, just attempting to handle EXPAND_WRITE into CONST_DECL looked easier to me.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2016-10-14 Jakub Jelinek <ja...@redhat.com> PR middle-end/77959 * expr.c (expand_expr_real_1) <case CONST_DECL>: For EXPAND_WRITE return a MEM. * gfortran.dg/pr77959.f90: New test. --- gcc/expr.c.jj 2016-10-09 13:19:09.000000000 +0200 +++ gcc/expr.c 2016-10-13 11:49:36.386993921 +0200 @@ -9914,6 +9914,19 @@ expand_expr_real_1 (tree exp, rtx target } case CONST_DECL: + if (modifier == EXPAND_WRITE) + { + /* Writing into CONST_DECL is always invalid, but handle it + gracefully. */ + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp)); + machine_mode address_mode = targetm.addr_space.address_mode (as); + op0 = expand_expr_addr_expr_1 (exp, NULL_RTX, address_mode, + EXPAND_NORMAL, as); + op0 = memory_address_addr_space (mode, op0, as); + temp = gen_rtx_MEM (mode, op0); + set_mem_addr_space (temp, as); + return temp; + } return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier); case REAL_CST: --- gcc/testsuite/gfortran.dg/pr77959.f90.jj 2016-10-13 11:57:30.019992471 +0200 +++ gcc/testsuite/gfortran.dg/pr77959.f90 2016-10-13 11:58:50.719969914 +0200 @@ -0,0 +1,16 @@ +! PR middle-end/77959 +! { dg-do compile } +! { dg-options "-O2" } + +program pr77959 + interface + subroutine foo(x) ! { dg-warning "Type mismatch in argument" } + real :: x + end + end interface + call foo(1.0) +end +subroutine foo(x) + complex :: x + x = x + 1 +end Jakub