https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93246
--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> --- So FRE optimizes wo.value = &buf; _48 = __MEM <struct Optional *> ((struct Optional * *)&wo); _20 = __MEM <const bool> ((bool *)_48); if (_20 != _Literal (bool) 0) goto __BB4; else goto __BB3; __BB(3): _48->inner.present = _Literal (bool) 1; goto __BB4; __BB(4): _49 = __MEM <struct Optional *> ((struct Optional * *)&wo); _52 = __MEM <const bool> ((bool *)_49); in a way disregarding the store via _48->inner.present. Adjusted testcase that doesn't need -fsanitize=address. I wonder if that results in the same bisection for the "fix"? #include <iostream> template <typename = void> struct Optional { auto is_present() const { return inner.present; } auto set_present() { if (not is_present()) inner.present = true; } struct InnerType { bool present = false; char padding[1] = {0}; }; using inner_t = InnerType; // InnerType inner = {}; // this works as expected! inner_t inner = {}; // this doesn't! }; template <typename WrappedType> struct Wrapper { auto operator-> () { return value; } WrappedType *value; }; void __attribute__((noipa)) foo(Optional<>& x) {} int main() { Optional<> buf{}; foo(buf); Wrapper<Optional<>> wo = {&buf}; wo->set_present(); auto x = wo->is_present(); auto y = wo->is_present(); std::cout << "x=" << x << ", y=" << y; auto z = wo->is_present(); std::cout << ", z=" << z << "\n"; }