diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index f6ec410bfac..8ec1f5a99e7 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1992,7 +1992,11 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( } } if (DiagnosticHandlerCallback) { +#if LLVM_VERSION_GE(19, 0) + DiagnosticHandlerCallback(&DI, DiagnosticHandlerContext); +#else DiagnosticHandlerCallback(DI, DiagnosticHandlerContext); +#endif return true; } return false; diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index fcfd05ccbac..6d083e66a9b 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1111,7 +1111,10 @@ fn as_range(&self) -> Option<&'pat PatRange<'tcx>> { #[derive(Debug, Clone)] pub(crate) struct MatchPair<'pat, 'tcx> { /// This place... - place: PlaceBuilder<'tcx>, + // This can be `None` if it referred to a non-captured place in a closure. + // Invariant: place.is_none() => test_case is Irrefutable + // In other words this must be `Some(_)` after simplification. + place: Option>, /// ... must pass this test... // Invariant: after creation and simplification in `Candidate::new()`, this must not be @@ -1595,11 +1598,12 @@ fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { fn pick_test( &mut self, candidates: &mut [&mut Candidate<'_, 'tcx>], - ) -> (PlaceBuilder<'tcx>, Test<'tcx>) { + ) -> (Place<'tcx>, Test<'tcx>) { // Extract the match-pair from the highest priority candidate let match_pair = &candidates.first().unwrap().match_pairs[0]; let test = self.test(match_pair); - let match_place = match_pair.place.clone(); + // Unwrap is ok after simplification. + let match_place = match_pair.place.unwrap(); debug!(?test, ?match_pair); (match_place, test) @@ -1640,7 +1644,7 @@ fn pick_test( /// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`. fn sort_candidates<'b, 'c, 'pat>( &mut self, - match_place: &PlaceBuilder<'tcx>, + match_place: Place<'tcx>, test: &Test<'tcx>, mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], ) -> ( @@ -1658,7 +1662,7 @@ fn sort_candidates<'b, 'c, 'pat>( // sorting. while let Some(candidate) = candidates.first_mut() { let Some(branch) = - self.sort_candidate(&match_place, test, candidate, &target_candidates) + self.sort_candidate(match_place, test, candidate, &target_candidates) else { break; }; @@ -1786,7 +1790,7 @@ fn test_candidates<'pat, 'b, 'c>( // For each of the N possible test outcomes, build the vector of candidates that applies if // the test has that particular outcome. let (remaining_candidates, target_candidates) = - self.sort_candidates(&match_place, &test, candidates); + self.sort_candidates(match_place, &test, candidates); // The block that we should branch to if none of the // `target_candidates` match. @@ -1826,7 +1830,7 @@ fn test_candidates<'pat, 'b, 'c>( scrutinee_span, start_block, remainder_start, - &match_place, + match_place, &test, target_blocks, ); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 9d77bd063e1..b66dd83b7ec 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -5,7 +5,6 @@ // identify what tests are needed, perform the tests, and then filter // the candidates based on the result. -use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Candidate, MatchPair, Test, TestBranch, TestCase, TestKind}; use crate::build::Builder; use rustc_data_structures::fx::FxIndexMap; @@ -55,18 +54,17 @@ pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test< Test { span: match_pair.pattern.span, kind } } - #[instrument(skip(self, target_blocks, place_builder), level = "debug")] + #[instrument(skip(self, target_blocks, place), level = "debug")] pub(super) fn perform_test( &mut self, match_start_span: Span, scrutinee_span: Span, block: BasicBlock, otherwise_block: BasicBlock, - place_builder: &PlaceBuilder<'tcx>, + place: Place<'tcx>, test: &Test<'tcx>, target_blocks: FxIndexMap, BasicBlock>, ) { - let place = place_builder.to_place(self); let place_ty = place.ty(&self.local_decls, self.tcx); debug!(?place, ?place_ty); let target_block = |branch| target_blocks.get(&branch).copied().unwrap_or(otherwise_block); @@ -475,7 +473,7 @@ fn non_scalar_compare( /// tighter match code if we do something a bit different. pub(super) fn sort_candidate( &mut self, - test_place: &PlaceBuilder<'tcx>, + test_place: Place<'tcx>, test: &Test<'tcx>, candidate: &mut Candidate<'_, 'tcx>, sorted_candidates: &FxIndexMap, Vec<&mut Candidate<'_, 'tcx>>>, @@ -486,8 +484,11 @@ pub(super) fn sort_candidate( // than one, but it'd be very unusual to have two sides that // both require tests; you'd expect one side to be simplified // away.) - let (match_pair_index, match_pair) = - candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?; + let (match_pair_index, match_pair) = candidate + .match_pairs + .iter() + .enumerate() + .find(|&(_, mp)| mp.place == Some(test_place))?; let fully_matched; let ret = match (&test.kind, &match_pair.test_case) { @@ -521,7 +522,7 @@ pub(super) fn sort_candidate( candidate .match_pairs .iter() - .any(|mp| mp.place == *test_place && is_covering_range(&mp.test_case)) + .any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case)) }; if sorted_candidates .get(&TestBranch::Failure) diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 1148cd19a01..bc6f0a26582 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -95,35 +95,37 @@ pub(crate) fn false_edges( impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { pub(in crate::build) fn new( - mut place: PlaceBuilder<'tcx>, + mut place_builder: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, cx: &mut Builder<'_, 'tcx>, ) -> MatchPair<'pat, 'tcx> { // Force the place type to the pattern's type. // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? - if let Some(resolved) = place.resolve_upvar(cx) { - place = resolved; + if let Some(resolved) = place_builder.resolve_upvar(cx) { + place_builder = resolved; } // Only add the OpaqueCast projection if the given place is an opaque type and the // expected type from the pattern is not. - let may_need_cast = match place.base() { + let may_need_cast = match place_builder.base() { PlaceBase::Local(local) => { - let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty; + let ty = + Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty; ty != pattern.ty && ty.has_opaque_types() } _ => true, }; if may_need_cast { - place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); + place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); } + let place = place_builder.try_to_place(cx); let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; let mut subpairs = Vec::new(); let test_case = match pattern.kind { PatKind::Never | PatKind::Wild | PatKind::Error(_) => default_irrefutable(), PatKind::Or { ref pats } => TestCase::Or { - pats: pats.iter().map(|pat| FlatPat::new(place.clone(), pat, cx)).collect(), + pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), }, PatKind::Range(ref range) => { @@ -142,13 +144,13 @@ pub(in crate::build) fn new( .. } => { // Apply the type ascription to the value at `match_pair.place` - let ascription = place.try_to_place(cx).map(|source| super::Ascription { + let ascription = place.map(|source| super::Ascription { annotation: annotation.clone(), source, variance, }); - subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); + subpairs.push(MatchPair::new(place_builder, subpattern, cx)); TestCase::Irrefutable { ascription, binding: None } } @@ -161,7 +163,7 @@ pub(in crate::build) fn new( ref subpattern, is_primary: _, } => { - let binding = place.try_to_place(cx).map(|source| super::Binding { + let binding = place.map(|source| super::Binding { span: pattern.span, source, var_id: var, @@ -170,14 +172,14 @@ pub(in crate::build) fn new( if let Some(subpattern) = subpattern.as_ref() { // this is the `x @ P` case; have to keep matching against `P` now - subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); + subpairs.push(MatchPair::new(place_builder, subpattern, cx)); } TestCase::Irrefutable { ascription: None, binding } } PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { // Apply a type ascription for the inline constant to the value at `match_pair.place` - let ascription = place.try_to_place(cx).map(|source| { + let ascription = place.map(|source| { let span = pattern.span; let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); let args = ty::InlineConstArgs::new( @@ -203,16 +205,16 @@ pub(in crate::build) fn new( super::Ascription { annotation, source, variance: ty::Contravariant } }); - subpairs.push(MatchPair::new(place.clone(), pattern, cx)); + subpairs.push(MatchPair::new(place_builder, pattern, cx)); TestCase::Irrefutable { ascription, binding: None } } PatKind::Array { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix); + cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); default_irrefutable() } PatKind::Slice { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix); + cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); if prefix.is_empty() && slice.is_some() && suffix.is_empty() { default_irrefutable() @@ -225,7 +227,7 @@ pub(in crate::build) fn new( } PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { - let downcast_place = place.clone().downcast(adt_def, variant_index); // `(x as Variant)` + let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` subpairs = cx.field_match_pairs(downcast_place, subpatterns); let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { @@ -247,13 +249,12 @@ pub(in crate::build) fn new( } PatKind::Leaf { ref subpatterns } => { - subpairs = cx.field_match_pairs(place.clone(), subpatterns); + subpairs = cx.field_match_pairs(place_builder, subpatterns); default_irrefutable() } PatKind::Deref { ref subpattern } => { - let place_builder = place.clone().deref(); - subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx)); default_irrefutable() } @@ -310,8 +311,8 @@ fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) { } } else { // Insert a Shallow borrow of any place that is switched on. - if let Some(resolved_place) = match_pair.place.try_to_place(self.cx) { - self.fake_borrows.insert(resolved_place); + if let Some(place) = match_pair.place { + self.fake_borrows.insert(place); } for subpair in &match_pair.subpairs { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ebc30c08910..20b7d0afa87 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -170,6 +170,7 @@ #![feature(unicode_internals)] #![feature(unsize)] #![feature(utf8_chunks)] +#![feature(vec_pop_if)] // tidy-alphabetical-end // // Language features: diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 3062f8664b7..8ca8046dac5 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2058,6 +2058,31 @@ pub fn pop(&mut self) -> Option { } } + /// Removes and returns the last element in a vector if the predicate + /// returns `true`, or [`None`] if the predicate returns false or the vector + /// is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_pop_if)] + /// + /// let mut vec = vec![1, 2, 3, 4]; + /// let pred = |x: &mut i32| *x % 2 == 0; + /// + /// assert_eq!(vec.pop_if(pred), Some(4)); + /// assert_eq!(vec, [1, 2, 3]); + /// assert_eq!(vec.pop_if(pred), None); + /// ``` + #[unstable(feature = "vec_pop_if", issue = "122741")] + pub fn pop_if(&mut self, f: F) -> Option + where + F: FnOnce(&mut T) -> bool, + { + let last = self.last_mut()?; + if f(last) { self.pop() } else { None } + } + /// Moves all the elements of `other` into `self`, leaving `other` empty. /// /// # Panics diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index f58998fbd79..04709af5c0a 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -43,6 +43,7 @@ #![feature(strict_provenance)] #![feature(drain_keep_rest)] #![feature(local_waker)] +#![feature(vec_pop_if)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index f1f841fe190..71d79893e01 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -2644,6 +2644,36 @@ fn test_vec_from_array_mut_ref() { assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]); } +#[test] +fn test_pop_if() { + let mut v = vec![1, 2, 3, 4]; + let pred = |x: &mut i32| *x % 2 == 0; + + assert_eq!(v.pop_if(pred), Some(4)); + assert_eq!(v, [1, 2, 3]); + + assert_eq!(v.pop_if(pred), None); + assert_eq!(v, [1, 2, 3]); +} + +#[test] +fn test_pop_if_empty() { + let mut v = Vec::::new(); + assert_eq!(v.pop_if(|_| true), None); + assert!(v.is_empty()); +} + +#[test] +fn test_pop_if_mutates() { + let mut v = vec![1]; + let pred = |x: &mut i32| { + *x += 1; + false + }; + assert_eq!(v.pop_if(pred), None); + assert_eq!(v, [2]); +} + /// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments /// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but /// `vec.insert(usize::MAX, val)` once slipped by! diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index d67493aaf4d..9b01d232611 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -580,6 +580,10 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { io::Read::read(&mut &*self, buf) } + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + io::Read::read_buf(&mut &*self, buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { io::Read::read_vectored(&mut &*self, bufs) } @@ -596,6 +600,10 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index d648cd08994..e0a8a7603d7 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -31,13 +31,14 @@ ///
Potential deadlock example /// /// ```text -/// // Thread 1 | // Thread 2 -/// let _rg = lock.read(); | -/// | // will block -/// | let _wg = lock.write(); -/// // may deadlock | -/// let _rg = lock.read(); | +/// // Thread 1 | // Thread 2 +/// let _rg1 = lock.read(); | +/// | // will block +/// | let _wg = lock.write(); +/// // may deadlock | +/// let _rg2 = lock.read(); | /// ``` +/// ///
/// /// The type parameter `T` represents the data that this lock protects. It is diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index a1c0321876f..9d8cc18b838 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -167,6 +167,8 @@ pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { } #[cfg(any( + target_os = "aix", + target_os = "dragonfly", // DragonFly 1.5 target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", @@ -174,6 +176,7 @@ pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { target_os = "illumos", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", // OpenBSD 2.7 ))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { let ret = cvt(unsafe { @@ -188,7 +191,9 @@ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io:: } #[cfg(not(any( + target_os = "aix", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", @@ -199,6 +204,8 @@ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io:: target_os = "linux", target_os = "macos", target_os = "netbsd", + target_os = "openbsd", + target_os = "watchos", )))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { io::default_read_vectored(|b| self.read_at(b, offset), bufs) @@ -236,9 +243,10 @@ fn preadv( // no `syscall` possible in these platform. #[cfg(any( all(target_os = "android", target_pointer_width = "32"), - target_os = "ios", - target_os = "tvos", - target_os = "macos", + target_os = "ios", // ios 14.0 + target_os = "tvos", // tvos 14.0 + target_os = "macos", // macos 11.0 + target_os = "watchos", // watchos 7.0 ))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); @@ -318,6 +326,8 @@ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { } #[cfg(any( + target_os = "aix", + target_os = "dragonfly", // DragonFly 1.5 target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", @@ -325,6 +335,7 @@ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { target_os = "illumos", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", // OpenBSD 2.7 ))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { let ret = cvt(unsafe { @@ -339,7 +350,9 @@ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result } #[cfg(not(any( + target_os = "aix", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", @@ -350,6 +363,8 @@ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result target_os = "linux", target_os = "macos", target_os = "netbsd", + target_os = "openbsd", + target_os = "watchos", )))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { io::default_write_vectored(|b| self.write_at(b, offset), bufs) @@ -387,9 +402,10 @@ fn pwritev( // no `syscall` possible in these platform. #[cfg(any( all(target_os = "android", target_pointer_width = "32"), - target_os = "ios", - target_os = "tvos", - target_os = "macos", + target_os = "ios", // ios 14.0 + target_os = "tvos", // tvos 14.0 + target_os = "macos", // macos 11.0 + target_os = "watchos", // watchos 7.0 ))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index a3e1b6782e8..4cd7c0e3059 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -424,7 +424,7 @@ pub fn available_parallelism() -> io::Result> { if !set.is_null() { let mut count: usize = 0; if libc::pthread_getaffinity_np(libc::pthread_self(), libc::_cpuset_size(set), set) == 0 { - for i in 0..u64::MAX { + for i in 0..libc::cpuid_t::MAX { match libc::_cpuset_isset(i, set) { -1 => break, 0 => continue,