Nonsense. Aliasing unlike-typed objects via memcpy is equivalent to pointer aliasing. memcpy has void pointer arguments. You're relying on the addresses of the source and destination objects being converted to void pointer.
All type punning is in the hands of the implementation. The language definition provides the syntax for it, which has the virtuel that all code which attempts to do type punning expresses it in the same manner. However, the language leaves it up to implementations to define whether type punning works, and with what caveats and restrictions.
> E.g. you can't memcpy a uint64 to a double and expect well-defined behavior.
Yes, you can. The behavior is implementation-defined but not undefined. (Well, it can trigger undefined behavior if the value corresponds to a signaling NaN, or if the implementation uses a nonstandard, non-IEEE format for doubles that has other "trap representations". But it's not otherwise undefined.)
The basis for this is that the aliasing rule has an explicit exception for reading or writing to objects using char pointers, i.e. byte-by-byte, regardless of the object's type. This exception is in both the C standard:
The memcpy function is defined as copying characters, so the exception applies to it too.
Both standards also explicitly define that objects (at least of POD types) have byte representations and those representations are implementation-defined (as opposed to triggering undefined behavior if you depend on them). For C:
> Except for bit-fields, objects are composed of contiguous sequences of one or more bytes, the number, order, and encoding of which are either explicitly specified or implementation-defined.
"access" refers to reading there. Not reading or writing. Objects may be treated as arrays of character type to the extent that their value may be examined that way.
If you memcpy a uint64_t to a double, the implementation is not required to notice that the double variable's value has changed; a subsequent access to that variable can continue to refer to a register. It's not a matter of what bit pattern was stored there.
> 3.1
> 1 access
>〈execution-time action〉 to read or modify the value of an object
Thus, the requirement is symmetrical. The compiler must consider any char write as potentially aliasing a subsequent read (or write) of any type, unless it can prove non-aliasing without depending on type. And similarly, it must consider a write of any type as potentially aliasing a subsequent char read/write.
Pointers are converted in order that they be used. Though the uses may be undefined, there is value in the conversion having a well-defined syntax. In effect, C and C++ allow certain intents to be expressed in a common way, without requiring implementations to make those intents work. This is better than having compiler-specific syntax for that sort of thing.