about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs36
-rw-r--r--tests/codegen/drop-in-place-noalias.rs42
2 files changed, 42 insertions, 36 deletions
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index b7d4d90f109..15c19104616 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -238,7 +238,7 @@ fn adjust_for_rust_scalar<'tcx>(
     layout: TyAndLayout<'tcx>,
     offset: Size,
     is_return: bool,
-    is_drop_target: bool,
+    drop_target_pointee: Option<Ty<'tcx>>,
 ) {
     // Booleans are always a noundef i1 that needs to be zero-extended.
     if scalar.is_bool() {
@@ -252,14 +252,24 @@ fn adjust_for_rust_scalar<'tcx>(
     }
 
     // Only pointer types handled below.
-    let Scalar::Initialized { value: Pointer(_), valid_range} = scalar else { return };
+    let Scalar::Initialized { value: Pointer(_), valid_range } = scalar else { return };
 
-    if !valid_range.contains(0) {
+    // Set `nonnull` if the validity range excludes zero, or for the argument to `drop_in_place`,
+    // which must be nonnull per its documented safety requirements.
+    if !valid_range.contains(0) || drop_target_pointee.is_some() {
         attrs.set(ArgAttribute::NonNull);
     }
 
     if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
-        if let Some(kind) = pointee.safe {
+        let kind = if let Some(kind) = pointee.safe {
+            Some(kind)
+        } else if let Some(pointee) = drop_target_pointee {
+            // The argument to `drop_in_place` is semantically equivalent to a mutable reference.
+            Some(PointerKind::MutableRef { unpin: pointee.is_unpin(cx.tcx, cx.param_env()) })
+        } else {
+            None
+        };
+        if let Some(kind) = kind {
             attrs.pointee_align = Some(pointee.align);
 
             // `Box` are not necessarily dereferenceable for the entire duration of the function as
@@ -307,18 +317,6 @@ fn adjust_for_rust_scalar<'tcx>(
                 attrs.set(ArgAttribute::ReadOnly);
             }
         }
-
-        // If this is the argument to `drop_in_place`, the contents of which we fully control as the
-        // compiler, then we mark this argument as `noalias`, aligned, and dereferenceable. (The
-        // standard library documents the necessary requirements to uphold these attributes for code
-        // that calls this method directly.) This can enable better optimizations, such as argument
-        // promotion.
-        if is_drop_target {
-            attrs.set(ArgAttribute::NoAlias);
-            attrs.set(ArgAttribute::NonNull);
-            attrs.pointee_size = pointee.size;
-            attrs.pointee_align = Some(pointee.align);
-        }
     }
 }
 
@@ -383,6 +381,10 @@ fn fn_abi_new_uncached<'tcx>(
         let _entered = span.enter();
         let is_return = arg_idx.is_none();
         let is_drop_target = is_drop_in_place && arg_idx == Some(0);
+        let drop_target_pointee = is_drop_target.then(|| match ty.kind() {
+            ty::RawPtr(ty::TypeAndMut { ty, .. }) => *ty,
+            _ => bug!("argument to drop_in_place is not a raw ptr: {:?}", ty),
+        });
 
         let layout = cx.layout_of(ty)?;
         let layout = if force_thin_self_ptr && arg_idx == Some(0) {
@@ -403,7 +405,7 @@ fn fn_abi_new_uncached<'tcx>(
                 *layout,
                 offset,
                 is_return,
-                is_drop_target,
+                drop_target_pointee,
             );
             attrs
         });
diff --git a/tests/codegen/drop-in-place-noalias.rs b/tests/codegen/drop-in-place-noalias.rs
index 64ac8760456..74d40c13c4c 100644
--- a/tests/codegen/drop-in-place-noalias.rs
+++ b/tests/codegen/drop-in-place-noalias.rs
@@ -1,34 +1,38 @@
-// Tests that the compiler can mark `drop_in_place` as `noalias` when safe to do so.
+// compile-flags: -C no-prepopulate-passes
+
+// Tests that the compiler can apply `noalias` and other &mut attributes to `drop_in_place`.
+// Note that non-Unpin types should not get `noalias`, matching &mut behavior.
 
 #![crate_type="lib"]
 
-use std::hint::black_box;
+use std::marker::PhantomPinned;
+
+// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}({{.*\*|ptr}} noalias noundef align 4 dereferenceable(12) %{{.+}})
 
-// CHECK: define{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}Foo{{.*}}({{.*}}noalias {{.*}} align 4 dereferenceable(12){{.*}})
+// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}({{.*\*|ptr}} noundef nonnull align 4 %{{.+}})
 
-#[repr(C)]
-pub struct Foo {
+pub struct StructUnpin {
     a: i32,
     b: i32,
     c: i32,
 }
 
-impl Drop for Foo {
-    #[inline(never)]
-    fn drop(&mut self) {
-        black_box(self.a);
-    }
+impl Drop for StructUnpin {
+    fn drop(&mut self) {}
+}
+
+pub struct StructNotUnpin {
+    a: i32,
+    b: i32,
+    c: i32,
+    p: PhantomPinned,
 }
 
-extern {
-    fn bar();
-    fn baz(foo: Foo);
+impl Drop for StructNotUnpin {
+    fn drop(&mut self) {}
 }
 
-pub fn haha() {
-    let foo = Foo { a: 1, b: 2, c: 3 };
-    unsafe {
-        bar();
-        baz(foo);
-    }
+pub unsafe fn main(x: StructUnpin, y: StructNotUnpin) {
+    drop(x);
+    drop(y);
 }