On Sun, Dec 3, 2023 at 9:51 PM Jason McKesson via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Sun, Dec 3, 2023 at 5:26 PM Thiago Macieira via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
> Some other code using NUA on your own types is wrong. One should only use NUA
> for types that declare that they don't need unique addresses. There's no
> property for this, therefore using NUA on arbitrary types is wrong.

While I can understand that, I don't really agree.

The primary purpose of NUA was for *empty* types, not to slip
something into the padding bits of a non-empty type. Yes, that's a
thing it *can* do, but that's not what it's for. Remember: the feature
was added so that you could have the member equivalent of empty base
optimizations. And one of the main purposes of EBO is for types like
allocators which are frequently empty and thus should be declared NUA
when they're members.

So if "using NUA on arbitrary types is wrong", then the feature is
fundamentally broken.

Using [[no_unique_address]] on arbitrary types is wrong.
Using [[no_unique_address]] on Allocator and Comparator members is fine-and-expected; those types are (1) frequently empty and (2) always understood by the client code to be value-semantic, i.e., the client code will never try to take their address or "use" every byte of their storage.

What I think Thiago meant, and certainly what I mean, is that it's wrong to use [[no_unique_address]] on the `value` member of an `optional` or `expected`; it's wrong to use it on the pointer members of a `vector` or `set`; it's wrong to use it on the `container` member of a `priority_queue`; it's wrong to use it on the elements of a `tuple` or the alternatives of a `variant`. It's wrong to use it arbitrarily.
The specific, limited, conservative, non-arbitrary place that it's okay to use it is on a policy type like Allocator or Comparator or Predicate or ExecutionPolicy that is expected to be empty most of the time. A client programmer who provides a non-empty type for such a parameter is expected to know what they're doing, and not to do anything too cavalier with memcpy, address-escaping, or address-comparison.