diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index 74dadb2572565..25c0bcc5b73ab 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -3,10 +3,13 @@ use crate::transform::MirPass; use rustc_hir::Mutability; use rustc_middle::mir::{ - BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, - StatementKind, + BasicBlock, LocalDecls, PlaceElem, SourceInfo, Statement, StatementKind, Terminator, + TerminatorKind, }; +use rustc_middle::mir::{BinOp, Body, Constant, Local, Operand, Place, ProjectionElem, Rvalue}; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::{sym, Symbol}; +use rustc_target::spec::abi::Abi; pub struct InstCombine; @@ -25,6 +28,10 @@ impl<'tcx> MirPass<'tcx> for InstCombine { _ => {} } } + + if let Some(terminator) = &mut block.terminator { + ctx.combine_copy_nonoverlapping(terminator, local_decls, &mut block.statements); + } } } } @@ -120,4 +127,78 @@ impl<'tcx, 'a> InstCombineContext<'tcx, 'a> { } } } + + fn func_as_intrinsic( + &self, + operand: &Operand<'tcx>, + locals: &LocalDecls<'tcx>, + ) -> Option { + let func_ty = operand.ty(locals, self.tcx); + + if let ty::FnDef(def_id, _) = *func_ty.kind() { + let fn_sig = func_ty.fn_sig(self.tcx); + + if fn_sig.abi() == Abi::RustIntrinsic { + return Some(self.tcx.item_name(def_id)); + } + } + + None + } + + fn find_copy_nonoverlapping( + &self, + terminator: &Terminator<'tcx>, + locals: &LocalDecls<'tcx>, + ) -> Option<(Local, Local, BasicBlock)> { + if let TerminatorKind::Call { func, args, destination: Some((_, next_bb)), .. } = + &terminator.kind + { + let intrinsic = self.func_as_intrinsic(func, locals)?; + + if intrinsic == sym::copy_nonoverlapping && args.len() == 3 { + let src = args[0].place()?.as_local()?; + let dest = args[1].place()?.as_local()?; + let constant = args[2].constant()?; + + if constant.literal.ty == self.tcx.types.usize { + let val = constant + .literal + .val + .try_to_value()? + .try_to_scalar()? + .to_machine_usize(&self.tcx) + .ok()?; + + if val == 1 { + return Some((src, dest, *next_bb)); + } + } + } + } + + None + } + + fn combine_copy_nonoverlapping( + &self, + terminator: &mut Terminator<'tcx>, + locals: &LocalDecls<'tcx>, + statements: &mut Vec>, + ) { + if let Some((src, dest, next_bb)) = self.find_copy_nonoverlapping(terminator, locals) { + trace!("replacing call to copy_nonoverlapping({:?}, {:?}, 1) intrinsic", src, dest); + let deref_projection = self.tcx._intern_place_elems(&[PlaceElem::Deref]); + + statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + Place { local: dest, projection: deref_projection }, + Rvalue::Use(Operand::Copy(Place { local: src, projection: deref_projection })), + ))), + }); + + terminator.kind = TerminatorKind::Goto { target: next_bb }; + } + } } diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index e509c35de40b8..842c9db334b11 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -482,6 +482,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) &multiple_return_terminators::MultipleReturnTerminators, &instcombine::InstCombine, + &simplify::SimplifyCfg::new("after-instcombine"), &const_prop::ConstProp, &simplify_branches::SimplifyBranches::new("after-const-prop"), &early_otherwise_branch::EarlyOtherwiseBranch, diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 7c1a9b82f99b2..305e4d707a35f 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1730,6 +1730,157 @@ extern "rust-intrinsic" { /// Allocate at compile time. Should not be called at runtime. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub fn const_allocate(size: usize, align: usize) -> *mut u8; + + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source + /// and destination must *not* overlap. + /// + /// For regions of memory which might overlap, use [`copy`] instead. + /// + /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but + /// with the argument order swapped. + /// + /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * `src` must be [valid] for reads of `count * size_of::()` bytes. + /// + /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. + /// + /// * Both `src` and `dst` must be properly aligned. + /// + /// * The region of memory beginning at `src` with a size of `count * + /// size_of::()` bytes must *not* overlap with the region of memory + /// beginning at `dst` with the same size. + /// + /// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of + /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values + /// in the region beginning at `*src` and the region beginning at `*dst` can + /// [violate memory safety][read-ownership]. + /// + /// Note that even if the effectively copied size (`count * size_of::()`) is + /// `0`, the pointers must be non-NULL and properly aligned. + /// + /// [`read`]: crate::ptr::read + /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value + /// [valid]: crate::ptr#safety + /// + /// # Examples + /// + /// Manually implement [`Vec::append`]: + /// + /// ``` + /// use std::ptr; + /// + /// /// Moves all the elements of `src` into `dst`, leaving `src` empty. + /// fn append(dst: &mut Vec, src: &mut Vec) { + /// let src_len = src.len(); + /// let dst_len = dst.len(); + /// + /// // Ensure that `dst` has enough capacity to hold all of `src`. + /// dst.reserve(src_len); + /// + /// unsafe { + /// // The call to offset is always safe because `Vec` will never + /// // allocate more than `isize::MAX` bytes. + /// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); + /// let src_ptr = src.as_ptr(); + /// + /// // Truncate `src` without dropping its contents. We do this first, + /// // to avoid problems in case something further down panics. + /// src.set_len(0); + /// + /// // The two regions cannot overlap because mutable references do + /// // not alias, and two different vectors cannot own the same + /// // memory. + /// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); + /// + /// // Notify `dst` that it now holds the contents of `src`. + /// dst.set_len(dst_len + src_len); + /// } + /// } + /// + /// let mut a = vec!['r']; + /// let mut b = vec!['u', 's', 't']; + /// + /// append(&mut a, &mut b); + /// + /// assert_eq!(a, &['r', 'u', 's', 't']); + /// assert!(b.is_empty()); + /// ``` + /// + /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append + #[doc(alias = "memcpy")] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); + + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source + /// and destination may overlap. + /// + /// If the source and destination will *never* overlap, + /// [`copy_nonoverlapping`] can be used instead. + /// + /// `copy` is semantically equivalent to C's [`memmove`], but with the argument + /// order swapped. Copying takes place as if the bytes were copied from `src` + /// to a temporary array and then copied from the array to `dst`. + /// + /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * `src` must be [valid] for reads of `count * size_of::()` bytes. + /// + /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. + /// + /// * Both `src` and `dst` must be properly aligned. + /// + /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of + /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values + /// in the region beginning at `*src` and the region beginning at `*dst` can + /// [violate memory safety][read-ownership]. + /// + /// Note that even if the effectively copied size (`count * size_of::()`) is + /// `0`, the pointers must be non-NULL and properly aligned. + /// + /// [`read`]: crate::ptr::read + /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value + /// [valid]: crate::ptr#safety + /// + /// # Examples + /// + /// Efficiently create a Rust vector from an unsafe buffer: + /// + /// ``` + /// use std::ptr; + /// + /// /// # Safety + /// /// + /// /// * `ptr` must be correctly aligned for its type and non-zero. + /// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. + /// /// * Those elements must not be used after calling this function unless `T: Copy`. + /// # #[allow(dead_code)] + /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { + /// let mut dst = Vec::with_capacity(elts); + /// + /// // SAFETY: Our precondition ensures the source is aligned and valid, + /// // and `Vec::with_capacity` ensures that we have usable space to write them. + /// ptr::copy(ptr, dst.as_mut_ptr(), elts); + /// + /// // SAFETY: We created it with this much capacity earlier, + /// // and the previous `copy` has initialized these elements. + /// dst.set_len(elts); + /// dst + /// } + /// ``` + #[doc(alias = "memmove")] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + pub fn copy(src: *const T, dst: *mut T, count: usize); } // Some functions are defined here because they accidentally got made @@ -1755,192 +1906,6 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - diff >= size } -/// Copies `count * size_of::()` bytes from `src` to `dst`. The source -/// and destination must *not* overlap. -/// -/// For regions of memory which might overlap, use [`copy`] instead. -/// -/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but -/// with the argument order swapped. -/// -/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must be [valid] for reads of `count * size_of::()` bytes. -/// -/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. -/// -/// * Both `src` and `dst` must be properly aligned. -/// -/// * The region of memory beginning at `src` with a size of `count * -/// size_of::()` bytes must *not* overlap with the region of memory -/// beginning at `dst` with the same size. -/// -/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values -/// in the region beginning at `*src` and the region beginning at `*dst` can -/// [violate memory safety][read-ownership]. -/// -/// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointers must be non-NULL and properly aligned. -/// -/// [`read`]: crate::ptr::read -/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value -/// [valid]: crate::ptr#safety -/// -/// # Examples -/// -/// Manually implement [`Vec::append`]: -/// -/// ``` -/// use std::ptr; -/// -/// /// Moves all the elements of `src` into `dst`, leaving `src` empty. -/// fn append(dst: &mut Vec, src: &mut Vec) { -/// let src_len = src.len(); -/// let dst_len = dst.len(); -/// -/// // Ensure that `dst` has enough capacity to hold all of `src`. -/// dst.reserve(src_len); -/// -/// unsafe { -/// // The call to offset is always safe because `Vec` will never -/// // allocate more than `isize::MAX` bytes. -/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); -/// let src_ptr = src.as_ptr(); -/// -/// // Truncate `src` without dropping its contents. We do this first, -/// // to avoid problems in case something further down panics. -/// src.set_len(0); -/// -/// // The two regions cannot overlap because mutable references do -/// // not alias, and two different vectors cannot own the same -/// // memory. -/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); -/// -/// // Notify `dst` that it now holds the contents of `src`. -/// dst.set_len(dst_len + src_len); -/// } -/// } -/// -/// let mut a = vec!['r']; -/// let mut b = vec!['u', 's', 't']; -/// -/// append(&mut a, &mut b); -/// -/// assert_eq!(a, &['r', 'u', 's', 't']); -/// assert!(b.is_empty()); -/// ``` -/// -/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append -#[doc(alias = "memcpy")] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] -#[inline] -pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { - extern "rust-intrinsic" { - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] - fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - } - - // FIXME: Perform these checks only at run time - /*if cfg!(debug_assertions) - && !(is_aligned_and_not_null(src) - && is_aligned_and_not_null(dst) - && is_nonoverlapping(src, dst, count)) - { - // Not panicking to keep codegen impact smaller. - abort(); - }*/ - - // SAFETY: the safety contract for `copy_nonoverlapping` must be - // upheld by the caller. - unsafe { copy_nonoverlapping(src, dst, count) } -} - -/// Copies `count * size_of::()` bytes from `src` to `dst`. The source -/// and destination may overlap. -/// -/// If the source and destination will *never* overlap, -/// [`copy_nonoverlapping`] can be used instead. -/// -/// `copy` is semantically equivalent to C's [`memmove`], but with the argument -/// order swapped. Copying takes place as if the bytes were copied from `src` -/// to a temporary array and then copied from the array to `dst`. -/// -/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must be [valid] for reads of `count * size_of::()` bytes. -/// -/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. -/// -/// * Both `src` and `dst` must be properly aligned. -/// -/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values -/// in the region beginning at `*src` and the region beginning at `*dst` can -/// [violate memory safety][read-ownership]. -/// -/// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointers must be non-NULL and properly aligned. -/// -/// [`read`]: crate::ptr::read -/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value -/// [valid]: crate::ptr#safety -/// -/// # Examples -/// -/// Efficiently create a Rust vector from an unsafe buffer: -/// -/// ``` -/// use std::ptr; -/// -/// /// # Safety -/// /// -/// /// * `ptr` must be correctly aligned for its type and non-zero. -/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. -/// /// * Those elements must not be used after calling this function unless `T: Copy`. -/// # #[allow(dead_code)] -/// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { -/// let mut dst = Vec::with_capacity(elts); -/// -/// // SAFETY: Our precondition ensures the source is aligned and valid, -/// // and `Vec::with_capacity` ensures that we have usable space to write them. -/// ptr::copy(ptr, dst.as_mut_ptr(), elts); -/// -/// // SAFETY: We created it with this much capacity earlier, -/// // and the previous `copy` has initialized these elements. -/// dst.set_len(elts); -/// dst -/// } -/// ``` -#[doc(alias = "memmove")] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] -#[inline] -pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { - extern "rust-intrinsic" { - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] - fn copy(src: *const T, dst: *mut T, count: usize); - } - - // FIXME: Perform these checks only at run time - /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) { - // Not panicking to keep codegen impact smaller. - abort(); - }*/ - - // SAFETY: the safety contract for `copy` must be upheld by the caller. - unsafe { copy(src, dst, count) } -} - /// Sets `count * size_of::()` bytes of memory starting at `dst` to /// `val`. /// diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 8d901c08f91a3..fd92ed6fe47f0 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -881,17 +881,12 @@ pub const unsafe fn read_unaligned(src: *const T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { - // We are calling the intrinsics directly to avoid function calls in the generated code - // as `intrinsics::copy_nonoverlapping` is a wrapper function. - extern "rust-intrinsic" { - fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - } - // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. unsafe { copy_nonoverlapping(&src as *const T, dst, 1); + // We are calling the intrinsic directly to avoid function calls in the generated code. intrinsics::forget(src); } } diff --git a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir index 04a8c94e003c4..0f718a720f4cc 100644 --- a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir +++ b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir @@ -3,47 +3,45 @@ fn num_to_digit(_1: char) -> u32 { debug num => _1; // in scope 0 at $DIR/issue-59352.rs:12:21: 12:24 let mut _0: u32; // return place in scope 0 at $DIR/issue-59352.rs:12:35: 12:38 - let mut _2: bool; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 - let mut _3: std::option::Option; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:41 - let mut _4: char; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:29 - let mut _5: u32; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 - let mut _10: isize; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:41 + let mut _3: char; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:29 + let mut _4: u32; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + let mut _9: isize; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 scope 1 (inlined char::methods::::is_digit) { // at $DIR/issue-59352.rs:14:8: 14:23 - debug self => _8; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - debug radix => _5; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - let mut _6: &std::option::Option; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - let _7: std::option::Option; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - let mut _8: char; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + debug self => _7; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + debug radix => _4; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + let mut _5: &std::option::Option; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + let _6: std::option::Option; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + let mut _7: char; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 scope 2 (inlined Option::::is_some) { // at $DIR/issue-59352.rs:14:8: 14:23 - debug self => _6; // in scope 2 at $DIR/issue-59352.rs:14:8: 14:23 + debug self => _5; // in scope 2 at $DIR/issue-59352.rs:14:8: 14:23 } } scope 3 (inlined #[track_caller] Option::::unwrap) { // at $DIR/issue-59352.rs:14:26: 14:50 - debug self => _3; // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50 - let mut _9: isize; // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50 + debug self => _2; // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50 + let mut _8: isize; // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50 scope 4 { debug val => _0; // in scope 4 at $DIR/issue-59352.rs:14:26: 14:50 } } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 - _8 = _1; // scope 0 at $DIR/issue-59352.rs:14:8: 14:11 - StorageLive(_5); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 - _5 = const 8_u32; // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + _7 = _1; // scope 0 at $DIR/issue-59352.rs:14:8: 14:11 + StorageLive(_4); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + _4 = const 8_u32; // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + StorageLive(_5); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 StorageLive(_6); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - StorageLive(_7); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - _7 = char::methods::::to_digit(move _8, const 8_u32) -> bb5; // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + _6 = char::methods::::to_digit(move _7, const 8_u32) -> bb5; // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 // mir::Constant // + span: $DIR/issue-59352.rs:14:8: 14:23 // + literal: Const { ty: fn(char, u32) -> std::option::Option {std::char::methods::::to_digit}, val: Value(Scalar()) } } bb1: { - StorageLive(_3); // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 - StorageLive(_4); // scope 0 at $DIR/issue-59352.rs:14:26: 14:29 - _4 = _1; // scope 0 at $DIR/issue-59352.rs:14:26: 14:29 - _3 = char::methods::::to_digit(move _4, const 8_u32) -> bb3; // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 + StorageLive(_2); // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 + StorageLive(_3); // scope 0 at $DIR/issue-59352.rs:14:26: 14:29 + _3 = _1; // scope 0 at $DIR/issue-59352.rs:14:26: 14:29 + _2 = char::methods::::to_digit(move _3, const 8_u32) -> bb3; // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 // mir::Constant // + span: $DIR/issue-59352.rs:14:30: 14:38 // + literal: Const { ty: fn(char, u32) -> std::option::Option {std::char::methods::::to_digit}, val: Value(Scalar()) } @@ -55,25 +53,23 @@ fn num_to_digit(_1: char) -> u32 { } bb3: { - StorageDead(_4); // scope 0 at $DIR/issue-59352.rs:14:40: 14:41 - StorageLive(_9); // scope 0 at $DIR/issue-59352.rs:14:26: 14:50 - _9 = discriminant(_3); // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 - switchInt(move _9) -> [0_isize: bb6, 1_isize: bb8, otherwise: bb7]; // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 + StorageDead(_3); // scope 0 at $DIR/issue-59352.rs:14:40: 14:41 + StorageLive(_8); // scope 0 at $DIR/issue-59352.rs:14:26: 14:50 + _8 = discriminant(_2); // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 + switchInt(move _8) -> [0_isize: bb6, 1_isize: bb8, otherwise: bb7]; // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 } bb4: { - StorageDead(_2); // scope 0 at $DIR/issue-59352.rs:14:62: 14:63 return; // scope 0 at $DIR/issue-59352.rs:15:2: 15:2 } bb5: { - _6 = &_7; // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - _10 = discriminant((*_6)); // scope 2 at $DIR/issue-59352.rs:14:8: 14:23 - _2 = Eq(_10, const 1_isize); // scope 2 at $DIR/issue-59352.rs:14:8: 14:23 + _5 = &_6; // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + _9 = discriminant((*_5)); // scope 2 at $DIR/issue-59352.rs:14:8: 14:23 + StorageDead(_5); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 StorageDead(_6); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - StorageDead(_7); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - StorageDead(_5); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/issue-59352.rs:14:5: 14:63 + StorageDead(_4); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + switchInt(move _9) -> [1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/issue-59352.rs:14:5: 14:63 } bb6: { @@ -94,9 +90,9 @@ fn num_to_digit(_1: char) -> u32 { } bb8: { - _0 = move ((_3 as Some).0: u32); // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 - StorageDead(_9); // scope 0 at $DIR/issue-59352.rs:14:26: 14:50 - StorageDead(_3); // scope 0 at $DIR/issue-59352.rs:14:49: 14:50 + _0 = move ((_2 as Some).0: u32); // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 + StorageDead(_8); // scope 0 at $DIR/issue-59352.rs:14:26: 14:50 + StorageDead(_2); // scope 0 at $DIR/issue-59352.rs:14:49: 14:50 goto -> bb4; // scope 0 at $DIR/issue-59352.rs:14:5: 14:63 } } diff --git a/src/test/ui/const-ptr/out_of_bounds_read.stderr b/src/test/ui/const-ptr/out_of_bounds_read.stderr index ca65a079947e0..c208883c5a803 100644 --- a/src/test/ui/const-ptr/out_of_bounds_read.stderr +++ b/src/test/ui/const-ptr/out_of_bounds_read.stderr @@ -1,13 +1,12 @@ error: any use of this value will cause an error - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | unsafe { copy_nonoverlapping(src, dst, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 - | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL - | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | inside `_READ` at $DIR/out_of_bounds_read.rs:13:33 +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `_READ` at $DIR/out_of_bounds_read.rs:13:33 | ::: $DIR/out_of_bounds_read.rs:13:5 | @@ -17,16 +16,15 @@ LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; = note: `#[deny(const_err)]` on by default error: any use of this value will cause an error - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | unsafe { copy_nonoverlapping(src, dst, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 - | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL - | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | inside `ptr::const_ptr::::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39 +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `ptr::const_ptr::::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39 | ::: $DIR/out_of_bounds_read.rs:14:5 | @@ -34,16 +32,15 @@ LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; | -------------------------------------------------------- error: any use of this value will cause an error - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | unsafe { copy_nonoverlapping(src, dst, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 - | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL - | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | inside `ptr::mut_ptr::::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - | inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37 +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `ptr::mut_ptr::::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + | inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37 | ::: $DIR/out_of_bounds_read.rs:15:5 |