Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,27 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.typed_swap_nonoverlapping_intrinsic(&args[0], &args[1])?;
}

sym::volatile_load => {

@oli-obk oli-obk Jul 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the shared space for intrinsics for miri and ctfe. But this impl will only be used by ctfe, so it should live in the ctfe intrinsic impl file

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the same impl should be used by CTFE and Miri.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I assumed we'd want do so extra checks in miri, although who but other threads would be randomly modifying memory idk either

let [ptr] = args else {
span_bug!(self.cur_span(), "invalid `volatile_load` call")
};
let place = self.deref_pointer(ptr)?;
self.copy_op(&place, dest)?;
}
sym::volatile_store => {
let [ptr, val] = args else {
span_bug!(self.cur_span(), "invalid `volatile_store` call")
};
let place = self.deref_pointer(ptr)?;
self.copy_op(val, &place)?;
}
sym::volatile_set_memory => {
let [ptr, val_byte, count] = args else {
span_bug!(self.cur_span(), "invalid `volatile_set_memory` call")
};
self.write_bytes_intrinsic(ptr, val_byte, count, "volatile_set_memory")?;
}

sym::vtable_size => {
let ptr = self.read_pointer(&args[0])?;
// `None` because we don't know which trait to expect here; any vtable is okay.
Expand Down
6 changes: 3 additions & 3 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -990,20 +990,20 @@ pub unsafe fn volatile_copy_memory<T>(dst: *mut T, src: *const T, count: usize);
/// [`write_bytes`]: ptr::write_bytes
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn volatile_set_memory<T>(dst: *mut T, val: u8, count: usize);
pub const unsafe fn volatile_set_memory<T>(dst: *mut T, val: u8, count: usize);

/// Performs a volatile load from the `src` pointer.
///
/// The stabilized version of this intrinsic is [`core::ptr::read_volatile`].
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn volatile_load<T>(src: *const T) -> T;
pub const unsafe fn volatile_load<T>(src: *const T) -> T;
/// Performs a volatile store to the `dst` pointer.
///
/// The stabilized version of this intrinsic is [`core::ptr::write_volatile`].
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn volatile_store<T>(dst: *mut T, val: T);
pub const unsafe fn volatile_store<T>(dst: *mut T, val: T);

/// Performs a volatile load from the `src` pointer
/// The pointer is not required to be aligned.
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1164,9 +1164,10 @@ impl<T: PointeeSized> *const T {
///
/// [`ptr::read_volatile`]: crate::ptr::read_volatile()
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_volatile", issue = "159094")]
#[inline]
#[track_caller]
pub unsafe fn read_volatile(self) -> T
pub const unsafe fn read_volatile(self) -> T
where
T: Sized,
{
Expand Down
12 changes: 10 additions & 2 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2061,6 +2061,9 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
///
/// Note that volatile memory operations where T is a zero-sized type are noops and may be ignored.
///
/// When invoked during const evaluation, this behaves like a regular read. In particular, such
/// reads must always follow the first of the two cases above.
///
/// [allocation]: crate::ptr#allocated-object
/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses
///
Expand Down Expand Up @@ -2116,9 +2119,10 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
/// ```
#[inline]
#[stable(feature = "volatile", since = "1.9.0")]
#[rustc_const_unstable(feature = "const_volatile", issue = "159094")]
#[track_caller]
#[rustc_diagnostic_item = "ptr_read_volatile"]
pub unsafe fn read_volatile<T>(src: *const T) -> T {
pub const unsafe fn read_volatile<T>(src: *const T) -> T {
// SAFETY: the caller must uphold the safety contract for `volatile_load`.
unsafe {
ub_checks::assert_unsafe_precondition!(
Expand Down Expand Up @@ -2169,6 +2173,9 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
/// dropped when operating on Rust memory. Additionally, it does not drop `src`. Semantically, `src`
/// is moved into the location pointed to by `dst`.
///
/// When invoked during const evaluation, this behaves like a regular write. In particular, such
/// reads must always follow the first of the two cases above.
///
/// [allocation]: crate::ptr#allocated-object
/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses
///
Expand Down Expand Up @@ -2218,9 +2225,10 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
/// ```
#[inline]
#[stable(feature = "volatile", since = "1.9.0")]
#[rustc_const_unstable(feature = "const_volatile", issue = "159094")]
#[rustc_diagnostic_item = "ptr_write_volatile"]
#[track_caller]
pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
pub const unsafe fn write_volatile<T>(dst: *mut T, src: T) {
// SAFETY: the caller must uphold the safety contract for `volatile_store`.
unsafe {
ub_checks::assert_unsafe_precondition!(
Expand Down
6 changes: 4 additions & 2 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1256,9 +1256,10 @@ impl<T: PointeeSized> *mut T {
///
/// [`ptr::read_volatile`]: crate::ptr::read_volatile()
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_volatile", issue = "159094")]
#[inline(always)]
#[track_caller]
pub unsafe fn read_volatile(self) -> T
pub const unsafe fn read_volatile(self) -> T
where
T: Sized,
{
Expand Down Expand Up @@ -1430,9 +1431,10 @@ impl<T: PointeeSized> *mut T {
///
/// [`ptr::write_volatile`]: crate::ptr::write_volatile()
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_volatile", issue = "159094")]
#[inline(always)]
#[track_caller]
pub unsafe fn write_volatile(self, val: T)
pub const unsafe fn write_volatile(self, val: T)
where
T: Sized,
{
Expand Down
17 changes: 0 additions & 17 deletions src/tools/miri/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,23 +135,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
return interp_ok(EmulateItemResult::AlreadyJumped);
}

// Raw memory accesses
"volatile_load" => {
let [place] = check_intrinsic_arg_count(args)?;
let place = this.deref_pointer(place)?;
this.copy_op(&place, dest)?;
}
"volatile_store" => {
let [place, dest] = check_intrinsic_arg_count(args)?;
let place = this.deref_pointer(place)?;
this.copy_op(dest, &place)?;
}

"volatile_set_memory" => {
let [ptr, val_byte, count] = check_intrinsic_arg_count(args)?;
this.write_bytes_intrinsic(ptr, val_byte, count, "volatile_set_memory")?;
}

// Memory model / provenance manipulation
"ptr_mask" => {
let [ptr, mask] = check_intrinsic_arg_count(args)?;
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/consts/const-eval/volatile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ check-pass
#![feature(const_volatile)]

const _READ: () = unsafe {
let x = 42i32;
let y = (&x as *const i32).read_volatile();
assert!(x == y);
};

const _WRITE: () = unsafe {
let mut x = 42i32;
(&mut x as *mut i32).write_volatile(13);
assert!(x == 13);
};

fn main() {}
Loading