Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/mir/retag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl<'a, 'tcx, V> RetagPlan<V> {
// the outermost `Box` is what determines the permission that gets created.
ty::Adt(adt, _) if adt.is_box() => Self::visit_box(bx, layout, is_fn_entry),
// Skip traversing for everything inside of `MaybeDangling`
ty::Adt(adt, _) if adt.is_maybe_dangling() => None,
_ if layout.ty.is_like_maybe_dangling() => None,
_ => Self::walk_value(bx, layout, is_fn_entry),
}
}
Expand Down
13 changes: 5 additions & 8 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1528,15 +1528,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
BackendRepr::Memory { .. } => unreachable!()
}
}
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
let old_may_dangle = mem::replace(&mut self.may_dangle, true);

let inner = self.ecx.project_field(val, FieldIdx::ZERO)?;
self.visit_value(&inner)?;

self.may_dangle = old_may_dangle;
}
_ => {
let may_dangle = self.may_dangle || val.layout.ty.is_like_maybe_dangling();
let old_may_dangle = mem::replace(&mut self.may_dangle, may_dangle);

// default handler
try_validation!(
self.walk_value(val),
Expand All @@ -1546,6 +1541,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) =>
InvalidMetaWrongTrait { expected_dyn_type, vtable_dyn_type },
);

self.may_dangle = old_may_dangle;
}
}

Expand Down
8 changes: 2 additions & 6 deletions compiler/rustc_middle/src/ty/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ bitflags::bitflags! {
/// Indicates whether the type is `FieldRepresentingType`.
const IS_FIELD_REPRESENTING_TYPE = 1 << 13;
/// Indicates whether the type is `MaybeDangling<_>`.
/// Note that this is not the only type with "maybe dangling" semantics!
/// Use `ty.is_like_maybe_dangling()` to check for that.
const IS_MAYBE_DANGLING = 1 << 14;
}
}
Expand Down Expand Up @@ -528,12 +530,6 @@ impl<'tcx> AdtDef<'tcx> {
self.flags().contains(AdtFlags::IS_MANUALLY_DROP)
}

/// Returns `true` if this is `MaybeDangling<T>`.
#[inline]
pub fn is_maybe_dangling(self) -> bool {
self.flags().contains(AdtFlags::IS_MAYBE_DANGLING)
}

/// Returns `true` if this is `Pin<T>`.
#[inline]
pub fn is_pin(self) -> bool {
Expand Down
29 changes: 15 additions & 14 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1090,20 +1090,6 @@ where
})
}

ty::Adt(adt_def, ..) if adt_def.is_maybe_dangling() => {
Self::ty_and_layout_pointee_info_at(this.field(cx, 0), cx, offset).map(|info| {
PointeeInfo {
// Mark the pointer as raw
// (thus removing noalias/readonly/etc in case of the llvm backend)
safe: None,
// Make sure we don't assert dereferenceability of the pointer.
size: Size::ZERO,
// Preserve the alignment assertion! That is required even inside `MaybeDangling`.
align: info.align,
}
})
}

_ => {
let mut data_variant = match &this.variants {
// Within the discriminant field, only the niche itself is
Expand Down Expand Up @@ -1179,6 +1165,21 @@ where
}
}

// Patch result if we are a MaybeDangling-like type.
if this.ty.is_like_maybe_dangling()
&& let Some(info) = result
{
result = Some(PointeeInfo {
// Mark the pointer as raw
// (thus removing noalias/readonly/etc in case of the llvm backend)
safe: None,
// Make sure we don't assert dereferenceability of the pointer.
size: Size::ZERO,
// Preserve the alignment assertion! That is required even inside `MaybeDangling`.
align: info.align,
});
}

result
}
};
Expand Down
18 changes: 17 additions & 1 deletion compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use rustc_type_ir::{
use tracing::instrument;
use ty::util::IntTypeExt;

use super::GenericParamDefKind;
use super::{AdtFlags, GenericParamDefKind};
use crate::infer::canonical::Canonical;
use crate::traits::ObligationCause;
use crate::ty::InferTy::*;
Expand Down Expand Up @@ -2198,6 +2198,22 @@ impl<'tcx> Ty<'tcx> {
pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
TypeWalker::new(self.into())
}

/// Returns `true` if this is a `MaybeDangling<T>`-like type, i.e., a type whose inner
/// references are not required to be dereferenceable and are not reborrowed.
#[inline]
pub fn is_like_maybe_dangling(self) -> bool {
match self.kind() {
ty::Adt(def, _) => {
// ManuallyDrop is "natively" like maybe-dangling so that we don't have
// to nest field types even deeper.
def.flags().contains(AdtFlags::IS_MAYBE_DANGLING)
|| def.flags().contains(AdtFlags::IS_MANUALLY_DROP)
}
ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineClosure(..) => true,
_ => false,
}
}
}

impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_mir_build/src/builder/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let place = b.project_deeper(&[ProjectionElem::Deref], tcx);
// Current type: `MaybeUninit<T>`. Field #1 is `ManuallyDrop<T>`.
let place = place.project_to_field(FieldIdx::from_u32(1), decls, tcx);
// Current type: `ManuallyDrop<T>`. Field #0 is `MaybeDangling<T>`.
let place = place.project_to_field(FieldIdx::ZERO, decls, tcx);
// Current type: `MaybeDangling<T>`. Field #0 is `T`.
// Current type: `ManuallyDrop<T>`. Field #0 is `T`.
let place = place.project_to_field(FieldIdx::ZERO, decls, tcx);
// Sanity check.
assert_eq!(place.ty(decls, tcx).ty, generic_args.type_at(0));
Expand Down
58 changes: 10 additions & 48 deletions library/core/src/mem/manually_drop.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::cmp::Ordering;
use crate::hash::{Hash, Hasher};
use crate::marker::{Destruct, StructuralPartialEq};
use crate::mem::MaybeDangling;
use crate::hash::Hash;
use crate::marker::Destruct;
use crate::ops::{Deref, DerefMut, DerefPure};
use crate::ptr;

Expand Down Expand Up @@ -152,11 +150,11 @@ use crate::ptr;
/// [`MaybeUninit`]: crate::mem::MaybeUninit
#[stable(feature = "manually_drop", since = "1.20.0")]
#[lang = "manually_drop"]
#[derive(Copy, Clone, Debug, Default)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
#[rustc_pub_transparent]
pub struct ManuallyDrop<T: ?Sized> {
value: MaybeDangling<T>,
value: T,
}

impl<T> ManuallyDrop<T> {
Expand All @@ -180,7 +178,7 @@ impl<T> ManuallyDrop<T> {
#[inline(always)]
#[rustc_no_writable]
pub const fn new(value: T) -> ManuallyDrop<T> {
ManuallyDrop { value: MaybeDangling::new(value) }
ManuallyDrop { value }
}

/// Extracts the value from the `ManuallyDrop` container.
Expand All @@ -198,9 +196,7 @@ impl<T> ManuallyDrop<T> {
#[rustc_const_stable(feature = "const_manually_drop", since = "1.32.0")]
#[inline(always)]
pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
// Cannot use `MaybeDangling::into_inner` as that does not yet have the desired semantics.
// SAFETY: We know this is a valid `T`. `slot` will not be dropped.
unsafe { (&raw const slot).cast::<T>().read() }
slot.value
}

/// Takes the value from the `ManuallyDrop<T>` container out.
Expand All @@ -225,7 +221,7 @@ impl<T> ManuallyDrop<T> {
pub const unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
// SAFETY: we are reading from a reference, which is guaranteed
// to be valid for reads.
unsafe { ptr::read(slot.value.as_ref()) }
unsafe { ptr::read(&slot.value) }
}
}

Expand Down Expand Up @@ -262,7 +258,7 @@ impl<T: ?Sized> ManuallyDrop<T> {
// SAFETY: we are dropping the value pointed to by a mutable reference
// which is guaranteed to be valid for writes.
// It is up to the caller to make sure that `slot` isn't dropped again.
unsafe { ptr::drop_in_place(slot.value.as_mut()) }
unsafe { ptr::drop_in_place(&mut slot.value) }
}
}

Expand All @@ -272,7 +268,7 @@ const impl<T: ?Sized> Deref for ManuallyDrop<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
self.value.as_ref()
&self.value
}
}

Expand All @@ -281,43 +277,9 @@ const impl<T: ?Sized> Deref for ManuallyDrop<T> {
const impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut T {
self.value.as_mut()
&mut self.value
}
}

#[unstable(feature = "deref_pure_trait", issue = "87121")]
unsafe impl<T: ?Sized> DerefPure for ManuallyDrop<T> {}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized + Eq> Eq for ManuallyDrop<T> {}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized + PartialEq> PartialEq for ManuallyDrop<T> {
fn eq(&self, other: &Self) -> bool {
self.value.as_ref().eq(other.value.as_ref())
}
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized> StructuralPartialEq for ManuallyDrop<T> {}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized + Ord> Ord for ManuallyDrop<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.value.as_ref().cmp(other.value.as_ref())
}
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized + PartialOrd> PartialOrd for ManuallyDrop<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.value.as_ref().partial_cmp(other.value.as_ref())
}
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized + Hash> Hash for ManuallyDrop<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.value.as_ref().hash(state);
}
}
6 changes: 0 additions & 6 deletions library/std/src/thread/lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use super::thread::Thread;
use super::{Result, spawnhook};
use crate::cell::UnsafeCell;
use crate::marker::PhantomData;
use crate::mem::MaybeDangling;
use crate::sync::Arc;
use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
use crate::sys::{AsInner, IntoInner, thread as imp};
Expand Down Expand Up @@ -57,14 +56,9 @@ where
Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None), _marker: PhantomData });
let their_packet = my_packet.clone();

// Pass `f` in `MaybeDangling` because actually that closure might *run longer than the lifetime of `F`*.
// See <https://github.com/rust-lang/rust/issues/101983> for more details.
let f = MaybeDangling::new(f);

// The entrypoint of the Rust thread, after platform-specific thread
// initialization is done.
let rust_start = move || {
let f = f.into_inner();
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.inherit_and_run());
crate::sys::backtrace::__rust_begin_short_backtrace(f)
Expand Down
6 changes: 3 additions & 3 deletions src/etc/gdb_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,20 +330,20 @@ def cast_to_internal(node):

for i in xrange(0, length + 1):
if height > 0:
child_ptr = edges[i]["value"]["value"][ZERO_FIELD]
child_ptr = edges[i]["value"]["value"]
for child in children_of_node(child_ptr, height - 1):
yield child
if i < length:
# Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
key_type_size = keys.type.sizeof
val_type_size = vals.type.sizeof
key = (
keys[i]["value"]["value"][ZERO_FIELD]
keys[i]["value"]["value"]
if key_type_size > 0
else gdb.parse_and_eval("()")
)
val = (
vals[i]["value"]["value"][ZERO_FIELD]
vals[i]["value"]["value"]
if val_type_size > 0
else gdb.parse_and_eval("()")
)
Expand Down
4 changes: 2 additions & 2 deletions src/etc/natvis/libcore.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
</Type>

<Type Name="core::mem::manually_drop::ManuallyDrop&lt;*&gt;">
<DisplayString>{value.__0}</DisplayString>
<DisplayString>{value}</DisplayString>
<Expand>
<ExpandedItem>value.__0</ExpandedItem>
<ExpandedItem>value</ExpandedItem>
</Expand>
</Type>

Expand Down
8 changes: 2 additions & 6 deletions src/tools/miri/tests/fail/async-shared-mutable.stack.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@ LL | *x = 1;
help: <TAG> was created by a Unique retag at offsets [RANGE]
--> tests/fail/async-shared-mutable.rs:LL:CC
|
LL | / core::future::poll_fn(move |_| {
LL | | *x = 1;
LL | | Poll::<()>::Pending
LL | | })
LL | | .await
| |______________^
LL | let x = &mut 0u8;
| ^^^^^^^^
help: <TAG> was later invalidated at offsets [RANGE] by a SharedReadOnly retag
--> tests/fail/async-shared-mutable.rs:LL:CC
|
Expand Down
8 changes: 2 additions & 6 deletions src/tools/miri/tests/fail/async-shared-mutable.tree.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,8 @@ LL | *x = 1;
help: the accessed tag <TAG> was created here, in the initial state Reserved
--> tests/fail/async-shared-mutable.rs:LL:CC
|
LL | / core::future::poll_fn(move |_| {
LL | | *x = 1;
LL | | Poll::<()>::Pending
LL | | })
LL | | .await
| |______________^
LL | let x = &mut 0u8;
| ^^^^^^^^
help: the accessed tag <TAG> later transitioned to Unique due to a child write access at offsets [RANGE]
--> tests/fail/async-shared-mutable.rs:LL:CC
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u16>: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN)
error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u16>: at .0, encountered an unaligned reference (required ALIGN byte alignment but found ALIGN)
--> tests/fail/unaligned_pointers/maybe_dangling_unalighed.rs:LL:CC
|
LL | transmute::<MaybeDangling<*const u16>, MaybeDangling<&u16>>(unaligned)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u8>: encountered a null reference
error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u8>: at .0, encountered a null reference
--> tests/fail/validity/maybe_dangling_null.rs:LL:CC
|
LL | unsafe { transmute::<MaybeDangling<*const u8>, MaybeDangling<&u8>>(null) };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&i8>: encountered a reference that is too close to the end of the address space for a pointee of 1 bytes
error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&i8>: at .0, encountered a reference that is too close to the end of the address space for a pointee of 1 bytes
--> tests/fail/validity/maybe_dangling_ref_too_big.rs:LL:CC
|
LL | let _x: MaybeDangling<&i8> = unsafe { transmute(usize::MAX) };
Expand Down
14 changes: 14 additions & 0 deletions src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ fn main() {
reference();
write_through_shared_ref();
large();
closure();
}

fn boxy() {
Expand Down Expand Up @@ -64,3 +65,16 @@ fn large() {
// Used to be rejected due to faulty logic for the "does this fit the address space" check.
let _x: MaybeDangling<&i8> = unsafe { mem::transmute(usize::MAX - 127) };
}

// A closure acts like MaybeDangling.
fn closure() {
fn invoke(f: impl FnOnce()) {
// The closure has captured a reference that will be freed while `invoke` runs.
f()
}

let p = Box::leak(Box::new(0i32));
invoke(move || {
drop(unsafe { Box::from_raw(p) });
});
}
Loading
Loading