diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 0520c9ac60c..21db7d0eebc 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -420,7 +420,15 @@ impl<'a> AstValidator<'a> { .iter() .flat_map(|i| i.attrs.as_ref()) .filter(|attr| { - let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn]; + let arr = [ + sym::allow, + sym::cfg, + sym::cfg_attr, + sym::deny, + sym::expect, + sym::forbid, + sym::warn, + ]; !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr) }) .for_each(|attr| { @@ -435,7 +443,7 @@ impl<'a> AstValidator<'a> { } else { self.err_handler().span_err( attr.span, - "allow, cfg, cfg_attr, deny, \ + "allow, cfg, cfg_attr, deny, expect, \ forbid, and warn are the only allowed built-in attributes in function parameters", ); } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 0ded6a421f5..75376cdc592 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -148,32 +148,15 @@ impl<'tcx> ReachableContext<'tcx> { hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) | hir::TraitItemKind::Type(..) => false, }, - Some(Node::ImplItem(impl_item)) => { - match impl_item.kind { - hir::ImplItemKind::Const(..) => true, - hir::ImplItemKind::Fn(..) => { - let attrs = self.tcx.codegen_fn_attrs(def_id); - let generics = self.tcx.generics_of(def_id); - if generics.requires_monomorphization(self.tcx) || attrs.requests_inline() { - true - } else { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let impl_did = self.tcx.hir().get_parent_item(hir_id); - // Check the impl. If the generics on the self - // type of the impl require inlining, this method - // does too. - match self.tcx.hir().expect_item(impl_did).kind { - hir::ItemKind::Impl { .. } => { - let generics = self.tcx.generics_of(impl_did); - generics.requires_monomorphization(self.tcx) - } - _ => false, - } - } - } - hir::ImplItemKind::TyAlias(_) => false, + Some(Node::ImplItem(impl_item)) => match impl_item.kind { + hir::ImplItemKind::Const(..) => true, + hir::ImplItemKind::Fn(..) => { + let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let impl_did = self.tcx.hir().get_parent_item(hir_id); + method_might_be_inlined(self.tcx, impl_item, impl_did) } - } + hir::ImplItemKind::TyAlias(_) => false, + }, Some(_) => false, None => false, // This will happen for default methods. } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index b83b0bf1ca5..f04f527ccb7 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -20,7 +20,7 @@ pub fn can_type_implement_copy<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, - cause: ObligationCause<'tcx>, + parent_cause: ObligationCause<'tcx>, ) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { @@ -59,7 +59,7 @@ pub fn can_type_implement_copy<'tcx>( .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did())) .has_param_types_or_consts() { - cause.clone() + parent_cause.clone() } else { ObligationCause::dummy_with_span(span) }; diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index c809b8bdd73..9f4e6a46d73 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -107,6 +107,10 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { for (field, ty) in fields { let field_span = tcx.def_span(field.did); + let field_ty_span = match tcx.hir().get_if_local(field.did) { + Some(hir::Node::Field(field_def)) => field_def.ty.span, + _ => field_span, + }; err.span_label(field_span, "this field does not implement `Copy`"); // Spin up a new FulfillmentContext, so we can get the _precise_ reason // why this field does not implement Copy. This is useful because sometimes @@ -119,7 +123,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { param_env, ty, tcx.lang_items().copy_trait().unwrap(), - traits::ObligationCause::dummy_with_span(field_span), + traits::ObligationCause::dummy_with_span(field_ty_span), ); for error in fulfill_cx.select_all_or_error(&infcx) { let error_predicate = error.obligation.predicate; diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 390030fa2b2..807c035fdbd 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -138,7 +138,11 @@ impl ThinBox { } } -/// A pointer to type-erased data, guaranteed to have a header `H` before the pointed-to location. +/// A pointer to type-erased data, guaranteed to either be: +/// 1. `NonNull::dangling()`, in the case where both the pointee (`T`) and +/// metadata (`H`) are ZSTs. +/// 2. A pointer to a valid `T` that has a header `H` directly before the +/// pointed-to location. struct WithHeader(NonNull, PhantomData); impl WithHeader { @@ -156,16 +160,27 @@ impl WithHeader { }; unsafe { - let ptr = alloc::alloc(layout); + // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so + // we use `layout.dangling()` for this case, which should have a valid + // alignment for both `T` and `H`. + let ptr = if layout.size() == 0 { + // Some paranoia checking, mostly so that the ThinBox tests are + // more able to catch issues. + debug_assert!( + value_offset == 0 && mem::size_of::() == 0 && mem::size_of::() == 0 + ); + layout.dangling() + } else { + let ptr = alloc::alloc(layout); + if ptr.is_null() { + alloc::handle_alloc_error(layout); + } + // Safety: + // - The size is at least `aligned_header_size`. + let ptr = ptr.add(value_offset) as *mut _; - if ptr.is_null() { - alloc::handle_alloc_error(layout); - } - // Safety: - // - The size is at least `aligned_header_size`. - let ptr = ptr.add(value_offset) as *mut _; - - let ptr = NonNull::new_unchecked(ptr); + NonNull::new_unchecked(ptr) + }; let result = WithHeader(ptr, PhantomData); ptr::write(result.header(), header); @@ -175,18 +190,28 @@ impl WithHeader { } } - // Safety: - // - Assumes that `value` can be dereferenced. + // Safety: + // - Assumes that either `value` can be dereferenced, or is the + // `NonNull::dangling()` we use when both `T` and `H` are ZSTs. unsafe fn drop(&self, value: *mut T) { unsafe { + let value_layout = Layout::for_value_raw(value); // SAFETY: Layout must have been computable if we're in drop - let (layout, value_offset) = - Self::alloc_layout(Layout::for_value_raw(value)).unwrap_unchecked(); + let (layout, value_offset) = Self::alloc_layout(value_layout).unwrap_unchecked(); - ptr::drop_in_place::(value); // We only drop the value because the Pointee trait requires that the metadata is copy - // aka trivially droppable - alloc::dealloc(self.0.as_ptr().sub(value_offset), layout); + // aka trivially droppable. + ptr::drop_in_place::(value); + + // Note: Don't deallocate if the layout size is zero, because the pointer + // didn't come from the allocator. + if layout.size() != 0 { + alloc::dealloc(self.0.as_ptr().sub(value_offset), layout); + } else { + debug_assert!( + value_offset == 0 && mem::size_of::() == 0 && value_layout.size() == 0 + ); + } } } @@ -198,7 +223,9 @@ impl WithHeader { // needed to align the header. Subtracting the header size from the aligned data pointer // will always result in an aligned header pointer, it just may not point to the // beginning of the allocation. - unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H } + let hp = unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H }; + debug_assert!(hp.is_aligned()); + hp } fn value(&self) -> *mut u8 { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 710a3985266..dbfe58056a5 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -169,6 +169,7 @@ #![feature(nll)] // Not necessary, but here to test the `nll` feature. #![feature(rustc_allow_const_fn_unstable)] #![feature(rustc_attrs)] +#![feature(pointer_is_aligned)] #![feature(slice_internals)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 601a87aa4ac..ffc7944ec7e 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -42,6 +42,9 @@ #![feature(panic_update_hook)] #![feature(slice_flatten)] #![feature(thin_box)] +#![feature(bench_black_box)] +#![feature(strict_provenance)] +#![feature(once_cell)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/thin_box.rs b/library/alloc/tests/thin_box.rs index 51d2e9324bf..70d1db8b457 100644 --- a/library/alloc/tests/thin_box.rs +++ b/library/alloc/tests/thin_box.rs @@ -1,3 +1,4 @@ +use core::fmt::Debug; use core::mem::size_of; use std::boxed::ThinBox; @@ -24,3 +25,231 @@ fn want_thin() { assert!(is_thin::<[i32]>()); assert!(is_thin::()); } + +#[track_caller] +fn verify_aligned(ptr: *const T) { + // Use `black_box` to attempt to obscure the fact that we're calling this + // function on pointers that come from box/references, which the compiler + // would otherwise realize is impossible (because it would mean we've + // already executed UB). + // + // That is, we'd *like* it to be possible for the asserts in this function + // to detect brokenness in the ThinBox impl. + // + // It would probably be better if we instead had these as debug_asserts + // inside `ThinBox`, prior to the point where we do the UB. Anyway, in + // practice these checks are mostly just smoke-detectors for an extremely + // broken `ThinBox` impl, since it's an extremely subtle piece of code. + let ptr = core::hint::black_box(ptr); + let align = core::mem::align_of::(); + assert!( + (ptr.addr() & (align - 1)) == 0 && !ptr.is_null(), + "misaligned ThinBox data; valid pointers to `{}` should be aligned to {align}: {ptr:p}", + core::any::type_name::(), + ); +} + +#[track_caller] +fn check_thin_sized(make: impl FnOnce() -> T) { + let value = make(); + let boxed = ThinBox::new(value.clone()); + let val = &*boxed; + verify_aligned(val as *const T); + assert_eq!(val, &value); +} + +#[track_caller] +fn check_thin_dyn(make: impl FnOnce() -> T) { + let value = make(); + let wanted_debug = format!("{value:?}"); + let boxed: ThinBox = ThinBox::new_unsize(value.clone()); + let val = &*boxed; + // wide reference -> wide pointer -> thin pointer + verify_aligned(val as *const dyn Debug as *const T); + let got_debug = format!("{val:?}"); + assert_eq!(wanted_debug, got_debug); +} + +macro_rules! define_test { + ( + @test_name: $testname:ident; + + $(#[$m:meta])* + struct $Type:ident($inner:ty); + + $($test_stmts:tt)* + ) => { + #[test] + fn $testname() { + use core::sync::atomic::{AtomicIsize, Ordering}; + // Define the type, and implement new/clone/drop in such a way that + // the number of live instances will be counted. + $(#[$m])* + #[derive(Debug, PartialEq)] + struct $Type { + _priv: $inner, + } + + impl Clone for $Type { + fn clone(&self) -> Self { + verify_aligned(self); + Self::new(self._priv.clone()) + } + } + + impl Drop for $Type { + fn drop(&mut self) { + verify_aligned(self); + Self::modify_live(-1); + } + } + + impl $Type { + fn new(i: $inner) -> Self { + Self::modify_live(1); + Self { _priv: i } + } + + fn modify_live(n: isize) -> isize { + static COUNTER: AtomicIsize = AtomicIsize::new(0); + COUNTER.fetch_add(n, Ordering::Relaxed) + n + } + + fn live_objects() -> isize { + Self::modify_live(0) + } + } + // Run the test statements + let _: () = { $($test_stmts)* }; + // Check that we didn't leak anything, or call drop too many times. + assert_eq!( + $Type::live_objects(), 0, + "Wrong number of drops of {}, `initializations - drops` should be 0.", + stringify!($Type), + ); + } + }; +} + +define_test! { + @test_name: align1zst; + struct Align1Zst(()); + + check_thin_sized(|| Align1Zst::new(())); + check_thin_dyn(|| Align1Zst::new(())); +} + +define_test! { + @test_name: align1small; + struct Align1Small(u8); + + check_thin_sized(|| Align1Small::new(50)); + check_thin_dyn(|| Align1Small::new(50)); +} + +define_test! { + @test_name: align1_size_not_pow2; + struct Align64NotPow2Size([u8; 79]); + + check_thin_sized(|| Align64NotPow2Size::new([100; 79])); + check_thin_dyn(|| Align64NotPow2Size::new([100; 79])); +} + +define_test! { + @test_name: align1big; + struct Align1Big([u8; 256]); + + check_thin_sized(|| Align1Big::new([5u8; 256])); + check_thin_dyn(|| Align1Big::new([5u8; 256])); +} + +// Note: `#[repr(align(2))]` is worth testing because +// - can have pointers which are misaligned, unlike align(1) +// - is still expected to have an alignment less than the alignment of a vtable. +define_test! { + @test_name: align2zst; + #[repr(align(2))] + struct Align2Zst(()); + + check_thin_sized(|| Align2Zst::new(())); + check_thin_dyn(|| Align2Zst::new(())); +} + +define_test! { + @test_name: align2small; + #[repr(align(2))] + struct Align2Small(u8); + + check_thin_sized(|| Align2Small::new(60)); + check_thin_dyn(|| Align2Small::new(60)); +} + +define_test! { + @test_name: align2full; + #[repr(align(2))] + struct Align2Full([u8; 2]); + check_thin_sized(|| Align2Full::new([3u8; 2])); + check_thin_dyn(|| Align2Full::new([3u8; 2])); +} + +define_test! { + @test_name: align2_size_not_pow2; + #[repr(align(2))] + struct Align2NotPower2Size([u8; 6]); + + check_thin_sized(|| Align2NotPower2Size::new([3; 6])); + check_thin_dyn(|| Align2NotPower2Size::new([3; 6])); +} + +define_test! { + @test_name: align2big; + #[repr(align(2))] + struct Align2Big([u8; 256]); + + check_thin_sized(|| Align2Big::new([5u8; 256])); + check_thin_dyn(|| Align2Big::new([5u8; 256])); +} + +define_test! { + @test_name: align64zst; + #[repr(align(64))] + struct Align64Zst(()); + + check_thin_sized(|| Align64Zst::new(())); + check_thin_dyn(|| Align64Zst::new(())); +} + +define_test! { + @test_name: align64small; + #[repr(align(64))] + struct Align64Small(u8); + + check_thin_sized(|| Align64Small::new(50)); + check_thin_dyn(|| Align64Small::new(50)); +} + +define_test! { + @test_name: align64med; + #[repr(align(64))] + struct Align64Med([u8; 64]); + check_thin_sized(|| Align64Med::new([10; 64])); + check_thin_dyn(|| Align64Med::new([10; 64])); +} + +define_test! { + @test_name: align64_size_not_pow2; + #[repr(align(64))] + struct Align64NotPow2Size([u8; 192]); + + check_thin_sized(|| Align64NotPow2Size::new([10; 192])); + check_thin_dyn(|| Align64NotPow2Size::new([10; 192])); +} + +define_test! { + @test_name: align64big; + #[repr(align(64))] + struct Align64Big([u8; 256]); + + check_thin_sized(|| Align64Big::new([10; 256])); + check_thin_dyn(|| Align64Big::new([10; 256])); +} diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs index f6083530005..46f45b19771 100644 --- a/library/std/src/sys/hermit/condvar.rs +++ b/library/std/src/sys/hermit/condvar.rs @@ -70,9 +70,13 @@ impl Condvar { mutex.lock(); res == 0 } +} - pub unsafe fn destroy(&self) { - let _ = abi::sem_destroy(self.sem1); - let _ = abi::sem_destroy(self.sem2); +impl Drop for Condvar { + fn drop(&mut self) { + unsafe { + let _ = abi::sem_destroy(self.sem1); + let _ = abi::sem_destroy(self.sem2); + } } } diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index 97b4c49896f..ef44bf411fb 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -215,7 +215,4 @@ impl Mutex { } guard.locked } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs index 690bb155e1a..d43fa08a171 100644 --- a/library/std/src/sys/hermit/rwlock.rs +++ b/library/std/src/sys/hermit/rwlock.rs @@ -84,12 +84,6 @@ impl RwLock { // FIXME: should only wake up one of these some of the time self.cond.notify_all(); } - - #[inline] - pub unsafe fn destroy(&self) { - self.lock.destroy(); - self.cond.destroy(); - } } impl State { diff --git a/library/std/src/sys/itron/condvar.rs b/library/std/src/sys/itron/condvar.rs index ed26c528027..008cd8fb1e3 100644 --- a/library/std/src/sys/itron/condvar.rs +++ b/library/std/src/sys/itron/condvar.rs @@ -117,8 +117,6 @@ impl Condvar { unsafe { mutex.lock() }; success } - - pub unsafe fn destroy(&self) {} } mod waiter_queue { diff --git a/library/std/src/sys/itron/mutex.rs b/library/std/src/sys/itron/mutex.rs index 5ee231882bb..2ba8454ff92 100644 --- a/library/std/src/sys/itron/mutex.rs +++ b/library/std/src/sys/itron/mutex.rs @@ -64,8 +64,10 @@ impl Mutex { } } } +} - pub unsafe fn destroy(&self) { +impl Drop for Mutex { + fn drop(&mut self) { if let Some(mtx) = self.mtx.get().map(|x| x.0) { expect_success_aborting(unsafe { abi::del_mtx(mtx) }, &"del_mtx"); } diff --git a/library/std/src/sys/sgx/condvar.rs b/library/std/src/sys/sgx/condvar.rs index c9736880b08..36534e0eff3 100644 --- a/library/std/src/sys/sgx/condvar.rs +++ b/library/std/src/sys/sgx/condvar.rs @@ -1,4 +1,5 @@ use crate::sys::locks::Mutex; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::time::Duration; use super::waitqueue::{SpinMutex, WaitQueue, WaitVariable}; @@ -7,16 +8,19 @@ pub struct Condvar { inner: SpinMutex>, } -pub type MovableCondvar = Box; +pub(crate) type MovableCondvar = LazyBox; + +impl LazyInit for Condvar { + fn init() -> Box { + Box::new(Self::new()) + } +} impl Condvar { pub const fn new() -> Condvar { Condvar { inner: SpinMutex::new(WaitVariable::new(())) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn notify_one(&self) { let _ = WaitQueue::notify_one(self.inner.lock()); @@ -38,7 +42,4 @@ impl Condvar { unsafe { mutex.lock() }; success } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/sgx/mutex.rs b/library/std/src/sys/sgx/mutex.rs index 98a390c4c2b..513cd77fd2a 100644 --- a/library/std/src/sys/sgx/mutex.rs +++ b/library/std/src/sys/sgx/mutex.rs @@ -1,11 +1,18 @@ use super::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable}; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; pub struct Mutex { inner: SpinMutex>, } // not movable: see UnsafeList implementation -pub type MovableMutex = Box; +pub(crate) type MovableMutex = LazyBox; + +impl LazyInit for Mutex { + fn init() -> Box { + Box::new(Self::new()) + } +} // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28 impl Mutex { @@ -52,7 +59,4 @@ impl Mutex { true } } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/sgx/rwlock.rs b/library/std/src/sys/sgx/rwlock.rs index 47be4c006ec..a97fb9ab026 100644 --- a/library/std/src/sys/sgx/rwlock.rs +++ b/library/std/src/sys/sgx/rwlock.rs @@ -2,6 +2,7 @@ mod tests; use crate::num::NonZeroUsize; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use super::waitqueue::{ try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable, @@ -13,7 +14,13 @@ pub struct RwLock { writer: SpinMutex>, } -pub type MovableRwLock = Box; +pub(crate) type MovableRwLock = LazyBox; + +impl LazyInit for RwLock { + fn init() -> Box { + Box::new(Self::new()) + } +} // Check at compile time that RwLock size matches C definition (see test_c_rwlock_initializer below) // @@ -168,9 +175,6 @@ impl RwLock { unsafe { self.__read_unlock(rguard, wguard) }; } } - - #[inline] - pub unsafe fn destroy(&self) {} } // The following functions are needed by libunwind. These symbols are named diff --git a/library/std/src/sys/solid/rwlock.rs b/library/std/src/sys/solid/rwlock.rs index df16cc680ad..433abc895f5 100644 --- a/library/std/src/sys/solid/rwlock.rs +++ b/library/std/src/sys/solid/rwlock.rs @@ -82,9 +82,11 @@ impl RwLock { let rwl = self.raw(); expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl"); } +} +impl Drop for RwLock { #[inline] - pub unsafe fn destroy(&self) { + fn drop(&mut self) { if let Some(rwl) = self.rwl.get().map(|x| x.0) { expect_success_aborting(unsafe { abi::rwl_del_rwl(rwl) }, &"rwl_del_rwl"); } diff --git a/library/std/src/sys/unix/locks/futex.rs b/library/std/src/sys/unix/locks/futex.rs index 7a63af1ad7c..a9a1a32c5af 100644 --- a/library/std/src/sys/unix/locks/futex.rs +++ b/library/std/src/sys/unix/locks/futex.rs @@ -24,9 +24,6 @@ impl Mutex { #[inline] pub unsafe fn init(&mut self) {} - #[inline] - pub unsafe fn destroy(&self) {} - #[inline] pub unsafe fn try_lock(&self) -> bool { self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok() @@ -118,12 +115,6 @@ impl Condvar { Self { futex: AtomicU32::new(0) } } - #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] - pub unsafe fn destroy(&self) {} - // All the memory orderings here are `Relaxed`, // because synchronization is done by unlocking and locking the mutex. diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs index 5ff1aba7974..1f902f50587 100644 --- a/library/std/src/sys/unix/locks/futex_rwlock.rs +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -63,9 +63,6 @@ impl RwLock { Self { state: AtomicU32::new(0), writer_notify: AtomicU32::new(0) } } - #[inline] - pub unsafe fn destroy(&self) {} - #[inline] pub unsafe fn try_read(&self) -> bool { self.state diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs index 04c5c489fc9..03400efa3c9 100644 --- a/library/std/src/sys/unix/locks/mod.rs +++ b/library/std/src/sys/unix/locks/mod.rs @@ -9,14 +9,14 @@ cfg_if::cfg_if! { ))] { mod futex; mod futex_rwlock; - pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar}; - pub use futex_rwlock::{RwLock, MovableRwLock}; + pub(crate) use futex::{Mutex, MovableMutex, MovableCondvar}; + pub(crate) use futex_rwlock::{RwLock, MovableRwLock}; } else { mod pthread_mutex; mod pthread_rwlock; mod pthread_condvar; - pub use pthread_mutex::{Mutex, MovableMutex}; - pub use pthread_rwlock::{RwLock, MovableRwLock}; - pub use pthread_condvar::{Condvar, MovableCondvar}; + pub(crate) use pthread_mutex::{Mutex, MovableMutex}; + pub(crate) use pthread_rwlock::{RwLock, MovableRwLock}; + pub(crate) use pthread_condvar::MovableCondvar; } } diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs index 099aa68706f..61c28d696bc 100644 --- a/library/std/src/sys/unix/locks/pthread_condvar.rs +++ b/library/std/src/sys/unix/locks/pthread_condvar.rs @@ -1,12 +1,13 @@ use crate::cell::UnsafeCell; use crate::sys::locks::{pthread_mutex, Mutex}; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::time::Duration; pub struct Condvar { inner: UnsafeCell, } -pub type MovableCondvar = Box; +pub(crate) type MovableCondvar = LazyBox; unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} @@ -18,6 +19,14 @@ fn saturating_cast_to_time_t(value: u64) -> libc::time_t { if value > ::MAX as u64 { ::MAX } else { value as libc::time_t } } +impl LazyInit for Condvar { + fn init() -> Box { + let mut condvar = Box::new(Self::new()); + unsafe { condvar.init() }; + condvar + } +} + impl Condvar { pub const fn new() -> Condvar { // Might be moved and address is changing it is better to avoid @@ -32,14 +41,14 @@ impl Condvar { target_os = "android", target_os = "redox" ))] - pub unsafe fn init(&mut self) {} + unsafe fn init(&mut self) {} // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet // So on that platform, init() should always be called // Moreover, that platform does not have pthread_condattr_setclock support, // hence that initialization should be skipped as well #[cfg(target_os = "espidf")] - pub unsafe fn init(&mut self) { + unsafe fn init(&mut self) { let r = libc::pthread_cond_init(self.inner.get(), crate::ptr::null()); assert_eq!(r, 0); } @@ -52,7 +61,7 @@ impl Condvar { target_os = "redox", target_os = "espidf" )))] - pub unsafe fn init(&mut self) { + unsafe fn init(&mut self) { use crate::mem::MaybeUninit; let mut attr = MaybeUninit::::uninit(); let r = libc::pthread_condattr_init(attr.as_mut_ptr()); @@ -179,14 +188,14 @@ impl Condvar { #[inline] #[cfg(not(target_os = "dragonfly"))] - pub unsafe fn destroy(&self) { + unsafe fn destroy(&mut self) { let r = libc::pthread_cond_destroy(self.inner.get()); debug_assert_eq!(r, 0); } #[inline] #[cfg(target_os = "dragonfly")] - pub unsafe fn destroy(&self) { + unsafe fn destroy(&mut self) { let r = libc::pthread_cond_destroy(self.inner.get()); // On DragonFly pthread_cond_destroy() returns EINVAL if called on // a condvar that was just initialized with @@ -195,3 +204,10 @@ impl Condvar { debug_assert!(r == 0 || r == libc::EINVAL); } } + +impl Drop for Condvar { + #[inline] + fn drop(&mut self) { + unsafe { self.destroy() }; + } +} diff --git a/library/std/src/sys/unix/locks/pthread_mutex.rs b/library/std/src/sys/unix/locks/pthread_mutex.rs index 76840ce74dd..916e898d890 100644 --- a/library/std/src/sys/unix/locks/pthread_mutex.rs +++ b/library/std/src/sys/unix/locks/pthread_mutex.rs @@ -1,12 +1,13 @@ use crate::cell::UnsafeCell; use crate::mem::MaybeUninit; use crate::sys::cvt_nz; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; pub struct Mutex { inner: UnsafeCell, } -pub type MovableMutex = Box; +pub(crate) type MovableMutex = LazyBox; #[inline] pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { @@ -16,6 +17,14 @@ pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} +impl LazyInit for Mutex { + fn init() -> Box { + let mut mutex = Box::new(Self::new()); + unsafe { mutex.init() }; + mutex + } +} + impl Mutex { pub const fn new() -> Mutex { // Might be moved to a different address, so it is better to avoid @@ -73,13 +82,13 @@ impl Mutex { } #[inline] #[cfg(not(target_os = "dragonfly"))] - pub unsafe fn destroy(&self) { + unsafe fn destroy(&mut self) { let r = libc::pthread_mutex_destroy(self.inner.get()); debug_assert_eq!(r, 0); } #[inline] #[cfg(target_os = "dragonfly")] - pub unsafe fn destroy(&self) { + unsafe fn destroy(&mut self) { let r = libc::pthread_mutex_destroy(self.inner.get()); // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. @@ -89,6 +98,13 @@ impl Mutex { } } +impl Drop for Mutex { + #[inline] + fn drop(&mut self) { + unsafe { self.destroy() }; + } +} + pub(super) struct PthreadMutexAttr<'a>(pub &'a mut MaybeUninit); impl Drop for PthreadMutexAttr<'_> { diff --git a/library/std/src/sys/unix/locks/pthread_rwlock.rs b/library/std/src/sys/unix/locks/pthread_rwlock.rs index 11a0c0457cd..75e5759c787 100644 --- a/library/std/src/sys/unix/locks/pthread_rwlock.rs +++ b/library/std/src/sys/unix/locks/pthread_rwlock.rs @@ -1,5 +1,6 @@ use crate::cell::UnsafeCell; use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; pub struct RwLock { inner: UnsafeCell, @@ -7,11 +8,17 @@ pub struct RwLock { num_readers: AtomicUsize, } -pub type MovableRwLock = Box; +pub(crate) type MovableRwLock = LazyBox; unsafe impl Send for RwLock {} unsafe impl Sync for RwLock {} +impl LazyInit for RwLock { + fn init() -> Box { + Box::new(Self::new()) + } +} + impl RwLock { pub const fn new() -> RwLock { RwLock { @@ -128,7 +135,7 @@ impl RwLock { self.raw_unlock(); } #[inline] - pub unsafe fn destroy(&self) { + unsafe fn destroy(&mut self) { let r = libc::pthread_rwlock_destroy(self.inner.get()); // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a // rwlock that was just initialized with @@ -141,3 +148,10 @@ impl RwLock { } } } + +impl Drop for RwLock { + #[inline] + fn drop(&mut self) { + unsafe { self.destroy() }; + } +} diff --git a/library/std/src/sys/unsupported/locks/condvar.rs b/library/std/src/sys/unsupported/locks/condvar.rs index 8dbe03bad9b..f27bf2b26bd 100644 --- a/library/std/src/sys/unsupported/locks/condvar.rs +++ b/library/std/src/sys/unsupported/locks/condvar.rs @@ -10,9 +10,6 @@ impl Condvar { Condvar {} } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn notify_one(&self) {} @@ -26,7 +23,4 @@ impl Condvar { pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { panic!("condvar wait not supported"); } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/unsupported/locks/mutex.rs b/library/std/src/sys/unsupported/locks/mutex.rs index cad991aae5e..56bad71b189 100644 --- a/library/std/src/sys/unsupported/locks/mutex.rs +++ b/library/std/src/sys/unsupported/locks/mutex.rs @@ -32,7 +32,4 @@ impl Mutex { pub unsafe fn try_lock(&self) -> bool { self.locked.replace(true) == false } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/unsupported/locks/rwlock.rs b/library/std/src/sys/unsupported/locks/rwlock.rs index 14fd351314c..bf6e2d3d080 100644 --- a/library/std/src/sys/unsupported/locks/rwlock.rs +++ b/library/std/src/sys/unsupported/locks/rwlock.rs @@ -62,7 +62,4 @@ impl RwLock { pub unsafe fn write_unlock(&self) { assert_eq!(self.mode.replace(0), -1); } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 9992e44b0e7..55b5ad314da 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -54,8 +54,8 @@ cfg_if::cfg_if! { #![allow(unsafe_op_in_unsafe_fn)] mod futex; mod futex_rwlock; - pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar}; - pub use futex_rwlock::{RwLock, MovableRwLock}; + pub(crate) use futex::{Mutex, MovableMutex, Condvar, MovableCondvar}; + pub(crate) use futex_rwlock::{RwLock, MovableRwLock}; } #[path = "atomics/futex.rs"] pub mod futex; diff --git a/library/std/src/sys/windows/locks/condvar.rs b/library/std/src/sys/windows/locks/condvar.rs index dfd8cfdceee..59e2c1be0f0 100644 --- a/library/std/src/sys/windows/locks/condvar.rs +++ b/library/std/src/sys/windows/locks/condvar.rs @@ -18,9 +18,6 @@ impl Condvar { Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { let r = c::SleepConditionVariableSRW(self.inner.get(), mutex::raw(mutex), c::INFINITE, 0); @@ -51,8 +48,4 @@ impl Condvar { pub unsafe fn notify_all(&self) { c::WakeAllConditionVariable(self.inner.get()) } - - pub unsafe fn destroy(&self) { - // ... - } } diff --git a/library/std/src/sys/windows/locks/mutex.rs b/library/std/src/sys/windows/locks/mutex.rs index 9fa280b8b76..08f55844a0e 100644 --- a/library/std/src/sys/windows/locks/mutex.rs +++ b/library/std/src/sys/windows/locks/mutex.rs @@ -53,9 +53,4 @@ impl Mutex { pub unsafe fn unlock(&self) { c::ReleaseSRWLockExclusive(raw(self)); } - - #[inline] - pub unsafe fn destroy(&self) { - // SRWLock does not need to be destroyed. - } } diff --git a/library/std/src/sys/windows/locks/rwlock.rs b/library/std/src/sys/windows/locks/rwlock.rs index 12906652e0b..a32df85e2f6 100644 --- a/library/std/src/sys/windows/locks/rwlock.rs +++ b/library/std/src/sys/windows/locks/rwlock.rs @@ -38,9 +38,4 @@ impl RwLock { pub unsafe fn write_unlock(&self) { c::ReleaseSRWLockExclusive(self.inner.get()) } - - #[inline] - pub unsafe fn destroy(&self) { - // ... - } } diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs index 67d4b126209..1def0518e0a 100644 --- a/library/std/src/sys_common/condvar.rs +++ b/library/std/src/sys_common/condvar.rs @@ -15,9 +15,7 @@ pub struct Condvar { impl Condvar { /// Creates a new condition variable for use. pub fn new() -> Self { - let mut c = imp::MovableCondvar::from(imp::Condvar::new()); - unsafe { c.init() }; - Self { inner: c, check: CondvarCheck::new() } + Self { inner: imp::MovableCondvar::new(), check: CondvarCheck::new() } } /// Signals one waiter on this condition variable to wake up. @@ -55,9 +53,3 @@ impl Condvar { self.inner.wait_timeout(mutex.raw(), dur) } } - -impl Drop for Condvar { - fn drop(&mut self) { - unsafe { self.inner.destroy() }; - } -} diff --git a/library/std/src/sys_common/condvar/check.rs b/library/std/src/sys_common/condvar/check.rs index d0d0d596518..ce8f3670487 100644 --- a/library/std/src/sys_common/condvar/check.rs +++ b/library/std/src/sys_common/condvar/check.rs @@ -1,6 +1,7 @@ use crate::ptr; use crate::sync::atomic::{AtomicPtr, Ordering}; use crate::sys::locks as imp; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::sys_common::mutex::MovableMutex; pub trait CondvarCheck { @@ -9,7 +10,7 @@ pub trait CondvarCheck { /// For boxed mutexes, a `Condvar` will check it's only ever used with the same /// mutex, based on its (stable) address. -impl CondvarCheck for Box { +impl CondvarCheck for LazyBox { type Check = SameMutexCheck; } diff --git a/library/std/src/sys_common/lazy_box.rs b/library/std/src/sys_common/lazy_box.rs new file mode 100644 index 00000000000..647c13d2437 --- /dev/null +++ b/library/std/src/sys_common/lazy_box.rs @@ -0,0 +1,77 @@ +#![allow(dead_code)] // Only used on some platforms. + +// This is used to wrap pthread {Mutex, Condvar, RwLock} in. + +use crate::marker::PhantomData; +use crate::ops::{Deref, DerefMut}; +use crate::ptr::null_mut; +use crate::sync::atomic::{ + AtomicPtr, + Ordering::{AcqRel, Acquire}, +}; + +pub(crate) struct LazyBox { + ptr: AtomicPtr, + _phantom: PhantomData, +} + +pub(crate) trait LazyInit { + /// This is called before the box is allocated, to provide the value to + /// move into the new box. + /// + /// It might be called more than once per LazyBox, as multiple threads + /// might race to initialize it concurrently, each constructing and initializing + /// their own box. (All but one of them will be destroyed right after.) + fn init() -> Box; +} + +impl LazyBox { + #[inline] + pub const fn new() -> Self { + Self { ptr: AtomicPtr::new(null_mut()), _phantom: PhantomData } + } + + #[inline] + fn get_pointer(&self) -> *mut T { + let ptr = self.ptr.load(Acquire); + if ptr.is_null() { self.initialize() } else { ptr } + } + + #[cold] + fn initialize(&self) -> *mut T { + let new_ptr = Box::into_raw(T::init()); + match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) { + Ok(_) => new_ptr, + Err(ptr) => { + // Lost the race to another thread. + // Drop the box we created, and use the one from the other thread instead. + drop(unsafe { Box::from_raw(new_ptr) }); + ptr + } + } + } +} + +impl Deref for LazyBox { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.get_pointer() } + } +} + +impl DerefMut for LazyBox { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.get_pointer() } + } +} + +impl Drop for LazyBox { + fn drop(&mut self) { + let ptr = *self.ptr.get_mut(); + if !ptr.is_null() { + drop(unsafe { Box::from_raw(ptr) }); + } + } +} diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 804727fbc54..80f56bf7522 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -24,6 +24,7 @@ pub mod backtrace; pub mod condvar; pub mod fs; pub mod io; +pub mod lazy_box; pub mod memchr; pub mod mutex; pub mod process; diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index 12a09c98605..36ea888d8de 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -61,9 +61,7 @@ unsafe impl Sync for MovableMutex {} impl MovableMutex { /// Creates a new mutex. pub fn new() -> Self { - let mut mutex = imp::MovableMutex::from(imp::Mutex::new()); - unsafe { mutex.init() }; - Self(mutex) + Self(imp::MovableMutex::new()) } pub(super) fn raw(&self) -> &imp::Mutex { @@ -92,9 +90,3 @@ impl MovableMutex { self.0.unlock() } } - -impl Drop for MovableMutex { - fn drop(&mut self) { - unsafe { self.0.destroy() }; - } -} diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 8f252308de7..8921af311d4 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -168,13 +168,6 @@ impl ReentrantMutex { } } -impl Drop for ReentrantMutex { - fn drop(&mut self) { - // Safety: We're the unique owner of this mutex and not going to use it afterwards. - unsafe { self.mutex.destroy() } - } -} - impl Deref for ReentrantMutexGuard<'_, T> { type Target = T; diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs index 12e7a72a344..abc9fd561f1 100644 --- a/library/std/src/sys_common/rwlock.rs +++ b/library/std/src/sys_common/rwlock.rs @@ -74,7 +74,7 @@ pub struct MovableRwLock(imp::MovableRwLock); impl MovableRwLock { /// Creates a new reader-writer lock for use. pub fn new() -> Self { - Self(imp::MovableRwLock::from(imp::RwLock::new())) + Self(imp::MovableRwLock::new()) } /// Acquires shared access to the underlying lock, blocking the current @@ -126,9 +126,3 @@ impl MovableRwLock { self.0.write_unlock() } } - -impl Drop for MovableRwLock { - fn drop(&mut self) { - unsafe { self.0.destroy() }; - } -} diff --git a/src/test/ui/attributes/attrs-on-params.rs b/src/test/ui/attributes/attrs-on-params.rs index 0e606eac1e8..158a4500bde 100644 --- a/src/test/ui/attributes/attrs-on-params.rs +++ b/src/test/ui/attributes/attrs-on-params.rs @@ -2,7 +2,7 @@ fn function(#[inline] param: u32) { //~^ ERROR attribute should be applied to function or closure - //~| ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes + //~| ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes } fn main() {} diff --git a/src/test/ui/attributes/attrs-on-params.stderr b/src/test/ui/attributes/attrs-on-params.stderr index 003f43d371a..306e862cb58 100644 --- a/src/test/ui/attributes/attrs-on-params.stderr +++ b/src/test/ui/attributes/attrs-on-params.stderr @@ -1,4 +1,4 @@ -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/attrs-on-params.rs:3:13 | LL | fn function(#[inline] param: u32) { diff --git a/src/test/ui/codegen/auxiliary/issue-97708-aux.rs b/src/test/ui/codegen/auxiliary/issue-97708-aux.rs new file mode 100644 index 00000000000..e296bd39113 --- /dev/null +++ b/src/test/ui/codegen/auxiliary/issue-97708-aux.rs @@ -0,0 +1,41 @@ +use std::{ptr::NonNull, task::Poll}; + +struct TaskRef; + +struct Header { + vtable: &'static Vtable, +} + +struct Vtable { + poll: unsafe fn(TaskRef) -> Poll<()>, + deallocate: unsafe fn(NonNull
), +} + +// in the "Header" type, which is a private type in maitake +impl Header { + pub(crate) const fn new_stub() -> Self { + unsafe fn nop(_ptr: TaskRef) -> Poll<()> { + Poll::Pending + } + + unsafe fn nop_deallocate(ptr: NonNull
) { + unreachable!("stub task ({ptr:p}) should never be deallocated!"); + } + + Self { vtable: &Vtable { poll: nop, deallocate: nop_deallocate } } + } +} + +// This is a public type in `maitake` +#[repr(transparent)] +#[cfg_attr(loom, allow(dead_code))] +pub struct TaskStub { + hdr: Header, +} + +impl TaskStub { + /// Create a new unique stub [`Task`]. + pub const fn new() -> Self { + Self { hdr: Header::new_stub() } + } +} diff --git a/src/test/ui/codegen/issue-97708.rs b/src/test/ui/codegen/issue-97708.rs new file mode 100644 index 00000000000..8cb28e9f1f6 --- /dev/null +++ b/src/test/ui/codegen/issue-97708.rs @@ -0,0 +1,9 @@ +// build-pass +// aux-build:issue-97708-aux.rs + +extern crate issue_97708_aux; +use issue_97708_aux::TaskStub; + +static TASK_STUB: TaskStub = TaskStub::new(); + +fn main() {} diff --git a/src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.rs b/src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.rs new file mode 100644 index 00000000000..5fdb710416f --- /dev/null +++ b/src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.rs @@ -0,0 +1,15 @@ +// check-pass +#![feature(lint_reasons)] + +#[warn(unused_variables)] + +/// This should catch the unused_variables lint and not emit anything +fn check_fulfilled_expectation(#[expect(unused_variables)] unused_value: u32) {} + +fn check_unfulfilled_expectation(#[expect(unused_variables)] used_value: u32) { + //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] + //~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default + println!("I use the value {used_value}"); +} + +fn main() {} diff --git a/src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.stderr b/src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.stderr new file mode 100644 index 00000000000..69f7cda08ef --- /dev/null +++ b/src/test/ui/lint/rfc-2383-lint-reason/expect_on_fn_params.stderr @@ -0,0 +1,10 @@ +warning: this lint expectation is unfulfilled + --> $DIR/expect_on_fn_params.rs:9:43 + | +LL | fn check_unfulfilled_expectation(#[expect(unused_variables)] used_value: u32) { + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unfulfilled_lint_expectations)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs index 6403b3f55c4..151659e35c0 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs @@ -7,11 +7,11 @@ extern "C" { /// Bar //~^ ERROR documentation comments cannot be applied to function #[must_use] - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters /// Baz //~^ ERROR documentation comments cannot be applied to function #[no_mangle] b: i32, - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters ); } @@ -23,11 +23,11 @@ type FnType = fn( /// Bar //~^ ERROR documentation comments cannot be applied to function #[must_use] - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters /// Baz //~^ ERROR documentation comments cannot be applied to function #[no_mangle] b: i32, - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters ); pub fn foo( @@ -38,11 +38,11 @@ pub fn foo( /// Bar //~^ ERROR documentation comments cannot be applied to function #[must_use] - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters /// Baz //~^ ERROR documentation comments cannot be applied to function #[no_mangle] b: i32, - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters ) {} struct SelfStruct {} @@ -58,11 +58,11 @@ impl SelfStruct { /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters /// Qux //~^ ERROR documentation comments cannot be applied to function #[no_mangle] b: i32, - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters ) {} fn issue_64682_associated_fn( @@ -73,11 +73,11 @@ impl SelfStruct { /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters /// Qux //~^ ERROR documentation comments cannot be applied to function #[no_mangle] b: i32, - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters ) {} } @@ -94,11 +94,11 @@ impl RefStruct { /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters /// Qux //~^ ERROR documentation comments cannot be applied to function #[no_mangle] b: i32, - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters ) {} } trait RefTrait { @@ -113,11 +113,11 @@ trait RefTrait { /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters /// Qux //~^ ERROR documentation comments cannot be applied to function #[no_mangle] b: i32, - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters ) {} fn issue_64682_associated_fn( @@ -128,11 +128,11 @@ trait RefTrait { /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters /// Qux //~^ ERROR documentation comments cannot be applied to function #[no_mangle] b: i32, - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters ) {} } @@ -148,11 +148,11 @@ impl RefTrait for RefStruct { /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters /// Qux //~^ ERROR documentation comments cannot be applied to function #[no_mangle] b: i32, - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters ) {} } @@ -165,10 +165,10 @@ fn main() { /// Bar //~^ ERROR documentation comments cannot be applied to function #[must_use] - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters /// Baz //~^ ERROR documentation comments cannot be applied to function #[no_mangle] b: i32 - //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters | {}; } diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr index edca8cea68d..7573e39d8eb 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr @@ -70,7 +70,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Bar | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:9:9 | LL | #[must_use] @@ -82,7 +82,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Baz | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:13:9 | LL | #[no_mangle] b: i32, @@ -100,7 +100,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Bar | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:25:5 | LL | #[must_use] @@ -112,7 +112,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Baz | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:29:5 | LL | #[no_mangle] b: i32, @@ -130,7 +130,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Bar | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:40:5 | LL | #[must_use] @@ -142,7 +142,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Baz | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:44:5 | LL | #[no_mangle] b: i32, @@ -166,7 +166,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Baz | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:60:9 | LL | #[must_use] @@ -178,7 +178,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Qux | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:64:9 | LL | #[no_mangle] b: i32, @@ -196,7 +196,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Baz | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:75:9 | LL | #[must_use] @@ -208,7 +208,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Qux | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:79:9 | LL | #[no_mangle] b: i32, @@ -232,7 +232,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Baz | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:96:9 | LL | #[must_use] @@ -244,7 +244,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Qux | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:100:9 | LL | #[no_mangle] b: i32, @@ -268,7 +268,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Baz | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:115:9 | LL | #[must_use] @@ -280,7 +280,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Qux | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:119:9 | LL | #[no_mangle] b: i32, @@ -298,7 +298,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Baz | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:130:9 | LL | #[must_use] @@ -310,7 +310,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Qux | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:134:9 | LL | #[no_mangle] b: i32, @@ -334,7 +334,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Baz | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:150:9 | LL | #[must_use] @@ -346,7 +346,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Qux | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:154:9 | LL | #[no_mangle] b: i32, @@ -364,7 +364,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Bar | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:167:9 | LL | #[must_use] @@ -376,7 +376,7 @@ error: documentation comments cannot be applied to function parameters LL | /// Baz | ^^^^^^^ doc comments are not allowed here -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/param-attrs-builtin-attrs.rs:171:9 | LL | #[no_mangle] b: i32 diff --git a/src/test/ui/rustdoc/check-doc-alias-attr-location.stderr b/src/test/ui/rustdoc/check-doc-alias-attr-location.stderr index 2b25882be21..650a82a23a9 100644 --- a/src/test/ui/rustdoc/check-doc-alias-attr-location.stderr +++ b/src/test/ui/rustdoc/check-doc-alias-attr-location.stderr @@ -1,4 +1,4 @@ -error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters --> $DIR/check-doc-alias-attr-location.rs:22:12 | LL | fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { diff --git a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr index 4eb1e318d97..faf730a5ce3 100644 --- a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr +++ b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr @@ -10,12 +10,12 @@ LL | pub size: Vector2 | -------------------- this field does not implement `Copy` | note: the `Copy` impl for `Vector2` requires that `K: Debug` - --> $DIR/missing-bound-in-derive-copy-impl-3.rs:12:5 + --> $DIR/missing-bound-in-derive-copy-impl-3.rs:12:14 | LL | pub loc: Vector2, - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ LL | pub size: Vector2 - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound | diff --git a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl.stderr b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl.stderr index 1cf2ab95bc3..11bc5409917 100644 --- a/src/test/ui/suggestions/missing-bound-in-derive-copy-impl.stderr +++ b/src/test/ui/suggestions/missing-bound-in-derive-copy-impl.stderr @@ -10,12 +10,12 @@ LL | pub size: Vector2 | -------------------- this field does not implement `Copy` | note: the `Copy` impl for `Vector2` requires that `K: Debug` - --> $DIR/missing-bound-in-derive-copy-impl.rs:11:5 + --> $DIR/missing-bound-in-derive-copy-impl.rs:11:14 | LL | pub loc: Vector2, - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ LL | pub size: Vector2 - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `K` | diff --git a/src/test/ui/union/union-copy.stderr b/src/test/ui/union/union-copy.stderr index 279808dd55b..8ecdafdde20 100644 --- a/src/test/ui/union/union-copy.stderr +++ b/src/test/ui/union/union-copy.stderr @@ -8,10 +8,10 @@ LL | impl Copy for W {} | ^^^^ | note: the `Copy` impl for `ManuallyDrop` requires that `String: Copy` - --> $DIR/union-copy.rs:8:5 + --> $DIR/union-copy.rs:8:8 | LL | a: std::mem::ManuallyDrop - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error