only set noalias on Box with the global allocator · rust-lang/rust@f391c07 (original) (raw)
File tree
17 files changed
lines changed
- rustc_codegen_gcc/example
- rustc_codegen_llvm/src/debuginfo
- rustc_codegen_ssa/src/mir
- rustc_const_eval/src/interpret
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"] |