about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs15
-rw-r--r--compiler/rustc_target/src/abi/mod.rs10
-rw-r--r--src/test/codegen/function-arguments.rs20
3 files changed, 36 insertions, 9 deletions
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 3c27e36795e..dde55dd9655 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2636,7 +2636,7 @@ where
                             if ty.is_unpin(tcx.at(DUMMY_SP), cx.param_env()) {
                                 PointerKind::UniqueBorrowed
                             } else {
-                                PointerKind::SharedMutable
+                                PointerKind::UniqueBorrowedPinned
                             }
                         }
                     }
@@ -3255,10 +3255,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                     // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
                     // for the entire duration of the function as they can be deallocated
-                    // at any time. Set their valid size to 0.
+                    // at any time. Same for shared mutable references. If LLVM had a
+                    // way to say "dereferenceable on entry" we could use it here.
                     attrs.pointee_size = match kind {
-                        PointerKind::UniqueOwned => Size::ZERO,
-                        _ => pointee.size,
+                        PointerKind::UniqueBorrowed
+                        | PointerKind::UniqueBorrowedPinned
+                        | PointerKind::Frozen => pointee.size,
+                        PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
                     };
 
                     // `Box`, `&T`, and `&mut T` cannot be undef.
@@ -3285,7 +3288,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     // or not to actually emit the attribute. It can also be controlled with the
                     // `-Zmutable-noalias` debugging option.
                     let no_alias = match kind {
-                        PointerKind::SharedMutable | PointerKind::UniqueBorrowed => false,
+                        PointerKind::SharedMutable
+                        | PointerKind::UniqueBorrowed
+                        | PointerKind::UniqueBorrowedPinned => false,
                         PointerKind::UniqueOwned => noalias_for_box,
                         PointerKind::Frozen => !is_return,
                     };
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index b8398daadf1..b35502d9ee4 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -1352,13 +1352,17 @@ pub enum PointerKind {
     /// Most general case, we know no restrictions to tell LLVM.
     SharedMutable,
 
-    /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`.
+    /// `&T` where `T` contains no `UnsafeCell`, is `dereferenceable`, `noalias` and `readonly`.
     Frozen,
 
-    /// `&mut T` which is `noalias` but not `readonly`.
+    /// `&mut T` which is `dereferenceable` and `noalias` but not `readonly`.
     UniqueBorrowed,
 
-    /// `Box<T>`, unlike `UniqueBorrowed`, it also has `noalias` on returns.
+    /// `&mut !Unpin`, which is `dereferenceable` but neither `noalias` nor `readonly`.
+    UniqueBorrowedPinned,
+
+    /// `Box<T>`, which is `noalias` (even on return types, unlike the above) but neither `readonly`
+    /// nor `dereferenceable`.
     UniqueOwned,
 }
 
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index ae6abe7a184..dda139be6fc 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -5,6 +5,7 @@
 
 use std::mem::MaybeUninit;
 use std::num::NonZeroU64;
+use std::marker::PhantomPinned;
 
 pub struct S {
   _field: [i32; 8],
@@ -14,6 +15,11 @@ pub struct UnsafeInner {
   _field: std::cell::UnsafeCell<i16>,
 }
 
+pub struct NotUnpin {
+  _field: i32,
+  _marker: PhantomPinned,
+}
+
 pub enum MyBool {
   True,
   False,
@@ -91,7 +97,7 @@ pub fn static_borrow(_: &'static i32) {
 pub fn named_borrow<'r>(_: &'r i32) {
 }
 
-// CHECK: @unsafe_borrow({{i16\*|ptr}} noundef align 2 dereferenceable(2) %_1)
+// CHECK: @unsafe_borrow({{i16\*|ptr}} noundef nonnull align 2 %_1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_borrow(_: &UnsafeInner) {
@@ -109,6 +115,18 @@ pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
 pub fn mutable_borrow(_: &mut i32) {
 }
 
+#[no_mangle]
+// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef align 4 dereferenceable(4) %_1)
+// This one is *not* `noalias` because it might be self-referential.
+pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
+}
+
+// CHECK: @notunpin_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
+// But `&NotUnpin` behaves perfectly normal.
+#[no_mangle]
+pub fn notunpin_borrow(_: &NotUnpin) {
+}
+
 // CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {