Skip to content

Commit 6448183

Browse files
ensure !Unpin types do not get noalias
1 parent 47444d7 commit 6448183

File tree

2 files changed

+42
-36
lines changed

2 files changed

+42
-36
lines changed

compiler/rustc_ty_utils/src/abi.rs

+19-17
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ fn adjust_for_rust_scalar<'tcx>(
238238
layout: TyAndLayout<'tcx>,
239239
offset: Size,
240240
is_return: bool,
241-
is_drop_target: bool,
241+
drop_target_pointee: Option<Ty<'tcx>>,
242242
) {
243243
// Booleans are always a noundef i1 that needs to be zero-extended.
244244
if scalar.is_bool() {
@@ -252,14 +252,24 @@ fn adjust_for_rust_scalar<'tcx>(
252252
}
253253

254254
// Only pointer types handled below.
255-
let Scalar::Initialized { value: Pointer(_), valid_range} = scalar else { return };
255+
let Scalar::Initialized { value: Pointer(_), valid_range } = scalar else { return };
256256

257-
if !valid_range.contains(0) {
257+
// Set `nonnull` if the validity range excludes zero, or for the argument to `drop_in_place`,
258+
// which must be nonnull per its documented safety requirements.
259+
if !valid_range.contains(0) || drop_target_pointee.is_some() {
258260
attrs.set(ArgAttribute::NonNull);
259261
}
260262

261263
if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
262-
if let Some(kind) = pointee.safe {
264+
let kind = if let Some(kind) = pointee.safe {
265+
Some(kind)
266+
} else if let Some(pointee) = drop_target_pointee {
267+
// The argument to `drop_in_place` is semantically equivalent to a mutable reference.
268+
Some(PointerKind::MutableRef { unpin: pointee.is_unpin(cx.tcx, cx.param_env()) })
269+
} else {
270+
None
271+
};
272+
if let Some(kind) = kind {
263273
attrs.pointee_align = Some(pointee.align);
264274

265275
// `Box` are not necessarily dereferenceable for the entire duration of the function as
@@ -307,18 +317,6 @@ fn adjust_for_rust_scalar<'tcx>(
307317
attrs.set(ArgAttribute::ReadOnly);
308318
}
309319
}
310-
311-
// If this is the argument to `drop_in_place`, the contents of which we fully control as the
312-
// compiler, then we mark this argument as `noalias`, aligned, and dereferenceable. (The
313-
// standard library documents the necessary requirements to uphold these attributes for code
314-
// that calls this method directly.) This can enable better optimizations, such as argument
315-
// promotion.
316-
if is_drop_target {
317-
attrs.set(ArgAttribute::NoAlias);
318-
attrs.set(ArgAttribute::NonNull);
319-
attrs.pointee_size = pointee.size;
320-
attrs.pointee_align = Some(pointee.align);
321-
}
322320
}
323321
}
324322

@@ -383,6 +381,10 @@ fn fn_abi_new_uncached<'tcx>(
383381
let _entered = span.enter();
384382
let is_return = arg_idx.is_none();
385383
let is_drop_target = is_drop_in_place && arg_idx == Some(0);
384+
let drop_target_pointee = is_drop_target.then(|| match ty.kind() {
385+
ty::RawPtr(ty::TypeAndMut { ty, .. }) => *ty,
386+
_ => bug!("argument to drop_in_place is not a raw ptr: {:?}", ty),
387+
});
386388

387389
let layout = cx.layout_of(ty)?;
388390
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
@@ -403,7 +405,7 @@ fn fn_abi_new_uncached<'tcx>(
403405
*layout,
404406
offset,
405407
is_return,
406-
is_drop_target,
408+
drop_target_pointee,
407409
);
408410
attrs
409411
});
+23-19
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,38 @@
1-
// Tests that the compiler can mark `drop_in_place` as `noalias` when safe to do so.
1+
// compile-flags: -C no-prepopulate-passes
2+
3+
// Tests that the compiler can apply `noalias` and other &mut attributes to `drop_in_place`.
4+
// Note that non-Unpin types should not get `noalias`, matching &mut behavior.
25

36
#![crate_type="lib"]
47

5-
use std::hint::black_box;
8+
use std::marker::PhantomPinned;
9+
10+
// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}({{.*\*|ptr}} noalias noundef align 4 dereferenceable(12) %{{.+}})
611

7-
// CHECK: define{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}Foo{{.*}}({{.*}}noalias {{.*}} align 4 dereferenceable(12){{.*}})
12+
// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}({{.*\*|ptr}} noundef nonnull align 4 %{{.+}})
813

9-
#[repr(C)]
10-
pub struct Foo {
14+
pub struct StructUnpin {
1115
a: i32,
1216
b: i32,
1317
c: i32,
1418
}
1519

16-
impl Drop for Foo {
17-
#[inline(never)]
18-
fn drop(&mut self) {
19-
black_box(self.a);
20-
}
20+
impl Drop for StructUnpin {
21+
fn drop(&mut self) {}
22+
}
23+
24+
pub struct StructNotUnpin {
25+
a: i32,
26+
b: i32,
27+
c: i32,
28+
p: PhantomPinned,
2129
}
2230

23-
extern {
24-
fn bar();
25-
fn baz(foo: Foo);
31+
impl Drop for StructNotUnpin {
32+
fn drop(&mut self) {}
2633
}
2734

28-
pub fn haha() {
29-
let foo = Foo { a: 1, b: 2, c: 3 };
30-
unsafe {
31-
bar();
32-
baz(foo);
33-
}
35+
pub unsafe fn main(x: StructUnpin, y: StructNotUnpin) {
36+
drop(x);
37+
drop(y);
3438
}

0 commit comments

Comments
 (0)