placement new on a class with reference field
To answer the currently open questions:
First question:
- What is the case of such code in C++14 or before (when std::launder didn't exist)? Probably it is UB - this is why std::launder was brought to the game, right?
Yes, it was UB. This is mentioned explicitly in the NB issues @Language Lawyer referred to:
Because of that issue all the standard libraries have undefined behaviors in widely used types. The only way to fix that issue is to adjust the lifetime rules to auto-launder the placement new. (https://github.com/cplusplus/nbballot/issues/7)
Second question:
If in C++20 we do not need std::launder for such a case, how the compiler can understand that the reference is being manipulated without our help (i.e. without "Pointer optimization barrier") to avoid caching of the reference value?
Compilers already know to not optimize object (or sub-object) value this way if a non-const member function was called between two usages of the object or if any function was called with the object as a parameter (passed by-ref), because this value may be changed by those functions. This change to the standard just added a few more cases where such optimization is illegal.
It is legal to replace objects with const-qualified and reference non-static data members. And now, in C++20, [the name of|a [pointer|reference] to] the original object will refer to the new object after replacement. The rules has been changed in response to RU007/US042 NB comments http://wg21.link/p1971r0#RU007:
RU007. [basic.life].8.3 Relax pointer value/aliasing rules
...
Change 6.7.3 [basic.life] bullet 8.3 as follows:
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:
...
the
type of theoriginal object isnot const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference typeneither a complete object that is const-qualified nor a subobject of such an object, and...