>Here's what I want:

>Point 1) void* and char* are exactly the >same.

 At hardware level they are already the same, a different pointer size is just a compiler concept, backed up by some bookkeeping.
void* has always the size of the CPU register, for efficiency, configuring it to a smaller size is a compiler concept, that is, instead of using the natural architecture instruction, the compiler issues a smaller register instruction.
Expl: instead of
mov rax, [valueOf ptr] => mov eax, [valueOf ptr]
         ^^^ in 64bit Arch use a     ^^^ 32bit void*

>Point 2) All data pointers have the same size >and alignment. So if you
>apply "sizeof" or "alignof" to any data pointer, >you always get the
>same answer. Same representation too, >obviously.

Currently they have all the same alignment.
The only difference is when you want to read the pointer value, 
if it is of size 2, use a CPU register of size 2
If it is of size 4, use a CPU register of size 4
...etc


>Point 3) No loss of precision when converting >between pointer types
>whose pointed-to type have differing >alignment requirements.

It is already the case. The compiler is not allowed to fiddle with the value's bits no matter what alignment the pointed-to type requires.
It is the responsibility of the programmer to observe type aliasing rules, otherwise UB.


>Specifically:

>Even though the memory address of a >'double' will always be a multiple
>of 8, I want the lower 3 bits of the pointer to >still retain their
>value, so that the following is possible:

Yes, it is currently preserved.
Hana Dusíková is using this guarantee for her pointer tagging proposal.

 >   Line 1:  char c;
 >   Line 2:  double *p = static_cast<double*> (static_cast<void*>(&c));
 >   Line 3:  char *p2 = static_cast<char*>(static_cast<void*>( p ));
 >   Line 4:  *p2 = 'h';

This snippet is totally fine and it is equivalent to:

char c;
char* p = &c;
*p = 'h';

No UB observed.

>Looking at Line #2, I could see that a >compiler could possibly
>zero-out the lower 3 bits of the value of 'p', >but I want this to be
>forbidden in C++26.

No it could not, and it is not allowed. The only thing you will MAYBE get is a misaligned pointer to a double memory location, and you should not dereference that pointer, because of aliasing incompatibility otherwise UB.

Try the following code:
#include <stdio.h>

int main()
{
    char arr[8];
    double* ptr = static_cast<double*>(static_cast<void*>(arr+3));
    printf("%p", ptr);

    return 0;
}

// possible output
// 0x7fff934a9d83
                               ^^ misaligned for a double.

>This would be a major simplification of data >pointers in C++, and it
>would aid in relocating objects into unaligned >memory (for example
>std::basic_string<char32_t> which contains a >pointer pointing into its
>own internal buffer).

I didn't understand this statement.