https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95349
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |rguenth at gcc dot gnu.org Keywords| |alias, wrong-code --- Comment #1 from Richard Biener <rguenth at gcc dot gnu.org> --- I think std::launder merely acts as optimization barrier here and without we manage to propagate the constant. We still "miscompile" things dependent on what exactly the C++ standard says. When seeing std::uint64_t* s3(double* p) { unsigned char storage[sizeof(std::uint64_t)]; std::memcpy(storage, p, sizeof(storage)); auto t = new(p) std::uint64_t; std::memcpy(t, storage, sizeof(storage)); return t; } the placement new has no effect (it's just passing through a pointer) and memcpy has C semantics, transfering the active dynamic type of 'p' through 'storage' back to 'p'. std::uint64_t f3() { double d = 3.14159; return *s3(&d); } ... which is still 'double'. Which you then access via an lvalue of type uint64_t which invokes undefined behavior. So in GCCs implementation reading of relevant standards you need -fno-strict-aliasing and your program is not conforming. So what goes on is that GCC optimizes s3 to just { return (uint64t *)p; } which makes f3 effectively do double d = 3.14159; return *(uint64_t *)&d; which arguably is bogus. Without the std::launder we are nice to the user and "optimize" the above to return the correct value. With std::launder we cannot do this since it breaks the pointer flow and we'll DSE the initialization of 'd' because it is not used (due to the undefinedness in case the load would alias it).