Skip to content

Commit 492b83c

Browse files
committed
Auto merge of #80290 - RalfJung:less-intrinsic-write, r=lcnr
implement ptr::write without dedicated intrinsic This makes `ptr::write` more consistent with `ptr::write_unaligned`, `ptr::read`, `ptr::read_unaligned`, all of which are implemented in terms of `copy_nonoverlapping`. This means we can also remove `move_val_init` implementations in codegen and Miri, and its special handling in the borrow checker. Also see [this Zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/ptr.3A.3Aread.20vs.20ptr.3A.3Awrite).
2 parents 63a83c5 + a5b89a0 commit 492b83c

File tree

11 files changed

+46
-408
lines changed

11 files changed

+46
-408
lines changed

compiler/rustc_mir/src/transform/check_unsafety.rs

-8
Original file line numberDiff line numberDiff line change
@@ -223,21 +223,13 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
223223
// Check for raw pointer `Deref`.
224224
for (base, proj) in place.iter_projections() {
225225
if proj == ProjectionElem::Deref {
226-
let source_info = self.source_info; // Backup source_info so we can restore it later.
227-
if base.projection.is_empty() && decl.internal {
228-
// Internal locals are used in the `move_val_init` desugaring.
229-
// We want to check unsafety against the source info of the
230-
// desugaring, rather than the source info of the RHS.
231-
self.source_info = self.body.local_decls[place.local].source_info;
232-
}
233226
let base_ty = base.ty(self.body, self.tcx).ty;
234227
if base_ty.is_unsafe_ptr() {
235228
self.require_unsafe(
236229
UnsafetyViolationKind::GeneralAndConstFn,
237230
UnsafetyViolationDetails::DerefOfRawPointer,
238231
)
239232
}
240-
self.source_info = source_info; // Restore backed-up source_info.
241233
}
242234
}
243235

compiler/rustc_mir_build/src/build/expr/into.rs

+34-74
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
1010
use rustc_hir as hir;
1111
use rustc_middle::middle::region;
1212
use rustc_middle::mir::*;
13-
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
14-
use rustc_span::symbol::sym;
15-
use rustc_target::spec::abi::Abi;
13+
use rustc_middle::ty::{CanonicalUserTypeAnnotation};
1614

1715
use std::slice;
1816

@@ -219,79 +217,41 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
219217
},
220218
)
221219
}
222-
ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => {
223-
let intrinsic = match *ty.kind() {
224-
ty::FnDef(def_id, _) => {
225-
let f = ty.fn_sig(this.hir.tcx());
226-
if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
227-
Some(this.hir.tcx().item_name(def_id))
228-
} else {
229-
None
230-
}
231-
}
232-
_ => None,
233-
};
220+
ExprKind::Call { ty: _, fun, args, from_hir_call, fn_span } => {
234221
let fun = unpack!(block = this.as_local_operand(block, fun));
235-
if let Some(sym::move_val_init) = intrinsic {
236-
// `move_val_init` has "magic" semantics - the second argument is
237-
// always evaluated "directly" into the first one.
238-
239-
let mut args = args.into_iter();
240-
let ptr = args.next().expect("0 arguments to `move_val_init`");
241-
let val = args.next().expect("1 argument to `move_val_init`");
242-
assert!(args.next().is_none(), ">2 arguments to `move_val_init`");
243-
244-
let ptr = this.hir.mirror(ptr);
245-
let ptr_ty = ptr.ty;
246-
// Create an *internal* temp for the pointer, so that unsafety
247-
// checking won't complain about the raw pointer assignment.
248-
let ptr_temp = this
249-
.local_decls
250-
.push(LocalDecl::with_source_info(ptr_ty, source_info).internal());
251-
let ptr_temp = Place::from(ptr_temp);
252-
// No need for a scope, ptr_temp doesn't need drop
253-
let block = unpack!(this.into(ptr_temp, None, block, ptr));
254-
// Maybe we should provide a scope here so that
255-
// `move_val_init` wouldn't leak on panic even with an
256-
// arbitrary `val` expression, but `schedule_drop`,
257-
// borrowck and drop elaboration all prevent us from
258-
// dropping `ptr_temp.deref()`.
259-
this.into(this.hir.tcx().mk_place_deref(ptr_temp), None, block, val)
260-
} else {
261-
let args: Vec<_> = args
262-
.into_iter()
263-
.map(|arg| unpack!(block = this.as_local_call_operand(block, arg)))
264-
.collect();
265-
266-
let success = this.cfg.start_new_block();
267-
268-
this.record_operands_moved(&args);
269-
270-
debug!("into_expr: fn_span={:?}", fn_span);
271-
272-
this.cfg.terminate(
273-
block,
274-
source_info,
275-
TerminatorKind::Call {
276-
func: fun,
277-
args,
278-
cleanup: None,
279-
// FIXME(varkor): replace this with an uninhabitedness-based check.
280-
// This requires getting access to the current module to call
281-
// `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
282-
destination: if expr.ty.is_never() {
283-
None
284-
} else {
285-
Some((destination, success))
286-
},
287-
from_hir_call,
288-
fn_span,
222+
let args: Vec<_> = args
223+
.into_iter()
224+
.map(|arg| unpack!(block = this.as_local_call_operand(block, arg)))
225+
.collect();
226+
227+
let success = this.cfg.start_new_block();
228+
229+
this.record_operands_moved(&args);
230+
231+
debug!("into_expr: fn_span={:?}", fn_span);
232+
233+
this.cfg.terminate(
234+
block,
235+
source_info,
236+
TerminatorKind::Call {
237+
func: fun,
238+
args,
239+
cleanup: None,
240+
// FIXME(varkor): replace this with an uninhabitedness-based check.
241+
// This requires getting access to the current module to call
242+
// `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
243+
destination: if expr.ty.is_never() {
244+
None
245+
} else {
246+
Some((destination, success))
289247
},
290-
);
291-
this.diverge_from(block);
292-
schedule_drop(this);
293-
success.unit()
294-
}
248+
from_hir_call,
249+
fn_span,
250+
},
251+
);
252+
this.diverge_from(block);
253+
schedule_drop(this);
254+
success.unit()
295255
}
296256
ExprKind::Use { source } => this.into(destination, scope, block, source),
297257
ExprKind::Borrow { arg, borrow_kind } => {

compiler/rustc_span/src/symbol.rs

-1
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,6 @@ symbols! {
716716
more_struct_aliases,
717717
movbe_target_feature,
718718
move_ref_pattern,
719-
move_val_init,
720719
mul,
721720
mul_assign,
722721
mul_with_overflow,

compiler/rustc_typeck/src/check/intrinsic.rs

-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
157157
}
158158
sym::forget => (1, vec![param(0)], tcx.mk_unit()),
159159
sym::transmute => (2, vec![param(0)], param(1)),
160-
sym::move_val_init => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
161160
sym::prefetch_read_data
162161
| sym::prefetch_write_data
163162
| sym::prefetch_read_instruction

library/core/src/intrinsics.rs

-7
Original file line numberDiff line numberDiff line change
@@ -768,13 +768,6 @@ extern "rust-intrinsic" {
768768
#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
769769
pub fn size_of<T>() -> usize;
770770

771-
/// Moves a value to an uninitialized memory location.
772-
///
773-
/// Drop glue is not run on the destination.
774-
///
775-
/// The stabilized version of this intrinsic is [`core::ptr::write`](crate::ptr::write).
776-
pub fn move_val_init<T>(dst: *mut T, src: T);
777-
778771
/// The minimum alignment of a type.
779772
///
780773
/// The stabilized version of this intrinsic is [`core::mem::align_of`](crate::mem::align_of).

library/core/src/ptr/mod.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -883,12 +883,19 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
883883
#[inline]
884884
#[stable(feature = "rust1", since = "1.0.0")]
885885
pub unsafe fn write<T>(dst: *mut T, src: T) {
886-
if cfg!(debug_assertions) && !is_aligned_and_not_null(dst) {
887-
// Not panicking to keep codegen impact smaller.
888-
abort();
886+
// We are calling the intrinsics directly to avoid function calls in the generated code
887+
// as `intrinsics::copy_nonoverlapping` is a wrapper function.
888+
extern "rust-intrinsic" {
889+
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
890+
}
891+
892+
// SAFETY: the caller must guarantee that `dst` is valid for writes.
893+
// `dst` cannot overlap `src` because the caller has mutable access
894+
// to `dst` while `src` is owned by this function.
895+
unsafe {
896+
copy_nonoverlapping(&src as *const T, dst, 1);
897+
intrinsics::forget(src);
889898
}
890-
// SAFETY: the caller must uphold the safety contract for `move_val_init`.
891-
unsafe { intrinsics::move_val_init(&mut *dst, src) }
892899
}
893900

894901
/// Overwrites a memory location with the given value without reading or

src/test/codegen/intrinsics/move-val-init.rs

-19
This file was deleted.

0 commit comments

Comments
 (0)