ensure !Unpin types do not get noalias
This commit is contained in:
parent
47444d7c25
commit
644818351b
2 changed files with 42 additions and 36 deletions
|
@ -238,7 +238,7 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||||
layout: TyAndLayout<'tcx>,
|
layout: TyAndLayout<'tcx>,
|
||||||
offset: Size,
|
offset: Size,
|
||||||
is_return: bool,
|
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.
|
// Booleans are always a noundef i1 that needs to be zero-extended.
|
||||||
if scalar.is_bool() {
|
if scalar.is_bool() {
|
||||||
|
@ -252,14 +252,24 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only pointer types handled below.
|
// 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);
|
attrs.set(ArgAttribute::NonNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
|
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);
|
attrs.pointee_align = Some(pointee.align);
|
||||||
|
|
||||||
// `Box` are not necessarily dereferenceable for the entire duration of the function as
|
// `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);
|
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 _entered = span.enter();
|
||||||
let is_return = arg_idx.is_none();
|
let is_return = arg_idx.is_none();
|
||||||
let is_drop_target = is_drop_in_place && arg_idx == Some(0);
|
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 = cx.layout_of(ty)?;
|
||||||
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
|
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
|
||||||
|
@ -403,7 +405,7 @@ fn fn_abi_new_uncached<'tcx>(
|
||||||
*layout,
|
*layout,
|
||||||
offset,
|
offset,
|
||||||
is_return,
|
is_return,
|
||||||
is_drop_target,
|
drop_target_pointee,
|
||||||
);
|
);
|
||||||
attrs
|
attrs
|
||||||
});
|
});
|
||||||
|
|
|
@ -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"]
|
#![crate_type="lib"]
|
||||||
|
|
||||||
use std::hint::black_box;
|
use std::marker::PhantomPinned;
|
||||||
|
|
||||||
// CHECK: define{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}Foo{{.*}}({{.*}}noalias {{.*}} align 4 dereferenceable(12){{.*}})
|
// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}({{.*\*|ptr}} noalias noundef align 4 dereferenceable(12) %{{.+}})
|
||||||
|
|
||||||
#[repr(C)]
|
// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}({{.*\*|ptr}} noundef nonnull align 4 %{{.+}})
|
||||||
pub struct Foo {
|
|
||||||
|
pub struct StructUnpin {
|
||||||
a: i32,
|
a: i32,
|
||||||
b: i32,
|
b: i32,
|
||||||
c: i32,
|
c: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Foo {
|
impl Drop for StructUnpin {
|
||||||
#[inline(never)]
|
fn drop(&mut self) {}
|
||||||
fn drop(&mut self) {
|
|
||||||
black_box(self.a);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern {
|
pub struct StructNotUnpin {
|
||||||
fn bar();
|
a: i32,
|
||||||
fn baz(foo: Foo);
|
b: i32,
|
||||||
|
c: i32,
|
||||||
|
p: PhantomPinned,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn haha() {
|
impl Drop for StructNotUnpin {
|
||||||
let foo = Foo { a: 1, b: 2, c: 3 };
|
fn drop(&mut self) {}
|
||||||
unsafe {
|
}
|
||||||
bar();
|
|
||||||
baz(foo);
|
pub unsafe fn main(x: StructUnpin, y: StructNotUnpin) {
|
||||||
}
|
drop(x);
|
||||||
|
drop(y);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue