Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
86 changes: 52 additions & 34 deletions compiler/rustc_const_eval/src/interpret/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
caller_args: &mut impl Iterator<
Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>),
>,
callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
callee_arg_idx: usize,
callee_args_abis: &mut impl Iterator<Item = (usize, &'y ArgAbi<'tcx, Ty<'tcx>>)>,
callee_arg: &mir::Place<'tcx>,
callee_ty: Ty<'tcx>,
already_live: bool,
Expand All @@ -282,15 +281,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
'tcx: 'x,
'tcx: 'y,
{
// Get next callee arg.
let (callee_arg_idx, callee_abi) = callee_args_abis.next().unwrap();
assert_eq!(callee_ty, callee_abi.layout.ty);
if callee_abi.is_ignore() {
// This one is skipped. Still must be made live though!
if !already_live {
self.storage_live(callee_arg.as_local().unwrap())?;
}
return interp_ok(());
}
// Find next caller arg.
// Get next caller arg.
let Some((caller_arg, caller_abi)) = caller_args.next() else {
throw_ub_format!("calling a function with fewer arguments than it requires");
};
Expand Down Expand Up @@ -348,6 +342,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
mut cont: ReturnContinuation,
) -> InterpResult<'tcx> {
let _trace = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty);
let def_id = instance.def_id();

// The first order of business is to figure out the callee signature.
// However, that requires the list of variadic arguments.
Expand Down Expand Up @@ -423,10 +418,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
"spread_arg: {:?}, locals: {:#?}",
body.spread_arg,
body.args_iter()
.map(|local| (local, self.layout_of_local(self.frame(), local, None).unwrap().ty,))
.map(|local| (local, self.layout_of_local(self.frame(), local, None).unwrap().ty))
.collect::<Vec<_>>()
);

// Determine whether there is a special VaList argument. This is always the
// last argument, and since arguments start at index 1 that's `arg_count`.
let va_list_arg = callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count));
// Determine whether this is a non-capturing closure. That's relevant as their first
// argument can be skipped (and that's the only kind of argument skipping we allow).
let is_non_capturing_closure =
(matches!(instance.def, ty::InstanceKind::ClosureOnceShim { .. })
|| self.tcx.is_closure_like(def_id))
&& {
let arg = &callee_fn_abi.args[0];
matches!(arg.layout.ty.kind(), ty::Closure (_def, closure_args) if {
closure_args.as_closure().upvar_tys().is_empty()
})
};

// In principle, we have two iterators: Where the arguments come from, and where
// they go to.

Expand All @@ -439,21 +449,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
caller_fn_abi.args.len(),
"mismatch between caller ABI and caller arguments",
);
let mut caller_args = args
.iter()
.zip(caller_fn_abi.args.iter())
.filter(|arg_and_abi| !arg_and_abi.1.is_ignore());
let mut caller_args = args.iter().zip(caller_fn_abi.args.iter());

// Now we have to spread them out across the callee's locals,
// taking into account the `spread_arg`. If we could write
// this is a single iterator (that handles `spread_arg`), then
// `pass_argument` would be the loop body. It takes care to
// not advance `caller_iter` for ignored arguments.
// `pass_argument` would be the loop body.
let mut callee_args_abis = callee_fn_abi.args.iter().enumerate();
// Determine whether there is a special VaList argument. This is always the
// last argument, and since arguments start at index 1 that's `arg_count`.
let va_list_arg = callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count));

// During argument passing, we want retagging with protectors.
M::with_retag_mode(self, RetagMode::FnEntry, |ecx| {
for local in body.args_iter() {
Expand All @@ -466,7 +468,32 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// type, but the result gets cached so this avoids calling the instantiation
// query *again* the next time this local is accessed.
let ty = ecx.layout_of_local(ecx.frame(), local, None)?.ty;
if Some(local) == va_list_arg {

// Some arguments are special: the first (`self`) argument of a non-capturing
// closure; the va_list argument; and the spread_arg.
if is_non_capturing_closure && local == mir::Local::arg(0) {
assert!(va_list_arg.is_none());
assert!(Some(local) != body.spread_arg);
// This argument might be missing on the caller side. So just initialize it in
// the callee.
let (callee_arg_idx, callee_abi) = callee_args_abis.next().unwrap();
assert!(callee_abi.layout.is_1zst() && callee_abi.is_ignore());
ecx.storage_live(local)?;
// And skip it in the caller, if present. We can tell whether it is present by
// comparing the number of arguments on the caller and callee side.
if caller_fn_abi.args.len() == callee_fn_abi.args.len() {
let (_caller_arg, caller_abi) = caller_args.next().unwrap();
if !caller_abi.layout.is_1zst() {
// The caller gave us some other, non-ignorable argument.
throw_ub!(AbiMismatchArgument {
arg_idx: callee_arg_idx,
caller_ty: caller_abi.layout.ty,
callee_ty: callee_abi.layout.ty
});
}
assert!(caller_abi.is_ignore());
}
} else if Some(local) == va_list_arg {
// This is the last callee-side argument of a variadic function.
// This argument is a VaList holding the remaining caller-side arguments.
ecx.storage_live(local)?;
Expand All @@ -476,12 +503,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {

// Consume the remaining arguments by putting them into the variable argument
// list.
let varargs = ecx.allocate_varargs(
&mut caller_args,
// "Ignored" arguments aren't actually passed, so the callee should also
// ignore them. (`pass_argument` does this for regular arguments.)
(&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()),
)?;
let varargs = ecx.allocate_varargs(&mut caller_args, &mut callee_args_abis)?;
// When the frame is dropped, these variable arguments are deallocated.
ecx.frame_mut().va_list = varargs.clone();
let key = ecx.va_list_ptr(varargs.into());
Expand All @@ -507,23 +529,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
&[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)],
*ecx.tcx,
);
let (idx, callee_abi) = callee_args_abis.next().unwrap();
ecx.pass_argument(
&mut caller_args,
callee_abi,
idx,
&mut callee_args_abis,
&dest,
field_ty,
/* already_live */ true,
)?;
}
} else {
// Normal argument. Cannot mark it as live yet, it might be unsized!
let (idx, callee_abi) = callee_args_abis.next().unwrap();
ecx.pass_argument(
&mut caller_args,
callee_abi,
idx,
&mut callee_args_abis,
&dest,
ty,
/* already_live */ false,
Expand Down
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
// Lints:
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(fuzzy_provenance_casts)]
#![deny(lossy_provenance_casts)]
#![warn(deprecated_in_future)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
Expand Down
1 change: 1 addition & 0 deletions library/alloctests/benches/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#![feature(strict_provenance_lints)]
#![feature(test)]
#![deny(fuzzy_provenance_casts)]
#![deny(lossy_provenance_casts)]

extern crate test;

Expand Down
4 changes: 2 additions & 2 deletions library/alloctests/tests/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ fn box_clone_from_ptr_stability() {
for size in (0..8).map(|i| 2usize.pow(i)) {
let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
let copy_raw = copy.as_ptr() as usize;
let copy_raw = copy.as_ptr();
copy.clone_from(&control);
assert_eq!(copy.as_ptr() as usize, copy_raw);
assert_eq!(copy.as_ptr(), copy_raw);
}
}

Expand Down
2 changes: 1 addition & 1 deletion library/alloctests/tests/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn check_overalign_requests<T: Allocator>(allocator: T) {
.collect();
for &ptr in &pointers {
assert_eq!(
(ptr.as_non_null_ptr().as_ptr() as usize) % align,
ptr.as_non_null_ptr().as_ptr().addr() % align,
0,
"Got a pointer less aligned than requested"
)
Expand Down
1 change: 1 addition & 0 deletions library/alloctests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#![feature(ptr_cast_slice)]
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)]
#![deny(lossy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)]

extern crate alloc;
Expand Down
2 changes: 1 addition & 1 deletion library/alloctests/tests/sort/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ fn self_cmp<T: Ord + Clone + Debug, S: Sort>(
pattern_fn(len).into_iter().map(|val| type_into_fn(val)).collect::<Vec<_>>();

let comparison_fn = |a: &T, b: &T| {
assert_ne!(a as *const T as usize, b as *const T as usize);
assert_ne!(a as *const T, b as *const T);
a.cmp(b)
};

Expand Down
8 changes: 4 additions & 4 deletions library/alloctests/tests/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,7 @@ fn test_into_iter_zst() {
struct AlignedZstWithDrop([u64; 0]);
impl Drop for AlignedZstWithDrop {
fn drop(&mut self) {
let addr = self as *mut _ as usize;
let addr = (self as *mut Self).addr();
assert!(hint::black_box(addr) % align_of::<u64>() == 0);
}
}
Expand Down Expand Up @@ -1356,10 +1356,10 @@ fn overaligned_allocations() {
for i in 0..0x1000 {
v.reserve_exact(i);
assert!(v[0].0 == 273);
assert!(v.as_ptr() as usize & 0xff == 0);
assert!(v.as_ptr().addr() & 0xff == 0);
v.shrink_to_fit();
assert!(v[0].0 == 273);
assert!(v.as_ptr() as usize & 0xff == 0);
assert!(v.as_ptr().addr() & 0xff == 0);
}
}

Expand Down Expand Up @@ -2574,7 +2574,7 @@ fn test_box_zero_allocator() {

unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
if layout.size() == 0 {
let addr = ptr.as_ptr() as usize;
let addr = ptr.as_ptr().addr();
let mut state = self.state.borrow_mut();
std::println!("freeing {addr}");
assert!(state.0.remove(&addr), "ZST free that wasn't allocated");
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
#![deny(rust_2021_incompatible_or_patterns)]
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(fuzzy_provenance_casts)]
#![deny(lossy_provenance_casts)]
#![warn(deprecated_in_future)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
Expand Down
1 change: 1 addition & 0 deletions library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ impl<T: PointeeSized> *const T {
/// [`with_exposed_provenance`]: with_exposed_provenance
#[inline(always)]
#[stable(feature = "exposed_provenance", since = "1.84.0")]
#[expect(lossy_provenance_casts, reason = "this *is* the replacement")]
pub fn expose_provenance(self) -> usize {
self.cast::<()>() as usize
}
Expand Down
6 changes: 3 additions & 3 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2618,21 +2618,21 @@ impl<F: FnPtr> Ord for F {
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<F: FnPtr> hash::Hash for F {
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
state.write_usize(self.addr() as _)
state.write_usize(self.addr().addr())
}
}

#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<F: FnPtr> fmt::Pointer for F {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::pointer_fmt_inner(self.addr() as _, f)
fmt::pointer_fmt_inner(self.addr().addr(), f)
}
}

#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<F: FnPtr> fmt::Debug for F {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::pointer_fmt_inner(self.addr() as _, f)
fmt::pointer_fmt_inner(self.addr().addr(), f)
}
}

Expand Down
1 change: 1 addition & 0 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ impl<T: PointeeSized> *mut T {
/// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut
#[inline(always)]
#[stable(feature = "exposed_provenance", since = "1.84.0")]
#[expect(lossy_provenance_casts, reason = "this *is* the replacement")]
pub fn expose_provenance(self) -> usize {
self.cast::<()>() as usize
}
Expand Down
4 changes: 2 additions & 2 deletions library/coretests/tests/char.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ fn test_encode_utf8() {
let mut buf = [0; char::MAX_LEN_UTF8];
let ptr = buf.as_ptr();
let s = input.encode_utf8(&mut buf);
assert_eq!(s.as_ptr() as usize, ptr as usize);
assert_eq!(s.as_ptr(), ptr);
assert!(str::from_utf8(s.as_bytes()).is_ok());
assert_eq!(s.as_bytes(), expect);
}
Expand All @@ -335,7 +335,7 @@ fn test_encode_utf16() {
let mut buf = [0; 2];
let ptr = buf.as_mut_ptr();
let b = input.encode_utf16(&mut buf);
assert_eq!(b.as_mut_ptr() as usize, ptr as usize);
assert_eq!(b.as_mut_ptr(), ptr);
assert_eq!(b, expect);
}

Expand Down
1 change: 1 addition & 0 deletions library/coretests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
// tidy-alphabetical-end
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)]
#![deny(lossy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)]

/// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality.
Expand Down
2 changes: 1 addition & 1 deletion library/coretests/tests/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ fn align_offset_stride_one() {
#[test]
fn align_offset_various_strides() {
unsafe fn test_stride<T>(ptr: *const T, align: usize) -> bool {
let numptr = ptr as usize;
let numptr = ptr.addr();
let mut expected = usize::MAX;
// Naive but definitely correct way to find the *first* aligned element of stride::<T>.
for el in 0..align {
Expand Down
2 changes: 1 addition & 1 deletion library/coretests/tests/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1886,7 +1886,7 @@ fn test_align_to_empty_mid() {
type Chunk = u32;
for offset in 0..4 {
let (_, mid, _) = unsafe { bytes[offset..offset + 1].align_to::<Chunk>() };
assert_eq!(mid.as_ptr() as usize % align_of::<Chunk>(), 0);
assert_eq!(mid.as_ptr().addr() % align_of::<Chunk>(), 0);
}
}

Expand Down
6 changes: 3 additions & 3 deletions library/coretests/tests/waker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ use std::task::{RawWaker, RawWakerVTable, Waker};
fn test_waker_getters() {
let raw_waker = RawWaker::new(ptr::without_provenance_mut(42usize), &WAKER_VTABLE);
let waker = unsafe { Waker::from_raw(raw_waker) };
assert_eq!(waker.data() as usize, 42);
assert_eq!(waker.data().addr(), 42);
assert!(ptr::eq(waker.vtable(), &WAKER_VTABLE));

let waker2 = waker.clone();
assert_eq!(waker2.data() as usize, 43);
assert_eq!(waker2.data().addr(), 43);
assert!(ptr::eq(waker2.vtable(), &WAKER_VTABLE));
}

static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
|data| RawWaker::new(ptr::without_provenance_mut(data as usize + 1), &WAKER_VTABLE),
|data| RawWaker::new(ptr::without_provenance_mut(data.addr() + 1), &WAKER_VTABLE),
|_| {},
|_| {},
|_| {},
Expand Down
9 changes: 8 additions & 1 deletion library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@
#![allow(unused_lifetimes)]
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)]
#![deny(lossy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)]
#![allow(rustdoc::redundant_explicit_links)]
#![warn(rustdoc::unescaped_backticks)]
Expand Down Expand Up @@ -723,7 +724,13 @@ pub mod alloc;
mod panicking;

#[path = "../../backtrace/src/lib.rs"]
#[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)]
#[allow(
dead_code,
unused_attributes,
fuzzy_provenance_casts,
lossy_provenance_casts,
unsafe_op_in_unsafe_fn
)]
mod backtrace_rs;

#[stable(feature = "cfg_select", since = "1.95.0")]
Expand Down
5 changes: 5 additions & 0 deletions library/std/src/os/unix/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,15 @@ pub trait JoinHandleExt {

#[stable(feature = "thread_extensions", since = "1.9.0")]
impl<T> JoinHandleExt for JoinHandle<T> {
// This is an int2ptr cast on some platforms (e.g., *-musl) where RawPthread
// is an integer but libc::pthread_t is a pointer. Exposed provenance is the
// safe choice here, but `as` also works when it's int2int or ptr2ptr.
#[allow(lossy_provenance_casts)]
fn as_pthread_t(&self) -> RawPthread {
self.as_inner().id() as RawPthread
}

#[allow(lossy_provenance_casts)] // see above for why
fn into_pthread_t(self) -> RawPthread {
self.into_inner().into_id() as RawPthread
}
Expand Down
Loading
Loading