Skip to content

Commit

Permalink
Auto merge of rust-lang#123121 - matthiaskrgr:rollup-e4glcv3, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang#122439 (match lowering: build the `Place` instead of keeping a `PlaceBuilder` around)
 - rust-lang#122880 (Unix: Support more platforms with `preadv` and `pwritev`)
 - rust-lang#123038 (std library thread.rs: fix NetBSD code for ILP32 CPUs.)
 - rust-lang#123084 (`UnixStream`: override `read_buf`)
 - rust-lang#123102 (RustWrapper: update call for llvm/llvm-project@44d037cc258dcf179d2c48…)
 - rust-lang#123107 (Implement `Vec::pop_if`)
 - rust-lang#123118 (Update `RwLock` deadlock example to not use shadowing)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Mar 27, 2024
2 parents 435b525 + bce5253 commit 37f9798
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 49 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 11 additions & 7 deletions compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,10 @@ impl<'pat, 'tcx> TestCase<'pat, '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<Place<'tcx>>,

/// ... must pass this test...
// Invariant: after creation and simplification in `Candidate::new()`, this must not be
Expand Down Expand Up @@ -1595,11 +1598,12 @@ impl<'a, 'tcx> Builder<'a, '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)
Expand Down Expand Up @@ -1640,7 +1644,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// - 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>],
) -> (
Expand All @@ -1658,7 +1662,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// 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;
};
Expand Down Expand Up @@ -1786,7 +1790,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// 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.
Expand Down Expand Up @@ -1826,7 +1830,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
scrutinee_span,
start_block,
remainder_start,
&match_place,
match_place,
&test,
target_blocks,
);
Expand Down
17 changes: 9 additions & 8 deletions compiler/rustc_mir_build/src/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -55,18 +54,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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<TestBranch<'tcx>, 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);
Expand Down Expand Up @@ -475,7 +473,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// 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<TestBranch<'tcx>, Vec<&mut Candidate<'_, 'tcx>>>,
Expand All @@ -486,8 +484,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// 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) {
Expand Down Expand Up @@ -521,7 +522,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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)
Expand Down
43 changes: 22 additions & 21 deletions compiler/rustc_mir_build/src/build/matches/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,35 +95,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

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) => {
Expand All @@ -142,13 +144,13 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
..
} => {
// 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 }
}

Expand All @@ -161,7 +163,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
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,
Expand All @@ -170,14 +172,14 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {

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(
Expand All @@ -203,16 +205,16 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
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()
Expand All @@ -225,7 +227,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
}

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)| {
Expand All @@ -247,13 +249,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
}

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()
}

Expand Down Expand Up @@ -310,8 +311,8 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, '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 {
Expand Down
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
#![feature(unicode_internals)]
#![feature(unsize)]
#![feature(utf8_chunks)]
#![feature(vec_pop_if)]
// tidy-alphabetical-end
//
// Language features:
Expand Down
25 changes: 25 additions & 0 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2058,6 +2058,31 @@ impl<T, A: Allocator> Vec<T, A> {
}
}

/// 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<F>(&mut self, f: F) -> Option<T>
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
Expand Down
1 change: 1 addition & 0 deletions library/alloc/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
30 changes: 30 additions & 0 deletions library/alloc/tests/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<i32>::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!
Expand Down
8 changes: 8 additions & 0 deletions library/std/src/os/unix/net/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,10 @@ impl io::Read for UnixStream {
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<usize> {
io::Read::read_vectored(&mut &*self, bufs)
}
Expand All @@ -596,6 +600,10 @@ impl<'a> io::Read for &'a UnixStream {
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<usize> {
self.0.read_vectored(bufs)
}
Expand Down
Loading

0 comments on commit 37f9798

Please sign in to comment.