diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 6aa88b86e4e60..40ba31d37f2f0 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -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>)>, callee_arg: &mir::Place<'tcx>, callee_ty: Ty<'tcx>, already_live: bool, @@ -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"); }; @@ -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. @@ -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::>() ); + // 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. @@ -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() { @@ -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)?; @@ -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()); @@ -507,11 +529,9 @@ 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, @@ -519,11 +539,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } 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, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 80f29511ebb8e..85697b1414f05 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -1,6 +1,44 @@ //! Declares Rust's target feature names for each target. //! Note that these are similar to but not always identical to LLVM's feature names, //! and Rust adds some features that do not correspond to LLVM features at all. +//! +//! The target features listed here can be used in `#[target_feature]` and `#[cfg(target_feature)]`. +//! They also do not trigger any warnings when used with `-Ctarget-feature`. +//! +//! Note that even unstable (and even entirely unlisted) features can be used with `-Ctarget-feature` +//! on stable. Using a feature not on the list of Rust target features only emits a warning. +//! Only `cfg(target_feature)` and `#[target_feature]` actually do any stability gating. +//! `cfg(target_feature)` for unstable features just works on nightly without any feature gate. +//! `#[target_feature]` requires a feature gate. +//! +//! When adding features to the below lists +//! check whether they're named already elsewhere in rust +//! e.g. in stdarch and whether the given name matches LLVM's +//! if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted. +//! Additionally, if the feature is not available in older version of LLVM supported by the current +//! rust, the same function must be updated to filter out these features to avoid triggering +//! warnings. +//! +//! Also note that all target features listed here must be purely additive: for target_feature 1.1 to +//! be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a +//! per-function level, since we would then allow safe calls from functions with `+soft-float` to +//! functions without that feature! +//! +//! It is important for soundness to consider the interaction of target features and the function +//! call ABI. For example, disabling the `x87` feature on x86 changes how scalar floats are passed as +//! arguments, so letting people toggle that feature would be unsound. To this end, the +//! [`Target::abi_required_features`] function computes which target features must and must not be +//! enabled for any given target, and individual features can also be marked as [`Forbidden`]. See +//! for some more context. +//! +//! The one exception to features that change the ABI is features that enable larger vector +//! registers. Those are permitted to be listed here. The `*_FOR_CORRECT_VECTOR_ABI` arrays store +//! information about which target feature is ABI-required for which vector size; this is used to +//! ensure that vectors can only be passed via `extern "C"` when the right feature is enabled. (For +//! the "Rust" ABI we generally pass vectors by-ref exactly to avoid these issues.) +//! Also see . +//! +//! Stabilizing a target feature requires t-lang approval. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_macros::StableHash; use rustc_span::{Symbol, sym}; @@ -32,9 +70,12 @@ pub enum Stability { Symbol, ), /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be - /// set in the target spec. It is never set in `cfg(target_feature)`. Used in - /// particular for features are actually ABI configuration flags (not all targets are as nice as - /// RISC-V and have an explicit way to set the ABI separate from target features). + /// set in the target spec. It is never set in `cfg(target_feature)`. Used in particular for + /// features are actually ABI configuration flags (such as "soft-float" on many targets). + /// However, "forbidden" target features can still sometimes be enabled via `-Ctarget-cpu` or + /// target feature implications (on the Rust/LLVM level). To prevent that, ABI-relevant target + /// features are ideally pinned down (required or forbidden) in + /// [`Target::abi_required_features`]. Forbidden { reason: &'static str, /// True if this is always an error, false if this can be reported as a warning when set via @@ -102,50 +143,11 @@ impl Stability { } } -// Here we list target features that rustc "understands": they can be used in `#[target_feature]` -// and `#[cfg(target_feature)]`. They also do not trigger any warnings when used with -// `-Ctarget-feature`. -// -// Note that even unstable (and even entirely unlisted) features can be used with `-Ctarget-feature` -// on stable. Using a feature not on the list of Rust target features only emits a warning. -// Only `cfg(target_feature)` and `#[target_feature]` actually do any stability gating. -// `cfg(target_feature)` for unstable features just works on nightly without any feature gate. -// `#[target_feature]` requires a feature gate. -// -// When adding features to the below lists -// check whether they're named already elsewhere in rust -// e.g. in stdarch and whether the given name matches LLVM's -// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted. -// Additionally, if the feature is not available in older version of LLVM supported by the current -// rust, the same function must be updated to filter out these features to avoid triggering -// warnings. -// -// Also note that all target features listed here must be purely additive: for target_feature 1.1 to -// be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a -// per-function level, since we would then allow safe calls from functions with `+soft-float` to -// functions without that feature! -// -// It is important for soundness to consider the interaction of targets features and the function -// call ABI. For example, disabling the `x87` feature on x86 changes how scalar floats are passed as -// arguments, so letting people toggle that feature would be unsound. To this end, the -// `abi_required_features` function computes which target features must and must not be enabled for -// any given target, and individual features can also be marked as `Forbidden`. -// See https://github.com/rust-lang/rust/issues/116344 for some more context. -// -// The one exception to features that change the ABI is features that enable larger vector -// registers. Those are permitted to be listed here. The `*_FOR_CORRECT_VECTOR_ABI` arrays store -// information about which target feature is ABI-required for which vector size; this is used to -// ensure that vectors can only be passed via `extern "C"` when the right feature is enabled. (For -// the "Rust" ABI we generally pass vectors by-ref exactly to avoid these issues.) -// Also see https://github.com/rust-lang/rust/issues/116558. -// -// Stabilizing a target feature requires t-lang approval. - -// If feature A "implies" feature B, then: -// - when A gets enabled (via `-Ctarget-feature` or `#[target_feature]`), we also enable B -// - when B gets disabled (via `-Ctarget-feature`), we also disable A -// -// Both of these are also applied transitively. +/// If feature A "implies" feature B, then: +/// - when A gets enabled (via `-Ctarget-feature` or `#[target_feature]`), we also enable B +/// - when B gets disabled (via `-Ctarget-feature`), we also disable A +/// +/// Both of these are also applied transitively. type ImpliedFeatures = &'static [&'static str]; static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3f0c0ab3080c5..f66dc648f809b 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -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)] diff --git a/library/alloctests/benches/lib.rs b/library/alloctests/benches/lib.rs index b7e09fc2e162b..2be7a24d2de7b 100644 --- a/library/alloctests/benches/lib.rs +++ b/library/alloctests/benches/lib.rs @@ -7,6 +7,7 @@ #![feature(strict_provenance_lints)] #![feature(test)] #![deny(fuzzy_provenance_casts)] +#![deny(lossy_provenance_casts)] extern crate test; diff --git a/library/alloctests/tests/boxed.rs b/library/alloctests/tests/boxed.rs index a0c3cb55edcc6..c73b7109fb387 100644 --- a/library/alloctests/tests/boxed.rs +++ b/library/alloctests/tests/boxed.rs @@ -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); } } diff --git a/library/alloctests/tests/heap.rs b/library/alloctests/tests/heap.rs index 246b341eeb387..8eb562622c0a4 100644 --- a/library/alloctests/tests/heap.rs +++ b/library/alloctests/tests/heap.rs @@ -25,7 +25,7 @@ fn check_overalign_requests(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" ) diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 1414835058b9a..b7c3e39c992b0 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -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; diff --git a/library/alloctests/tests/sort/tests.rs b/library/alloctests/tests/sort/tests.rs index 09b76773d6b24..ec4c4fa619ddf 100644 --- a/library/alloctests/tests/sort/tests.rs +++ b/library/alloctests/tests/sort/tests.rs @@ -746,7 +746,7 @@ fn self_cmp( pattern_fn(len).into_iter().map(|val| type_into_fn(val)).collect::>(); 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) }; diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index 54bdc4c19cfae..ccf9b8095b290 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -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::() == 0); } } @@ -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); } } @@ -2574,7 +2574,7 @@ fn test_box_zero_allocator() { unsafe fn deallocate(&self, ptr: NonNull, 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"); diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index b16996acb1c44..1cdf52de8cad8 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -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)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 5cbbebf9f4788..0a7f9b920364a 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -183,6 +183,7 @@ impl *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 } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index ff2c18d685b65..593011edecf27 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2618,21 +2618,21 @@ impl Ord for F { #[stable(feature = "fnptr_impls", since = "1.4.0")] impl hash::Hash for F { fn hash(&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 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 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) } } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 53ef7f754d201..4b68d96aeae68 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -174,6 +174,7 @@ impl *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 } diff --git a/library/coretests/tests/char.rs b/library/coretests/tests/char.rs index 877017f682c97..43372005ad5f3 100644 --- a/library/coretests/tests/char.rs +++ b/library/coretests/tests/char.rs @@ -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); } @@ -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); } diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 89e8d5d8185ee..aa6aa1478bd70 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -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. diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs index 93f9454d71378..9dbaf6690c81c 100644 --- a/library/coretests/tests/ptr.rs +++ b/library/coretests/tests/ptr.rs @@ -384,7 +384,7 @@ fn align_offset_stride_one() { #[test] fn align_offset_various_strides() { unsafe fn test_stride(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::. for el in 0..align { diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs index 2bb62f36bb0e6..a4db7304fff90 100644 --- a/library/coretests/tests/slice.rs +++ b/library/coretests/tests/slice.rs @@ -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::() }; - assert_eq!(mid.as_ptr() as usize % align_of::(), 0); + assert_eq!(mid.as_ptr().addr() % align_of::(), 0); } } diff --git a/library/coretests/tests/waker.rs b/library/coretests/tests/waker.rs index 4889b8959ece4..be8b07b8ad009 100644 --- a/library/coretests/tests/waker.rs +++ b/library/coretests/tests/waker.rs @@ -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), |_| {}, |_| {}, |_| {}, diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 8086cab34cf44..addbb407083c7 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -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)] @@ -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")] diff --git a/library/std/src/os/unix/thread.rs b/library/std/src/os/unix/thread.rs index 32085e525942e..efb349b18d6b5 100644 --- a/library/std/src/os/unix/thread.rs +++ b/library/std/src/os/unix/thread.rs @@ -31,10 +31,15 @@ pub trait JoinHandleExt { #[stable(feature = "thread_extensions", since = "1.9.0")] impl JoinHandleExt for JoinHandle { + // 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 } diff --git a/library/std/src/random.rs b/library/std/src/random.rs index a18dcf98ec7fc..8274060e5cedf 100644 --- a/library/std/src/random.rs +++ b/library/std/src/random.rs @@ -16,6 +16,8 @@ use crate::sys::random as sys; /// security is not a concern, consider using an alternative random number /// generator (potentially seeded from this one). /// +/// If you need to fill a buffer with random bytes, use `DefaultRandomSource.fill_bytes(&mut buf)`. +/// /// # Underlying sources /// /// Platform | Source @@ -54,6 +56,7 @@ use crate::sys::random as sys; /// /// [`getrandom`]: https://www.man7.org/linux/man-pages/man2/getrandom.2.html /// [`/dev/urandom`]: https://www.man7.org/linux/man-pages/man4/random.4.html +#[doc(alias = "getrandom", alias = "getentropy", alias = "arc4random")] #[derive(Default, Debug, Clone, Copy)] #[unstable(feature = "random", issue = "130703")] pub struct DefaultRandomSource; diff --git a/library/std/src/sync/mpmc/select.rs b/library/std/src/sync/mpmc/select.rs index 56a83fee2e119..ff537aa686157 100644 --- a/library/std/src/sync/mpmc/select.rs +++ b/library/std/src/sync/mpmc/select.rs @@ -22,7 +22,7 @@ impl Operation { /// and is alive for the entire duration of a blocking operation. #[inline] pub fn hook(r: &mut T) -> Operation { - let val = r as *mut T as usize; + let val = (r as *mut T).addr(); // Make sure that the pointer address doesn't equal the numerical representation of // `Selected::{Waiting, Aborted, Disconnected}`. assert!(val > 2); diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index c743462501922..4f645e16fbb6f 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -25,7 +25,7 @@ impl Default for ZeroToken { impl fmt::Debug for ZeroToken { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&(self.0 as usize), f) + fmt::Debug::fmt(&self.0.addr(), f) } } diff --git a/library/std/src/sys/args/sgx.rs b/library/std/src/sys/args/sgx.rs index 6ff94f5681b6f..9403059e7c607 100644 --- a/library/std/src/sys/args/sgx.rs +++ b/library/std/src/sys/args/sgx.rs @@ -1,4 +1,5 @@ -#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers +// FIXME: this module systematically confuses pointers and integers +#![allow(fuzzy_provenance_casts, lossy_provenance_casts)] use crate::ffi::OsString; use crate::num::NonZero; diff --git a/library/std/src/sys/env/sgx.rs b/library/std/src/sys/env/sgx.rs index 09090ec7cf0dd..0c19fcc848f4d 100644 --- a/library/std/src/sys/env/sgx.rs +++ b/library/std/src/sys/env/sgx.rs @@ -1,4 +1,5 @@ -#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers +// FIXME: this module systematically confuses pointers and integers +#![allow(fuzzy_provenance_casts, lossy_provenance_casts)] pub use super::common::Env; use crate::collections::HashMap; diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 2b284cc40b94b..7b2c8e5a8024a 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -3,7 +3,8 @@ //! This module contains the facade (aka platform-specific) implementations of //! OS level functionality for Fortanix SGX. #![deny(unsafe_op_in_unsafe_fn)] -#![allow(fuzzy_provenance_casts)] // FIXME: this entire module systematically confuses pointers and integers +// FIXME: this entire module systematically confuses pointers and integers +#![allow(fuzzy_provenance_casts, lossy_provenance_casts)] use crate::io; use crate::sync::atomic::{Atomic, AtomicBool, Ordering}; diff --git a/library/std/src/sys/thread_local/key/tests.rs b/library/std/src/sys/thread_local/key/tests.rs index c7d2c8e6301ef..5e5243d9835ed 100644 --- a/library/std/src/sys/thread_local/key/tests.rs +++ b/library/std/src/sys/thread_local/key/tests.rs @@ -18,8 +18,8 @@ fn smoke() { assert!(get(k2).is_null()); set(k1, ptr::without_provenance_mut(1)); set(k2, ptr::without_provenance_mut(2)); - assert_eq!(get(k1) as usize, 1); - assert_eq!(get(k2) as usize, 2); + assert_eq!(get(k1).addr(), 1); + assert_eq!(get(k2).addr(), 2); } } diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 4b934c039a36f..78b6f7c35e8db 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -152,11 +152,11 @@ where { let (tx, rx) = channel(); - let x: Box<_> = Box::new(1); - let x_in_parent = (&*x) as *const i32 as usize; + let x: Box = Box::new(1); + let x_in_parent = (&raw const *x).addr(); spawnfn(Box::new(move || { - let x_in_child = (&*x) as *const i32 as usize; + let x_in_child = (&raw const *x).addr(); tx.send(x_in_child).unwrap(); })); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 68a4f928464f1..3b497e1db923c 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1999,12 +1999,16 @@ impl Step for Sysroot { } // Copy the compiler into the correct sysroot. - // NOTE(#108767): We intentionally don't copy `rustc-dev` artifacts until they're requested with `builder.ensure(Rustc)`. - // This fixes an issue where we'd have multiple copies of libc in the sysroot with no way to tell which to load. - // There are a few quirks of bootstrap that interact to make this reliable: + // + // FIXME(#156525): investigate if this is still needed. + // + // NOTE(#108767): We intentionally don't copy `rustc-dev` artifacts until they're + // requested with `builder.ensure(Rustc)`. This fixes an issue where we'd have multiple + // copies of libc in the sysroot with no way to tell which to load. There are a few + // quirks of bootstrap that interact to make this reliable: // 1. The order `Step`s are run is hard-coded in `builder.rs` and not configurable. This - // avoids e.g. reordering `test::UiFulldeps` before `test::Ui` and causing the latter to - // fail because of duplicate metadata. + // avoids e.g. reordering `test::UiFulldeps` before `test::Ui` and causing the latter + // to fail because of duplicate metadata. // 2. The sysroot is deleted and recreated between each invocation, so running `x test // ui-fulldeps && x test ui` can't cause failures. let mut filtered_files = Vec::new(); diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 2329bb93b4d3d..935844daa9d7c 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -510,7 +510,7 @@ impl Step for Rustfmt { let compilers = RustcPrivateCompilers::new(builder, stage, host); let rustfmt_build = builder.ensure(tool::Rustfmt::from_compilers(compilers)); - let mut rustfmt = tool::prepare_tool_cargo( + let mut cargo = tool::prepare_tool_cargo( builder, rustfmt_build.build_compiler, Mode::ToolRustcPrivate, @@ -521,10 +521,10 @@ impl Step for Rustfmt { &[], ); - rustfmt.args(["--bin", "rustfmt", "--"]); - rustfmt.args(builder.config.args()); + cargo.args(["--bin", "rustfmt", "--"]); + cargo.args(builder.config.args()); - rustfmt.into_cmd().run(builder); + cargo.into_cmd().run(builder); } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index c28fe4ad832d3..fb45fcf5dcc42 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -579,6 +579,11 @@ impl Step for Rustfmt { let build_compiler = self.compilers.build_compiler(); let target = self.compilers.target(); + // FIXME(#156525): `compile::Sysroot::run` intentionally do not copy `rustc-dev` artifacts + // until they're requested with `builder.ensure(Rustc)`, relevant for `download-rustc` + // flows. + builder.ensure(compile::Rustc::new(build_compiler, target)); + let mut cargo = tool::prepare_tool_cargo( builder, build_compiler, @@ -941,6 +946,11 @@ impl Step for Clippy { let target_compiler = self.compilers.target_compiler(); let build_compiler = self.compilers.build_compiler(); + // FIXME(#156525): `compile::Sysroot::run` intentionally do not copy `rustc-dev` artifacts + // until they're requested with `builder.ensure(Rustc)`, relevant for `download-rustc` + // flows. + builder.ensure(compile::Rustc::new(build_compiler, target)); + let mut cargo = tool::prepare_tool_cargo( builder, build_compiler, diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index ed5c2586a5ed6..a75d5e4db8998 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -224,6 +224,12 @@ pub fn prepare_tool_cargo( // avoid rebuilding when running tests. cargo.env("SYSROOT", builder.sysroot(compiler)); + // Make sure we explicitly add rustc_private libs to path centrally here so that + // RustcPrivate tools can pick them up. + if mode == Mode::ToolRustcPrivate { + cargo.add_rustc_lib_path(builder); + } + // if tools are using lzma we want to force the build script to build its // own copy cargo.env("LZMA_API_STATIC", "1"); diff --git a/src/ci/scripts/free-disk-space-linux.sh b/src/ci/scripts/free-disk-space-linux.sh index 590e594e6aef4..167abf01ac880 100755 --- a/src/ci/scripts/free-disk-space-linux.sh +++ b/src/ci/scripts/free-disk-space-linux.sh @@ -277,6 +277,10 @@ cleanPackages() { fi WAIT_DPKG_LOCK="-o DPkg::Lock::Timeout=60" + # This update is intended to fix any broken state of the index and make + # sure it is fresh. Otherwise we've had problems with missing mirror + # entries. + sudo apt-get update -qq sudo apt-get ${WAIT_DPKG_LOCK} -qq remove -y --fix-missing "${packages[@]}" sudo apt-get ${WAIT_DPKG_LOCK} autoremove -y \ diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 901a7fd340afe..42845124eda50 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1089,7 +1089,13 @@ fn clean_fn_or_proc_macro<'tcx>( match macro_kind { Some(kind) => clean_proc_macro(item, name, kind, cx.tcx), None => { - let mut func = clean_function(cx, sig, generics, ParamsSrc::Body(body_id)); + let mut func = clean_function( + cx, + sig, + generics, + ParamsSrc::Body(body_id), + item.owner_id.to_def_id(), + ); clean_fn_decl_legacy_const_generics(&mut func, attrs); FunctionItem(func) } @@ -1127,18 +1133,30 @@ fn clean_function<'tcx>( sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'tcx>, params: ParamsSrc<'tcx>, + def_id: DefId, ) -> Box { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: Generics must be cleaned before params. let generics = clean_generics(generics, cx); - let params = match params { - ParamsSrc::Body(body_id) => clean_params_via_body(cx, sig.decl.inputs, body_id), - // Let's not perpetuate anon params from Rust 2015; use `_` for them. - ParamsSrc::Idents(idents) => clean_params(cx, sig.decl.inputs, idents, |ident| { - Some(ident.map_or(kw::Underscore, |ident| ident.name)) - }), + let decl = if sig.decl.opt_delegation_sig_id().is_some() { + // A delegation item (`reuse path::method`) has no resolved signature in the + // HIR: its inputs and return type are `InferDelegation` nodes that clean to + // `_`, and an `async` header over that inferred return type would panic in + // `sugared_async_return_type`. The resolved signature only exists on the ty + // side, so clean that instead, exactly like an inlined item. This both fixes + // the rendered `-> _` / `self: _` and makes the async sugaring well-defined. + let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); + clean_poly_fn_sig(cx, Some(def_id), sig) + } else { + let params = match params { + ParamsSrc::Body(body_id) => clean_params_via_body(cx, sig.decl.inputs, body_id), + // Let's not perpetuate anon params from Rust 2015; use `_` for them. + ParamsSrc::Idents(idents) => clean_params(cx, sig.decl.inputs, idents, |ident| { + Some(ident.map_or(kw::Underscore, |ident| ident.name)) + }), + }; + clean_fn_decl_with_params(cx, sig.decl, Some(&sig.header), params) }; - let decl = clean_fn_decl_with_params(cx, sig.decl, Some(&sig.header), params); (generics, decl) }); Box::new(Function { decl, generics }) @@ -1270,11 +1288,18 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext RequiredAssocConstItem(generics, Box::new(clean_ty(ty, cx))) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body)); + let m = + clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body), local_did); MethodItem(m, Defaultness::from_trait_item(trait_item.defaultness)) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => { - let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents)); + let m = clean_function( + cx, + sig, + trait_item.generics, + ParamsSrc::Idents(idents), + local_did, + ); RequiredMethodItem(m, Defaultness::from_trait_item(trait_item.defaultness)) } hir::TraitItemKind::Type(bounds, Some(default)) => { @@ -1315,7 +1340,7 @@ pub(crate) fn clean_impl_item<'tcx>( type_: clean_ty(ty, cx), })), hir::ImplItemKind::Fn(ref sig, body) => { - let m = clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body)); + let m = clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body), local_did); let defaultness = match impl_.impl_kind { hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final, hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness, @@ -3254,7 +3279,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( cx.with_param_env(def_id, |cx| { let kind = match item.kind { hir::ForeignItemKind::Fn(sig, idents, generics) => ForeignFunctionItem( - clean_function(cx, &sig, generics, ParamsSrc::Idents(idents)), + clean_function(cx, &sig, generics, ParamsSrc::Idents(idents), def_id), sig.header.safety(), ), hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem( diff --git a/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs b/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs new file mode 100644 index 0000000000000..77dab904fdbba --- /dev/null +++ b/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs @@ -0,0 +1,13 @@ +#![feature(c_variadic)] + +// While 1-ZST are currently ignored on most ABIs, we don't guarantee that, and it's UB to +// rely on it. + +fn main() { + unsafe extern "C" fn variadic(mut ap: ...) { + ap.next_arg::(); + ap.next_arg::(); //~ERROR: requested `i32` is incompatible with next argument of type `()` + } + + unsafe { variadic(0i32, (), 1i32) } +} diff --git a/src/tools/miri/tests/fail/c-variadic-ignored-argument.stderr b/src/tools/miri/tests/fail/c-variadic-ignored-argument.stderr new file mode 100644 index 0000000000000..6c1291611c4ae --- /dev/null +++ b/src/tools/miri/tests/fail/c-variadic-ignored-argument.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: va_arg type mismatch: requested `i32` is incompatible with next argument of type `()` + --> tests/fail/c-variadic-ignored-argument.rs:LL:CC + | +LL | ap.next_arg::(); + | ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: main::variadic + at tests/fail/c-variadic-ignored-argument.rs:LL:CC + 1: main + at tests/fail/c-variadic-ignored-argument.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs new file mode 100644 index 0000000000000..064b5a510f3ea --- /dev/null +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs @@ -0,0 +1,19 @@ +#![feature(fn_traits, unboxed_closures)] + +use std::mem::transmute; + +#[repr(align(4))] +struct Zst; + +fn foo(_: F) { + // Calls the given F FnOnce, but passing an over-aligned ZST instead of the closure / function item + let f = unsafe { transmute::(F::call_once) }; + f(Zst) +} + +fn main() { + foo(move || { + //~^ERROR: /calling a function whose parameter #1 has type .* passing argument of type Zst/ + println!("non-capturing closure"); + }); +} diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.stderr new file mode 100644 index 0000000000000..53a155b8f8c7b --- /dev/null +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.stderr @@ -0,0 +1,26 @@ +error: Undefined Behavior: calling a function whose parameter #1 has type {closure@tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC} passing argument of type Zst + --> tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + | +LL | foo(move || { + | _________^ +LL | | +LL | | println!("non-capturing closure"); +LL | | }); + | |_____^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets + = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::{closure#0} + at tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + 1: foo + at tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + 2: main + at tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/fn_arg_never_type.rs b/src/tools/miri/tests/fail/validity/fn_arg_never_type.rs new file mode 100644 index 0000000000000..a6ffb325191b0 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/fn_arg_never_type.rs @@ -0,0 +1,13 @@ +use std::mem::transmute; + +enum Never {} + +fn foo(x: Never) { //~ERROR: invalid value of type Never + let ptr = &raw const x; + println!("{ptr:p}"); +} + +fn main() { + let f = unsafe { transmute::(foo) }; + f(()); +} diff --git a/src/tools/miri/tests/fail/validity/fn_arg_never_type.stderr b/src/tools/miri/tests/fail/validity/fn_arg_never_type.stderr new file mode 100644 index 0000000000000..36ffcf24790a3 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/fn_arg_never_type.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: constructing invalid value of type Never: encountered a value of uninhabited type `Never` + --> tests/fail/validity/fn_arg_never_type.rs:LL:CC + | +LL | fn foo(x: Never) { + | ^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: foo + at tests/fail/validity/fn_arg_never_type.rs:LL:CC + 1: main + at tests/fail/validity/fn_arg_never_type.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs b/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs deleted file mode 100644 index fe09a03edfffc..0000000000000 --- a/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ ignore-target: windows # does not ignore ZST arguments -//@ ignore-target: powerpc # does not ignore ZST arguments -//@ ignore-target: s390x # does not ignore ZST arguments -//@ ignore-target: sparc # does not ignore ZST arguments -#![feature(c_variadic)] - -// Some platforms ignore ZSTs, meaning that the argument is not passed, even though it is part -// of the callee's ABI. Test that this doesn't trip any asserts. -// -// NOTE: this test only succeeds when the `()` argument uses `Passmode::Ignore`. For some targets, -// notably msvc, such arguments are not ignored, which would cause UB when attempting to read the -// second `i32` argument while the next item in the variable argument list is `()`. - -fn main() { - unsafe extern "C" fn variadic(mut ap: ...) { - ap.next_arg::(); - ap.next_arg::(); - } - - unsafe { variadic(0i32, (), 1i32) } -} diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs index 37795daa55c84..94cb5695fac50 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -151,4 +151,9 @@ fn main() { let rc = Rc::new(0); let rc_ptr: *mut i32 = unsafe { mem::transmute_copy(&rc) }; test_abi_compat(rc, rc_ptr); + + // Non-capturing closures are special because we rely on them being `PassMode::Ignore`. + // Make sure that does not break newtype wrapping for them. + let non_capturing_closure = || {}; + test_abi_compat(non_capturing_closure.clone(), Wrapper(non_capturing_closure)); } diff --git a/tests/rustdoc-html/async/async-fn-delegation.rs b/tests/rustdoc-html/async/async-fn-delegation.rs new file mode 100644 index 0000000000000..7d891ac8be637 --- /dev/null +++ b/tests/rustdoc-html/async/async-fn-delegation.rs @@ -0,0 +1,42 @@ +//@ edition: 2021 + +// Regression test for . +// +// rustdoc used to ICE with "unexpected async fn return type" when cleaning a +// delegated (`reuse`) async fn: the delegation's HIR signature is unresolved +// (`InferDelegation`), so its return type cleaned to `_` even though the header +// is `async`, and unconditionally sugaring that inferred type panicked. +// +// We now clean the resolved (ty-side) signature for delegation items, like we +// already do for inlined items. That both avoids the ICE and renders the real +// return type and `self` parameter instead of `-> _` / `self: _`. +// +// Note: the `` generic on the free-function variants is a pre-existing +// quirk of how delegation generics are rendered (plain sync delegation prints it +// too); it is tracked separately and is not what this test is about. + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![crate_name = "async_delegation"] + +pub trait Trait { + async fn unit(&self) {} + async fn nonunit(&self) -> i32 { + 0 + } +} + +//@ has async_delegation/fn.unit.html '//pre[@class="rust item-decl"]' 'pub async fn unit(&self)' +pub reuse Trait::unit; +//@ has async_delegation/fn.nonunit.html '//pre[@class="rust item-decl"]' 'pub async fn nonunit(&self) -> i32' +pub reuse Trait::nonunit; + +pub struct S; +impl Trait for S {} + +//@ has async_delegation/struct.S.html '//*[@class="code-header"]' 'pub async fn unit(self: &S)' +//@ has async_delegation/struct.S.html '//*[@class="code-header"]' 'pub async fn nonunit(self: &S) -> i32' +impl S { + pub reuse Trait::unit { self } + pub reuse Trait::nonunit { self } +}