Description
Problem statement
When using extern type
s to interface with opaque types from C libraries, I often find it natural to use a reference to this type (the foreign-types
crate captures this idea as well).
However, in C it can be considered an implementation detail whether an opaque pointer uses tagged pointers under the hood or not, which means that for a Rust library to be sound, it cannot work with references to extern type
s, they must always be accessed as raw pointers.
Proposed solution
While workable, I think this is overly restrictive, so I would like to propose that we allow any bit-pattern other than NULL in references to extern type
s.
That is, we guarantee that &ExternType
is bit-wise compatible with NonNull<ExternType>
: It has no alignment requirements, and may be a tagged or dangling pointer.
TODO: Unsure about aliasing requirements, they would probably still hold somewhat in the same way they do now.
Consequences
I don't think this would impact optimization potential, extern type
s are only directly accessed from code that already knows the concrete size of the type (and in that case, will just convert the extern type
to the concrete type).
However, there are two negatives:
- The pointer part of
&dyn Trait
would be subject to the same restrictions (since one may coerce an extern type to that) - this need not be guaranteed to the user though. &dyn Trait
and&ExternType
can't use other niche-optimizations than the usual null-pointer optimization.
Just to clarify, &Foo
in the following example would still be subject to the usual dereferenceability restrictions, but &Bar
would not.
extern "C" {
type Opaque;
}
#[repr(C)]
struct Foo {
a: i16,
b: Opaque,
}
#[repr(C)]
struct Bar {
a: PhantomData<i32>, // ZST
b: Opaque,
}