I am assuming that this is for interfacing to a C library where the C defined type is a pointer type that you want to use within Modula-2.
In general terms, you only get the type safety if the compiler has a definition for the type. If you cast a C pointer to ADDRESS, then as far as the Modula-2 compiler is concerned this is of type ADDRESS and per language definition any pointer is compatible with ADDRESS.
However, when interfacing to C, it is advisable to use a layered approach
* a low level library that directly interfaces to the C API
* a user level library that imports the low level library and wraps the types and functions, adding type safety
I have done this in one of my projects and the code is on github.
The code base is cross-platform (AmigaOS, MacOS X, MS-DOS, OS/2, OpenVMS, Posix, Windows), multi-dialect (PIM3/4 and ISO) and multi-compiler (ca.14 or 15 different M2 compilers) and thus there is a lowest level interface to the various OS' C APIs, often with separate implementations for different platforms. At this level there is no type safety, but on top is a Modula-2 library that imports the low-level interface, wraps the types and functions and provides type safety for the user level. User level code should never directly use the low level libraries.
For example, there are several low level libraries to interface to the C stdio library for POSIX platforms:
At this level there is an unsafe file type ...
TYPE FILE = ADDRESS;
On top of the low-level library, I implemented a file IO library in Modula-2
At this level, there is a safe file type ...
TYPE File; (* OPAQUE *)
This is the user-level library that the project code uses. The low-level libraries are only called by this library.
hope this helps.