only set noalias on Box with the global allocator · rust-lang/rust@f391c07 (original) (raw)

File tree

17 files changed

lines changed

17 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -1612,8 +1612,9 @@ pub enum PointerKind {
1612 1612 SharedRef { frozen: bool },
1613 1613 /// Mutable reference. `unpin` indicates the absence of any pinned data.
1614 1614 MutableRef { unpin: bool },
1615 -/// Box. `unpin` indicates the absence of any pinned data.
1616 - Box { unpin: bool },
1615 +/// Box. `unpin` indicates the absence of any pinned data. `global` indicates whether this box
1616 + /// uses the global allocator or a custom one.
1617 + Box { unpin: bool, global: bool },
1617 1618 }
1618 1619
1619 1620 /// Note that this information is advisory only, and backends are free to ignore it.
@@ -1622,6 +1623,8 @@ pub enum PointerKind {
1622 1623 pub struct PointeeInfo {
1623 1624 pub size: Size,
1624 1625 pub align: Align,
1626 +/// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to
1627 + /// be reliable.
1625 1628 pub safe: Option<PointerKind>,
1626 1629 }
1627 1630
Original file line number Diff line number Diff line change
@@ -525,8 +525,11 @@ pub struct Unique<T: ?Sized> {
525 525 impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
526 526 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
527 527
528 +#[lang = "global_alloc_ty"]
529 +pub struct Global;
530 +
528 531 #[lang = "owned_box"]
529 -pub struct Box<T: ?Sized, A = ()>(Unique<T>, A);
532 +pub struct Box<T: ?Sized, A = Global>(Unique<T>, A);
530 533
531 534 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
532 535
@@ -536,7 +539,7 @@ impl Box {
536 539 let size = intrinsics::size_of::<T>();
537 540 let ptr = libc::malloc(size);
538 541 intrinsics::copy(&val as *const T as *const u8, ptr, size);
539 -Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, ())
542 +Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, Global)
540 543 }
541 544 }
542 545 }
Original file line number Diff line number Diff line change
@@ -74,10 +74,6 @@ fn unsize_ptr<'tcx>(
74 74 | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
75 75 (src, unsized_info(fx, *a, *b, old_info))
76 76 }
77 -(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
78 -let (a, b) = (src_layout.ty.boxed_ty(), dst_layout.ty.boxed_ty());
79 -(src, unsized_info(fx, a, b, old_info))
80 -}
81 77 (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
82 78 assert_eq!(def_a, def_b);
83 79
Original file line number Diff line number Diff line change
@@ -472,6 +472,7 @@ pub trait Allocator {
472 472
473 473 impl Allocator for () {}
474 474
475 +#[lang = "global_alloc_ty"]
475 476 pub struct Global;
476 477
477 478 impl Allocator for Global {}
Original file line number Diff line number Diff line change
@@ -454,9 +454,13 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
454 454 ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
455 455 build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id)
456 456 }
457 -// Box<T, A> may have a non-1-ZST allocator A. In that case, we
458 -// cannot treat Box<T, A> as just an owned alias of `*mut T`.
459 - ty::Adt(def, args) if def.is_box() && cx.layout_of(args.type_at(1)).is_1zst() => {
457 +// Some `Box` are newtyped pointers, make debuginfo aware of that.
458 +// Only works if the allocator argument is a 1-ZST and hence irrelevant for layout
459 +// (or if there is no allocator argument).
460 + ty::Adt(def, args)
461 +if def.is_box()
462 + && args.get(1).map_or(true, |arg
463 +{
460 464 build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id)
461 465 }
462 466 ty::FnDef(..) | ty::FnPtr(_) => build_subroutine_type_di_node(cx, unique_type_id),
Original file line number Diff line number Diff line change
@@ -204,6 +204,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
204 204
205 205 pub fn deref<Cx: LayoutTypeMethods<'tcx>>(self, cx: &Cx) -> PlaceRef<'tcx, V> {
206 206 if self.layout.ty.is_box() {
207 +// Derefer should have removed all Box derefs
207 208 bug!("dereferencing {:?} in codegen", self.layout.ty);
208 209 }
209 210
Original file line number Diff line number Diff line change
@@ -437,6 +437,7 @@ where
437 437 trace!("deref to {} on {:?}", val.layout.ty, *val);
438 438
439 439 if val.layout.ty.is_box() {
440 +// Derefer should have removed all Box derefs
440 441 bug!("dereferencing {}", val.layout.ty);
441 442 }
442 443
Original file line number Diff line number Diff line change
@@ -359,14 +359,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
359 359 Ok(Some(match ty.kind() {
360 360 ty::Ref(_, ty, _) => *ty,
361 361 ty::RawPtr(mt) => mt.ty,
362 -// We should only accept `Box` with the default allocator.
363 -// It's hard to test for that though so we accept every 1-ZST allocator.
364 - ty::Adt(def, args)
365 -if def.is_box()
366 - && self.layout_of(args[1].expect_ty()).is_ok_and(|l
367 -{
368 - args[0].expect_ty()
369 -}
362 +// We only accept `Box` with the default allocator.
363 + _ if ty.is_box_global(*self.tcx) => ty.boxed_ty(),
370 364 _ => return Ok(None),
371 365 }))
372 366 };
Original file line number Diff line number Diff line change
@@ -267,6 +267,8 @@ language_item_table! {
267 267 EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None;
268 268
269 269 OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1);
270 +GlobalAlloc, sym::global_alloc_ty, global_alloc_ty, Target::Struct, GenericRequirement::None;
271 +
270 272 // Experimental language item for Miri
271 273 PtrUnique, sym::ptr_unique, ptr_unique, Target::Struct, GenericRequirement::Exact(1);
272 274
Original file line number Diff line number Diff line change
@@ -969,6 +969,8 @@ where
969 969 }
970 970 }
971 971
972 +/// Compute the information for the pointer stored at the given offset inside this type.
973 + /// This will recurse into fields of ADTs to find the inner pointer.
972 974 fn ty_and_layout_pointee_info_at(
973 975 this: TyAndLayout<'tcx>,
974 976 cx: &C,
@@ -1068,15 +1070,17 @@ where
1068 1070 }
1069 1071 }
1070 1072
1071 -// FIXME(eddyb) This should be for `ptr::Unique`, not `Box`.
1073 +// Fixup info for the first field of a `Box`. Recursive traversal will have found
1074 +// the raw pointer, so size and align are set to the boxed type, but `pointee.safe`
1075 +// will still be `None`.
1072 1076 if let Some(ref mut pointee) = result {
1073 -if let ty::Adt(def, _) = this.ty.kind() {
1074 -if def.is_box() && offset.bytes() == 0 {
1075 - let optimize = tcx.sess.opts.optimize != OptLevel::No;
1076 - pointee.safe = Some(PointerKind::Box {
1077 - unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()),
1078 -});
1079 -}
1077 +if offset.bytes() == 0 && this.ty.is_box() {
1078 +debug_assert!(pointee.safe.is_none());
1079 +let optimize = tcx.sess.opts.optimize != OptLevel::No;
1080 + pointee.safe = Some(PointerKind::Box {
1081 +unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()),
1082 +global: this.ty.is_box_global(tcx),
1083 +});
1080 1084 }
1081 1085 }
1082 1086
Original file line number Diff line number Diff line change
@@ -1999,6 +1999,27 @@ impl<'tcx> Ty<'tcx> {
1999 1999 }
2000 2000 }
2001 2001
2002 +/// Tests whether this is a Box using the global allocator.
2003 + #[inline]
2004 +pub fn is_box_global(self, tcx: TyCtxt<'tcx>) -> bool {
2005 +match self.kind() {
2006 +Adt(def, args) if def.is_box() => {
2007 +let Some(alloc) = args.get(1) else {
2008 +// Single-argument Box is always global. (for "minicore" tests)
2009 +return true;
2010 +};
2011 +if let Some(alloc_adt) = alloc.expect_ty().ty_adt_def() {
2012 +let global_alloc = tcx.require_lang_item(LangItem::GlobalAlloc, None);
2013 + alloc_adt.did() == global_alloc
2014 +} else {
2015 +// Allocator is not an ADT...
2016 +false
2017 +}
2018 +}
2019 + _ => false,
2020 +}
2021 +}
2022 +
2002 2023 /// Panics if called on any type other than `Box`.
2003 2024 pub fn boxed_ty(self) -> Ty<'tcx> {
2004 2025 match self.kind() {
Original file line number Diff line number Diff line change
@@ -896,6 +896,7 @@ symbols! {
896 896 generic_const_items,
897 897 generic_param_attrs,
898 898 get_context,
899 + global_alloc_ty,
899 900 global_allocator,
900 901 global_asm,
901 902 globs,
Original file line number Diff line number Diff line change
@@ -452,7 +452,7 @@ fn adjust_for_rust_scalar<'tcx>(
452 452 let no_alias = match kind {
453 453 PointerKind::SharedRef { frozen } => frozen,
454 454 PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref,
455 -PointerKind::Box { unpin } => unpin && noalias_for_box,
455 +PointerKind::Box { unpin, global } => unpin && global && noalias_for_box,
456 456 };
457 457 // We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
458 458 // (see https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745).
Original file line number Diff line number Diff line change
@@ -50,6 +50,8 @@ extern "Rust" {
50 50 #[unstable(feature = "allocator_api", issue = "32838")]
51 51 #[derive(Copy, Clone, Default, Debug)]
52 52 #[cfg(not(test))]
53 +// the compiler needs to know when a Box uses the global allocator vs a custom one
54 +#[cfg_attr(not(bootstrap), lang = "global_alloc_ty")]
53 55 pub struct Global;
54 56
55 57 #[cfg(test)]
Original file line number Diff line number Diff line change
@@ -2062,6 +2062,9 @@ impl<Args: Tuple, F: AsyncFn + ?Sized, A: Allocator> AsyncFn for Box
2062 2062 #[unstable(feature = "coerce_unsized", issue = "18598")]
2063 2063 impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
2064 2064
2065 +// It is quite crucial that we only allow the `Global` allocator here.
2066 +// Handling arbitrary custom allocators (which can affect the `Box` layout heavily!)
2067 +// would need a lot of codegen and interpreter adjustments.
2065 2068 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
2066 2069 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T, Global> {}
2067 2070
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
2 2 #![crate_type = "lib"]
3 3 #![feature(dyn_star)]
4 4 #![feature(generic_nonzero)]
5 +#![feature(allocator_api)]
5 6
6 7 use std::mem::MaybeUninit;
7 8 use std::num::NonZero;
@@ -182,6 +183,15 @@ pub fn _box(x: Box) -> Box {
182 183 x
183 184 }
184 185
186 +// With a custom allocator, it should *not* have `noalias`. (See
187 +// https://github.com/rust-lang/miri/issues/3341 for why.) The second argument is the allocator,
188 +// which is a reference here that still carries `noalias` as usual.
189 +// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly align 1 %x.1)
190 +#[no_mangle]
191 +pub fn _box_custom(x: Box<i32, &std::alloc::Global>) {
192 +drop(x)
193 +}
194 +
185 195 // CHECK: noundef nonnull align 4 ptr @notunpin_box(ptr noundef nonnull align 4 %x)
186 196 #[no_mangle]
187 197 pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
Original file line number Diff line number Diff line change
@@ -160,6 +160,7 @@ mod prelude {
160 160 pub _marker: PhantomData<T>,
161 161 }
162 162
163 +#[lang = "global_alloc_ty"]
163 164 pub struct Global;
164 165
165 166 #[lang = "owned_box"]