Auto merge of #120594 - saethlin:delayed-debug-asserts, r=oli-obk

Toggle assert_unsafe_precondition in codegen instead of expansion

The goal of this PR is to make some of the unsafe precondition checks in the standard library available in debug builds. Some UI tests are included to verify that it does that.

The diff is large, but most of it is blessing mir-opt tests and I've also split up this PR so it can be reviewed commit-by-commit.

This PR:
1. Adds a new intrinsic, `debug_assertions` which is lowered to a new MIR NullOp, and only to a constant after monomorphization
2. Rewrites `assume_unsafe_precondition` to check the new intrinsic, and be monomorphic.
3. Skips codegen of the `assume` intrinsic in unoptimized builds, because that was silly before but with these checks it's *very* silly
4. The checks with the most overhead are `ptr::read`/`ptr::write` and `NonNull::new_unchecked`. I've simply added `#[cfg(debug_assertions)]` to the checks for `ptr::read`/`ptr::write` because I was unable to come up with any (good) ideas for decreasing their impact. But for `NonNull::new_unchecked` I found that the majority of callers can use a different function, often a safe one.

Yes, this PR slows down the compile time of some programs. But in our benchmark suite it's never more than 1% icount, and the average icount change in debug-full programs is 0.22%. I think that is acceptable for such an improvement in developer experience.

https://github.com/rust-lang/rust/issues/120539#issuecomment-1922687101
This commit is contained in:
bors
2024-02-09 13:33:38 +00:00
65 changed files with 1480 additions and 1293 deletions
@@ -1983,6 +1983,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
ConstraintCategory::SizedBound,
);
}
&Rvalue::NullaryOp(NullOp::DebugAssertions, _) => {}
Rvalue::ShallowInitBox(operand, ty) => {
self.check_operand(operand, location);
@@ -767,6 +767,15 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
NullOp::OffsetOf(fields) => {
layout.offset_of_subfield(fx, fields.iter()).bytes()
}
NullOp::DebugAssertions => {
let val = fx.tcx.sess.opts.debug_assertions;
let val = CValue::by_val(
fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()),
fx.layout_of(fx.tcx.types.bool),
);
lval.write_cvalue(fx, val);
return;
}
};
let val = CValue::by_val(
fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(val).unwrap()),
+10 -4
View File
@@ -672,17 +672,23 @@ pub fn codegen_rvalue_operand(
let val = match null_op {
mir::NullOp::SizeOf => {
assert!(bx.cx().type_is_sized(ty));
layout.size.bytes()
let val = layout.size.bytes();
bx.cx().const_usize(val)
}
mir::NullOp::AlignOf => {
assert!(bx.cx().type_is_sized(ty));
layout.align.abi.bytes()
let val = layout.align.abi.bytes();
bx.cx().const_usize(val)
}
mir::NullOp::OffsetOf(fields) => {
layout.offset_of_subfield(bx.cx(), fields.iter()).bytes()
let val = layout.offset_of_subfield(bx.cx(), fields.iter()).bytes();
bx.cx().const_usize(val)
}
mir::NullOp::DebugAssertions => {
let val = bx.tcx().sess.opts.debug_assertions;
bx.cx().const_bool(val)
}
};
let val = bx.cx().const_usize(val);
let tcx = self.cx.tcx();
OperandRef {
val: OperandValue::Immediate(val),
@@ -1,5 +1,6 @@
use rustc_middle::mir;
use rustc_middle::mir::NonDivergingIntrinsic;
use rustc_session::config::OptLevel;
use super::FunctionCx;
use super::LocalRef;
@@ -67,8 +68,10 @@ pub fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx
self.codegen_coverage(bx, coverage, statement.source_info.scope);
}
mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
let op_val = self.codegen_operand(bx, op);
bx.assume(op_val.immediate());
if !matches!(bx.tcx().sess.opts.optimize, OptLevel::No | OptLevel::Less) {
let op_val = self.codegen_operand(bx, op);
bx.assume(op_val.immediate());
}
}
mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
mir::CopyNonOverlapping { ref count, ref src, ref dst },
@@ -246,13 +246,25 @@ pub fn eval_rvalue_into_place(
);
}
let val = match null_op {
mir::NullOp::SizeOf => layout.size.bytes(),
mir::NullOp::AlignOf => layout.align.abi.bytes(),
mir::NullOp::SizeOf => {
let val = layout.size.bytes();
Scalar::from_target_usize(val, self)
}
mir::NullOp::AlignOf => {
let val = layout.align.abi.bytes();
Scalar::from_target_usize(val, self)
}
mir::NullOp::OffsetOf(fields) => {
layout.offset_of_subfield(self, fields.iter()).bytes()
let val = layout.offset_of_subfield(self, fields.iter()).bytes();
Scalar::from_target_usize(val, self)
}
mir::NullOp::DebugAssertions => {
// The checks hidden behind this are always better done by the interpreter
// itself, because it knows the runtime state better.
Scalar::from_bool(false)
}
};
self.write_scalar(Scalar::from_target_usize(val, self), &dest)?;
self.write_scalar(val, &dest)?;
}
ShallowInitBox(ref operand, _) => {
@@ -544,7 +544,10 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
Rvalue::Cast(_, _, _) => {}
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) => {}
Rvalue::NullaryOp(
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::DebugAssertions,
_,
) => {}
Rvalue::ShallowInitBox(_, _) => {}
Rvalue::UnaryOp(_, operand) => {
@@ -1139,7 +1139,7 @@ macro_rules! check_kinds {
Rvalue::Repeat(_, _)
| Rvalue::ThreadLocalRef(_)
| Rvalue::AddressOf(_, _)
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _)
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::DebugAssertions, _)
| Rvalue::Discriminant(_) => {}
}
self.super_rvalue(rvalue, location);
@@ -112,7 +112,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir
| sym::forget
| sym::black_box
| sym::variant_count
| sym::ptr_mask => hir::Unsafety::Normal,
| sym::ptr_mask
| sym::debug_assertions => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
};
@@ -461,6 +462,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
(0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
}
sym::debug_assertions => (0, Vec::new(), tcx.types.bool),
other => {
tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
return;
+1
View File
@@ -907,6 +907,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
NullOp::SizeOf => write!(fmt, "SizeOf({t})"),
NullOp::AlignOf => write!(fmt, "AlignOf({t})"),
NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
NullOp::DebugAssertions => write!(fmt, "cfg!(debug_assertions)"),
}
}
ThreadLocalRef(did) => ty::tls::with(|tcx| {
+2
View File
@@ -1361,6 +1361,8 @@ pub enum NullOp<'tcx> {
AlignOf,
/// Returns the offset of a field
OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>),
/// cfg!(debug_assertions), but expanded in codegen
DebugAssertions,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+1
View File
@@ -194,6 +194,7 @@ pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
tcx.types.usize
}
Rvalue::NullaryOp(NullOp::DebugAssertions, _) => tcx.types.bool,
Rvalue::Aggregate(ref ak, ref ops) => match **ak {
AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
AggregateKind::Tuple => {
@@ -429,7 +429,10 @@ fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
| Rvalue::AddressOf(..)
| Rvalue::Discriminant(..)
| Rvalue::Len(..)
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {}
| Rvalue::NullaryOp(
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::DebugAssertions,
_,
) => {}
}
}
@@ -634,6 +634,7 @@ fn eval_rvalue(&mut self, rvalue: &Rvalue<'tcx>, dest: &Place<'tcx>) -> Option<(
NullOp::OffsetOf(fields) => {
op_layout.offset_of_subfield(self, fields.iter()).bytes()
}
NullOp::DebugAssertions => return None,
};
ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into()
}
+1
View File
@@ -489,6 +489,7 @@ fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> {
NullOp::OffsetOf(fields) => {
layout.offset_of_subfield(&self.ecx, fields.iter()).bytes()
}
NullOp::DebugAssertions => return None,
};
let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
let imm = ImmTy::try_from_uint(val, usize_layout)?;
@@ -2,10 +2,12 @@
use crate::simplify::simplify_duplicate_switch_targets;
use rustc_middle::mir::*;
use rustc_middle::ty::layout;
use rustc_middle::ty::layout::ValidityRequirement;
use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt};
use rustc_span::symbol::Symbol;
use rustc_target::abi::FieldIdx;
use rustc_target::spec::abi::Abi;
pub struct InstSimplify;
@@ -38,6 +40,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
block.terminator.as_mut().unwrap(),
&mut block.statements,
);
ctx.simplify_nounwind_call(block.terminator.as_mut().unwrap());
simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap());
}
}
@@ -252,6 +255,28 @@ fn simplify_primitive_clone(
terminator.kind = TerminatorKind::Goto { target: destination_block };
}
fn simplify_nounwind_call(&self, terminator: &mut Terminator<'tcx>) {
let TerminatorKind::Call { func, unwind, .. } = &mut terminator.kind else {
return;
};
let Some((def_id, _)) = func.const_fn_def() else {
return;
};
let body_ty = self.tcx.type_of(def_id).skip_binder();
let body_abi = match body_ty.kind() {
ty::FnDef(..) => body_ty.fn_sig(self.tcx).abi(),
ty::Closure(..) => Abi::RustCall,
ty::Coroutine(..) => Abi::Rust,
_ => bug!("unexpected body ty: {:?}", body_ty),
};
if !layout::fn_can_unwind(self.tcx, Some(def_id), body_abi) {
*unwind = UnwindAction::Unreachable;
}
}
fn simplify_intrinsic_assert(
&self,
terminator: &mut Terminator<'tcx>,
@@ -21,6 +21,17 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
sym::unreachable => {
terminator.kind = TerminatorKind::Unreachable;
}
sym::debug_assertions => {
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
*destination,
Rvalue::NullaryOp(NullOp::DebugAssertions, tcx.types.bool),
))),
});
terminator.kind = TerminatorKind::Goto { target };
}
sym::forget => {
if let Some(target) = *target {
block.statements.push(Statement {
@@ -446,6 +446,7 @@ fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable>
NullOp::SizeOf => {}
NullOp::AlignOf => {}
NullOp::OffsetOf(_) => {}
NullOp::DebugAssertions => {}
},
Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
@@ -257,6 +257,7 @@ fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf(
indices.iter().map(|idx| idx.stable(tables)).collect(),
),
DebugAssertions => stable_mir::mir::NullOp::DebugAssertions,
}
}
}
+3
View File
@@ -639,6 +639,7 @@ pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
Ok(Ty::usize_ty())
}
Rvalue::NullaryOp(NullOp::DebugAssertions, _) => Ok(Ty::bool_ty()),
Rvalue::Aggregate(ak, ops) => match *ak {
AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
AggregateKind::Tuple => Ok(Ty::new_tuple(
@@ -1005,6 +1006,8 @@ pub enum NullOp {
AlignOf,
/// Returns the offset of a field.
OffsetOf(Vec<(VariantIdx, FieldIdx)>),
/// cfg!(debug_assertions), but at codegen time
DebugAssertions,
}
impl Operand {
+7 -6
View File
@@ -207,11 +207,7 @@ fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
// Allocators currently return a `NonNull<[u8]>` whose length
// matches the size requested. If that ever changes, the capacity
// here should change to `ptr.len() / mem::size_of::<T>()`.
Self {
ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
cap: unsafe { Cap(capacity) },
alloc,
}
Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc }
}
}
@@ -239,6 +235,11 @@ pub fn ptr(&self) -> *mut T {
self.ptr.as_ptr()
}
#[inline]
pub fn non_null(&self) -> NonNull<T> {
NonNull::from(self.ptr)
}
/// Gets the capacity of the allocation.
///
/// This will always be `usize::MAX` if `T` is zero-sized.
@@ -398,7 +399,7 @@ unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) {
// Allocators currently return a `NonNull<[u8]>` whose length matches
// the size requested. If that ever changes, the capacity here should
// change to `ptr.len() / mem::size_of::<T>()`.
self.ptr = unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) };
self.ptr = Unique::from(ptr.cast());
self.cap = unsafe { Cap(cap) };
}
+1 -1
View File
@@ -136,7 +136,7 @@ pub(super) fn forget_allocation_drop_remaining(&mut self) {
// struct and then overwriting &mut self.
// this creates less assembly
self.cap = 0;
self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) };
self.buf = RawVec::NEW.non_null();
self.ptr = self.buf;
self.end = self.buf.as_ptr();
+3 -3
View File
@@ -2861,16 +2861,16 @@ impl<T, A: Allocator> IntoIterator for Vec<T, A> {
#[inline]
fn into_iter(self) -> Self::IntoIter {
unsafe {
let mut me = ManuallyDrop::new(self);
let me = ManuallyDrop::new(self);
let alloc = ManuallyDrop::new(ptr::read(me.allocator()));
let begin = me.as_mut_ptr();
let buf = me.buf.non_null();
let begin = buf.as_ptr();
let end = if T::IS_ZST {
begin.wrapping_byte_add(me.len())
} else {
begin.add(me.len()) as *const T
};
let cap = me.buf.capacity();
let buf = NonNull::new_unchecked(begin);
IntoIter { buf, phantom: PhantomData, cap, alloc, ptr: buf, end }
}
}
+1 -1
View File
@@ -27,7 +27,7 @@ pub(super) const fn from_u32(i: u32) -> Option<char> {
unsafe {
assert_unsafe_precondition!(
"invalid value for `char`",
(i: u32) => char_try_from_u32(i).is_ok()
(i: u32 = i) => char_try_from_u32(i).is_ok()
);
transmute(i)
}
+1 -1
View File
@@ -148,7 +148,7 @@
unsafe {
intrinsics::assert_unsafe_precondition!(
"hint::assert_unchecked must never be called when the condition is false",
(cond: bool) => cond,
(cond: bool = cond) => cond,
);
crate::intrinsics::assume(cond);
}
+96 -38
View File
@@ -56,7 +56,7 @@
use crate::marker::DiscriminantKind;
use crate::marker::Tuple;
use crate::mem;
use crate::mem::{self, align_of};
pub mod mir;
pub mod simd;
@@ -2569,6 +2569,17 @@ pub fn const_eval_select<ARG: Tuple, F, G, RET>(
#[rustc_nounwind]
#[cfg(not(bootstrap))]
pub fn is_val_statically_known<T: Copy>(arg: T) -> bool;
#[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
#[rustc_safe_intrinsic]
#[cfg(not(bootstrap))]
pub(crate) fn debug_assertions() -> bool;
}
#[cfg(bootstrap)]
#[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
pub(crate) const fn debug_assertions() -> bool {
cfg!(debug_assertions)
}
// FIXME: Seems using `unstable` here completely ignores `rustc_allow_const_fn_unstable`
@@ -2587,10 +2598,27 @@ pub fn const_eval_select<ARG: Tuple, F, G, RET>(
/// Check that the preconditions of an unsafe function are followed, if debug_assertions are on,
/// and only at runtime.
///
/// This macro should be called as `assert_unsafe_precondition!([Generics](name: Type) => Expression)`
/// where the names specified will be moved into the macro as captured variables, and defines an item
/// to call `const_eval_select` on. The tokens inside the square brackets are used to denote generics
/// for the function declarations and can be omitted if there is no generics.
/// This macro should be called as
/// `assert_unsafe_precondition!((expr => name: Type, expr => name: Type) => Expression)`
/// where each `expr` will be evaluated and passed in as function argument `name: Type`. Then all
/// those arguments are passed to a function via [`const_eval_select`].
///
/// These checks are behind a condition which is evaluated at codegen time, not expansion time like
/// [`debug_assert`]. This means that a standard library built with optimizations and debug
/// assertions disabled will have these checks optimized out of its monomorphizations, but if a
/// a caller of the standard library has debug assertions enabled and monomorphizes an expansion of
/// this macro, that monomorphization will contain the check.
///
/// Since these checks cannot be optimized out in MIR, some care must be taken in both call and
/// implementation to mitigate their compile-time overhead. The runtime function that we
/// [`const_eval_select`] to is monomorphic, `#[inline(never)]`, and `#[rustc_nounwind]`. That
/// combination of properties ensures that the code for the checks is only compiled once, and has a
/// minimal impact on the caller's code size.
///
/// Caller should also introducing any other `let` bindings or any code outside this macro in order
/// to call it. Since the precompiled standard library is built with full debuginfo and these
/// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
/// debuginfo to have a measurable compile-time impact on debug builds.
///
/// # Safety
///
@@ -2604,26 +2632,24 @@ pub fn const_eval_select<ARG: Tuple, F, G, RET>(
///
/// So in a sense it is UB if this macro is useful, but we expect callers of `unsafe fn` to make
/// the occasional mistake, and this check should help them figure things out.
#[allow_internal_unstable(const_eval_select)] // permit this to be called in stably-const fn
#[allow_internal_unstable(const_eval_select, delayed_debug_assertions)] // permit this to be called in stably-const fn
macro_rules! assert_unsafe_precondition {
($name:expr, $([$($tt:tt)*])?($($i:ident:$ty:ty),*$(,)?) => $e:expr $(,)?) => {
if cfg!(debug_assertions) {
// allow non_snake_case to allow capturing const generics
#[allow(non_snake_case)]
#[inline(always)]
fn runtime$(<$($tt)*>)?($($i:$ty),*) {
($message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {
{
#[inline(never)]
#[rustc_nounwind]
fn precondition_check($($name:$ty),*) {
if !$e {
// don't unwind to reduce impact on code size
::core::panicking::panic_nounwind(
concat!("unsafe precondition(s) violated: ", $name)
concat!("unsafe precondition(s) violated: ", $message)
);
}
}
#[allow(non_snake_case)]
#[inline]
const fn comptime$(<$($tt)*>)?($(_:$ty),*) {}
const fn comptime($(_:$ty),*) {}
::core::intrinsics::const_eval_select(($($i,)*), comptime, runtime);
if ::core::intrinsics::debug_assertions() {
::core::intrinsics::const_eval_select(($($arg,)*), comptime, precondition_check);
}
}
};
}
@@ -2632,30 +2658,47 @@ const fn comptime$(<$($tt)*>)?($(_:$ty),*) {}
/// Checks whether `ptr` is properly aligned with respect to
/// `align_of::<T>()`.
#[inline]
pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
!ptr.is_null() && ptr.is_aligned()
pub(crate) fn is_aligned_and_not_null(ptr: *const (), align: usize) -> bool {
!ptr.is_null() && ptr.is_aligned_to(align)
}
/// Checks whether an allocation of `len` instances of `T` exceeds
/// the maximum allowed allocation size.
#[inline]
pub(crate) fn is_valid_allocation_size<T>(len: usize) -> bool {
let max_len = const {
let size = crate::mem::size_of::<T>();
if size == 0 { usize::MAX } else { isize::MAX as usize / size }
};
pub(crate) fn is_valid_allocation_size(size: usize, len: usize) -> bool {
let max_len = if size == 0 { usize::MAX } else { isize::MAX as usize / size };
len <= max_len
}
pub(crate) fn is_nonoverlapping_mono(
src: *const (),
dst: *const (),
size: usize,
count: usize,
) -> bool {
let src_usize = src.addr();
let dst_usize = dst.addr();
let Some(size) = size.checked_mul(count) else {
crate::panicking::panic_nounwind(
"is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
)
};
let diff = src_usize.abs_diff(dst_usize);
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
// they do not overlap.
diff >= size
}
/// Checks whether the regions of memory starting at `src` and `dst` of size
/// `count * size_of::<T>()` do *not* overlap.
#[inline]
pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
let src_usize = src.addr();
let dst_usize = dst.addr();
let size = mem::size_of::<T>()
.checked_mul(count)
.expect("is_nonoverlapping: `size_of::<T>() * count` overflows a usize");
let Some(size) = mem::size_of::<T>().checked_mul(count) else {
// Use panic_nounwind instead of Option::expect, so that this function is nounwind.
crate::panicking::panic_nounwind(
"is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
)
};
let diff = src_usize.abs_diff(dst_usize);
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
// they do not overlap.
@@ -2766,10 +2809,16 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
assert_unsafe_precondition!(
"ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
and the specified memory ranges do not overlap",
[T](src: *const T, dst: *mut T, count: usize) =>
is_aligned_and_not_null(src)
&& is_aligned_and_not_null(dst)
&& is_nonoverlapping(src, dst, count)
(
src: *const () = src as *const (),
dst: *mut () = dst as *mut (),
size: usize = size_of::<T>(),
align: usize = align_of::<T>(),
count: usize = count,
) =>
is_aligned_and_not_null(src, align)
&& is_aligned_and_not_null(dst, align)
&& is_nonoverlapping_mono(src, dst, size, count)
);
copy_nonoverlapping(src, dst, count)
}
@@ -2859,9 +2908,15 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
// SAFETY: the safety contract for `copy` must be upheld by the caller.
unsafe {
assert_unsafe_precondition!(
"ptr::copy requires that both pointer arguments are aligned and non-null",
[T](src: *const T, dst: *mut T) =>
is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)
"ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
and the specified memory ranges do not overlap",
(
src: *const () = src as *const (),
dst: *mut () = dst as *mut (),
align: usize = align_of::<T>(),
) =>
is_aligned_and_not_null(src, align)
&& is_aligned_and_not_null(dst, align)
);
copy(src, dst, count)
}
@@ -2934,7 +2989,10 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
unsafe {
assert_unsafe_precondition!(
"ptr::write_bytes requires that the destination pointer is aligned and non-null",
[T](dst: *mut T) => is_aligned_and_not_null(dst)
(
addr: *const () = dst as *const (),
align: usize = align_of::<T>(),
) => is_aligned_and_not_null(addr, align)
);
write_bytes(dst, val, count)
}
-1
View File
@@ -1033,7 +1033,6 @@ pub fn unwrap_or_default(self) -> T
#[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
#[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
pub const unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_some());
match self {
Some(val) => val,
// SAFETY: the safety contract must be upheld by the caller.
+5 -3
View File
@@ -806,13 +806,15 @@ pub fn mask(self, mask: usize) -> *const T {
where
T: Sized,
{
let this = self;
// SAFETY: The comparison has no side-effects, and the intrinsic
// does this check internally in the CTFE implementation.
unsafe {
assert_unsafe_precondition!(
"ptr::sub_ptr requires `this >= origin`",
[T](this: *const T, origin: *const T) => this >= origin
"ptr::sub_ptr requires `self >= origin`",
(
this: *const () = self as *const (),
origin: *const () = origin as *const (),
) => this >= origin
)
};
+34 -11
View File
@@ -381,11 +381,11 @@
use crate::fmt;
use crate::hash;
use crate::intrinsics::{
self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping,
self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping_mono,
};
use crate::marker::FnPtr;
use crate::mem::{self, MaybeUninit};
use crate::mem::{self, align_of, size_of, MaybeUninit};
mod alignment;
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
@@ -967,10 +967,16 @@ macro_rules! attempt_swap_as_chunks {
assert_unsafe_precondition!(
"ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \
and the specified memory ranges do not overlap",
[T](x: *mut T, y: *mut T, count: usize) =>
is_aligned_and_not_null(x)
&& is_aligned_and_not_null(y)
&& is_nonoverlapping(x, y, count)
(
x: *mut () = x as *mut (),
y: *mut () = y as *mut (),
size: usize = size_of::<T>(),
align: usize = align_of::<T>(),
count: usize = count,
) =>
is_aligned_and_not_null(x, align)
&& is_aligned_and_not_null(y, align)
&& is_nonoverlapping_mono(x, y, size, count)
);
}
@@ -1061,7 +1067,10 @@ macro_rules! attempt_swap_as_chunks {
unsafe {
assert_unsafe_precondition!(
"ptr::replace requires that the pointer argument is aligned and non-null",
[T](dst: *mut T) => is_aligned_and_not_null(dst)
(
addr: *const () = dst as *const (),
align: usize = align_of::<T>(),
) => is_aligned_and_not_null(addr, align)
);
mem::swap(&mut *dst, &mut src); // cannot overlap
}
@@ -1207,9 +1216,13 @@ macro_rules! attempt_swap_as_chunks {
// SAFETY: the caller must guarantee that `src` is valid for reads.
unsafe {
#[cfg(debug_assertions)] // Too expensive to always enable (for now?)
assert_unsafe_precondition!(
"ptr::read requires that the pointer argument is aligned and non-null",
[T](src: *const T) => is_aligned_and_not_null(src)
(
addr: *const () = src as *const (),
align: usize = align_of::<T>(),
) => is_aligned_and_not_null(addr, align)
);
crate::intrinsics::read_via_copy(src)
}
@@ -1411,9 +1424,13 @@ macro_rules! attempt_swap_as_chunks {
// `dst` cannot overlap `src` because the caller has mutable access
// to `dst` while `src` is owned by this function.
unsafe {
#[cfg(debug_assertions)] // Too expensive to always enable (for now?)
assert_unsafe_precondition!(
"ptr::write requires that the pointer argument is aligned and non-null",
[T](dst: *mut T) => is_aligned_and_not_null(dst)
(
addr: *mut () = dst as *mut (),
align: usize = align_of::<T>(),
) => is_aligned_and_not_null(addr, align)
);
intrinsics::write_via_move(dst, src)
}
@@ -1581,7 +1598,10 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
unsafe {
assert_unsafe_precondition!(
"ptr::read_volatile requires that the pointer argument is aligned and non-null",
[T](src: *const T) => is_aligned_and_not_null(src)
(
addr: *const () = src as *const (),
align: usize = align_of::<T>(),
) => is_aligned_and_not_null(addr, align)
);
intrinsics::volatile_load(src)
}
@@ -1656,7 +1676,10 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
unsafe {
assert_unsafe_precondition!(
"ptr::write_volatile requires that the pointer argument is aligned and non-null",
[T](dst: *mut T) => is_aligned_and_not_null(dst)
(
addr: *mut () = dst as *mut (),
align: usize = align_of::<T>(),
) => is_aligned_and_not_null(addr, align)
);
intrinsics::volatile_store(dst, src);
}
+8 -9
View File
@@ -218,7 +218,10 @@ impl<T: ?Sized> NonNull<T> {
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
// SAFETY: the caller must guarantee that `ptr` is non-null.
unsafe {
assert_unsafe_precondition!("NonNull::new_unchecked requires that the pointer is non-null", [T: ?Sized](ptr: *mut T) => !ptr.is_null());
assert_unsafe_precondition!(
"NonNull::new_unchecked requires that the pointer is non-null",
(ptr: *mut () = ptr as *mut ()) => !ptr.is_null()
);
NonNull { pointer: ptr as _ }
}
}
@@ -470,7 +473,7 @@ pub const fn as_ptr(self) -> *mut T {
#[inline]
pub const fn cast<U>(self) -> NonNull<U> {
// SAFETY: `self` is a `NonNull` pointer which is necessarily non-null
unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) }
unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
}
/// Calculates the offset from a pointer.
@@ -1588,8 +1591,7 @@ pub const fn len(self) -> usize {
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
pub const fn as_non_null_ptr(self) -> NonNull<T> {
// SAFETY: We know `self` is non-null.
unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) }
self.cast()
}
/// Returns a raw pointer to the slice's buffer.
@@ -1825,9 +1827,7 @@ fn hash<H: hash::Hasher>(&self, state: &mut H) {
impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
#[inline]
fn from(unique: Unique<T>) -> Self {
// SAFETY: A Unique pointer cannot be null, so the conditions for
// new_unchecked() are respected.
unsafe { NonNull::new_unchecked(unique.as_ptr()) }
unique.as_non_null_ptr()
}
}
@@ -1850,8 +1850,7 @@ impl<T: ?Sized> From<&T> for NonNull<T> {
/// This conversion is safe and infallible since references cannot be null.
#[inline]
fn from(reference: &T) -> Self {
// SAFETY: A reference cannot be null, so the conditions for
// new_unchecked() are respected.
// SAFETY: A reference cannot be null.
unsafe { NonNull { pointer: reference as *const T } }
}
}
+8 -1
View File
@@ -106,6 +106,13 @@ pub const fn as_ptr(self) -> *mut T {
self.pointer.as_ptr()
}
/// Acquires the underlying `*mut` pointer.
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub const fn as_non_null_ptr(self) -> NonNull<T> {
self.pointer
}
/// Dereferences the content.
///
/// The resulting lifetime is bound to self so this behaves "as if"
@@ -138,7 +145,7 @@ pub const fn as_ptr(self) -> *mut T {
pub const fn cast<U>(self) -> Unique<U> {
// FIXME(const-hack): replace with `From`
// SAFETY: is `NonNull`
unsafe { Unique::new_unchecked(self.pointer.cast().as_ptr()) }
Unique { pointer: self.pointer.cast(), _marker: PhantomData }
}
}
+8 -7
View File
@@ -87,12 +87,13 @@ unsafe impl<T: Sync> Send for Iter<'_, T> {}
impl<'a, T> Iter<'a, T> {
#[inline]
pub(super) fn new(slice: &'a [T]) -> Self {
let ptr = slice.as_ptr();
let len = slice.len();
let ptr: NonNull<T> = NonNull::from(slice).cast();
// SAFETY: Similar to `IterMut::new`.
unsafe {
let end_or_len = if T::IS_ZST { invalid(slice.len()) } else { ptr.add(slice.len()) };
let end_or_len = if T::IS_ZST { invalid(len) } else { ptr.as_ptr().add(len) };
Self { ptr: NonNull::new_unchecked(ptr as *mut T), end_or_len, _marker: PhantomData }
Self { ptr, end_or_len, _marker: PhantomData }
}
}
@@ -208,7 +209,8 @@ unsafe impl<T: Send> Send for IterMut<'_, T> {}
impl<'a, T> IterMut<'a, T> {
#[inline]
pub(super) fn new(slice: &'a mut [T]) -> Self {
let ptr = slice.as_mut_ptr();
let len = slice.len();
let ptr: NonNull<T> = NonNull::from(slice).cast();
// SAFETY: There are several things here:
//
// `ptr` has been obtained by `slice.as_ptr()` where `slice` is a valid
@@ -226,10 +228,9 @@ pub(super) fn new(slice: &'a mut [T]) -> Self {
// See the `next_unchecked!` and `is_empty!` macros as well as the
// `post_inc_start` method for more information.
unsafe {
let end_or_len =
if T::IS_ZST { invalid_mut(slice.len()) } else { ptr.add(slice.len()) };
let end_or_len = if T::IS_ZST { invalid_mut(len) } else { ptr.as_ptr().add(len) };
Self { ptr: NonNull::new_unchecked(ptr), end_or_len, _marker: PhantomData }
Self { ptr, end_or_len, _marker: PhantomData }
}
}
+17 -4
View File
@@ -4,6 +4,7 @@
use crate::intrinsics::{
assert_unsafe_precondition, is_aligned_and_not_null, is_valid_allocation_size,
};
use crate::mem::{align_of, size_of};
use crate::ops::Range;
use crate::ptr;
@@ -96,8 +97,14 @@
unsafe {
assert_unsafe_precondition!(
"slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
[T](data: *const T, len: usize) => is_aligned_and_not_null(data)
&& is_valid_allocation_size::<T>(len)
(
data: *mut () = data as *mut (),
size: usize = size_of::<T>(),
align: usize = align_of::<T>(),
len: usize = len,
) =>
is_aligned_and_not_null(data, align)
&& is_valid_allocation_size(size, len)
);
&*ptr::slice_from_raw_parts(data, len)
}
@@ -143,8 +150,14 @@
unsafe {
assert_unsafe_precondition!(
"slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
[T](data: *mut T, len: usize) => is_aligned_and_not_null(data)
&& is_valid_allocation_size::<T>(len)
(
data: *mut () = data as *mut (),
size: usize = size_of::<T>(),
align: usize = align_of::<T>(),
len: usize = len,
) =>
is_aligned_and_not_null(data, align)
&& is_valid_allocation_size(size, len)
);
&mut *ptr::slice_from_raw_parts_mut(data, len)
}
@@ -174,7 +174,7 @@ fn check_rvalue<'tcx>(
))
}
},
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => {
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::DebugAssertions, _) | Rvalue::ShallowInitBox(_, _) => {
Ok(())
},
Rvalue::UnaryOp(_, operand) => {
+1 -1
View File
@@ -15,7 +15,7 @@
const ENTRY_LIMIT: usize = 900;
// FIXME: The following limits should be reduced eventually.
const ISSUES_ENTRY_LIMIT: usize = 1819;
const ROOT_ENTRY_LIMIT: usize = 871;
const ROOT_ENTRY_LIMIT: usize = 872;
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
"rs", // test source files
+2 -2
View File
@@ -2,8 +2,8 @@
// only-x86_64
// ignore-sgx
// revisions: opt-speed opt-size
// [opt-speed] compile-flags: -Copt-level=1
// [opt-size] compile-flags: -Copt-level=s
// [opt-speed] compile-flags: -Copt-level=2 -Cdebug-assertions=no
// [opt-size] compile-flags: -Copt-level=s -Cdebug-assertions=no
#![crate_type="rlib"]
#![feature(core_intrinsics)]
@@ -24,29 +24,11 @@
debug ptr => _6;
scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: *const [bool; 0];
let mut _9: *mut [bool; 0];
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 12 {
scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) {
debug ptr => _9;
scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) {
debug self => _9;
let mut _10: *mut u8;
scope 15 {
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _10;
scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _10;
scope 18 {
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _10;
}
}
}
}
}
}
}
}
}
}
@@ -66,6 +48,7 @@
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_9);
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
@@ -73,30 +56,41 @@
_7 = const 1_usize;
_6 = const {0x1 as *mut [bool; 0]};
StorageDead(_7);
StorageLive(_8);
StorageLive(_9);
StorageLive(_10);
_8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _8 };
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
StorageLive(_11);
StorageLive(_8);
_8 = cfg!(debug_assertions);
switchInt(move _8) -> [0: bb3, otherwise: bb2];
}
bb1: {
StorageDead(_1);
return;
}
bb2: {
_10 = const {0x1 as *mut [bool; 0]} as *mut () (PtrToPtr);
_9 = NonNull::<T>::new_unchecked::precondition_check(move _10) -> [return: bb3, unwind unreachable];
}
bb3: {
StorageDead(_8);
_11 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _11 };
StorageDead(_11);
StorageDead(_10);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_9);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
}
}
@@ -24,29 +24,11 @@
debug ptr => _6;
scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: *const [bool; 0];
let mut _9: *mut [bool; 0];
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 12 {
scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) {
debug ptr => _9;
scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) {
debug self => _9;
let mut _10: *mut u8;
scope 15 {
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _10;
scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _10;
scope 18 {
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _10;
}
}
}
}
}
}
}
}
}
}
@@ -66,6 +48,7 @@
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_9);
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
@@ -73,25 +56,11 @@
_7 = const 1_usize;
_6 = const {0x1 as *mut [bool; 0]};
StorageDead(_7);
StorageLive(_8);
StorageLive(_9);
StorageLive(_10);
_8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _8 };
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
StorageLive(_11);
StorageLive(_8);
_8 = cfg!(debug_assertions);
switchInt(move _8) -> [0: bb4, otherwise: bb3];
}
bb1: {
@@ -102,5 +71,30 @@
bb2 (cleanup): {
resume;
}
bb3: {
_10 = const {0x1 as *mut [bool; 0]} as *mut () (PtrToPtr);
_9 = NonNull::<T>::new_unchecked::precondition_check(move _10) -> [return: bb4, unwind unreachable];
}
bb4: {
StorageDead(_8);
_11 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _11 };
StorageDead(_11);
StorageDead(_10);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_9);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
}
}
@@ -24,29 +24,11 @@
debug ptr => _6;
scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: *const [bool; 0];
let mut _9: *mut [bool; 0];
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 12 {
scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) {
debug ptr => _9;
scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) {
debug self => _9;
let mut _10: *mut u8;
scope 15 {
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _10;
scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _10;
scope 18 {
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _10;
}
}
}
}
}
}
}
}
}
}
@@ -66,6 +48,7 @@
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_9);
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
@@ -73,30 +56,41 @@
_7 = const 1_usize;
_6 = const {0x1 as *mut [bool; 0]};
StorageDead(_7);
StorageLive(_8);
StorageLive(_9);
StorageLive(_10);
_8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _8 };
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
StorageLive(_11);
StorageLive(_8);
_8 = cfg!(debug_assertions);
switchInt(move _8) -> [0: bb3, otherwise: bb2];
}
bb1: {
StorageDead(_1);
return;
}
bb2: {
_10 = const {0x1 as *mut [bool; 0]} as *mut () (PtrToPtr);
_9 = NonNull::<T>::new_unchecked::precondition_check(move _10) -> [return: bb3, unwind unreachable];
}
bb3: {
StorageDead(_8);
_11 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _11 };
StorageDead(_11);
StorageDead(_10);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_9);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
}
}
@@ -24,29 +24,11 @@
debug ptr => _6;
scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: *const [bool; 0];
let mut _9: *mut [bool; 0];
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 12 {
scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) {
debug ptr => _9;
scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) {
debug self => _9;
let mut _10: *mut u8;
scope 15 {
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _10;
scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _10;
scope 18 {
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _10;
}
}
}
}
}
}
}
}
}
}
@@ -66,6 +48,7 @@
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_9);
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
@@ -73,25 +56,11 @@
_7 = const 1_usize;
_6 = const {0x1 as *mut [bool; 0]};
StorageDead(_7);
StorageLive(_8);
StorageLive(_9);
StorageLive(_10);
_8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _8 };
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
StorageLive(_11);
StorageLive(_8);
_8 = cfg!(debug_assertions);
switchInt(move _8) -> [0: bb4, otherwise: bb3];
}
bb1: {
@@ -102,5 +71,30 @@
bb2 (cleanup): {
resume;
}
bb3: {
_10 = const {0x1 as *mut [bool; 0]} as *mut () (PtrToPtr);
_9 = NonNull::<T>::new_unchecked::precondition_check(move _10) -> [return: bb4, unwind unreachable];
}
bb4: {
StorageDead(_8);
_11 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _11 };
StorageDead(_11);
StorageDead(_10);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_9);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
}
}
@@ -24,29 +24,11 @@
debug ptr => _6;
scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: *const [bool; 0];
let mut _9: *mut [bool; 0];
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 12 {
scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) {
debug ptr => _9;
scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) {
debug self => _9;
let mut _10: *mut u8;
scope 15 {
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _10;
scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _10;
scope 18 {
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _10;
}
}
}
}
}
}
}
}
}
}
@@ -66,6 +48,7 @@
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_9);
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
@@ -75,31 +58,43 @@
+ _7 = const 1_usize;
+ _6 = const {0x1 as *mut [bool; 0]};
StorageDead(_7);
StorageLive(_8);
StorageLive(_9);
StorageLive(_10);
- _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+ _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _8 };
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
StorageLive(_11);
StorageLive(_8);
_8 = cfg!(debug_assertions);
switchInt(move _8) -> [0: bb3, otherwise: bb2];
}
bb1: {
StorageDead(_1);
return;
}
bb2: {
- _10 = _6 as *mut () (PtrToPtr);
+ _10 = const {0x1 as *mut [bool; 0]} as *mut () (PtrToPtr);
_9 = NonNull::<T>::new_unchecked::precondition_check(move _10) -> [return: bb3, unwind unreachable];
}
bb3: {
StorageDead(_8);
- _11 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+ _11 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _11 };
StorageDead(_11);
StorageDead(_10);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_9);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
}
}
@@ -24,29 +24,11 @@
debug ptr => _6;
scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: *const [bool; 0];
let mut _9: *mut [bool; 0];
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 12 {
scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) {
debug ptr => _9;
scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) {
debug self => _9;
let mut _10: *mut u8;
scope 15 {
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _10;
scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _10;
scope 18 {
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _10;
}
}
}
}
}
}
}
}
}
}
@@ -66,6 +48,7 @@
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_9);
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
@@ -75,26 +58,11 @@
+ _7 = const 1_usize;
+ _6 = const {0x1 as *mut [bool; 0]};
StorageDead(_7);
StorageLive(_8);
StorageLive(_9);
StorageLive(_10);
- _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+ _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _8 };
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
StorageLive(_11);
StorageLive(_8);
_8 = cfg!(debug_assertions);
switchInt(move _8) -> [0: bb4, otherwise: bb3];
}
bb1: {
@@ -105,5 +73,32 @@
bb2 (cleanup): {
resume;
}
bb3: {
- _10 = _6 as *mut () (PtrToPtr);
+ _10 = const {0x1 as *mut [bool; 0]} as *mut () (PtrToPtr);
_9 = NonNull::<T>::new_unchecked::precondition_check(move _10) -> [return: bb4, unwind unreachable];
}
bb4: {
StorageDead(_8);
- _11 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+ _11 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _11 };
StorageDead(_11);
StorageDead(_10);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_9);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
}
}
@@ -24,29 +24,11 @@
debug ptr => _6;
scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: *const [bool; 0];
let mut _9: *mut [bool; 0];
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 12 {
scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) {
debug ptr => _9;
scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) {
debug self => _9;
let mut _10: *mut u8;
scope 15 {
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _10;
scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _10;
scope 18 {
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _10;
}
}
}
}
}
}
}
}
}
}
@@ -66,6 +48,7 @@
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_9);
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
@@ -75,31 +58,43 @@
+ _7 = const 1_usize;
+ _6 = const {0x1 as *mut [bool; 0]};
StorageDead(_7);
StorageLive(_8);
StorageLive(_9);
StorageLive(_10);
- _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+ _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _8 };
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
StorageLive(_11);
StorageLive(_8);
_8 = cfg!(debug_assertions);
switchInt(move _8) -> [0: bb3, otherwise: bb2];
}
bb1: {
StorageDead(_1);
return;
}
bb2: {
- _10 = _6 as *mut () (PtrToPtr);
+ _10 = const {0x1 as *mut [bool; 0]} as *mut () (PtrToPtr);
_9 = NonNull::<T>::new_unchecked::precondition_check(move _10) -> [return: bb3, unwind unreachable];
}
bb3: {
StorageDead(_8);
- _11 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+ _11 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _11 };
StorageDead(_11);
StorageDead(_10);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_9);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
}
}
@@ -24,29 +24,11 @@
debug ptr => _6;
scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: *const [bool; 0];
let mut _9: *mut [bool; 0];
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 12 {
scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) {
debug ptr => _9;
scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) {
debug self => _9;
let mut _10: *mut u8;
scope 15 {
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _10;
scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _10;
scope 18 {
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _10;
}
}
}
}
}
}
}
}
}
}
@@ -66,6 +48,7 @@
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_9);
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
@@ -75,26 +58,11 @@
+ _7 = const 1_usize;
+ _6 = const {0x1 as *mut [bool; 0]};
StorageDead(_7);
StorageLive(_8);
StorageLive(_9);
StorageLive(_10);
- _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+ _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _8 };
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
StorageLive(_11);
StorageLive(_8);
_8 = cfg!(debug_assertions);
switchInt(move _8) -> [0: bb4, otherwise: bb3];
}
bb1: {
@@ -105,5 +73,32 @@
bb2 (cleanup): {
resume;
}
bb3: {
- _10 = _6 as *mut () (PtrToPtr);
+ _10 = const {0x1 as *mut [bool; 0]} as *mut () (PtrToPtr);
_9 = NonNull::<T>::new_unchecked::precondition_check(move _10) -> [return: bb4, unwind unreachable];
}
bb4: {
StorageDead(_8);
- _11 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+ _11 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
_5 = NonNull::<[bool; 0]> { pointer: _11 };
StorageDead(_11);
StorageDead(_10);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
StorageDead(_4);
_2 = Box::<[bool]>(_3, const std::alloc::Global);
StorageDead(_9);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
}
}
+1 -1
View File
@@ -2,7 +2,7 @@
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
// ignore-debug: the debug assertions prevent the inlining we are testing for
// compile-flags: -Zmir-opt-level=2 -Zinline-mir
// compile-flags: -Zmir-opt-level=2 -Zinline-mir -Cdebug-assertions=no
// EMIT_MIR unwrap_unchecked.unwrap_unchecked.Inline.diff
// EMIT_MIR unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir
@@ -7,41 +7,44 @@
let mut _2: std::option::Option<T>;
+ scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) {
+ debug self => _2;
+ let mut _3: &std::option::Option<T>;
+ let mut _4: isize;
+ let mut _5: bool;
+ let mut _3: isize;
+ scope 2 {
+ debug val => _0;
+ }
+ scope 3 {
+ scope 5 (inlined unreachable_unchecked) {
+ scope 6 {
+ scope 7 (inlined unreachable_unchecked::runtime) {
+ }
+ scope 4 (inlined unreachable_unchecked) {
+ let mut _4: bool;
+ let _5: ();
+ scope 5 {
+ }
+ }
+ }
+ scope 4 (inlined Option::<T>::is_some) {
+ debug self => _3;
+ }
+ }
bb0: {
StorageLive(_2);
_2 = move _1;
- _0 = Option::<T>::unwrap_unchecked(move _2) -> [return: bb1, unwind unreachable];
- }
-
- bb1: {
+ StorageLive(_3);
+ StorageLive(_4);
+ StorageLive(_5);
+ _4 = discriminant(_2);
+ _5 = Eq(_4, const 1_isize);
+ assume(move _5);
+ _3 = discriminant(_2);
+ switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2];
}
bb1: {
+ StorageLive(_4);
+ _4 = cfg!(debug_assertions);
+ assume(_4);
+ _5 = unreachable_unchecked::precondition_check() -> [return: bb2, unwind unreachable];
+ }
+
+ bb2: {
+ unreachable;
+ }
+
+ bb3: {
+ _0 = move ((_2 as Some).0: T);
+ StorageDead(_5);
+ StorageDead(_4);
+ StorageDead(_3);
StorageDead(_2);
return;
@@ -7,48 +7,51 @@
let mut _2: std::option::Option<T>;
+ scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) {
+ debug self => _2;
+ let mut _3: &std::option::Option<T>;
+ let mut _4: isize;
+ let mut _5: bool;
+ let mut _3: isize;
+ scope 2 {
+ debug val => _0;
+ }
+ scope 3 {
+ scope 5 (inlined unreachable_unchecked) {
+ scope 6 {
+ scope 7 (inlined unreachable_unchecked::runtime) {
+ }
+ scope 4 (inlined unreachable_unchecked) {
+ let mut _4: bool;
+ let _5: ();
+ scope 5 {
+ }
+ }
+ }
+ scope 4 (inlined Option::<T>::is_some) {
+ debug self => _3;
+ }
+ }
bb0: {
StorageLive(_2);
_2 = move _1;
- _0 = Option::<T>::unwrap_unchecked(move _2) -> [return: bb1, unwind: bb2];
- }
-
- bb1: {
+ StorageLive(_3);
+ StorageLive(_4);
+ StorageLive(_5);
+ _4 = discriminant(_2);
+ _5 = Eq(_4, const 1_isize);
+ assume(move _5);
+ _0 = move ((_2 as Some).0: T);
+ StorageDead(_5);
+ StorageDead(_4);
+ StorageDead(_3);
StorageDead(_2);
return;
- }
-
+ _3 = discriminant(_2);
+ switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2];
}
bb1: {
- StorageDead(_2);
- return;
+ StorageLive(_4);
+ _4 = cfg!(debug_assertions);
+ assume(_4);
+ _5 = unreachable_unchecked::precondition_check() -> [return: bb2, unwind unreachable];
}
- bb2 (cleanup): {
- resume;
+ bb2: {
+ unreachable;
+ }
+
+ bb3: {
+ _0 = move ((_2 as Some).0: T);
+ StorageDead(_5);
+ StorageDead(_3);
+ StorageDead(_2);
+ return;
}
}
@@ -6,35 +6,39 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) {
debug self => _1;
let mut _2: isize;
let mut _3: bool;
let mut _4: &std::option::Option<T>;
scope 2 {
debug val => _0;
}
scope 3 {
scope 5 (inlined unreachable_unchecked) {
scope 6 {
scope 7 (inlined unreachable_unchecked::runtime) {
}
scope 4 (inlined unreachable_unchecked) {
let mut _3: bool;
let _4: ();
scope 5 {
}
}
}
scope 4 (inlined Option::<T>::is_some) {
debug self => _4;
}
}
bb0: {
StorageLive(_4);
StorageLive(_2);
StorageLive(_3);
_2 = discriminant(_1);
_3 = Eq(_2, const 1_isize);
assume(move _3);
switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb3];
}
bb1: {
StorageLive(_3);
_3 = cfg!(debug_assertions);
assume(_3);
_4 = unreachable_unchecked::precondition_check() -> [return: bb3, unwind unreachable];
}
bb2: {
_0 = ((_1 as Some).0: T);
StorageDead(_3);
StorageDead(_2);
StorageDead(_4);
return;
}
bb3: {
unreachable;
}
}
@@ -6,35 +6,39 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) {
debug self => _1;
let mut _2: isize;
let mut _3: bool;
let mut _4: &std::option::Option<T>;
scope 2 {
debug val => _0;
}
scope 3 {
scope 5 (inlined unreachable_unchecked) {
scope 6 {
scope 7 (inlined unreachable_unchecked::runtime) {
}
scope 4 (inlined unreachable_unchecked) {
let mut _3: bool;
let _4: ();
scope 5 {
}
}
}
scope 4 (inlined Option::<T>::is_some) {
debug self => _4;
}
}
bb0: {
StorageLive(_4);
StorageLive(_2);
StorageLive(_3);
_2 = discriminant(_1);
_3 = Eq(_2, const 1_isize);
assume(move _3);
switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb3];
}
bb1: {
StorageLive(_3);
_3 = cfg!(debug_assertions);
assume(_3);
_4 = unreachable_unchecked::precondition_check() -> [return: bb3, unwind unreachable];
}
bb2: {
_0 = ((_1 as Some).0: T);
StorageDead(_3);
StorageDead(_2);
StorageDead(_4);
return;
}
bb3: {
unreachable;
}
}
@@ -4,19 +4,31 @@ fn ub_if_b(_1: Thing) -> Thing {
debug t => _1;
let mut _0: Thing;
let mut _2: isize;
let mut _3: bool;
scope 1 (inlined unreachable_unchecked) {
let mut _3: bool;
let _4: ();
scope 2 {
scope 3 (inlined unreachable_unchecked::runtime) {
}
}
}
bb0: {
_2 = discriminant(_1);
_3 = Eq(_2, const 0_isize);
assume(move _3);
switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb3];
}
bb1: {
_0 = move _1;
return;
}
bb2: {
StorageLive(_3);
_3 = cfg!(debug_assertions);
assume(_3);
_4 = unreachable_unchecked::precondition_check() -> [return: bb3, unwind unreachable];
}
bb3: {
unreachable;
}
}
@@ -0,0 +1,16 @@
// MIR for `manual_replace` after PreCodegen
fn manual_replace(_1: &mut u32, _2: u32) -> u32 {
debug r => _1;
debug v => _2;
let mut _0: u32;
scope 1 {
debug temp => _0;
}
bb0: {
_0 = (*_1);
(*_1) = _2;
return;
}
}
@@ -1,66 +0,0 @@
// MIR for `mem_replace` after PreCodegen
fn mem_replace(_1: &mut u32, _2: u32) -> u32 {
debug r => _1;
debug v => _2;
let mut _0: u32;
scope 1 (inlined std::mem::replace::<u32>) {
debug dest => _1;
debug src => _2;
scope 2 {
scope 3 {
debug result => _0;
scope 16 (inlined std::ptr::write::<u32>) {
debug dst => _1;
debug src => _2;
scope 17 {
}
}
}
scope 4 (inlined std::ptr::read::<u32>) {
debug src => _1;
let mut _3: *const u32;
scope 5 {
scope 6 (inlined std::ptr::read::runtime::<u32>) {
debug src => _3;
scope 7 (inlined intrinsics::is_aligned_and_not_null::<u32>) {
debug ptr => _3;
scope 8 (inlined std::ptr::const_ptr::<impl *const u32>::is_null) {
debug self => _3;
let mut _4: *const u8;
scope 9 {
scope 10 (inlined std::ptr::const_ptr::<impl *const T>::is_null::runtime_impl) {
debug ptr => _4;
scope 11 (inlined std::ptr::const_ptr::<impl *const u8>::addr) {
debug self => _4;
scope 12 {
scope 13 (inlined std::ptr::const_ptr::<impl *const u8>::cast::<()>) {
debug self => _4;
}
}
}
}
}
}
scope 14 (inlined std::ptr::const_ptr::<impl *const u32>::is_aligned) {
debug self => _3;
scope 15 (inlined align_of::<u32>) {
}
}
}
}
}
}
}
}
bb0: {
StorageLive(_3);
StorageLive(_4);
_0 = (*_1);
StorageDead(_4);
StorageDead(_3);
(*_1) = _2;
return;
}
}
@@ -0,0 +1,33 @@
// MIR for `mem_replace` after PreCodegen
fn mem_replace(_1: &mut u32, _2: u32) -> u32 {
debug r => _1;
debug v => _2;
let mut _0: u32;
scope 1 (inlined std::mem::replace::<u32>) {
debug dest => _1;
debug src => _2;
scope 2 {
scope 3 {
debug result => _0;
scope 6 (inlined std::ptr::write::<u32>) {
debug dst => _1;
debug src => _2;
scope 7 {
}
}
}
scope 4 (inlined std::ptr::read::<u32>) {
debug src => _1;
scope 5 {
}
}
}
}
bb0: {
_0 = (*_1);
(*_1) = _2;
return;
}
}
@@ -0,0 +1,33 @@
// MIR for `mem_replace` after PreCodegen
fn mem_replace(_1: &mut u32, _2: u32) -> u32 {
debug r => _1;
debug v => _2;
let mut _0: u32;
scope 1 (inlined std::mem::replace::<u32>) {
debug dest => _1;
debug src => _2;
scope 2 {
scope 3 {
debug result => _0;
scope 6 (inlined std::ptr::write::<u32>) {
debug dst => _1;
debug src => _2;
scope 7 {
}
}
}
scope 4 (inlined std::ptr::read::<u32>) {
debug src => _1;
scope 5 {
}
}
}
}
bb0: {
_0 = (*_1);
(*_1) = _2;
return;
}
}
+2 -1
View File
@@ -1,7 +1,8 @@
// skip-filecheck
// compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2
// compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Zinline-mir
// only-64bit
// ignore-debug the standard library debug assertions leak into this test
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
#![crate_type = "lib"]
@@ -4,171 +4,165 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
debug slice => _1;
debug f => _2;
let mut _0: ();
let mut _13: std::slice::Iter<'_, T>;
let mut _14: std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _15: std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _16: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _17: std::option::Option<(usize, &T)>;
let mut _18: isize;
let mut _21: &impl Fn(usize, &T);
let mut _22: (usize, &T);
let _23: ();
let mut _15: std::slice::Iter<'_, T>;
let mut _16: std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _17: std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _18: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _19: std::option::Option<(usize, &T)>;
let mut _20: isize;
let mut _23: &impl Fn(usize, &T);
let mut _24: (usize, &T);
let _25: ();
scope 1 {
debug iter => _15;
let _19: usize;
let _20: &T;
debug iter => _17;
let _21: usize;
let _22: &T;
scope 2 {
debug i => _19;
debug x => _20;
debug i => _21;
debug x => _22;
}
}
scope 3 (inlined core::slice::<impl [T]>::iter) {
debug self => _1;
scope 4 (inlined std::slice::Iter::<'_, T>::new) {
debug slice => _1;
let _4: *const T;
let mut _5: bool;
let mut _6: usize;
let mut _8: usize;
let mut _9: *mut T;
let mut _11: std::ptr::NonNull<T>;
let mut _12: *const T;
let _3: usize;
let mut _5: std::ptr::NonNull<[T]>;
let mut _10: bool;
let mut _11: *mut T;
let mut _12: *mut T;
let mut _14: *const T;
scope 5 {
debug ptr => _4;
debug len => _3;
let _9: std::ptr::NonNull<T>;
scope 6 {
let _7: *const T;
debug ptr => _9;
scope 7 {
debug end_or_len => _7;
scope 13 (inlined NonNull::<T>::new_unchecked) {
debug ptr => _9;
let mut _10: *const T;
let mut _24: *mut T;
scope 14 {
scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) {
debug ptr => _24;
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) {
debug self => _24;
let mut _25: *mut u8;
scope 17 {
scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _25;
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _25;
scope 20 {
scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _25;
}
}
}
}
}
}
}
let _13: *const T;
scope 8 {
debug end_or_len => _13;
}
scope 14 (inlined invalid::<T>) {
debug addr => _3;
scope 15 {
}
}
scope 16 (inlined NonNull::<T>::as_ptr) {
debug self => _9;
}
scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
debug self => _11;
debug count => _3;
scope 18 {
}
}
}
scope 9 (inlined invalid::<T>) {
debug addr => _8;
scope 10 {
}
}
scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
debug reference => _1;
let mut _4: *const [T];
scope 10 {
}
scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) {
debug self => _4;
debug count => _6;
scope 12 {
}
scope 11 (inlined NonNull::<[T]>::cast::<T>) {
debug self => _5;
let mut _6: *mut [T];
let mut _7: *mut T;
let mut _8: *const T;
scope 12 {
scope 13 (inlined NonNull::<[T]>::as_ptr) {
debug self => _5;
}
}
}
}
scope 8 (inlined core::slice::<impl [T]>::as_ptr) {
debug self => _1;
let mut _3: *const [T];
}
}
}
scope 22 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
debug self => _13;
scope 23 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
debug iter => _13;
scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
debug self => _15;
scope 20 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
debug iter => _15;
}
}
scope 24 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
debug self => _14;
scope 21 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
debug self => _16;
}
bb0: {
StorageLive(_13);
StorageLive(_4);
StorageLive(_15);
StorageLive(_3);
_3 = &raw const (*_1);
_4 = move _3 as *const T (PtrToPtr);
StorageDead(_3);
StorageLive(_7);
StorageLive(_9);
StorageLive(_4);
StorageLive(_8);
_3 = Len((*_1));
StorageLive(_5);
_5 = const _;
switchInt(move _5) -> [0: bb1, otherwise: bb2];
_4 = &raw const (*_1);
_5 = NonNull::<[T]> { pointer: _4 };
StorageLive(_7);
StorageLive(_6);
_6 = _4 as *mut [T] (PtrToPtr);
_7 = move _6 as *mut T (PtrToPtr);
_8 = move _7 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_6);
StorageDead(_7);
_9 = NonNull::<T> { pointer: _8 };
StorageDead(_5);
StorageLive(_13);
StorageLive(_10);
_10 = const _;
switchInt(move _10) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageLive(_6);
_6 = Len((*_1));
_7 = Offset(_4, _6);
StorageDead(_6);
StorageLive(_12);
StorageLive(_11);
_11 = _8 as *mut T (PtrToPtr);
_12 = Offset(_11, _3);
StorageDead(_11);
_13 = move _12 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_12);
goto -> bb3;
}
bb2: {
StorageLive(_8);
_8 = Len((*_1));
_7 = _8 as *const T (Transmute);
StorageDead(_8);
_13 = _3 as *const T (Transmute);
goto -> bb3;
}
bb3: {
StorageDead(_5);
StorageLive(_11);
StorageLive(_9);
_9 = _4 as *mut T (PtrToPtr);
StorageLive(_10);
StorageLive(_24);
StorageLive(_25);
_10 = _9 as *const T (PointerCoercion(MutToConstPointer));
_11 = NonNull::<T> { pointer: _10 };
StorageDead(_25);
StorageDead(_24);
StorageDead(_10);
StorageDead(_9);
StorageLive(_12);
_12 = _7;
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_12);
StorageDead(_11);
StorageDead(_7);
StorageDead(_4);
_14 = Enumerate::<std::slice::Iter<'_, T>> { iter: _13, count: const 0_usize };
StorageLive(_14);
_14 = _13;
_15 = std::slice::Iter::<'_, T> { ptr: _9, end_or_len: move _14, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_14);
StorageDead(_13);
StorageLive(_15);
_15 = _14;
StorageDead(_8);
StorageDead(_4);
StorageDead(_9);
StorageDead(_3);
_16 = Enumerate::<std::slice::Iter<'_, T>> { iter: _15, count: const 0_usize };
StorageDead(_15);
StorageLive(_17);
_17 = _16;
goto -> bb4;
}
bb4: {
StorageLive(_17);
StorageLive(_16);
_16 = &mut _15;
_17 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _16) -> [return: bb5, unwind unreachable];
StorageLive(_19);
StorageLive(_18);
_18 = &mut _17;
_19 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _18) -> [return: bb5, unwind unreachable];
}
bb5: {
StorageDead(_16);
_18 = discriminant(_17);
switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10];
StorageDead(_18);
_20 = discriminant(_19);
switchInt(move _20) -> [0: bb6, 1: bb8, otherwise: bb10];
}
bb6: {
StorageDead(_19);
StorageDead(_17);
StorageDead(_15);
drop(_2) -> [return: bb7, unwind unreachable];
}
@@ -177,19 +171,19 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
}
bb8: {
_19 = (((_17 as Some).0: (usize, &T)).0: usize);
_20 = (((_17 as Some).0: (usize, &T)).1: &T);
StorageLive(_21);
_21 = &_2;
StorageLive(_22);
_22 = (_19, _20);
_23 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _21, move _22) -> [return: bb9, unwind unreachable];
_21 = (((_19 as Some).0: (usize, &T)).0: usize);
_22 = (((_19 as Some).0: (usize, &T)).1: &T);
StorageLive(_23);
_23 = &_2;
StorageLive(_24);
_24 = (_21, _22);
_25 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _23, move _24) -> [return: bb9, unwind unreachable];
}
bb9: {
StorageDead(_22);
StorageDead(_21);
StorageDead(_17);
StorageDead(_24);
StorageDead(_23);
StorageDead(_19);
goto -> bb4;
}
@@ -4,171 +4,165 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
debug slice => _1;
debug f => _2;
let mut _0: ();
let mut _13: std::slice::Iter<'_, T>;
let mut _14: std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _15: std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _16: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _17: std::option::Option<(usize, &T)>;
let mut _18: isize;
let mut _21: &impl Fn(usize, &T);
let mut _22: (usize, &T);
let _23: ();
let mut _15: std::slice::Iter<'_, T>;
let mut _16: std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _17: std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _18: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>;
let mut _19: std::option::Option<(usize, &T)>;
let mut _20: isize;
let mut _23: &impl Fn(usize, &T);
let mut _24: (usize, &T);
let _25: ();
scope 1 {
debug iter => _15;
let _19: usize;
let _20: &T;
debug iter => _17;
let _21: usize;
let _22: &T;
scope 2 {
debug i => _19;
debug x => _20;
debug i => _21;
debug x => _22;
}
}
scope 3 (inlined core::slice::<impl [T]>::iter) {
debug self => _1;
scope 4 (inlined std::slice::Iter::<'_, T>::new) {
debug slice => _1;
let _4: *const T;
let mut _5: bool;
let mut _6: usize;
let mut _8: usize;
let mut _9: *mut T;
let mut _11: std::ptr::NonNull<T>;
let mut _12: *const T;
let _3: usize;
let mut _5: std::ptr::NonNull<[T]>;
let mut _10: bool;
let mut _11: *mut T;
let mut _12: *mut T;
let mut _14: *const T;
scope 5 {
debug ptr => _4;
debug len => _3;
let _9: std::ptr::NonNull<T>;
scope 6 {
let _7: *const T;
debug ptr => _9;
scope 7 {
debug end_or_len => _7;
scope 13 (inlined NonNull::<T>::new_unchecked) {
debug ptr => _9;
let mut _10: *const T;
let mut _24: *mut T;
scope 14 {
scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) {
debug ptr => _24;
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) {
debug self => _24;
let mut _25: *mut u8;
scope 17 {
scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _25;
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _25;
scope 20 {
scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _25;
}
}
}
}
}
}
}
let _13: *const T;
scope 8 {
debug end_or_len => _13;
}
scope 14 (inlined invalid::<T>) {
debug addr => _3;
scope 15 {
}
}
scope 16 (inlined NonNull::<T>::as_ptr) {
debug self => _9;
}
scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
debug self => _11;
debug count => _3;
scope 18 {
}
}
}
scope 9 (inlined invalid::<T>) {
debug addr => _8;
scope 10 {
}
}
scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
debug reference => _1;
let mut _4: *const [T];
scope 10 {
}
scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) {
debug self => _4;
debug count => _6;
scope 12 {
}
scope 11 (inlined NonNull::<[T]>::cast::<T>) {
debug self => _5;
let mut _6: *mut [T];
let mut _7: *mut T;
let mut _8: *const T;
scope 12 {
scope 13 (inlined NonNull::<[T]>::as_ptr) {
debug self => _5;
}
}
}
}
scope 8 (inlined core::slice::<impl [T]>::as_ptr) {
debug self => _1;
let mut _3: *const [T];
}
}
}
scope 22 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
debug self => _13;
scope 23 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
debug iter => _13;
scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
debug self => _15;
scope 20 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
debug iter => _15;
}
}
scope 24 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
debug self => _14;
scope 21 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
debug self => _16;
}
bb0: {
StorageLive(_13);
StorageLive(_4);
StorageLive(_15);
StorageLive(_3);
_3 = &raw const (*_1);
_4 = move _3 as *const T (PtrToPtr);
StorageDead(_3);
StorageLive(_7);
StorageLive(_9);
StorageLive(_4);
StorageLive(_8);
_3 = Len((*_1));
StorageLive(_5);
_5 = const _;
switchInt(move _5) -> [0: bb1, otherwise: bb2];
_4 = &raw const (*_1);
_5 = NonNull::<[T]> { pointer: _4 };
StorageLive(_7);
StorageLive(_6);
_6 = _4 as *mut [T] (PtrToPtr);
_7 = move _6 as *mut T (PtrToPtr);
_8 = move _7 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_6);
StorageDead(_7);
_9 = NonNull::<T> { pointer: _8 };
StorageDead(_5);
StorageLive(_13);
StorageLive(_10);
_10 = const _;
switchInt(move _10) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageLive(_6);
_6 = Len((*_1));
_7 = Offset(_4, _6);
StorageDead(_6);
StorageLive(_12);
StorageLive(_11);
_11 = _8 as *mut T (PtrToPtr);
_12 = Offset(_11, _3);
StorageDead(_11);
_13 = move _12 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_12);
goto -> bb3;
}
bb2: {
StorageLive(_8);
_8 = Len((*_1));
_7 = _8 as *const T (Transmute);
StorageDead(_8);
_13 = _3 as *const T (Transmute);
goto -> bb3;
}
bb3: {
StorageDead(_5);
StorageLive(_11);
StorageLive(_9);
_9 = _4 as *mut T (PtrToPtr);
StorageLive(_10);
StorageLive(_24);
StorageLive(_25);
_10 = _9 as *const T (PointerCoercion(MutToConstPointer));
_11 = NonNull::<T> { pointer: _10 };
StorageDead(_25);
StorageDead(_24);
StorageDead(_10);
StorageDead(_9);
StorageLive(_12);
_12 = _7;
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_12);
StorageDead(_11);
StorageDead(_7);
StorageDead(_4);
_14 = Enumerate::<std::slice::Iter<'_, T>> { iter: _13, count: const 0_usize };
StorageLive(_14);
_14 = _13;
_15 = std::slice::Iter::<'_, T> { ptr: _9, end_or_len: move _14, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_14);
StorageDead(_13);
StorageLive(_15);
_15 = _14;
StorageDead(_8);
StorageDead(_4);
StorageDead(_9);
StorageDead(_3);
_16 = Enumerate::<std::slice::Iter<'_, T>> { iter: _15, count: const 0_usize };
StorageDead(_15);
StorageLive(_17);
_17 = _16;
goto -> bb4;
}
bb4: {
StorageLive(_17);
StorageLive(_16);
_16 = &mut _15;
_17 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _16) -> [return: bb5, unwind: bb11];
StorageLive(_19);
StorageLive(_18);
_18 = &mut _17;
_19 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _18) -> [return: bb5, unwind: bb11];
}
bb5: {
StorageDead(_16);
_18 = discriminant(_17);
switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10];
StorageDead(_18);
_20 = discriminant(_19);
switchInt(move _20) -> [0: bb6, 1: bb8, otherwise: bb10];
}
bb6: {
StorageDead(_19);
StorageDead(_17);
StorageDead(_15);
drop(_2) -> [return: bb7, unwind continue];
}
@@ -177,19 +171,19 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
}
bb8: {
_19 = (((_17 as Some).0: (usize, &T)).0: usize);
_20 = (((_17 as Some).0: (usize, &T)).1: &T);
StorageLive(_21);
_21 = &_2;
StorageLive(_22);
_22 = (_19, _20);
_23 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _21, move _22) -> [return: bb9, unwind: bb11];
_21 = (((_19 as Some).0: (usize, &T)).0: usize);
_22 = (((_19 as Some).0: (usize, &T)).1: &T);
StorageLive(_23);
_23 = &_2;
StorageLive(_24);
_24 = (_21, _22);
_25 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _23, move _24) -> [return: bb9, unwind: bb11];
}
bb9: {
StorageDead(_22);
StorageDead(_21);
StorageDead(_17);
StorageDead(_24);
StorageDead(_23);
StorageDead(_19);
goto -> bb4;
}
@@ -4,159 +4,153 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
debug slice => _1;
debug f => _2;
let mut _0: ();
let mut _13: std::slice::Iter<'_, T>;
let mut _14: std::slice::Iter<'_, T>;
let mut _15: &mut std::slice::Iter<'_, T>;
let mut _16: std::option::Option<&T>;
let mut _17: isize;
let mut _19: &impl Fn(&T);
let mut _20: (&T,);
let _21: ();
let mut _15: std::slice::Iter<'_, T>;
let mut _16: std::slice::Iter<'_, T>;
let mut _17: &mut std::slice::Iter<'_, T>;
let mut _18: std::option::Option<&T>;
let mut _19: isize;
let mut _21: &impl Fn(&T);
let mut _22: (&T,);
let _23: ();
scope 1 {
debug iter => _14;
let _18: &T;
debug iter => _16;
let _20: &T;
scope 2 {
debug x => _18;
debug x => _20;
}
}
scope 3 (inlined core::slice::<impl [T]>::iter) {
debug self => _1;
scope 4 (inlined std::slice::Iter::<'_, T>::new) {
debug slice => _1;
let _4: *const T;
let mut _5: bool;
let mut _6: usize;
let mut _8: usize;
let mut _9: *mut T;
let mut _11: std::ptr::NonNull<T>;
let mut _12: *const T;
let _3: usize;
let mut _5: std::ptr::NonNull<[T]>;
let mut _10: bool;
let mut _11: *mut T;
let mut _12: *mut T;
let mut _14: *const T;
scope 5 {
debug ptr => _4;
debug len => _3;
let _9: std::ptr::NonNull<T>;
scope 6 {
let _7: *const T;
debug ptr => _9;
scope 7 {
debug end_or_len => _7;
scope 13 (inlined NonNull::<T>::new_unchecked) {
debug ptr => _9;
let mut _10: *const T;
let mut _22: *mut T;
scope 14 {
scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) {
debug ptr => _22;
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) {
debug self => _22;
let mut _23: *mut u8;
scope 17 {
scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _23;
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _23;
scope 20 {
scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _23;
}
}
}
}
}
}
}
let _13: *const T;
scope 8 {
debug end_or_len => _13;
}
scope 14 (inlined invalid::<T>) {
debug addr => _3;
scope 15 {
}
}
scope 16 (inlined NonNull::<T>::as_ptr) {
debug self => _9;
}
scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
debug self => _11;
debug count => _3;
scope 18 {
}
}
}
scope 9 (inlined invalid::<T>) {
debug addr => _8;
scope 10 {
}
}
scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
debug reference => _1;
let mut _4: *const [T];
scope 10 {
}
scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) {
debug self => _4;
debug count => _6;
scope 12 {
}
scope 11 (inlined NonNull::<[T]>::cast::<T>) {
debug self => _5;
let mut _6: *mut [T];
let mut _7: *mut T;
let mut _8: *const T;
scope 12 {
scope 13 (inlined NonNull::<[T]>::as_ptr) {
debug self => _5;
}
}
}
}
scope 8 (inlined core::slice::<impl [T]>::as_ptr) {
debug self => _1;
let mut _3: *const [T];
}
}
}
scope 22 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
debug self => _13;
scope 19 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
debug self => _15;
}
bb0: {
StorageLive(_4);
StorageLive(_3);
_3 = &raw const (*_1);
_4 = move _3 as *const T (PtrToPtr);
StorageDead(_3);
StorageLive(_7);
StorageLive(_9);
StorageLive(_4);
StorageLive(_8);
_3 = Len((*_1));
StorageLive(_5);
_5 = const _;
switchInt(move _5) -> [0: bb1, otherwise: bb2];
_4 = &raw const (*_1);
_5 = NonNull::<[T]> { pointer: _4 };
StorageLive(_7);
StorageLive(_6);
_6 = _4 as *mut [T] (PtrToPtr);
_7 = move _6 as *mut T (PtrToPtr);
_8 = move _7 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_6);
StorageDead(_7);
_9 = NonNull::<T> { pointer: _8 };
StorageDead(_5);
StorageLive(_13);
StorageLive(_10);
_10 = const _;
switchInt(move _10) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageLive(_6);
_6 = Len((*_1));
_7 = Offset(_4, _6);
StorageDead(_6);
StorageLive(_12);
StorageLive(_11);
_11 = _8 as *mut T (PtrToPtr);
_12 = Offset(_11, _3);
StorageDead(_11);
_13 = move _12 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_12);
goto -> bb3;
}
bb2: {
StorageLive(_8);
_8 = Len((*_1));
_7 = _8 as *const T (Transmute);
StorageDead(_8);
_13 = _3 as *const T (Transmute);
goto -> bb3;
}
bb3: {
StorageDead(_5);
StorageLive(_11);
StorageLive(_9);
_9 = _4 as *mut T (PtrToPtr);
StorageLive(_10);
StorageLive(_22);
StorageLive(_23);
_10 = _9 as *const T (PointerCoercion(MutToConstPointer));
_11 = NonNull::<T> { pointer: _10 };
StorageDead(_23);
StorageDead(_22);
StorageDead(_10);
StorageDead(_9);
StorageLive(_12);
_12 = _7;
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_12);
StorageDead(_11);
StorageDead(_7);
StorageDead(_4);
StorageLive(_14);
_14 = _13;
_15 = std::slice::Iter::<'_, T> { ptr: _9, end_or_len: move _14, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_14);
StorageDead(_13);
StorageDead(_8);
StorageDead(_4);
StorageDead(_9);
StorageDead(_3);
StorageLive(_16);
_16 = _15;
goto -> bb4;
}
bb4: {
StorageLive(_16);
StorageLive(_15);
_15 = &mut _14;
_16 = <std::slice::Iter<'_, T> as Iterator>::next(move _15) -> [return: bb5, unwind unreachable];
StorageLive(_18);
StorageLive(_17);
_17 = &mut _16;
_18 = <std::slice::Iter<'_, T> as Iterator>::next(move _17) -> [return: bb5, unwind unreachable];
}
bb5: {
StorageDead(_15);
_17 = discriminant(_16);
switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10];
StorageDead(_17);
_19 = discriminant(_18);
switchInt(move _19) -> [0: bb6, 1: bb8, otherwise: bb10];
}
bb6: {
StorageDead(_18);
StorageDead(_16);
StorageDead(_14);
drop(_2) -> [return: bb7, unwind unreachable];
}
@@ -165,18 +159,18 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
}
bb8: {
_18 = ((_16 as Some).0: &T);
StorageLive(_19);
_19 = &_2;
StorageLive(_20);
_20 = (_18,);
_21 = <impl Fn(&T) as Fn<(&T,)>>::call(move _19, move _20) -> [return: bb9, unwind unreachable];
_20 = ((_18 as Some).0: &T);
StorageLive(_21);
_21 = &_2;
StorageLive(_22);
_22 = (_20,);
_23 = <impl Fn(&T) as Fn<(&T,)>>::call(move _21, move _22) -> [return: bb9, unwind unreachable];
}
bb9: {
StorageDead(_20);
StorageDead(_19);
StorageDead(_16);
StorageDead(_22);
StorageDead(_21);
StorageDead(_18);
goto -> bb4;
}
@@ -4,159 +4,153 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
debug slice => _1;
debug f => _2;
let mut _0: ();
let mut _13: std::slice::Iter<'_, T>;
let mut _14: std::slice::Iter<'_, T>;
let mut _15: &mut std::slice::Iter<'_, T>;
let mut _16: std::option::Option<&T>;
let mut _17: isize;
let mut _19: &impl Fn(&T);
let mut _20: (&T,);
let _21: ();
let mut _15: std::slice::Iter<'_, T>;
let mut _16: std::slice::Iter<'_, T>;
let mut _17: &mut std::slice::Iter<'_, T>;
let mut _18: std::option::Option<&T>;
let mut _19: isize;
let mut _21: &impl Fn(&T);
let mut _22: (&T,);
let _23: ();
scope 1 {
debug iter => _14;
let _18: &T;
debug iter => _16;
let _20: &T;
scope 2 {
debug x => _18;
debug x => _20;
}
}
scope 3 (inlined core::slice::<impl [T]>::iter) {
debug self => _1;
scope 4 (inlined std::slice::Iter::<'_, T>::new) {
debug slice => _1;
let _4: *const T;
let mut _5: bool;
let mut _6: usize;
let mut _8: usize;
let mut _9: *mut T;
let mut _11: std::ptr::NonNull<T>;
let mut _12: *const T;
let _3: usize;
let mut _5: std::ptr::NonNull<[T]>;
let mut _10: bool;
let mut _11: *mut T;
let mut _12: *mut T;
let mut _14: *const T;
scope 5 {
debug ptr => _4;
debug len => _3;
let _9: std::ptr::NonNull<T>;
scope 6 {
let _7: *const T;
debug ptr => _9;
scope 7 {
debug end_or_len => _7;
scope 13 (inlined NonNull::<T>::new_unchecked) {
debug ptr => _9;
let mut _10: *const T;
let mut _22: *mut T;
scope 14 {
scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) {
debug ptr => _22;
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) {
debug self => _22;
let mut _23: *mut u8;
scope 17 {
scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _23;
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _23;
scope 20 {
scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _23;
}
}
}
}
}
}
}
let _13: *const T;
scope 8 {
debug end_or_len => _13;
}
scope 14 (inlined invalid::<T>) {
debug addr => _3;
scope 15 {
}
}
scope 16 (inlined NonNull::<T>::as_ptr) {
debug self => _9;
}
scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
debug self => _11;
debug count => _3;
scope 18 {
}
}
}
scope 9 (inlined invalid::<T>) {
debug addr => _8;
scope 10 {
}
}
scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
debug reference => _1;
let mut _4: *const [T];
scope 10 {
}
scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) {
debug self => _4;
debug count => _6;
scope 12 {
}
scope 11 (inlined NonNull::<[T]>::cast::<T>) {
debug self => _5;
let mut _6: *mut [T];
let mut _7: *mut T;
let mut _8: *const T;
scope 12 {
scope 13 (inlined NonNull::<[T]>::as_ptr) {
debug self => _5;
}
}
}
}
scope 8 (inlined core::slice::<impl [T]>::as_ptr) {
debug self => _1;
let mut _3: *const [T];
}
}
}
scope 22 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
debug self => _13;
scope 19 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
debug self => _15;
}
bb0: {
StorageLive(_4);
StorageLive(_3);
_3 = &raw const (*_1);
_4 = move _3 as *const T (PtrToPtr);
StorageDead(_3);
StorageLive(_7);
StorageLive(_9);
StorageLive(_4);
StorageLive(_8);
_3 = Len((*_1));
StorageLive(_5);
_5 = const _;
switchInt(move _5) -> [0: bb1, otherwise: bb2];
_4 = &raw const (*_1);
_5 = NonNull::<[T]> { pointer: _4 };
StorageLive(_7);
StorageLive(_6);
_6 = _4 as *mut [T] (PtrToPtr);
_7 = move _6 as *mut T (PtrToPtr);
_8 = move _7 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_6);
StorageDead(_7);
_9 = NonNull::<T> { pointer: _8 };
StorageDead(_5);
StorageLive(_13);
StorageLive(_10);
_10 = const _;
switchInt(move _10) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageLive(_6);
_6 = Len((*_1));
_7 = Offset(_4, _6);
StorageDead(_6);
StorageLive(_12);
StorageLive(_11);
_11 = _8 as *mut T (PtrToPtr);
_12 = Offset(_11, _3);
StorageDead(_11);
_13 = move _12 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_12);
goto -> bb3;
}
bb2: {
StorageLive(_8);
_8 = Len((*_1));
_7 = _8 as *const T (Transmute);
StorageDead(_8);
_13 = _3 as *const T (Transmute);
goto -> bb3;
}
bb3: {
StorageDead(_5);
StorageLive(_11);
StorageLive(_9);
_9 = _4 as *mut T (PtrToPtr);
StorageLive(_10);
StorageLive(_22);
StorageLive(_23);
_10 = _9 as *const T (PointerCoercion(MutToConstPointer));
_11 = NonNull::<T> { pointer: _10 };
StorageDead(_23);
StorageDead(_22);
StorageDead(_10);
StorageDead(_9);
StorageLive(_12);
_12 = _7;
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_12);
StorageDead(_11);
StorageDead(_7);
StorageDead(_4);
StorageLive(_14);
_14 = _13;
_15 = std::slice::Iter::<'_, T> { ptr: _9, end_or_len: move _14, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_14);
StorageDead(_13);
StorageDead(_8);
StorageDead(_4);
StorageDead(_9);
StorageDead(_3);
StorageLive(_16);
_16 = _15;
goto -> bb4;
}
bb4: {
StorageLive(_16);
StorageLive(_15);
_15 = &mut _14;
_16 = <std::slice::Iter<'_, T> as Iterator>::next(move _15) -> [return: bb5, unwind: bb11];
StorageLive(_18);
StorageLive(_17);
_17 = &mut _16;
_18 = <std::slice::Iter<'_, T> as Iterator>::next(move _17) -> [return: bb5, unwind: bb11];
}
bb5: {
StorageDead(_15);
_17 = discriminant(_16);
switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10];
StorageDead(_17);
_19 = discriminant(_18);
switchInt(move _19) -> [0: bb6, 1: bb8, otherwise: bb10];
}
bb6: {
StorageDead(_18);
StorageDead(_16);
StorageDead(_14);
drop(_2) -> [return: bb7, unwind continue];
}
@@ -165,18 +159,18 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
}
bb8: {
_18 = ((_16 as Some).0: &T);
StorageLive(_19);
_19 = &_2;
StorageLive(_20);
_20 = (_18,);
_21 = <impl Fn(&T) as Fn<(&T,)>>::call(move _19, move _20) -> [return: bb9, unwind: bb11];
_20 = ((_18 as Some).0: &T);
StorageLive(_21);
_21 = &_2;
StorageLive(_22);
_22 = (_20,);
_23 = <impl Fn(&T) as Fn<(&T,)>>::call(move _21, move _22) -> [return: bb9, unwind: bb11];
}
bb9: {
StorageDead(_20);
StorageDead(_19);
StorageDead(_16);
StorageDead(_22);
StorageDead(_21);
StorageDead(_18);
goto -> bb4;
}
@@ -4,174 +4,168 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
debug slice => _1;
debug f => _2;
let mut _0: ();
let mut _13: std::slice::Iter<'_, T>;
let mut _14: std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _15: std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _16: &mut std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _18: std::option::Option<&T>;
let mut _19: isize;
let mut _21: &impl Fn(&T);
let mut _22: (&T,);
let _23: ();
let mut _15: std::slice::Iter<'_, T>;
let mut _16: std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _17: std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _18: &mut std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _20: std::option::Option<&T>;
let mut _21: isize;
let mut _23: &impl Fn(&T);
let mut _24: (&T,);
let _25: ();
scope 1 {
debug iter => _15;
let _20: &T;
debug iter => _17;
let _22: &T;
scope 2 {
debug x => _20;
debug x => _22;
}
scope 25 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
debug self => _16;
let mut _17: &mut std::slice::Iter<'_, T>;
scope 22 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
debug self => _18;
let mut _19: &mut std::slice::Iter<'_, T>;
}
}
scope 3 (inlined core::slice::<impl [T]>::iter) {
debug self => _1;
scope 4 (inlined std::slice::Iter::<'_, T>::new) {
debug slice => _1;
let _4: *const T;
let mut _5: bool;
let mut _6: usize;
let mut _8: usize;
let mut _9: *mut T;
let mut _11: std::ptr::NonNull<T>;
let mut _12: *const T;
let _3: usize;
let mut _5: std::ptr::NonNull<[T]>;
let mut _10: bool;
let mut _11: *mut T;
let mut _12: *mut T;
let mut _14: *const T;
scope 5 {
debug ptr => _4;
debug len => _3;
let _9: std::ptr::NonNull<T>;
scope 6 {
let _7: *const T;
debug ptr => _9;
scope 7 {
debug end_or_len => _7;
scope 13 (inlined NonNull::<T>::new_unchecked) {
debug ptr => _9;
let mut _10: *const T;
let mut _24: *mut T;
scope 14 {
scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) {
debug ptr => _24;
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) {
debug self => _24;
let mut _25: *mut u8;
scope 17 {
scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _25;
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _25;
scope 20 {
scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _25;
}
}
}
}
}
}
}
let _13: *const T;
scope 8 {
debug end_or_len => _13;
}
scope 14 (inlined invalid::<T>) {
debug addr => _3;
scope 15 {
}
}
scope 16 (inlined NonNull::<T>::as_ptr) {
debug self => _9;
}
scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
debug self => _11;
debug count => _3;
scope 18 {
}
}
}
scope 9 (inlined invalid::<T>) {
debug addr => _8;
scope 10 {
}
}
scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
debug reference => _1;
let mut _4: *const [T];
scope 10 {
}
scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) {
debug self => _4;
debug count => _6;
scope 12 {
}
scope 11 (inlined NonNull::<[T]>::cast::<T>) {
debug self => _5;
let mut _6: *mut [T];
let mut _7: *mut T;
let mut _8: *const T;
scope 12 {
scope 13 (inlined NonNull::<[T]>::as_ptr) {
debug self => _5;
}
}
}
}
scope 8 (inlined core::slice::<impl [T]>::as_ptr) {
debug self => _1;
let mut _3: *const [T];
}
}
}
scope 22 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
debug self => _13;
scope 23 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
debug iter => _13;
scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
debug self => _15;
scope 20 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
debug iter => _15;
}
}
scope 24 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
debug self => _14;
scope 21 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
debug self => _16;
}
bb0: {
StorageLive(_13);
StorageLive(_4);
StorageLive(_15);
StorageLive(_3);
_3 = &raw const (*_1);
_4 = move _3 as *const T (PtrToPtr);
StorageDead(_3);
StorageLive(_7);
StorageLive(_9);
StorageLive(_4);
StorageLive(_8);
_3 = Len((*_1));
StorageLive(_5);
_5 = const _;
switchInt(move _5) -> [0: bb1, otherwise: bb2];
_4 = &raw const (*_1);
_5 = NonNull::<[T]> { pointer: _4 };
StorageLive(_7);
StorageLive(_6);
_6 = _4 as *mut [T] (PtrToPtr);
_7 = move _6 as *mut T (PtrToPtr);
_8 = move _7 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_6);
StorageDead(_7);
_9 = NonNull::<T> { pointer: _8 };
StorageDead(_5);
StorageLive(_13);
StorageLive(_10);
_10 = const _;
switchInt(move _10) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageLive(_6);
_6 = Len((*_1));
_7 = Offset(_4, _6);
StorageDead(_6);
StorageLive(_12);
StorageLive(_11);
_11 = _8 as *mut T (PtrToPtr);
_12 = Offset(_11, _3);
StorageDead(_11);
_13 = move _12 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_12);
goto -> bb3;
}
bb2: {
StorageLive(_8);
_8 = Len((*_1));
_7 = _8 as *const T (Transmute);
StorageDead(_8);
_13 = _3 as *const T (Transmute);
goto -> bb3;
}
bb3: {
StorageDead(_5);
StorageLive(_11);
StorageLive(_9);
_9 = _4 as *mut T (PtrToPtr);
StorageLive(_10);
StorageLive(_24);
StorageLive(_25);
_10 = _9 as *const T (PointerCoercion(MutToConstPointer));
_11 = NonNull::<T> { pointer: _10 };
StorageDead(_25);
StorageDead(_24);
StorageDead(_10);
StorageDead(_9);
StorageLive(_12);
_12 = _7;
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_12);
StorageDead(_11);
StorageDead(_7);
StorageDead(_4);
_14 = Rev::<std::slice::Iter<'_, T>> { iter: _13 };
StorageLive(_14);
_14 = _13;
_15 = std::slice::Iter::<'_, T> { ptr: _9, end_or_len: move _14, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_14);
StorageDead(_13);
StorageLive(_15);
_15 = _14;
StorageDead(_8);
StorageDead(_4);
StorageDead(_9);
StorageDead(_3);
_16 = Rev::<std::slice::Iter<'_, T>> { iter: _15 };
StorageDead(_15);
StorageLive(_17);
_17 = _16;
goto -> bb4;
}
bb4: {
StorageLive(_18);
_16 = &mut _15;
StorageLive(_17);
_17 = &mut (_15.0: std::slice::Iter<'_, T>);
_18 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _17) -> [return: bb5, unwind unreachable];
StorageLive(_20);
_18 = &mut _17;
StorageLive(_19);
_19 = &mut (_17.0: std::slice::Iter<'_, T>);
_20 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _19) -> [return: bb5, unwind unreachable];
}
bb5: {
StorageDead(_17);
_19 = discriminant(_18);
switchInt(move _19) -> [0: bb6, 1: bb8, otherwise: bb10];
StorageDead(_19);
_21 = discriminant(_20);
switchInt(move _21) -> [0: bb6, 1: bb8, otherwise: bb10];
}
bb6: {
StorageDead(_18);
StorageDead(_15);
StorageDead(_20);
StorageDead(_17);
drop(_2) -> [return: bb7, unwind unreachable];
}
@@ -180,18 +174,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
}
bb8: {
_20 = ((_18 as Some).0: &T);
StorageLive(_21);
_21 = &_2;
StorageLive(_22);
_22 = (_20,);
_23 = <impl Fn(&T) as Fn<(&T,)>>::call(move _21, move _22) -> [return: bb9, unwind unreachable];
_22 = ((_20 as Some).0: &T);
StorageLive(_23);
_23 = &_2;
StorageLive(_24);
_24 = (_22,);
_25 = <impl Fn(&T) as Fn<(&T,)>>::call(move _23, move _24) -> [return: bb9, unwind unreachable];
}
bb9: {
StorageDead(_22);
StorageDead(_21);
StorageDead(_18);
StorageDead(_24);
StorageDead(_23);
StorageDead(_20);
goto -> bb4;
}
@@ -4,174 +4,168 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
debug slice => _1;
debug f => _2;
let mut _0: ();
let mut _13: std::slice::Iter<'_, T>;
let mut _14: std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _15: std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _16: &mut std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _18: std::option::Option<&T>;
let mut _19: isize;
let mut _21: &impl Fn(&T);
let mut _22: (&T,);
let _23: ();
let mut _15: std::slice::Iter<'_, T>;
let mut _16: std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _17: std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _18: &mut std::iter::Rev<std::slice::Iter<'_, T>>;
let mut _20: std::option::Option<&T>;
let mut _21: isize;
let mut _23: &impl Fn(&T);
let mut _24: (&T,);
let _25: ();
scope 1 {
debug iter => _15;
let _20: &T;
debug iter => _17;
let _22: &T;
scope 2 {
debug x => _20;
debug x => _22;
}
scope 25 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
debug self => _16;
let mut _17: &mut std::slice::Iter<'_, T>;
scope 22 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
debug self => _18;
let mut _19: &mut std::slice::Iter<'_, T>;
}
}
scope 3 (inlined core::slice::<impl [T]>::iter) {
debug self => _1;
scope 4 (inlined std::slice::Iter::<'_, T>::new) {
debug slice => _1;
let _4: *const T;
let mut _5: bool;
let mut _6: usize;
let mut _8: usize;
let mut _9: *mut T;
let mut _11: std::ptr::NonNull<T>;
let mut _12: *const T;
let _3: usize;
let mut _5: std::ptr::NonNull<[T]>;
let mut _10: bool;
let mut _11: *mut T;
let mut _12: *mut T;
let mut _14: *const T;
scope 5 {
debug ptr => _4;
debug len => _3;
let _9: std::ptr::NonNull<T>;
scope 6 {
let _7: *const T;
debug ptr => _9;
scope 7 {
debug end_or_len => _7;
scope 13 (inlined NonNull::<T>::new_unchecked) {
debug ptr => _9;
let mut _10: *const T;
let mut _24: *mut T;
scope 14 {
scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) {
debug ptr => _24;
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) {
debug self => _24;
let mut _25: *mut u8;
scope 17 {
scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
debug ptr => _25;
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
debug self => _25;
scope 20 {
scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
debug self => _25;
}
}
}
}
}
}
}
let _13: *const T;
scope 8 {
debug end_or_len => _13;
}
scope 14 (inlined invalid::<T>) {
debug addr => _3;
scope 15 {
}
}
scope 16 (inlined NonNull::<T>::as_ptr) {
debug self => _9;
}
scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
debug self => _11;
debug count => _3;
scope 18 {
}
}
}
scope 9 (inlined invalid::<T>) {
debug addr => _8;
scope 10 {
}
}
scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
debug reference => _1;
let mut _4: *const [T];
scope 10 {
}
scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) {
debug self => _4;
debug count => _6;
scope 12 {
}
scope 11 (inlined NonNull::<[T]>::cast::<T>) {
debug self => _5;
let mut _6: *mut [T];
let mut _7: *mut T;
let mut _8: *const T;
scope 12 {
scope 13 (inlined NonNull::<[T]>::as_ptr) {
debug self => _5;
}
}
}
}
scope 8 (inlined core::slice::<impl [T]>::as_ptr) {
debug self => _1;
let mut _3: *const [T];
}
}
}
scope 22 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
debug self => _13;
scope 23 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
debug iter => _13;
scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
debug self => _15;
scope 20 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
debug iter => _15;
}
}
scope 24 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
debug self => _14;
scope 21 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
debug self => _16;
}
bb0: {
StorageLive(_13);
StorageLive(_4);
StorageLive(_15);
StorageLive(_3);
_3 = &raw const (*_1);
_4 = move _3 as *const T (PtrToPtr);
StorageDead(_3);
StorageLive(_7);
StorageLive(_9);
StorageLive(_4);
StorageLive(_8);
_3 = Len((*_1));
StorageLive(_5);
_5 = const _;
switchInt(move _5) -> [0: bb1, otherwise: bb2];
_4 = &raw const (*_1);
_5 = NonNull::<[T]> { pointer: _4 };
StorageLive(_7);
StorageLive(_6);
_6 = _4 as *mut [T] (PtrToPtr);
_7 = move _6 as *mut T (PtrToPtr);
_8 = move _7 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_6);
StorageDead(_7);
_9 = NonNull::<T> { pointer: _8 };
StorageDead(_5);
StorageLive(_13);
StorageLive(_10);
_10 = const _;
switchInt(move _10) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageLive(_6);
_6 = Len((*_1));
_7 = Offset(_4, _6);
StorageDead(_6);
StorageLive(_12);
StorageLive(_11);
_11 = _8 as *mut T (PtrToPtr);
_12 = Offset(_11, _3);
StorageDead(_11);
_13 = move _12 as *const T (PointerCoercion(MutToConstPointer));
StorageDead(_12);
goto -> bb3;
}
bb2: {
StorageLive(_8);
_8 = Len((*_1));
_7 = _8 as *const T (Transmute);
StorageDead(_8);
_13 = _3 as *const T (Transmute);
goto -> bb3;
}
bb3: {
StorageDead(_5);
StorageLive(_11);
StorageLive(_9);
_9 = _4 as *mut T (PtrToPtr);
StorageLive(_10);
StorageLive(_24);
StorageLive(_25);
_10 = _9 as *const T (PointerCoercion(MutToConstPointer));
_11 = NonNull::<T> { pointer: _10 };
StorageDead(_25);
StorageDead(_24);
StorageDead(_10);
StorageDead(_9);
StorageLive(_12);
_12 = _7;
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_12);
StorageDead(_11);
StorageDead(_7);
StorageDead(_4);
_14 = Rev::<std::slice::Iter<'_, T>> { iter: _13 };
StorageLive(_14);
_14 = _13;
_15 = std::slice::Iter::<'_, T> { ptr: _9, end_or_len: move _14, _marker: const ZeroSized: PhantomData<&T> };
StorageDead(_14);
StorageDead(_13);
StorageLive(_15);
_15 = _14;
StorageDead(_8);
StorageDead(_4);
StorageDead(_9);
StorageDead(_3);
_16 = Rev::<std::slice::Iter<'_, T>> { iter: _15 };
StorageDead(_15);
StorageLive(_17);
_17 = _16;
goto -> bb4;
}
bb4: {
StorageLive(_18);
_16 = &mut _15;
StorageLive(_17);
_17 = &mut (_15.0: std::slice::Iter<'_, T>);
_18 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _17) -> [return: bb5, unwind: bb11];
StorageLive(_20);
_18 = &mut _17;
StorageLive(_19);
_19 = &mut (_17.0: std::slice::Iter<'_, T>);
_20 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _19) -> [return: bb5, unwind: bb11];
}
bb5: {
StorageDead(_17);
_19 = discriminant(_18);
switchInt(move _19) -> [0: bb6, 1: bb8, otherwise: bb10];
StorageDead(_19);
_21 = discriminant(_20);
switchInt(move _21) -> [0: bb6, 1: bb8, otherwise: bb10];
}
bb6: {
StorageDead(_18);
StorageDead(_15);
StorageDead(_20);
StorageDead(_17);
drop(_2) -> [return: bb7, unwind continue];
}
@@ -180,18 +174,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
}
bb8: {
_20 = ((_18 as Some).0: &T);
StorageLive(_21);
_21 = &_2;
StorageLive(_22);
_22 = (_20,);
_23 = <impl Fn(&T) as Fn<(&T,)>>::call(move _21, move _22) -> [return: bb9, unwind: bb11];
_22 = ((_20 as Some).0: &T);
StorageLive(_23);
_23 = &_2;
StorageLive(_24);
_24 = (_22,);
_25 = <impl Fn(&T) as Fn<(&T,)>>::call(move _23, move _24) -> [return: bb9, unwind: bb11];
}
bb9: {
StorageDead(_22);
StorageDead(_21);
StorageDead(_18);
StorageDead(_24);
StorageDead(_23);
StorageDead(_20);
goto -> bb4;
}
+1 -1
View File
@@ -1,3 +1,3 @@
thread 'main' panicked at library/alloc/src/raw_vec.rs:570:5:
thread 'main' panicked at library/alloc/src/raw_vec.rs:571:5:
capacity overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
@@ -0,0 +1,11 @@
// run-fail
// compile-flags: -Copt-level=3 -Cdebug-assertions=yes
// error-pattern: unsafe precondition(s) violated: slice::from_raw_parts
// ignore-debug
// ignore-wasm32-bare no panic messages
fn main() {
unsafe {
let _s: &[u64] = std::slice::from_raw_parts(1usize as *const u64, 0);
}
}
@@ -0,0 +1,11 @@
// run-fail
// compile-flags: -Copt-level=3 -Cdebug-assertions=yes
// error-pattern: unsafe precondition(s) violated: slice::from_raw_parts
// ignore-debug
// ignore-wasm32-bare no panic messages
fn main() {
unsafe {
let _s: &[u8] = std::slice::from_raw_parts(std::ptr::null(), 0);
}
}
@@ -0,0 +1,12 @@
// run-fail
// compile-flags: -Copt-level=3 -Cdebug-assertions=yes
// error-pattern: unsafe precondition(s) violated: hint::assert_unchecked
// ignore-debug
// ignore-wasm32-bare no panic messages
fn main() {
unsafe {
let sli: &[u8] = &[0];
sli.get_unchecked(1);
}
}