To expand on the accepted answer, the reason why this is allowed:
ImmutablePoint init = { .x = x, .y = y };
ImmutablePoint *p = malloc(sizeof *p);
memcpy(p, &init, sizeof *p);
Is because memory returned by malloc (or more accurately, the object returned) has no effective type and is therefore allowed to be written to. Then once memcpy is used to copy in the source object, the effective type of the allocated object becomes ImmutablePoint.
This is spelled out in section 6.5p6 of the C standard:
The effective type of an object for an access to its stored value is
the declared type of the object, if any. 87) If a value is
stored into an object having no declared type through an lvalue having
a type that is not a character type, then the type of the lvalue
becomes the effective type of the object for that access and for
subsequent accesses that do not modify the stored value. If a value is
copied into an object having no declared type using memcpy or memmove,
or is copied as an array of character type, then the effective type of
the modified object for that access and for subsequent accesses that
do not modify the value is the effective type of the object from which
the value is copied, if it has one. For all other accesses to an
object having no declared type, the effective type of the object is
simply the type of the lvalue used for the access.
87) Allocated objects have no declared type.