https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86318
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |NEW Last reconfirmed| |2018-06-26 CC| |rguenth at gcc dot gnu.org Ever confirmed|0 |1 --- Comment #1 from Richard Biener <rguenth at gcc dot gnu.org> --- Confirmed. It is the frontend doing the optimization likely during its folding. The middle-end doesn't in any way honor 'const' since const S s = { .... }; can be expanded (gimplified) to a automatic variable initialized by one or multiple assignments (so that automatic variable isn't "constant"): For example g1: g1 () { const int a[1]; int _1; <bb 2> : a[0] = 1; f (&a); _1 = a[0]; if (_1 != 1) so here a[0] is assigned to. If we'd always place such constants in .rodata (use a CONST_DECL) things might work but then optimization cannot elide (parts of) such initializer. Previously RTL had a thing like RTX_UNCHANGING which meant values do not change once set. But that was a recipie for desaster (wrong-code). For simple cases like g1 the FE could fold the read from *a but I could see the following case as difficult for the FE to "fold" (unless you want to "constexpr" evaluate all stmts). void g3 (void) { const struct S s = { 1 }; f (&s); struct S q = s; if (q.i != 1) abort (); } A solution on the optimizer side is difficult, it would likely need to separate "initialization" from "modification" somehow. Like wrapping the "const" a's in the accesses: g1 () { const int a[1]; int _1; <bb 2> : a[0] = 1; f (&CONST<a>); _1 = CONST<a>[0]; either by a bit on the reference trees or by an explicit handled-component. The address-taking context is somewhat awkward to deal with I think. In the end it would be the FEs responsibility to "wrap" stuff or the gimplifier could wrap all but the initialization stmts. Or we could do it the other way around, wrap the initialization refs.