Hi! The following testcase is miscompiled, because during cp_finish_decl when handling the initializer of the reference we clear TREE_READONLY, because it needs to be initialized at runtime, but the (useless) later extern decl has TREE_READONLY set and when we are merging the two decls, we set TREE_READONLY on the old decl back. The middle-end then sees TREE_READONLY variable and because it has NULL DECL_INITIAL, assumes it is all zeros.
This patch prevents it by honoring TREE_READONLY from the decl with an initializer (if any) instead of oring TREE_READONLY from both decls. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk (and after some time for 6.x)? 2016-06-14 Jakub Jelinek <ja...@redhat.com> PR c++/71528 * decl.c (duplicate_decls): For DECL_INITIALIZED_P non-external olddecl vars, preserve their TREE_READONLY bit. * g++.dg/opt/pr71528.C: New test. --- gcc/cp/decl.c.jj 2016-06-13 20:45:11.000000000 +0200 +++ gcc/cp/decl.c 2016-06-14 16:08:03.796145254 +0200 @@ -2066,6 +2066,14 @@ duplicate_decls (tree newdecl, tree oldd if (VAR_P (newdecl)) { DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl); + /* For already initialized vars, TREE_READONLY could have been + cleared in cp_finish_decl, because the var needs runtime + initialization or destruction. Make sure not to set + TREE_READONLY on it again. */ + if (DECL_INITIALIZED_P (olddecl) + && !DECL_EXTERNAL (olddecl) + && !TREE_READONLY (olddecl)) + TREE_READONLY (newdecl) = 0; DECL_INITIALIZED_P (newdecl) |= DECL_INITIALIZED_P (olddecl); DECL_NONTRIVIALLY_INITIALIZED_P (newdecl) |= DECL_NONTRIVIALLY_INITIALIZED_P (olddecl); --- gcc/testsuite/g++.dg/opt/pr71528.C.jj 2016-06-14 16:17:06.161368105 +0200 +++ gcc/testsuite/g++.dg/opt/pr71528.C 2016-06-14 16:10:12.000000000 +0200 @@ -0,0 +1,23 @@ +// PR c++/71528 +// { dg-do run } +// { dg-options "-O2" } + +extern int &x; +int y; + +int & +foo () +{ + return y; +} + +int &x = foo (); + +int +main () +{ + if (&x != &y) + __builtin_abort (); +} + +extern int &x; Jakub