about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-05-22 18:08:13 +0200
committerGitHub <noreply@github.com>2019-05-22 18:08:13 +0200
commit7cd8d3d8d00bcadb32a4243f33b91c7b89af7a69 (patch)
treeb167a1dabb4ded350807e1245a9b99dfd5019938 /src/libcore
parent37ff5d388f8c004ca248adb635f1cc84d347eda0 (diff)
parenta31dc8e3b153ac3073f9fb14d8e523a350fe10f2 (diff)
downloadrust-7cd8d3d8d00bcadb32a4243f33b91c7b89af7a69.tar.gz
rust-7cd8d3d8d00bcadb32a4243f33b91c7b89af7a69.zip
Rollup merge of #60300 - mjbshaw:ffi_types, r=rkruppe
Allow null-pointer-optimized enums in FFI if their underlying representation is FFI safe

I'm not sure if this requires an RFC. I attempted to start [a discussion on internals.rust-lang.org](https://internals.rust-lang.org/t/options-ffi-safety-and-guarantees-for-abi-compatibility-with-nonnull-optimizations/9784) and when no one really objected I figured I'd go ahead and try implementing this.

This allows types like `Option<NonZeroU8>` to be used in FFI without triggering the `improper_ctypes` lint. This works by changing the `is_repr_nullable_ptr` function to consider an enum `E` to be FFI-safe if:

- `E` has no explicit `#[repr(...)]`.
- It only has two variants.
- One of those variants is empty (meaning it has no fields).
- The other variant has only one field.
- That field is one of the following:
  - `&T`
  - `&mut T`
  - `extern "C" fn`
  - `core::num::NonZero*`
  - `core::ptr::NonNull<T>`
  - `#[repr(transparent)] struct` wrapper around one of the types in this list.
- The size of `E` and its field are both known and are both the same size (implying `E` is participating in the nonnull optimization).

This logic seems consistent with [the Rust nomicon](https://doc.rust-lang.org/nomicon/repr-rust.html).
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/num/mod.rs1
-rw-r--r--src/libcore/ptr.rs1
2 files changed, 2 insertions, 0 deletions
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 562a7a4b3c7..932c0eaa4c7 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -50,6 +50,7 @@ assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", s
                 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
                 #[repr(transparent)]
                 #[rustc_layout_scalar_valid_range_start(1)]
+                #[cfg_attr(not(stage0), rustc_nonnull_optimization_guaranteed)]
                 pub struct $Ty($Int);
             }
 
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 006b1e143ee..4bb4d3ee466 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -2938,6 +2938,7 @@ impl<'a, T: ?Sized> From<NonNull<T>> for Unique<T> {
 #[stable(feature = "nonnull", since = "1.25.0")]
 #[repr(transparent)]
 #[rustc_layout_scalar_valid_range_start(1)]
+#[cfg_attr(not(stage0), rustc_nonnull_optimization_guaranteed)]
 pub struct NonNull<T: ?Sized> {
     pointer: *const T,
 }