diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index cb9e0234c49ff..4ceca60e23cee 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -156,6 +156,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> { sup: self.static_region, sub: next_static_idx.into(), locations: Locations::All(DUMMY_SP), + span: DUMMY_SP, category: ConstraintCategory::Internal, variance_info: VarianceDiagInfo::default(), }) diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index d41143ee763ad..14f0e5f620aee 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -2,6 +2,7 @@ use rustc_data_structures::graph::scc::Sccs; use rustc_index::vec::IndexVec; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; +use rustc_span::Span; use std::fmt; use std::ops::Index; @@ -87,6 +88,12 @@ pub struct OutlivesConstraint<'tcx> { /// Where did this constraint arise? pub locations: Locations, + /// The `Span` associated with the creation of this constraint. + /// This should be used in preference to obtaining the span from + /// `locations`, since the `locations` may give a poor span + /// in some cases (e.g. converting a constraint from a promoted). + pub span: Span, + /// What caused this constraint? pub category: ConstraintCategory, diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index 97233b930c395..fe5193102f958 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -74,14 +74,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); constraints.sort_by_key(|c| (c.sup, c.sub)); for constraint in &constraints { - let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint; + let OutlivesConstraint { sup, sub, locations, category, span, variance_info: _ } = + constraint; let (name, arg) = match locations { Locations::All(span) => { ("All", tcx.sess.source_map().span_to_embeddable_string(*span)) } Locations::Single(loc) => ("Single", format!("{:?}", loc)), }; - with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?; + with_msg(&format!( + "{:?}: {:?} due to {:?} at {}({}) ({:?}", + sup, sub, category, name, arg, span + ))?; } Ok(()) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index dabf61715ce58..cf03f34a4ec5f 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1733,7 +1733,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { crate fn retrieve_closure_constraint_info( &self, - body: &Body<'tcx>, + _body: &Body<'tcx>, constraint: &OutlivesConstraint<'tcx>, ) -> BlameConstraint<'tcx> { let loc = match constraint.locations { @@ -1760,7 +1760,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .unwrap_or(BlameConstraint { category: constraint.category, from_closure: false, - cause: ObligationCause::dummy_with_span(body.source_info(loc).span), + cause: ObligationCause::dummy_with_span(constraint.span), variance_info: constraint.variance_info, }) } @@ -1869,6 +1869,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { sup: r, sub: constraint.min_choice, locations: Locations::All(p_c.definition_span), + span: p_c.definition_span, category: ConstraintCategory::OpaqueType, variance_info: ty::VarianceDiagInfo::default(), }; @@ -2017,7 +2018,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { category: constraint.category, from_closure: false, cause: ObligationCause::new( - constraint.locations.span(body), + constraint.span, CRATE_HIR_ID, cause_code.clone(), ), diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 5022cb98b821d..21190a850b7b1 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -8,7 +8,7 @@ use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; use crate::{ constraints::OutlivesConstraint, @@ -26,6 +26,7 @@ crate struct ConstraintConversion<'a, 'tcx> { implicit_region_bound: Option>, param_env: ty::ParamEnv<'tcx>, locations: Locations, + span: Span, category: ConstraintCategory, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, } @@ -38,6 +39,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { implicit_region_bound: Option>, param_env: ty::ParamEnv<'tcx>, locations: Locations, + span: Span, category: ConstraintCategory, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, ) -> Self { @@ -49,6 +51,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { implicit_region_bound, param_env, locations, + span, category, constraints, } @@ -153,6 +156,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { self.constraints.outlives_constraints.push(OutlivesConstraint { locations: self.locations, category: self.category, + span: self.span, sub, sup, variance_info: ty::VarianceDiagInfo::default(), diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index f8439d2e16355..f08f2e1b12da6 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -316,6 +316,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { self.implicit_region_bound, self.param_env, Locations::All(DUMMY_SP), + DUMMY_SP, ConstraintCategory::Internal, &mut self.constraints, ) diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 83c8ecba1f17a..e6f996491a41b 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -235,6 +235,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(self.implicit_region_bound), self.param_env, Locations::All(DUMMY_SP), + DUMMY_SP, ConstraintCategory::Internal, &mut self.borrowck_context.constraints, ) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index ece801716b2db..6dcdd46816e0d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1141,6 +1141,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(self.implicit_region_bound), self.param_env, locations, + locations.span(self.body), category, &mut self.borrowck_context.constraints, ) @@ -2401,6 +2402,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { sup: ref_region.to_region_vid(), sub: borrow_region.to_region_vid(), locations: location.to_locations(), + span: location.to_locations().span(body), category, variance_info: ty::VarianceDiagInfo::default(), }); diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index f0106630797d3..f98d2c3128c52 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -116,6 +116,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> sup, sub, locations: self.locations, + span: self.locations.span(self.type_checker.body), category: self.category, variance_info: info, }, diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index f0fff602fe4cf..827959113b907 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -679,7 +679,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return_place: Option<&PlaceTy<'tcx, M::PointerTag>>, return_to_block: StackPopCleanup, ) -> InterpResult<'tcx> { - debug!("body: {:#?}", body); + trace!("body: {:#?}", body); // first push a stack frame so we have access to the local substs let pre_frame = Frame { body, @@ -836,7 +836,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(()); } - debug!("locals: {:#?}", frame.locals); + trace!("locals: {:#?}", frame.locals); // Cleanup: deallocate all locals that are backed by an allocation. for local in &frame.locals { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index e8ee0fe6ea6ee..b1d7ab6a098be 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -870,9 +870,17 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { range: AllocRange, val: ScalarMaybeUninit, ) -> InterpResult<'tcx> { + let range = self.range.subrange(range); + debug!( + "write_scalar in {} at {:#x}, size {}: {:?}", + self.alloc_id, + range.start.bytes(), + range.size.bytes(), + val + ); Ok(self .alloc - .write_scalar(&self.tcx, self.range.subrange(range), val) + .write_scalar(&self.tcx, range, val) .map_err(|e| e.to_interp_error(self.alloc_id))?) } @@ -895,10 +903,19 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit> { - Ok(self + let range = self.range.subrange(range); + let res = self .alloc - .read_scalar(&self.tcx, self.range.subrange(range)) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .read_scalar(&self.tcx, range) + .map_err(|e| e.to_interp_error(self.alloc_id))?; + debug!( + "read_scalar in {} at {:#x}, size {}: {:?}", + self.alloc_id, + range.start.bytes(), + range.size.bytes(), + res + ); + Ok(res) } pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit> { diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 7723f7a64f769..c628406064fb6 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -515,6 +515,9 @@ impl Allocation { if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE { return Err(AllocError::PartialPointerOverwrite(first)); } + warn!( + "Partial pointer overwrite! De-initializing memory at offsets {first:?}..{start:?}." + ); self.init_mask.set_range(first, start, false); } if last > end { @@ -523,10 +526,15 @@ impl Allocation { last - cx.data_layout().pointer_size, )); } + warn!( + "Partial pointer overwrite! De-initializing memory at offsets {end:?}..{last:?}." + ); self.init_mask.set_range(end, last, false); } // Forget all the relocations. + // Since relocations do not overlap, we know that removing until `last` (exclusive) is fine, + // i.e., this will not remove any other relocations just after the ones we care about. self.relocations.0.remove_range(first..last); Ok(()) diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index a04ac33827424..cee657e9da244 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -255,10 +255,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { func: fun, args, cleanup: None, - // FIXME(varkor): replace this with an uninhabitedness-based check. - // This requires getting access to the current module to call - // `tcx.is_ty_uninhabited_from`, which is currently tricky to do. - destination: if expr.ty.is_never() { + // The presence or absence of a return edge affects control-flow sensitive + // MIR checks and ultimately whether code is accepted or not. We can only + // omit the return edge if a return type is visibly uninhabited to a module + // that makes the call. + destination: if this.tcx.is_ty_uninhabited_from( + this.parent_module, + expr.ty, + this.param_env, + ) { None } else { Some((destination, success)) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 901635dc488a7..3c51f79186274 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -350,6 +350,7 @@ struct Builder<'a, 'tcx> { def_id: DefId, hir_id: hir::HirId, + parent_module: DefId, check_overflow: bool, fn_span: Span, arg_count: usize, @@ -807,15 +808,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let lint_level = LintLevel::Explicit(hir_id); + let param_env = tcx.param_env(def.did); let mut builder = Builder { thir, tcx, infcx, typeck_results: tcx.typeck_opt_const_arg(def), region_scope_tree: tcx.region_scope_tree(def.did), - param_env: tcx.param_env(def.did), + param_env, def_id: def.did.to_def_id(), hir_id, + parent_module: tcx.parent_module(hir_id).to_def_id(), check_overflow, cfg: CFG { basic_blocks: IndexVec::new() }, fn_span: span, diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs index da63c068384a2..e4ff21b25bd9c 100644 --- a/library/std/src/sys/unix/weak.rs +++ b/library/std/src/sys/unix/weak.rs @@ -25,7 +25,8 @@ use crate::ffi::CStr; use crate::marker::PhantomData; use crate::mem; -use crate::sync::atomic::{self, AtomicUsize, Ordering}; +use crate::ptr; +use crate::sync::atomic::{self, AtomicPtr, Ordering}; // We can use true weak linkage on ELF targets. #[cfg(not(any(target_os = "macos", target_os = "ios")))] @@ -83,13 +84,13 @@ pub(crate) macro dlsym { } pub(crate) struct DlsymWeak { name: &'static str, - addr: AtomicUsize, + func: AtomicPtr, _marker: PhantomData, } impl DlsymWeak { pub(crate) const fn new(name: &'static str) -> Self { - DlsymWeak { name, addr: AtomicUsize::new(1), _marker: PhantomData } + DlsymWeak { name, func: AtomicPtr::new(ptr::invalid_mut(1)), _marker: PhantomData } } #[inline] @@ -97,11 +98,11 @@ impl DlsymWeak { unsafe { // Relaxed is fine here because we fence before reading through the // pointer (see the comment below). - match self.addr.load(Ordering::Relaxed) { - 1 => self.initialize(), - 0 => None, - addr => { - let func = mem::transmute_copy::(&addr); + match self.func.load(Ordering::Relaxed) { + func if func.addr() == 1 => self.initialize(), + func if func.is_null() => None, + func => { + let func = mem::transmute_copy::<*mut libc::c_void, F>(&func); // The caller is presumably going to read through this value // (by calling the function we've dlsymed). This means we'd // need to have loaded it with at least C11's consume @@ -129,25 +130,22 @@ impl DlsymWeak { // Cold because it should only happen during first-time initialization. #[cold] unsafe fn initialize(&self) -> Option { - assert_eq!(mem::size_of::(), mem::size_of::()); + assert_eq!(mem::size_of::(), mem::size_of::<*mut libc::c_void>()); let val = fetch(self.name); // This synchronizes with the acquire fence in `get`. - self.addr.store(val, Ordering::Release); + self.func.store(val, Ordering::Release); - match val { - 0 => None, - addr => Some(mem::transmute_copy::(&addr)), - } + if val.is_null() { None } else { Some(mem::transmute_copy::<*mut libc::c_void, F>(&val)) } } } -unsafe fn fetch(name: &str) -> usize { +unsafe fn fetch(name: &str) -> *mut libc::c_void { let name = match CStr::from_bytes_with_nul(name.as_bytes()) { Ok(cstr) => cstr, - Err(..) => return 0, + Err(..) => return ptr::null_mut(), }; - libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize + libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) } #[cfg(not(any(target_os = "linux", target_os = "android")))] diff --git a/library/std/src/sys/wasm/atomics/condvar.rs b/library/std/src/sys/wasm/atomics/condvar.rs deleted file mode 100644 index f06c07c54093f..0000000000000 --- a/library/std/src/sys/wasm/atomics/condvar.rs +++ /dev/null @@ -1,102 +0,0 @@ -use crate::arch::wasm32; -use crate::cmp; -use crate::mem; -use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; -use crate::sys::locks::Mutex; -use crate::time::Duration; - -pub struct Condvar { - cnt: AtomicUsize, -} - -pub type MovableCondvar = Condvar; - -// Condition variables are implemented with a simple counter internally that is -// likely to cause spurious wakeups. Blocking on a condition variable will first -// read the value of the internal counter, unlock the given mutex, and then -// block if and only if the counter's value is still the same. Notifying a -// condition variable will modify the counter (add one for now) and then wake up -// a thread waiting on the address of the counter. -// -// A thread waiting on the condition variable will as a result avoid going to -// sleep if it's notified after the lock is unlocked but before it fully goes to -// sleep. A sleeping thread is guaranteed to be woken up at some point as it can -// only be woken up with a call to `wake`. -// -// Note that it's possible for 2 or more threads to be woken up by a call to -// `notify_one` with this implementation. That can happen where the modification -// of `cnt` causes any threads in the middle of `wait` to avoid going to sleep, -// and the subsequent `wake` may wake up a thread that's actually blocking. We -// consider this a spurious wakeup, though, which all users of condition -// variables must already be prepared to handle. As a result, this source of -// spurious wakeups is currently though to be ok, although it may be problematic -// later on if it causes too many spurious wakeups. - -impl Condvar { - pub const fn new() -> Condvar { - Condvar { cnt: AtomicUsize::new(0) } - } - - #[inline] - pub unsafe fn init(&mut self) { - // nothing to do - } - - pub unsafe fn notify_one(&self) { - self.cnt.fetch_add(1, SeqCst); - // SAFETY: ptr() is always valid - unsafe { - wasm32::memory_atomic_notify(self.ptr(), 1); - } - } - - #[inline] - pub unsafe fn notify_all(&self) { - self.cnt.fetch_add(1, SeqCst); - // SAFETY: ptr() is always valid - unsafe { - wasm32::memory_atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone" - } - } - - pub unsafe fn wait(&self, mutex: &Mutex) { - // "atomically block and unlock" implemented by loading our current - // counter's value, unlocking the mutex, and blocking if the counter - // still has the same value. - // - // Notifications happen by incrementing the counter and then waking a - // thread. Incrementing the counter after we unlock the mutex will - // prevent us from sleeping and otherwise the call to `wake` will - // wake us up once we're asleep. - let ticket = self.cnt.load(SeqCst) as i32; - mutex.unlock(); - let val = wasm32::memory_atomic_wait32(self.ptr(), ticket, -1); - // 0 == woken, 1 == not equal to `ticket`, 2 == timeout (shouldn't happen) - debug_assert!(val == 0 || val == 1); - mutex.lock(); - } - - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let ticket = self.cnt.load(SeqCst) as i32; - mutex.unlock(); - let nanos = dur.as_nanos(); - let nanos = cmp::min(i64::MAX as u128, nanos); - - // If the return value is 2 then a timeout happened, so we return - // `false` as we weren't actually notified. - let ret = wasm32::memory_atomic_wait32(self.ptr(), ticket, nanos as i64) != 2; - mutex.lock(); - return ret; - } - - #[inline] - pub unsafe fn destroy(&self) { - // nothing to do - } - - #[inline] - fn ptr(&self) -> *mut i32 { - assert_eq!(mem::size_of::(), mem::size_of::()); - self.cnt.as_mut_ptr() as *mut i32 - } -} diff --git a/library/std/src/sys/wasm/atomics/futex.rs b/library/std/src/sys/wasm/atomics/futex.rs index bbe9bd6951af9..11413ba3bf564 100644 --- a/library/std/src/sys/wasm/atomics/futex.rs +++ b/library/std/src/sys/wasm/atomics/futex.rs @@ -3,19 +3,33 @@ use crate::convert::TryInto; use crate::sync::atomic::AtomicU32; use crate::time::Duration; -pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) { +/// Wait for a futex_wake operation to wake us. +/// +/// Returns directly if the futex doesn't hold the expected value. +/// +/// Returns false on timeout, and true in all other cases. +pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) -> bool { let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1); unsafe { wasm32::memory_atomic_wait32( futex as *const AtomicU32 as *mut i32, expected as i32, timeout, - ); + ) < 2 } } -pub fn futex_wake(futex: &AtomicU32) { +/// Wake up one thread that's blocked on futex_wait on this futex. +/// +/// Returns true if this actually woke up such a thread, +/// or false if no thread was waiting on this futex. +pub fn futex_wake(futex: &AtomicU32) -> bool { + unsafe { wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 } +} + +/// Wake up all threads that are waiting on futex_wait on this futex. +pub fn futex_wake_all(futex: &AtomicU32) { unsafe { - wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1); + wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32); } } diff --git a/library/std/src/sys/wasm/atomics/mutex.rs b/library/std/src/sys/wasm/atomics/mutex.rs deleted file mode 100644 index 1acc8392444c1..0000000000000 --- a/library/std/src/sys/wasm/atomics/mutex.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::arch::wasm32; -use crate::mem; -use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; - -pub struct Mutex { - locked: AtomicUsize, -} - -pub type MovableMutex = Mutex; - -// Mutexes have a pretty simple implementation where they contain an `i32` -// internally that is 0 when unlocked and 1 when the mutex is locked. -// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and -// if it fails it then waits for a notification. Releasing a lock is then done -// by swapping in 0 and then notifying any waiters, if present. - -impl Mutex { - pub const fn new() -> Mutex { - Mutex { locked: AtomicUsize::new(0) } - } - - #[inline] - pub unsafe fn init(&mut self) { - // nothing to do - } - - pub unsafe fn lock(&self) { - while !self.try_lock() { - // SAFETY: the caller must uphold the safety contract for `memory_atomic_wait32`. - let val = unsafe { - wasm32::memory_atomic_wait32( - self.ptr(), - 1, // we expect our mutex is locked - -1, // wait infinitely - ) - }; - // we should have either woke up (0) or got a not-equal due to a - // race (1). We should never time out (2) - debug_assert!(val == 0 || val == 1); - } - } - - pub unsafe fn unlock(&self) { - let prev = self.locked.swap(0, SeqCst); - debug_assert_eq!(prev, 1); - wasm32::memory_atomic_notify(self.ptr(), 1); // wake up one waiter, if any - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() - } - - #[inline] - pub unsafe fn destroy(&self) { - // nothing to do - } - - #[inline] - fn ptr(&self) -> *mut i32 { - assert_eq!(mem::size_of::(), mem::size_of::()); - self.locked.as_mut_ptr() as *mut i32 - } -} diff --git a/library/std/src/sys/wasm/atomics/rwlock.rs b/library/std/src/sys/wasm/atomics/rwlock.rs deleted file mode 100644 index 690bb155e1a27..0000000000000 --- a/library/std/src/sys/wasm/atomics/rwlock.rs +++ /dev/null @@ -1,145 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::sys::locks::{Condvar, Mutex}; - -pub struct RwLock { - lock: Mutex, - cond: Condvar, - state: UnsafeCell, -} - -pub type MovableRwLock = RwLock; - -enum State { - Unlocked, - Reading(usize), - Writing, -} - -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} - -// This rwlock implementation is a relatively simple implementation which has a -// condition variable for readers/writers as well as a mutex protecting the -// internal state of the lock. A current downside of the implementation is that -// unlocking the lock will notify *all* waiters rather than just readers or just -// writers. This can cause lots of "thundering stampede" problems. While -// hopefully correct this implementation is very likely to want to be changed in -// the future. - -impl RwLock { - pub const fn new() -> RwLock { - RwLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) } - } - - #[inline] - pub unsafe fn read(&self) { - self.lock.lock(); - while !(*self.state.get()).inc_readers() { - self.cond.wait(&self.lock); - } - self.lock.unlock(); - } - - #[inline] - pub unsafe fn try_read(&self) -> bool { - self.lock.lock(); - let ok = (*self.state.get()).inc_readers(); - self.lock.unlock(); - return ok; - } - - #[inline] - pub unsafe fn write(&self) { - self.lock.lock(); - while !(*self.state.get()).inc_writers() { - self.cond.wait(&self.lock); - } - self.lock.unlock(); - } - - #[inline] - pub unsafe fn try_write(&self) -> bool { - self.lock.lock(); - let ok = (*self.state.get()).inc_writers(); - self.lock.unlock(); - return ok; - } - - #[inline] - pub unsafe fn read_unlock(&self) { - self.lock.lock(); - let notify = (*self.state.get()).dec_readers(); - self.lock.unlock(); - if notify { - // FIXME: should only wake up one of these some of the time - self.cond.notify_all(); - } - } - - #[inline] - pub unsafe fn write_unlock(&self) { - self.lock.lock(); - (*self.state.get()).dec_writers(); - self.lock.unlock(); - // 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 { - fn inc_readers(&mut self) -> bool { - match *self { - State::Unlocked => { - *self = State::Reading(1); - true - } - State::Reading(ref mut cnt) => { - *cnt += 1; - true - } - State::Writing => false, - } - } - - fn inc_writers(&mut self) -> bool { - match *self { - State::Unlocked => { - *self = State::Writing; - true - } - State::Reading(_) | State::Writing => false, - } - } - - fn dec_readers(&mut self) -> bool { - let zero = match *self { - State::Reading(ref mut cnt) => { - *cnt -= 1; - *cnt == 0 - } - State::Unlocked | State::Writing => invalid(), - }; - if zero { - *self = State::Unlocked; - } - zero - } - - fn dec_writers(&mut self) { - match *self { - State::Writing => {} - State::Unlocked | State::Reading(_) => invalid(), - } - *self = State::Unlocked; - } -} - -fn invalid() -> ! { - panic!("inconsistent rwlock"); -} diff --git a/library/std/src/sys/wasm/atomics/thread.rs b/library/std/src/sys/wasm/atomics/thread.rs index 16418a06226e4..714b704922794 100644 --- a/library/std/src/sys/wasm/atomics/thread.rs +++ b/library/std/src/sys/wasm/atomics/thread.rs @@ -53,37 +53,3 @@ pub mod guard { None } } - -// We currently just use our own thread-local to store our -// current thread's ID, and then we lazily initialize it to something allocated -// from a global counter. -pub fn my_id() -> u32 { - use crate::sync::atomic::{AtomicU32, Ordering::SeqCst}; - - static NEXT_ID: AtomicU32 = AtomicU32::new(0); - - #[thread_local] - static mut MY_ID: u32 = 0; - - unsafe { - // If our thread ID isn't set yet then we need to allocate one. Do so - // with with a simple "atomically add to a global counter" strategy. - // This strategy doesn't handled what happens when the counter - // overflows, however, so just abort everything once the counter - // overflows and eventually we could have some sort of recycling scheme - // (or maybe this is all totally irrelevant by that point!). In any case - // though we're using a CAS loop instead of a `fetch_add` to ensure that - // the global counter never overflows. - if MY_ID == 0 { - let mut cur = NEXT_ID.load(SeqCst); - MY_ID = loop { - let next = cur.checked_add(1).unwrap_or_else(|| crate::process::abort()); - match NEXT_ID.compare_exchange(cur, next, SeqCst, SeqCst) { - Ok(_) => break next, - Err(i) => cur = i, - } - }; - } - MY_ID - } -} diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 9f6700caf14bf..9992e44b0e756 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -49,16 +49,13 @@ pub mod time; cfg_if::cfg_if! { if #[cfg(target_feature = "atomics")] { - #[path = "atomics/condvar.rs"] - mod condvar; - #[path = "atomics/mutex.rs"] - mod mutex; - #[path = "atomics/rwlock.rs"] - mod rwlock; + #[path = "../unix/locks"] pub mod locks { - pub use super::condvar::*; - pub use super::mutex::*; - pub use super::rwlock::*; + #![allow(unsafe_op_in_unsafe_fn)] + mod futex; + mod futex_rwlock; + pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar}; + pub use futex_rwlock::{RwLock, MovableRwLock}; } #[path = "atomics/futex.rs"] pub mod futex; diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d688f798956d6..e98466777e01e 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -3,7 +3,7 @@ use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; use std::env; use std::ffi::OsStr; -use std::fmt::Debug; +use std::fmt::{Debug, Write}; use std::fs; use std::hash::Hash; use std::ops::Deref; @@ -125,7 +125,8 @@ impl TaskPath { if found_kind.is_empty() { panic!("empty kind in task path {}", path.display()); } - kind = Some(Kind::parse(found_kind)); + kind = Kind::parse(found_kind); + assert!(kind.is_some()); path = Path::new(found_prefix).join(components.as_path()); } } @@ -429,43 +430,53 @@ pub enum Kind { Check, Clippy, Fix, + Format, Test, Bench, - Dist, Doc, + Clean, + Dist, Install, Run, + Setup, } impl Kind { - fn parse(string: &str) -> Kind { - match string { - "build" => Kind::Build, - "check" => Kind::Check, + pub fn parse(string: &str) -> Option { + // these strings, including the one-letter aliases, must match the x.py help text + Some(match string { + "build" | "b" => Kind::Build, + "check" | "c" => Kind::Check, "clippy" => Kind::Clippy, "fix" => Kind::Fix, - "test" => Kind::Test, + "fmt" => Kind::Format, + "test" | "t" => Kind::Test, "bench" => Kind::Bench, + "doc" | "d" => Kind::Doc, + "clean" => Kind::Clean, "dist" => Kind::Dist, - "doc" => Kind::Doc, "install" => Kind::Install, - "run" => Kind::Run, - other => panic!("unknown kind: {}", other), - } + "run" | "r" => Kind::Run, + "setup" => Kind::Setup, + _ => return None, + }) } - fn as_str(&self) -> &'static str { + pub fn as_str(&self) -> &'static str { match self { Kind::Build => "build", Kind::Check => "check", Kind::Clippy => "clippy", Kind::Fix => "fix", + Kind::Format => "fmt", Kind::Test => "test", Kind::Bench => "bench", - Kind::Dist => "dist", Kind::Doc => "doc", + Kind::Clean => "clean", + Kind::Dist => "dist", Kind::Install => "install", Kind::Run => "run", + Kind::Setup => "setup", } } } @@ -509,7 +520,7 @@ impl<'a> Builder<'a> { native::Lld, native::CrtBeginEnd ), - Kind::Check | Kind::Clippy { .. } | Kind::Fix => describe!( + Kind::Check => describe!( check::Std, check::Rustc, check::Rustdoc, @@ -639,32 +650,29 @@ impl<'a> Builder<'a> { install::Rustc ), Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0), + // These commands either don't use paths, or they're special-cased in Build::build() + Kind::Clean | Kind::Clippy | Kind::Fix | Kind::Format | Kind::Setup => vec![], } } - pub fn get_help(build: &Build, subcommand: &str) -> Option { - let kind = match subcommand { - "build" | "b" => Kind::Build, - "doc" | "d" => Kind::Doc, - "test" | "t" => Kind::Test, - "bench" => Kind::Bench, - "dist" => Kind::Dist, - "install" => Kind::Install, - _ => return None, - }; + pub fn get_help(build: &Build, kind: Kind) -> Option { + let step_descriptions = Builder::get_step_descriptions(kind); + if step_descriptions.is_empty() { + return None; + } let builder = Self::new_internal(build, kind, vec![]); let builder = &builder; // The "build" kind here is just a placeholder, it will be replaced with something else in // the following statement. let mut should_run = ShouldRun::new(builder, Kind::Build); - for desc in Builder::get_step_descriptions(builder.kind) { + for desc in step_descriptions { should_run.kind = desc.kind; should_run = (desc.should_run)(should_run); } let mut help = String::from("Available paths:\n"); let mut add_path = |path: &Path| { - help.push_str(&format!(" ./x.py {} {}\n", subcommand, path.display())); + t!(write!(help, " ./x.py {} {}\n", kind.as_str(), path.display())); }; for pathset in should_run.paths { match pathset { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 1a4e6a9688803..a82eb52e232b4 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -8,7 +8,7 @@ use std::process; use getopts::Options; -use crate::builder::Builder; +use crate::builder::{Builder, Kind}; use crate::config::{Config, TargetSelection}; use crate::setup::Profile; use crate::util::t; @@ -243,27 +243,7 @@ To learn more about a subcommand, run `./x.py -h`", // the subcommand. Therefore we must manually identify the subcommand first, so that we can // complete the definition of the options. Then we can use the getopt::Matches object from // there on out. - let subcommand = args.iter().find(|&s| { - (s == "build") - || (s == "b") - || (s == "check") - || (s == "c") - || (s == "clippy") - || (s == "fix") - || (s == "fmt") - || (s == "test") - || (s == "t") - || (s == "bench") - || (s == "doc") - || (s == "d") - || (s == "clean") - || (s == "dist") - || (s == "install") - || (s == "run") - || (s == "r") - || (s == "setup") - }); - let subcommand = match subcommand { + let subcommand = match args.iter().find_map(|s| Kind::parse(&s)) { Some(s) => s, None => { // No or an invalid subcommand -- show the general usage and subcommand help @@ -276,8 +256,8 @@ To learn more about a subcommand, run `./x.py -h`", }; // Some subcommands get extra options - match subcommand.as_str() { - "test" | "t" => { + match subcommand { + Kind::Test => { opts.optflag("", "no-fail-fast", "Run all tests regardless of failure"); opts.optmulti( "", @@ -316,22 +296,22 @@ To learn more about a subcommand, run `./x.py -h`", `//rustfix_missing_coverage.txt`", ); } - "check" | "c" => { + Kind::Check => { opts.optflag("", "all-targets", "Check all targets"); } - "bench" => { + Kind::Bench => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); } - "clippy" => { + Kind::Clippy => { opts.optflag("", "fix", "automatically apply lint suggestions"); } - "doc" | "d" => { + Kind::Doc => { opts.optflag("", "open", "open the docs in a browser"); } - "clean" => { + Kind::Clean => { opts.optflag("", "all", "clean all build artifacts"); } - "fmt" => { + Kind::Format => { opts.optflag("", "check", "check formatting instead of applying."); } _ => {} @@ -339,25 +319,22 @@ To learn more about a subcommand, run `./x.py -h`", // fn usage() let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! { - let mut extra_help = String::new(); - - // All subcommands except `clean` can have an optional "Available paths" section - if verbose { - let config = Config::parse(&["build".to_string()]); - let build = Build::new(config); - - let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); - extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); - } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") { - extra_help.push_str( - format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand) - .as_str(), - ); - } + let config = Config::parse(&["build".to_string()]); + let build = Build::new(config); + let paths = Builder::get_help(&build, subcommand); println!("{}", opts.usage(subcommand_help)); - if !extra_help.is_empty() { - println!("{}", extra_help); + if let Some(s) = paths { + if verbose { + println!("{}", s); + } else { + println!( + "Run `./x.py {} -h -v` to see a list of available paths.", + subcommand.as_str() + ); + } + } else if verbose { + panic!("No paths available for subcommand `{}`", subcommand.as_str()); } process::exit(exit_code); }; @@ -375,7 +352,7 @@ To learn more about a subcommand, run `./x.py -h`", // ^-- option ^ ^- actual subcommand // \_ arg to option could be mistaken as subcommand let mut pass_sanity_check = true; - match matches.free.get(0) { + match matches.free.get(0).and_then(|s| Kind::parse(&s)) { Some(check_subcommand) => { if check_subcommand != subcommand { pass_sanity_check = false; @@ -394,8 +371,8 @@ To learn more about a subcommand, run `./x.py -h`", process::exit(1); } // Extra help text for some commands - match subcommand.as_str() { - "build" | "b" => { + match subcommand { + Kind::Build => { subcommand_help.push_str( "\n Arguments: @@ -415,7 +392,7 @@ Arguments: ./x.py build ", ); } - "check" | "c" => { + Kind::Check => { subcommand_help.push_str( "\n Arguments: @@ -427,7 +404,7 @@ Arguments: If no arguments are passed then many artifacts are checked.", ); } - "clippy" => { + Kind::Clippy => { subcommand_help.push_str( "\n Arguments: @@ -438,7 +415,7 @@ Arguments: ./x.py clippy library/core library/proc_macro", ); } - "fix" => { + Kind::Fix => { subcommand_help.push_str( "\n Arguments: @@ -449,7 +426,7 @@ Arguments: ./x.py fix library/core library/proc_macro", ); } - "fmt" => { + Kind::Format => { subcommand_help.push_str( "\n Arguments: @@ -460,7 +437,7 @@ Arguments: ./x.py fmt --check", ); } - "test" | "t" => { + Kind::Test => { subcommand_help.push_str( "\n Arguments: @@ -488,7 +465,7 @@ Arguments: ./x.py test --stage 1", ); } - "doc" | "d" => { + Kind::Doc => { subcommand_help.push_str( "\n Arguments: @@ -506,7 +483,7 @@ Arguments: ./x.py doc --stage 1", ); } - "run" | "r" => { + Kind::Run => { subcommand_help.push_str( "\n Arguments: @@ -518,7 +495,7 @@ Arguments: At least a tool needs to be called.", ); } - "setup" => { + Kind::Setup => { subcommand_help.push_str(&format!( "\n x.py setup creates a `config.toml` which changes the defaults for x.py itself. @@ -535,7 +512,7 @@ Arguments: Profile::all_for_help(" ").trim_end() )); } - _ => {} + Kind::Bench | Kind::Clean | Kind::Dist | Kind::Install => {} }; // Get any optional paths which occur after the subcommand let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); @@ -547,9 +524,9 @@ Arguments: usage(0, &opts, verbose, &subcommand_help); } - let cmd = match subcommand.as_str() { - "build" | "b" => Subcommand::Build { paths }, - "check" | "c" => { + let cmd = match subcommand { + Kind::Build => Subcommand::Build { paths }, + Kind::Check => { if matches.opt_present("all-targets") { eprintln!( "Warning: --all-targets is now on by default and does not need to be passed explicitly." @@ -557,9 +534,9 @@ Arguments: } Subcommand::Check { paths } } - "clippy" => Subcommand::Clippy { paths, fix: matches.opt_present("fix") }, - "fix" => Subcommand::Fix { paths }, - "test" | "t" => Subcommand::Test { + Kind::Clippy => Subcommand::Clippy { paths, fix: matches.opt_present("fix") }, + Kind::Fix => Subcommand::Fix { paths }, + Kind::Test => Subcommand::Test { paths, bless: matches.opt_present("bless"), force_rerun: matches.opt_present("force-rerun"), @@ -578,9 +555,9 @@ Arguments: DocTests::Yes }, }, - "bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") }, - "doc" | "d" => Subcommand::Doc { paths, open: matches.opt_present("open") }, - "clean" => { + Kind::Bench => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") }, + Kind::Doc => Subcommand::Doc { paths, open: matches.opt_present("open") }, + Kind::Clean => { if !paths.is_empty() { println!("\nclean does not take a path argument\n"); usage(1, &opts, verbose, &subcommand_help); @@ -588,17 +565,17 @@ Arguments: Subcommand::Clean { all: matches.opt_present("all") } } - "fmt" => Subcommand::Format { check: matches.opt_present("check"), paths }, - "dist" => Subcommand::Dist { paths }, - "install" => Subcommand::Install { paths }, - "run" | "r" => { + Kind::Format => Subcommand::Format { check: matches.opt_present("check"), paths }, + Kind::Dist => Subcommand::Dist { paths }, + Kind::Install => Subcommand::Install { paths }, + Kind::Run => { if paths.is_empty() { println!("\nrun requires at least a path!\n"); usage(1, &opts, verbose, &subcommand_help); } Subcommand::Run { paths } } - "setup" => { + Kind::Setup => { let profile = if paths.len() > 1 { println!("\nat most one profile can be passed to setup\n"); usage(1, &opts, verbose, &subcommand_help) @@ -618,9 +595,6 @@ Arguments: }; Subcommand::Setup { profile } } - _ => { - usage(1, &opts, verbose, &subcommand_help); - } }; if let Subcommand::Check { .. } = &cmd { diff --git a/src/test/codegen/set-discriminant-invalid.rs b/src/test/codegen/set-discriminant-invalid.rs index d9614f062b7e9..bccb9e4c75862 100644 --- a/src/test/codegen/set-discriminant-invalid.rs +++ b/src/test/codegen/set-discriminant-invalid.rs @@ -28,7 +28,7 @@ impl IntoError for Api #[no_mangle] fn into_error(self, error: Self::Source) -> Error { Error::Api { - source: (|v| v)(error), + source: error, } } } diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff index bea33073366f7..3b890e4be2e29 100644 --- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff @@ -4,21 +4,22 @@ fn h() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12 let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 -+ let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 -+ let mut _9: (); // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16 -+ let mut _10: (); // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16 ++ let mut _2: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ let mut _3: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ let mut _10: (); // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16 ++ let mut _11: (); // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16 + scope 1 (inlined call_twice:: ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22 -+ debug f => _2; // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37 -+ let _3: !; // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10 -+ let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14 -+ let mut _6: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14 -+ let mut _7: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7 -+ let mut _8: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10 ++ debug f => _3; // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37 ++ let _4: !; // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10 ++ let mut _5: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14 ++ let mut _7: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14 ++ let mut _8: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7 ++ let mut _9: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10 + scope 2 { -+ debug a => _3; // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10 -+ let _5: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10 ++ debug a => _4; // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10 ++ let _6: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10 + scope 3 { -+ debug b => _5; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10 ++ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10 + } + scope 6 (inlined ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:28:13: 28:16 + scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -33,27 +34,25 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 -- _1 = call_twice:: ! {sleep}>(sleep) -> bb1; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 +- call_twice:: ! {sleep}>(sleep); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 -+ _2 = sleep; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ StorageLive(_3); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ _3 = sleep; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 // mir::Constant - // + span: $DIR/inline-diverging.rs:22:5: 22:15 - // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice:: ! {sleep}>}, val: Value(Scalar()) } - // mir::Constant // + span: $DIR/inline-diverging.rs:22:16: 22:21 // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar()) } -+ StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10 -+ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14 -+ _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14 -+ StorageLive(_9); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16 -+ _9 = const (); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16 ++ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10 ++ StorageLive(_5); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14 ++ _5 = &_3; // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14 ++ StorageLive(_10); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16 ++ _10 = const (); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16 + goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12 - } - - bb1: { -- StorageDead(_1); // scope 0 at $DIR/inline-diverging.rs:22:22: 22:23 -- _0 = const (); // scope 0 at $DIR/inline-diverging.rs:21:12: 23:2 -- return; // scope 0 at $DIR/inline-diverging.rs:23:2: 23:2 ++ } ++ ++ bb1: { + goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12 } } diff --git a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir index 5fb57c285beca..4aff444515809 100644 --- a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir @@ -21,7 +21,7 @@ fn main() -> () { StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 _3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 - _2 = transmute::<(), Void>(move _3) -> [return: bb1, unwind: bb4]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 + transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 // mir::Constant // + span: $DIR/issue-72181-1.rs:17:9: 17:40 // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir index 9f235248ca59f..8423128123ab7 100644 --- a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir +++ b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir @@ -25,14 +25,14 @@ | '_#2r live at {bb0[0..=1]} | '_#3r live at {bb0[0..=1]} | '_#4r live at {bb0[0..=1]} -| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) -| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) -| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) -| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) -| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) -| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) -| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) -| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) +| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0) +| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0) +| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0) +| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0) +| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0) +| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0) +| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0) +| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0) | fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) -> bool { debug w => _1; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:26: 12:27 diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index ed94a1ecf0062..f79e2705ad29c 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -18,8 +18,8 @@ | '_#3r live at {bb1[0]} | '_#4r live at {bb1[1..=3]} | '_#5r live at {bb1[4..=7], bb2[0..=2]} -| '_#3r: '_#4r due to Assignment at Single(bb1[0]) -| '_#4r: '_#5r due to Assignment at Single(bb1[3]) +| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0) +| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0) | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11 diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 95997b2070172..162cacef8a54a 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -18,8 +18,8 @@ | '_#3r live at {bb1[0]} | '_#4r live at {bb1[1..=3]} | '_#5r live at {bb1[4..=7], bb2[0..=2]} -| '_#3r: '_#4r due to Assignment at Single(bb1[0]) -| '_#4r: '_#5r due to Assignment at Single(bb1[3]) +| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0) +| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0) | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11 diff --git a/src/test/mir-opt/storage_ranges.main.nll.0.mir b/src/test/mir-opt/storage_ranges.main.nll.0.mir index e02580135af38..b383c5ec9dc60 100644 --- a/src/test/mir-opt/storage_ranges.main.nll.0.mir +++ b/src/test/mir-opt/storage_ranges.main.nll.0.mir @@ -16,7 +16,7 @@ | '_#1r live at {bb0[0..=22]} | '_#3r live at {bb0[10]} | '_#4r live at {bb0[11]} -| '_#3r: '_#4r due to Assignment at Single(bb0[10]) +| '_#3r: '_#4r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0) | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/storage_ranges.rs:3:11: 3:11 diff --git a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr index 111d243959a13..b60bac541f4c8 100644 --- a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr @@ -119,27 +119,17 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran 78 00 00 00 ff ff ff ff │ x....... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:92:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:92:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at ..0.1: encountered a value of uninhabited type Never - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - 00 00 00 00 00 00 00 00 │ ........ - } + | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:94:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:94:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at ..0.1: encountered a value of the never type `!` - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - 00 00 00 00 00 00 00 00 │ ........ - } + | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type error: aborting due to 13 previous errors diff --git a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr index eee132bae00bc..1d81e2b3eed86 100644 --- a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr @@ -119,27 +119,17 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran 78 00 00 00 ff ff ff ff │ x....... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:92:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:92:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at ..0.1: encountered a value of uninhabited type Never - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - 00 00 00 00 00 00 00 00 │ ........ - } + | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:94:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:94:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at ..0.1: encountered a value of the never type `!` - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - 00 00 00 00 00 00 00 00 │ ........ - } + | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type error: aborting due to 13 previous errors diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index e408d8ec072e3..86288685303ca 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -90,9 +90,9 @@ const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute // All variants are uninhabited but also have data. // Use `0` as constant to make behavior endianess-independent. const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; -//~^ ERROR is undefined behavior +//~^ ERROR evaluation of constant value failed const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; -//~^ ERROR is undefined behavior +//~^ ERROR evaluation of constant value failed fn main() { } diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr index 7dc1ec865af8a..bbb8511a65410 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr @@ -10,14 +10,11 @@ LL | unsafe { std::mem::transmute(()) } LL | const FOO: [Empty; 3] = [foo(); 3]; | ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26 -error[E0080]: it is undefined behavior to use this value - --> $DIR/validate_uninhabited_zsts.rs:16:1 +error[E0080]: evaluation of constant value failed + --> $DIR/validate_uninhabited_zsts.rs:16:35 | LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 0, align: 1) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type warning: the type `!` does not permit zero-initialization --> $DIR/validate_uninhabited_zsts.rs:4:14 diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr index 7dc1ec865af8a..bbb8511a65410 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr @@ -10,14 +10,11 @@ LL | unsafe { std::mem::transmute(()) } LL | const FOO: [Empty; 3] = [foo(); 3]; | ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26 -error[E0080]: it is undefined behavior to use this value - --> $DIR/validate_uninhabited_zsts.rs:16:1 +error[E0080]: evaluation of constant value failed + --> $DIR/validate_uninhabited_zsts.rs:16:35 | LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 0, align: 1) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type warning: the type `!` does not permit zero-initialization --> $DIR/validate_uninhabited_zsts.rs:4:14 diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs index 346504845561d..990d5a308238f 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs @@ -14,7 +14,7 @@ const FOO: [Empty; 3] = [foo(); 3]; #[warn(const_err)] const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed //~| WARN the type `Empty` does not permit zero-initialization fn main() { diff --git a/src/test/ui/generator/issue-93161.rs b/src/test/ui/generator/issue-93161.rs index 9988acbcb73e1..92305609c835c 100644 --- a/src/test/ui/generator/issue-93161.rs +++ b/src/test/ui/generator/issue-93161.rs @@ -1,5 +1,6 @@ // edition:2021 // run-pass +// compile-flags: -Zdrop-tracking #![feature(never_type)] @@ -32,7 +33,7 @@ fn never() -> Never { } async fn includes_never(crash: bool, x: u32) -> u32 { - let mut result = async { x * x }.await; + let result = async { x * x }.await; if !crash { return result; } diff --git a/src/test/ui/rfc1623.base.stderr b/src/test/ui/rfc1623.base.stderr index 6d389a1317a9f..364c8c8f7069e 100644 --- a/src/test/ui/rfc1623.base.stderr +++ b/src/test/ui/rfc1623.base.stderr @@ -1,5 +1,5 @@ error: implementation of `FnOnce` is not general enough - --> $DIR/rfc1623.rs:36:8 + --> $DIR/rfc1623.rs:32:8 | LL | f: &id, | ^^^ implementation of `FnOnce` is not general enough diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr index f85b6ff8ff75b..2eff4708547d8 100644 --- a/src/test/ui/rfc1623.nll.stderr +++ b/src/test/ui/rfc1623.nll.stderr @@ -1,63 +1,35 @@ error[E0308]: mismatched types - --> $DIR/rfc1623.rs:29:35 + --> $DIR/rfc1623.rs:32:8 | -LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { - | ___________________________________^ -LL | | -LL | | -LL | | -... | -LL | | -LL | | }; - | |_^ one type is more general than the other +LL | f: &id, + | ^^^ one type is more general than the other | = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>` found type `Fn<(&Foo<'_>,)>` error[E0308]: mismatched types - --> $DIR/rfc1623.rs:29:35 + --> $DIR/rfc1623.rs:32:8 | -LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { - | ___________________________________^ -LL | | -LL | | -LL | | -... | -LL | | -LL | | }; - | |_^ one type is more general than the other +LL | f: &id, + | ^^^ one type is more general than the other | = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>` found type `Fn<(&Foo<'_>,)>` error: implementation of `FnOnce` is not general enough - --> $DIR/rfc1623.rs:29:35 + --> $DIR/rfc1623.rs:32:8 | -LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { - | ___________________________________^ -LL | | -LL | | -LL | | -... | -LL | | -LL | | }; - | |_^ implementation of `FnOnce` is not general enough +LL | f: &id, + | ^^^ implementation of `FnOnce` is not general enough | = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2` error: implementation of `FnOnce` is not general enough - --> $DIR/rfc1623.rs:29:35 + --> $DIR/rfc1623.rs:32:8 | -LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { - | ___________________________________^ -LL | | -LL | | -LL | | -... | -LL | | -LL | | }; - | |_^ implementation of `FnOnce` is not general enough +LL | f: &id, + | ^^^ implementation of `FnOnce` is not general enough | = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2` diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs index 0e9d214032425..443da0aa955f9 100644 --- a/src/test/ui/rfc1623.rs +++ b/src/test/ui/rfc1623.rs @@ -27,14 +27,14 @@ fn id(t: T) -> T { } static SOME_STRUCT: &SomeStruct = &SomeStruct { - //[nll]~^ ERROR mismatched types - //[nll]~| ERROR mismatched types - //[nll]~| ERROR implementation of `FnOnce` is not general enough - //[nll]~| ERROR implementation of `FnOnce` is not general enough foo: &Foo { bools: &[false, true] }, bar: &Bar { bools: &[true, true] }, f: &id, //[base]~^ ERROR implementation of `FnOnce` is not general enough + //[nll]~^^ ERROR mismatched types + //[nll]~| ERROR mismatched types + //[nll]~| ERROR implementation of `FnOnce` is not general enough + //[nll]~| ERROR implementation of `FnOnce` is not general enough }; // very simple test for a 'static static with default lifetime diff --git a/src/test/ui/statics/uninhabited-static.rs b/src/test/ui/statics/uninhabited-static.rs index d564547489106..f5c6f444317fe 100644 --- a/src/test/ui/statics/uninhabited-static.rs +++ b/src/test/ui/statics/uninhabited-static.rs @@ -11,11 +11,11 @@ extern { static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type //~| WARN: previously accepted -//~| ERROR undefined behavior to use this value +//~| ERROR could not evaluate static initializer //~| WARN: type `Void` does not permit zero-initialization static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type //~| WARN: previously accepted -//~| ERROR undefined behavior to use this value +//~| ERROR could not evaluate static initializer //~| WARN: type `Void` does not permit zero-initialization fn main() {} diff --git a/src/test/ui/statics/uninhabited-static.stderr b/src/test/ui/statics/uninhabited-static.stderr index c38cf10d6e648..1e0becb7d5aa8 100644 --- a/src/test/ui/statics/uninhabited-static.stderr +++ b/src/test/ui/statics/uninhabited-static.stderr @@ -43,23 +43,17 @@ LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; = note: for more information, see issue #74840 = note: uninhabited statics cannot be initialized, and any access would be an immediate error -error[E0080]: it is undefined behavior to use this value - --> $DIR/uninhabited-static.rs:12:1 +error[E0080]: could not evaluate static initializer + --> $DIR/uninhabited-static.rs:12:31 | LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 0, align: 1) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type -error[E0080]: it is undefined behavior to use this value - --> $DIR/uninhabited-static.rs:16:1 +error[E0080]: could not evaluate static initializer + --> $DIR/uninhabited-static.rs:16:32 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 0, align: 1) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type warning: the type `Void` does not permit zero-initialization --> $DIR/uninhabited-static.rs:12:31 diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs b/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs new file mode 100644 index 0000000000000..b37ec2696de2f --- /dev/null +++ b/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs @@ -0,0 +1,29 @@ +// Verifies that MIR building for a call expression respects +// privacy when checking if a call return type is uninhabited. + +pub mod widget { + enum Unimplemented {} + pub struct Widget(Unimplemented); + + impl Widget { + pub fn new() -> Widget { + todo!(); + } + } + + pub fn f() { + let x: &mut u32; + Widget::new(); + // Ok. Widget type returned from new is known to be uninhabited + // and the following code is considered unreachable. + *x = 1; + } +} + +fn main() { + let y: &mut u32; + widget::Widget::new(); + // Error. Widget type is not known to be uninhabited here, + // so the following code is considered reachable. + *y = 2; //~ ERROR use of possibly-uninitialized variable +} diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr new file mode 100644 index 0000000000000..fb1953411685e --- /dev/null +++ b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr @@ -0,0 +1,9 @@ +error[E0381]: use of possibly-uninitialized variable: `y` + --> $DIR/privately-uninhabited-mir-call.rs:28:5 + | +LL | *y = 2; + | ^^^^^^ use of possibly-uninitialized `y` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr index 33f762ccf6301..e7960960774fc 100644 --- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr +++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr @@ -1,11 +1,27 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/issue-45087-unreachable-unsafe.rs:6:5 + --> $DIR/issue-45087-unreachable-unsafe.rs:7:5 | LL | *(1 as *mut u32) = 42; | ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer | = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior -error: aborting due to previous error +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/issue-45087-unreachable-unsafe.rs:17:5 + | +LL | *a = 1; + | ^^^^^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/issue-45087-unreachable-unsafe.rs:29:5 + | +LL | *b = 1; + | ^^^^^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs index 071cea8fbd78b..3e3da667c0b08 100644 --- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs +++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs @@ -1,3 +1,4 @@ +// Verify that unreachable code undergoes unsafety checks. // revisions: mir thir // [thir]compile-flags: -Z thir-unsafeck @@ -6,3 +7,25 @@ fn main() { *(1 as *mut u32) = 42; //~^ ERROR dereference of raw pointer is unsafe } + +fn panic() -> ! { + panic!(); +} + +fn f(a: *mut u32) { + panic(); + *a = 1; + //~^ ERROR dereference of raw pointer is unsafe +} + +enum Void {} + +fn uninhabited() -> Void { + panic!(); +} + +fn g(b: *mut u32) { + uninhabited(); + *b = 1; + //~^ ERROR dereference of raw pointer is unsafe +} diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr index 73a113652b833..e81adad450750 100644 --- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr +++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr @@ -1,11 +1,27 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/issue-45087-unreachable-unsafe.rs:6:5 + --> $DIR/issue-45087-unreachable-unsafe.rs:7:5 | LL | *(1 as *mut u32) = 42; | ^^^^^^^^^^^^^^^^ dereference of raw pointer | = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior -error: aborting due to previous error +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/issue-45087-unreachable-unsafe.rs:17:5 + | +LL | *a = 1; + | ^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/issue-45087-unreachable-unsafe.rs:29:5 + | +LL | *b = 1; + | ^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0133`.