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
commit 8fb67fb37f
65 changed files with 1480 additions and 1293 deletions

View File

@ -1983,6 +1983,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::SizedBound,
);
}
&Rvalue::NullaryOp(NullOp::DebugAssertions, _) => {}
Rvalue::ShallowInitBox(operand, ty) => {
self.check_operand(operand, location);

View File

@ -767,6 +767,15 @@ fn codegen_stmt<'tcx>(
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()),

View File

@ -672,17 +672,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
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),

View File

@ -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 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
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 },

View File

@ -246,13 +246,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
);
}
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, _) => {

View File

@ -544,7 +544,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
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) => {

View File

@ -1139,7 +1139,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
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);

View File

@ -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;

View File

@ -907,6 +907,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
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| {

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)]

View File

@ -194,6 +194,7 @@ impl<'tcx> Rvalue<'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 => {

View File

@ -429,7 +429,10 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
| Rvalue::AddressOf(..)
| Rvalue::Discriminant(..)
| Rvalue::Len(..)
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {}
| Rvalue::NullaryOp(
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::DebugAssertions,
_,
) => {}
}
}

View File

@ -634,6 +634,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
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()
}

View File

@ -489,6 +489,7 @@ impl<'body, 'tcx> VnState<'body, '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)?;

View File

@ -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 @@ impl<'tcx> MirPass<'tcx> for InstSimplify {
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 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
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>,

View File

@ -21,6 +21,17 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
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 {

View File

@ -446,6 +446,7 @@ impl<'tcx> Validator<'_, 'tcx> {
NullOp::SizeOf => {}
NullOp::AlignOf => {}
NullOp::OffsetOf(_) => {}
NullOp::DebugAssertions => {}
},
Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),

View File

@ -257,6 +257,7 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf(
indices.iter().map(|idx| idx.stable(tables)).collect(),
),
DebugAssertions => stable_mir::mir::NullOp::DebugAssertions,
}
}
}

View File

@ -639,6 +639,7 @@ impl Rvalue {
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 {

View File

@ -207,11 +207,7 @@ impl<T, A: Allocator> RawVec<T, A> {
// 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 @@ impl<T, A: Allocator> RawVec<T, A> {
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 @@ impl<T, A: Allocator> RawVec<T, A> {
// 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) };
}

View File

@ -136,7 +136,7 @@ impl<T, A: Allocator> IntoIter<T, A> {
// 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();

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 }
}
}

View File

@ -27,7 +27,7 @@ pub(super) const unsafe fn from_u32_unchecked(i: u32) -> 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)
}

View File

@ -148,7 +148,7 @@ pub const unsafe fn assert_unchecked(cond: bool) {
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);
}

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 @@ extern "rust-intrinsic" {
#[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 const unsafe fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
/// 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 const unsafe fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
///
/// 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 @@ pub(crate) use assert_unsafe_precondition;
/// 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 const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
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 const unsafe fn copy<T>(src: *const T, dst: *mut 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 const unsafe fn write_bytes<T>(dst: *mut T, val: u8, 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)
}

View File

@ -1033,7 +1033,6 @@ impl<T> Option<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.

View File

@ -806,13 +806,15 @@ impl<T: ?Sized> *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
)
};

View File

@ -381,11 +381,11 @@ use crate::cmp::Ordering;
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 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
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 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
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 @@ pub const unsafe fn read<T>(src: *const T) -> T {
// 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 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
// `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);
}

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 @@ impl<T: ?Sized> NonNull<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 @@ impl<T> NonNull<[T]> {
#[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 @@ impl<T: ?Sized> hash::Hash for NonNull<T> {
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 } }
}
}

View File

@ -106,6 +106,13 @@ impl<T: ?Sized> Unique<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 @@ impl<T: ?Sized> Unique<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 }
}
}

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 @@ impl<'a, T> IterMut<'a, T> {
// 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 }
}
}

View File

@ -4,6 +4,7 @@ use crate::array;
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 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
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 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
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)
}

View File

@ -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) => {

View File

@ -15,7 +15,7 @@ use std::path::{Path, PathBuf};
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

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)]

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -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];
}
}

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

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

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"]

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}