diff options
| -rw-r--r-- | compiler/rustc_ty_utils/src/abi.rs | 36 | ||||
| -rw-r--r-- | tests/codegen/drop-in-place-noalias.rs | 42 |
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); } |
