Skip to content

Commit de0ebde

Browse files
committed
Allow reading a *mut without an internal cast
1 parent 74c4821 commit de0ebde

16 files changed

+144
-50
lines changed

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
380380
sym::likely => (0, vec![tcx.types.bool], tcx.types.bool),
381381
sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool),
382382

383-
sym::read_via_copy => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)),
383+
sym::read_via_copy => (2, vec![param(0)], param(1)),
384384
sym::write_via_move => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
385385

386386
sym::discriminant_value => {

library/core/src/intrinsics.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@
5454
)]
5555
#![allow(missing_docs)]
5656

57-
use crate::marker::DiscriminantKind;
58-
use crate::marker::Tuple;
57+
#[cfg(not(bootstrap))]
58+
use crate::marker::PointerLike;
59+
use crate::marker::{DiscriminantKind, Tuple};
5960
use crate::mem;
6061

6162
pub mod mir;
@@ -1429,7 +1430,7 @@ extern "rust-intrinsic" {
14291430
#[must_use = "returns a new pointer rather than modifying its argument"]
14301431
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
14311432
#[rustc_nounwind]
1432-
pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
1433+
pub fn offset<Ptr: PointerLike, Delta>(dst: Ptr, offset: Delta) -> Ptr;
14331434

14341435
/// The bootstrap version of this is more restricted.
14351436
#[cfg(bootstrap)]
@@ -2257,9 +2258,21 @@ extern "rust-intrinsic" {
22572258
/// This is an implementation detail of [`crate::ptr::read`] and should
22582259
/// not be used anywhere else. See its comments for why this exists.
22592260
///
2260-
/// This intrinsic can *only* be called where the pointer is a local without
2261+
/// `Ptr` must be some kind of pointer to `T`.
2262+
///
2263+
/// This intrinsic can *only* be called where the `ptr` is a local without
22612264
/// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it
22622265
/// trivially obeys runtime-MIR rules about derefs in operands.
2266+
///
2267+
/// Not meeting the above requirements may arbitrarily misbehave, and
2268+
/// per MCP#620 that's *not* a compiler bug.
2269+
#[cfg(not(bootstrap))]
2270+
#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
2271+
#[rustc_nounwind]
2272+
pub fn read_via_copy<Ptr: PointerLike, T>(ptr: Ptr) -> T;
2273+
2274+
/// The bootstrap version of this intrinsic is more limited.
2275+
#[cfg(bootstrap)]
22632276
#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
22642277
#[rustc_nounwind]
22652278
pub fn read_via_copy<T>(ptr: *const T) -> T;

library/core/src/mem/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -909,11 +909,12 @@ pub fn take<T: Default>(dest: &mut T) -> T {
909909
#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
910910
#[cfg_attr(not(test), rustc_diagnostic_item = "mem_replace")]
911911
pub const fn replace<T>(dest: &mut T, src: T) -> T {
912+
let dest: *mut T = dest;
912913
// SAFETY: We read from `dest` but directly write `src` into it afterwards,
913914
// such that the old value is not duplicated. Nothing is dropped and
914915
// nothing here can panic.
915916
unsafe {
916-
let result = ptr::read(dest);
917+
let result = ptr::read_mut(dest);
917918
ptr::write(dest, src);
918919
result
919920
}

library/core/src/ptr/mod.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,23 @@ pub const unsafe fn read<T>(src: *const T) -> T {
11681168
"ptr::read requires that the pointer argument is aligned and non-null",
11691169
[T](src: *const T) => is_aligned_and_not_null(src)
11701170
);
1171-
crate::intrinsics::read_via_copy(src)
1171+
intrinsics::read_via_copy(src)
1172+
}
1173+
}
1174+
1175+
/// Like [`read`], but on `*mut` to avoid a `&raw const*`.
1176+
///
1177+
/// # Safety
1178+
///
1179+
/// Same as [`read`].
1180+
pub(crate) const unsafe fn read_mut<T>(src: *mut T) -> T {
1181+
// SAFETY: see `read` above
1182+
unsafe {
1183+
assert_unsafe_precondition!(
1184+
"ptr::read requires that the pointer argument is aligned and non-null",
1185+
[T](src: *mut T) => is_aligned_and_not_null(src)
1186+
);
1187+
intrinsics::read_via_copy(src)
11721188
}
11731189
}
11741190

library/core/src/ptr/mut_ptr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,8 +1312,8 @@ impl<T: ?Sized> *mut T {
13121312
where
13131313
T: Sized,
13141314
{
1315-
// SAFETY: the caller must uphold the safety contract for ``.
1316-
unsafe { read(self) }
1315+
// SAFETY: the caller must uphold the safety contract for `read_mut`.
1316+
unsafe { read_mut(self) }
13171317
}
13181318

13191319
/// Performs a volatile read of the value from `self` without moving it. This

tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
_4 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56
2525
- _3 = option_payload_ptr::<usize>(move _4) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
2626
- // mir::Constant
27-
- // + span: $DIR/lower_intrinsics.rs:137:18: 137:54
27+
- // + span: $DIR/lower_intrinsics.rs:142:18: 142:54
2828
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<usize>) -> *const usize {option_payload_ptr::<usize>}, val: Value(<ZST>) }
2929
+ _3 = &raw const (((*_4) as Some).0: usize); // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
3030
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
@@ -37,7 +37,7 @@
3737
_6 = &raw const (*_2); // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56
3838
- _5 = option_payload_ptr::<String>(move _6) -> [return: bb2, unwind unreachable]; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
3939
- // mir::Constant
40-
- // + span: $DIR/lower_intrinsics.rs:138:18: 138:54
40+
- // + span: $DIR/lower_intrinsics.rs:143:18: 143:54
4141
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<String>) -> *const String {option_payload_ptr::<String>}, val: Value(<ZST>) }
4242
+ _5 = &raw const (((*_6) as Some).0: std::string::String); // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
4343
+ goto -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57

tests/mir-opt/lower_intrinsics.ptr_offset.LowerIntrinsics.diff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
_4 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:33: +1:34
1616
- _0 = offset::<*const i32, isize>(move _3, move _4) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35
1717
- // mir::Constant
18-
- // + span: $DIR/lower_intrinsics.rs:144:5: 144:29
18+
- // + span: $DIR/lower_intrinsics.rs:149:5: 149:29
1919
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, isize) -> *const i32 {offset::<*const i32, isize>}, val: Value(<ZST>) }
2020
+ _0 = Offset(move _3, move _4); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35
2121
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
- // MIR for `ptr_offset_mut` before LowerIntrinsics
2+
+ // MIR for `ptr_offset_mut` after LowerIntrinsics
3+
4+
fn ptr_offset_mut(_1: *mut i32, _2: usize) -> *mut i32 {
5+
debug p => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:30: +0:31
6+
debug d => _2; // in scope 0 at $DIR/lower_intrinsics.rs:+0:43: +0:44
7+
let mut _0: *mut i32; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:56: +0:64
8+
let mut _3: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31
9+
let mut _4: usize; // in scope 0 at $DIR/lower_intrinsics.rs:+1:33: +1:34
10+
11+
bb0: {
12+
StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31
13+
_3 = _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31
14+
StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:33: +1:34
15+
_4 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:33: +1:34
16+
- _0 = offset::<*mut i32, usize>(move _3, move _4) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35
17+
- // mir::Constant
18+
- // + span: $DIR/lower_intrinsics.rs:154:5: 154:29
19+
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*mut i32, usize) -> *mut i32 {offset::<*mut i32, usize>}, val: Value(<ZST>) }
20+
+ _0 = Offset(move _3, move _4); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35
21+
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35
22+
}
23+
24+
bb1: {
25+
StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35
26+
StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35
27+
return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
28+
}
29+
}
30+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
- // MIR for `read_via_copy_mut` before LowerIntrinsics
2+
+ // MIR for `read_via_copy_mut` after LowerIntrinsics
3+
4+
fn read_via_copy_mut(_1: *mut i64) -> i64 {
5+
debug r => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:33: +0:34
6+
let mut _0: i64; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:52
7+
let mut _2: *mut i64; // in scope 0 at $DIR/lower_intrinsics.rs:+1:37: +1:38
8+
9+
bb0: {
10+
StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:37: +1:38
11+
_2 = _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:37: +1:38
12+
- _0 = read_via_copy::<*mut i64, i64>(move _2) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:39
13+
- // mir::Constant
14+
- // + span: $DIR/lower_intrinsics.rs:129:5: 129:36
15+
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*mut i64) -> i64 {read_via_copy::<*mut i64, i64>}, val: Value(<ZST>) }
16+
+ _0 = (*_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:39
17+
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:39
18+
}
19+
20+
bb1: {
21+
StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:38: +1:39
22+
return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
23+
}
24+
}
25+

tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
fn read_via_copy_primitive(_1: &i32) -> i32 {
55
debug r => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:32: +0:33
66
let mut _0: i32; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:44: +0:47
7-
let mut _2: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47
7+
let mut _2: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47
88
scope 1 {
99
}
1010

1111
bb0: {
1212
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
13-
_2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
14-
- _0 = read_via_copy::<i32>(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
13+
_2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
14+
- _0 = read_via_copy::<&i32, i32>(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
1515
- // mir::Constant
1616
- // + span: $DIR/lower_intrinsics.rs:119:14: 119:45
17-
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::<i32>}, val: Value(<ZST>) }
17+
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&i32) -> i32 {read_via_copy::<&i32, i32>}, val: Value(<ZST>) }
1818
+ _0 = (*_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
1919
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
2020
}

tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
fn read_via_copy_uninhabited(_1: &Never) -> Never {
55
debug r => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:34: +0:35
66
let mut _0: Never; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:48: +0:53
7-
let mut _2: *const Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47
7+
let mut _2: &Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47
88
scope 1 {
99
}
1010

1111
bb0: {
1212
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
13-
_2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
14-
- _0 = read_via_copy::<Never>(move _2) -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
13+
_2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
14+
- _0 = read_via_copy::<&Never, Never>(move _2) -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
1515
- // mir::Constant
1616
- // + span: $DIR/lower_intrinsics.rs:124:14: 124:45
17-
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::<Never>}, val: Value(<ZST>) }
17+
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&Never) -> Never {read_via_copy::<&Never, Never>}, val: Value(<ZST>) }
1818
+ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
1919
}
2020
}

tests/mir-opt/lower_intrinsics.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ pub fn read_via_copy_uninhabited(r: &Never) -> Never {
124124
unsafe { core::intrinsics::read_via_copy(r) }
125125
}
126126

127+
// EMIT_MIR lower_intrinsics.read_via_copy_mut.LowerIntrinsics.diff
128+
pub unsafe fn read_via_copy_mut(r: *mut i64) -> i64 {
129+
core::intrinsics::read_via_copy(r)
130+
}
131+
127132
// EMIT_MIR lower_intrinsics.write_via_move_string.LowerIntrinsics.diff
128133
pub fn write_via_move_string(r: &mut String, v: String) {
129134
unsafe { core::intrinsics::write_via_move(r, v) }
@@ -143,3 +148,8 @@ pub fn option_payload(o: &Option<usize>, p: &Option<String>) {
143148
pub unsafe fn ptr_offset(p: *const i32, d: isize) -> *const i32 {
144149
core::intrinsics::offset(p, d)
145150
}
151+
152+
// EMIT_MIR lower_intrinsics.ptr_offset_mut.LowerIntrinsics.diff
153+
pub unsafe fn ptr_offset_mut(p: *mut i32, d: usize) -> *mut i32 {
154+
core::intrinsics::offset(p, d)
155+
}

tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.diff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
_4 = move _2; // scope 1 at $DIR/lower_intrinsics.rs:+1:50: +1:51
1818
- _0 = write_via_move::<String>(move _3, move _4) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:52
1919
- // mir::Constant
20-
- // + span: $DIR/lower_intrinsics.rs:129:14: 129:46
20+
- // + span: $DIR/lower_intrinsics.rs:134:14: 134:46
2121
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*mut String, String) {write_via_move::<String>}, val: Value(<ZST>) }
2222
+ (*_3) = move _4; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:52
2323
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:52

0 commit comments

Comments
 (0)