Auto merge of #141791 - workingjubilee:rollup-qnqicy9, r=workingjubilee
Rollup of 8 pull requests Successful merges: - rust-lang/rust#140825 (Add Range parameter to `BTreeMap::extract_if` and `BTreeSet::extract_if`) - rust-lang/rust#141077 (Fix the issue of typo of comma in arm parsing) - rust-lang/rust#141237 (Implement ((un)checked_)exact_div methods for integers) - rust-lang/rust#141494 (mir-opt: Do not transform non-int type in match_branches) - rust-lang/rust#141609 (core: begin deduplicating pointer docs) - rust-lang/rust#141768 (ci: use arm to calculate job matrix) - rust-lang/rust#141771 (Increase timeout for new bors try builds) - rust-lang/rust#141781 (Fix spans for unsafe binders) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0b00e6847b
31 changed files with 716 additions and 217 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -46,7 +46,7 @@ jobs:
|
|||
# If you want to modify CI jobs, take a look at src/ci/github-actions/jobs.yml.
|
||||
calculate_matrix:
|
||||
name: Calculate job matrix
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-24.04-arm
|
||||
outputs:
|
||||
jobs: ${{ steps.jobs.outputs.jobs }}
|
||||
run_type: ${{ steps.jobs.outputs.run_type }}
|
||||
|
|
|
|||
|
|
@ -284,12 +284,14 @@ fn can_cast(
|
|||
let v = match src_layout.ty.kind() {
|
||||
ty::Uint(_) => from_scalar.to_uint(src_layout.size),
|
||||
ty::Int(_) => from_scalar.to_int(src_layout.size) as u128,
|
||||
_ => unreachable!("invalid int"),
|
||||
// We can also transform the values of other integer representations (such as char),
|
||||
// although this may not be practical in real-world scenarios.
|
||||
_ => return false,
|
||||
};
|
||||
let size = match *cast_ty.kind() {
|
||||
ty::Int(t) => Integer::from_int_ty(&tcx, t).size(),
|
||||
ty::Uint(t) => Integer::from_uint_ty(&tcx, t).size(),
|
||||
_ => unreachable!("invalid int"),
|
||||
_ => return false,
|
||||
};
|
||||
let v = size.truncate(v);
|
||||
let cast_scalar = ScalarInt::try_from_uint(v, size).unwrap();
|
||||
|
|
|
|||
|
|
@ -3311,26 +3311,44 @@ impl<'a> Parser<'a> {
|
|||
let sm = this.psess.source_map();
|
||||
if let Ok(expr_lines) = sm.span_to_lines(expr_span)
|
||||
&& let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
|
||||
&& arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col
|
||||
&& expr_lines.lines.len() == 2
|
||||
{
|
||||
// We check whether there's any trailing code in the parse span,
|
||||
// if there isn't, we very likely have the following:
|
||||
//
|
||||
// X | &Y => "y"
|
||||
// | -- - missing comma
|
||||
// | |
|
||||
// | arrow_span
|
||||
// X | &X => "x"
|
||||
// | - ^^ self.token.span
|
||||
// | |
|
||||
// | parsed until here as `"y" & X`
|
||||
err.span_suggestion_short(
|
||||
arm_start_span.shrink_to_hi(),
|
||||
"missing a comma here to end this `match` arm",
|
||||
",",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col {
|
||||
// We check whether there's any trailing code in the parse span,
|
||||
// if there isn't, we very likely have the following:
|
||||
//
|
||||
// X | &Y => "y"
|
||||
// | -- - missing comma
|
||||
// | |
|
||||
// | arrow_span
|
||||
// X | &X => "x"
|
||||
// | - ^^ self.token.span
|
||||
// | |
|
||||
// | parsed until here as `"y" & X`
|
||||
err.span_suggestion_short(
|
||||
arm_start_span.shrink_to_hi(),
|
||||
"missing a comma here to end this `match` arm",
|
||||
",",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if arm_start_lines.lines[0].end_col + rustc_span::CharPos(1)
|
||||
== expr_lines.lines[0].end_col
|
||||
{
|
||||
// similar to the above, but we may typo a `.` or `/` at the end of the line
|
||||
let comma_span = arm_start_span
|
||||
.shrink_to_hi()
|
||||
.with_hi(arm_start_span.hi() + rustc_span::BytePos(1));
|
||||
if let Ok(res) = sm.span_to_snippet(comma_span)
|
||||
&& (res == "." || res == "/")
|
||||
{
|
||||
err.span_suggestion_short(
|
||||
comma_span,
|
||||
"you might have meant to write a `,` to end this `match` arm",
|
||||
",",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err.span_label(
|
||||
|
|
|
|||
|
|
@ -934,8 +934,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
|||
)
|
||||
}
|
||||
TyKind::UnsafeBinder(unsafe_binder) => {
|
||||
// FIXME(unsafe_binder): Better span
|
||||
let span = ty.span;
|
||||
let span = ty.span.shrink_to_lo().to(unsafe_binder.inner_ty.span.shrink_to_lo());
|
||||
self.with_generic_param_rib(
|
||||
&unsafe_binder.generic_params,
|
||||
RibKind::Normal,
|
||||
|
|
|
|||
|
|
@ -1151,7 +1151,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
K: Ord,
|
||||
F: FnMut(&K, &mut V) -> bool,
|
||||
{
|
||||
self.extract_if(|k, v| !f(k, v)).for_each(drop);
|
||||
self.extract_if(.., |k, v| !f(k, v)).for_each(drop);
|
||||
}
|
||||
|
||||
/// Moves all elements from `other` into `self`, leaving `other` empty.
|
||||
|
|
@ -1397,7 +1397,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates an iterator that visits all elements (key-value pairs) in
|
||||
/// Creates an iterator that visits elements (key-value pairs) in the specified range in
|
||||
/// ascending key order and uses a closure to determine if an element
|
||||
/// should be removed.
|
||||
///
|
||||
|
|
@ -1423,33 +1423,42 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
|
||||
/// let evens: BTreeMap<_, _> = map.extract_if(|k, _v| k % 2 == 0).collect();
|
||||
/// let evens: BTreeMap<_, _> = map.extract_if(.., |k, _v| k % 2 == 0).collect();
|
||||
/// let odds = map;
|
||||
/// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), [0, 2, 4, 6]);
|
||||
/// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]);
|
||||
///
|
||||
/// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
|
||||
/// let low: BTreeMap<_, _> = map.extract_if(0..4, |_k, _v| true).collect();
|
||||
/// let high = map;
|
||||
/// assert_eq!(low.keys().copied().collect::<Vec<_>>(), [0, 1, 2, 3]);
|
||||
/// assert_eq!(high.keys().copied().collect::<Vec<_>>(), [4, 5, 6, 7]);
|
||||
/// ```
|
||||
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A>
|
||||
pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, K, V, R, F, A>
|
||||
where
|
||||
K: Ord,
|
||||
R: RangeBounds<K>,
|
||||
F: FnMut(&K, &mut V) -> bool,
|
||||
{
|
||||
let (inner, alloc) = self.extract_if_inner();
|
||||
let (inner, alloc) = self.extract_if_inner(range);
|
||||
ExtractIf { pred, inner, alloc }
|
||||
}
|
||||
|
||||
pub(super) fn extract_if_inner(&mut self) -> (ExtractIfInner<'_, K, V>, A)
|
||||
pub(super) fn extract_if_inner<R>(&mut self, range: R) -> (ExtractIfInner<'_, K, V, R>, A)
|
||||
where
|
||||
K: Ord,
|
||||
R: RangeBounds<K>,
|
||||
{
|
||||
if let Some(root) = self.root.as_mut() {
|
||||
let (root, dormant_root) = DormantMutRef::new(root);
|
||||
let front = root.borrow_mut().first_leaf_edge();
|
||||
let first = root.borrow_mut().lower_bound(SearchBound::from_range(range.start_bound()));
|
||||
(
|
||||
ExtractIfInner {
|
||||
length: &mut self.length,
|
||||
dormant_root: Some(dormant_root),
|
||||
cur_leaf_edge: Some(front),
|
||||
cur_leaf_edge: Some(first),
|
||||
range,
|
||||
},
|
||||
(*self.alloc).clone(),
|
||||
)
|
||||
|
|
@ -1459,6 +1468,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
length: &mut self.length,
|
||||
dormant_root: None,
|
||||
cur_leaf_edge: None,
|
||||
range,
|
||||
},
|
||||
(*self.alloc).clone(),
|
||||
)
|
||||
|
|
@ -1917,18 +1927,19 @@ pub struct ExtractIf<
|
|||
'a,
|
||||
K,
|
||||
V,
|
||||
R,
|
||||
F,
|
||||
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
|
||||
> {
|
||||
pred: F,
|
||||
inner: ExtractIfInner<'a, K, V>,
|
||||
inner: ExtractIfInner<'a, K, V, R>,
|
||||
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
|
||||
alloc: A,
|
||||
}
|
||||
|
||||
/// Most of the implementation of ExtractIf are generic over the type
|
||||
/// of the predicate, thus also serving for BTreeSet::ExtractIf.
|
||||
pub(super) struct ExtractIfInner<'a, K, V> {
|
||||
pub(super) struct ExtractIfInner<'a, K, V, R> {
|
||||
/// Reference to the length field in the borrowed map, updated live.
|
||||
length: &'a mut usize,
|
||||
/// Buried reference to the root field in the borrowed map.
|
||||
|
|
@ -1938,10 +1949,13 @@ pub(super) struct ExtractIfInner<'a, K, V> {
|
|||
/// Empty if the map has no root, if iteration went beyond the last leaf edge,
|
||||
/// or if a panic occurred in the predicate.
|
||||
cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
|
||||
/// Range over which iteration was requested. We don't need the left side, but we
|
||||
/// can't extract the right side without requiring K: Clone.
|
||||
range: R,
|
||||
}
|
||||
|
||||
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||
impl<K, V, F, A> fmt::Debug for ExtractIf<'_, K, V, F, A>
|
||||
impl<K, V, R, F, A> fmt::Debug for ExtractIf<'_, K, V, R, F, A>
|
||||
where
|
||||
K: fmt::Debug,
|
||||
V: fmt::Debug,
|
||||
|
|
@ -1953,8 +1967,10 @@ where
|
|||
}
|
||||
|
||||
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||
impl<K, V, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, F, A>
|
||||
impl<K, V, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, R, F, A>
|
||||
where
|
||||
K: PartialOrd,
|
||||
R: RangeBounds<K>,
|
||||
F: FnMut(&K, &mut V) -> bool,
|
||||
{
|
||||
type Item = (K, V);
|
||||
|
|
@ -1968,7 +1984,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> ExtractIfInner<'a, K, V> {
|
||||
impl<'a, K, V, R> ExtractIfInner<'a, K, V, R> {
|
||||
/// Allow Debug implementations to predict the next element.
|
||||
pub(super) fn peek(&self) -> Option<(&K, &V)> {
|
||||
let edge = self.cur_leaf_edge.as_ref()?;
|
||||
|
|
@ -1978,10 +1994,22 @@ impl<'a, K, V> ExtractIfInner<'a, K, V> {
|
|||
/// Implementation of a typical `ExtractIf::next` method, given the predicate.
|
||||
pub(super) fn next<F, A: Allocator + Clone>(&mut self, pred: &mut F, alloc: A) -> Option<(K, V)>
|
||||
where
|
||||
K: PartialOrd,
|
||||
R: RangeBounds<K>,
|
||||
F: FnMut(&K, &mut V) -> bool,
|
||||
{
|
||||
while let Ok(mut kv) = self.cur_leaf_edge.take()?.next_kv() {
|
||||
let (k, v) = kv.kv_mut();
|
||||
|
||||
// On creation, we navigated directly to the left bound, so we need only check the
|
||||
// right bound here to decide whether to stop.
|
||||
match self.range.end_bound() {
|
||||
Bound::Included(ref end) if (*k).le(end) => (),
|
||||
Bound::Excluded(ref end) if (*k).lt(end) => (),
|
||||
Bound::Unbounded => (),
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
if pred(k, v) {
|
||||
*self.length -= 1;
|
||||
let (kv, pos) = kv.remove_kv_tracking(
|
||||
|
|
@ -2013,7 +2041,13 @@ impl<'a, K, V> ExtractIfInner<'a, K, V> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||
impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
|
||||
impl<K, V, R, F> FusedIterator for ExtractIf<'_, K, V, R, F>
|
||||
where
|
||||
K: PartialOrd,
|
||||
R: RangeBounds<K>,
|
||||
F: FnMut(&K, &mut V) -> bool,
|
||||
{
|
||||
}
|
||||
|
||||
#[stable(feature = "btree_range", since = "1.17.0")]
|
||||
impl<'a, K, V> Iterator for Range<'a, K, V> {
|
||||
|
|
|
|||
|
|
@ -944,7 +944,7 @@ mod test_extract_if {
|
|||
#[test]
|
||||
fn empty() {
|
||||
let mut map: BTreeMap<i32, i32> = BTreeMap::new();
|
||||
map.extract_if(|_, _| unreachable!("there's nothing to decide on")).for_each(drop);
|
||||
map.extract_if(.., |_, _| unreachable!("there's nothing to decide on")).for_each(drop);
|
||||
assert_eq!(map.height(), None);
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -954,7 +954,7 @@ mod test_extract_if {
|
|||
fn consumed_keeping_all() {
|
||||
let pairs = (0..3).map(|i| (i, i));
|
||||
let mut map = BTreeMap::from_iter(pairs);
|
||||
assert!(map.extract_if(|_, _| false).eq(iter::empty()));
|
||||
assert!(map.extract_if(.., |_, _| false).eq(iter::empty()));
|
||||
map.check();
|
||||
}
|
||||
|
||||
|
|
@ -963,18 +963,42 @@ mod test_extract_if {
|
|||
fn consumed_removing_all() {
|
||||
let pairs = (0..3).map(|i| (i, i));
|
||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||
assert!(map.extract_if(|_, _| true).eq(pairs));
|
||||
assert!(map.extract_if(.., |_, _| true).eq(pairs));
|
||||
assert!(map.is_empty());
|
||||
map.check();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn consumed_removing_some() {
|
||||
let pairs = (0..3).map(|i| (i, i));
|
||||
let map = BTreeMap::from_iter(pairs);
|
||||
for x in 0..3 {
|
||||
for y in 0..3 {
|
||||
let mut map = map.clone();
|
||||
assert!(map.extract_if(x..y, |_, _| true).eq((x..y).map(|i| (i, i))));
|
||||
for i in 0..3 {
|
||||
assert_ne!(map.contains_key(&i), (x..y).contains(&i));
|
||||
}
|
||||
}
|
||||
}
|
||||
for x in 0..3 {
|
||||
for y in 0..2 {
|
||||
let mut map = map.clone();
|
||||
assert!(map.extract_if(x..=y, |_, _| true).eq((x..=y).map(|i| (i, i))));
|
||||
for i in 0..3 {
|
||||
assert_ne!(map.contains_key(&i), (x..=y).contains(&i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Explicitly consumes the iterator and modifies values through it.
|
||||
#[test]
|
||||
fn mutating_and_keeping() {
|
||||
let pairs = (0..3).map(|i| (i, i));
|
||||
let mut map = BTreeMap::from_iter(pairs);
|
||||
assert!(
|
||||
map.extract_if(|_, v| {
|
||||
map.extract_if(.., |_, v| {
|
||||
*v += 6;
|
||||
false
|
||||
})
|
||||
|
|
@ -991,7 +1015,7 @@ mod test_extract_if {
|
|||
let pairs = (0..3).map(|i| (i, i));
|
||||
let mut map = BTreeMap::from_iter(pairs);
|
||||
assert!(
|
||||
map.extract_if(|_, v| {
|
||||
map.extract_if(.., |_, v| {
|
||||
*v += 6;
|
||||
true
|
||||
})
|
||||
|
|
@ -1005,7 +1029,7 @@ mod test_extract_if {
|
|||
fn underfull_keeping_all() {
|
||||
let pairs = (0..3).map(|i| (i, i));
|
||||
let mut map = BTreeMap::from_iter(pairs);
|
||||
map.extract_if(|_, _| false).for_each(drop);
|
||||
map.extract_if(.., |_, _| false).for_each(drop);
|
||||
assert!(map.keys().copied().eq(0..3));
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1015,7 +1039,7 @@ mod test_extract_if {
|
|||
let pairs = (0..3).map(|i| (i, i));
|
||||
for doomed in 0..3 {
|
||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||
map.extract_if(|i, _| *i == doomed).for_each(drop);
|
||||
map.extract_if(.., |i, _| *i == doomed).for_each(drop);
|
||||
assert_eq!(map.len(), 2);
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1026,7 +1050,7 @@ mod test_extract_if {
|
|||
let pairs = (0..3).map(|i| (i, i));
|
||||
for sacred in 0..3 {
|
||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||
map.extract_if(|i, _| *i != sacred).for_each(drop);
|
||||
map.extract_if(.., |i, _| *i != sacred).for_each(drop);
|
||||
assert!(map.keys().copied().eq(sacred..=sacred));
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1036,7 +1060,7 @@ mod test_extract_if {
|
|||
fn underfull_removing_all() {
|
||||
let pairs = (0..3).map(|i| (i, i));
|
||||
let mut map = BTreeMap::from_iter(pairs);
|
||||
map.extract_if(|_, _| true).for_each(drop);
|
||||
map.extract_if(.., |_, _| true).for_each(drop);
|
||||
assert!(map.is_empty());
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1045,7 +1069,7 @@ mod test_extract_if {
|
|||
fn height_0_keeping_all() {
|
||||
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
||||
let mut map = BTreeMap::from_iter(pairs);
|
||||
map.extract_if(|_, _| false).for_each(drop);
|
||||
map.extract_if(.., |_, _| false).for_each(drop);
|
||||
assert!(map.keys().copied().eq(0..node::CAPACITY));
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1055,7 +1079,7 @@ mod test_extract_if {
|
|||
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
||||
for doomed in 0..node::CAPACITY {
|
||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||
map.extract_if(|i, _| *i == doomed).for_each(drop);
|
||||
map.extract_if(.., |i, _| *i == doomed).for_each(drop);
|
||||
assert_eq!(map.len(), node::CAPACITY - 1);
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1066,7 +1090,7 @@ mod test_extract_if {
|
|||
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
||||
for sacred in 0..node::CAPACITY {
|
||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||
map.extract_if(|i, _| *i != sacred).for_each(drop);
|
||||
map.extract_if(.., |i, _| *i != sacred).for_each(drop);
|
||||
assert!(map.keys().copied().eq(sacred..=sacred));
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1076,7 +1100,7 @@ mod test_extract_if {
|
|||
fn height_0_removing_all() {
|
||||
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
||||
let mut map = BTreeMap::from_iter(pairs);
|
||||
map.extract_if(|_, _| true).for_each(drop);
|
||||
map.extract_if(.., |_, _| true).for_each(drop);
|
||||
assert!(map.is_empty());
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1084,7 +1108,7 @@ mod test_extract_if {
|
|||
#[test]
|
||||
fn height_0_keeping_half() {
|
||||
let mut map = BTreeMap::from_iter((0..16).map(|i| (i, i)));
|
||||
assert_eq!(map.extract_if(|i, _| *i % 2 == 0).count(), 8);
|
||||
assert_eq!(map.extract_if(.., |i, _| *i % 2 == 0).count(), 8);
|
||||
assert_eq!(map.len(), 8);
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1093,7 +1117,7 @@ mod test_extract_if {
|
|||
fn height_1_removing_all() {
|
||||
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
|
||||
let mut map = BTreeMap::from_iter(pairs);
|
||||
map.extract_if(|_, _| true).for_each(drop);
|
||||
map.extract_if(.., |_, _| true).for_each(drop);
|
||||
assert!(map.is_empty());
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1103,7 +1127,7 @@ mod test_extract_if {
|
|||
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
|
||||
for doomed in 0..MIN_INSERTS_HEIGHT_1 {
|
||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||
map.extract_if(|i, _| *i == doomed).for_each(drop);
|
||||
map.extract_if(.., |i, _| *i == doomed).for_each(drop);
|
||||
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_1 - 1);
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1114,7 +1138,7 @@ mod test_extract_if {
|
|||
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
|
||||
for sacred in 0..MIN_INSERTS_HEIGHT_1 {
|
||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||
map.extract_if(|i, _| *i != sacred).for_each(drop);
|
||||
map.extract_if(.., |i, _| *i != sacred).for_each(drop);
|
||||
assert!(map.keys().copied().eq(sacred..=sacred));
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1125,7 +1149,7 @@ mod test_extract_if {
|
|||
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
||||
for doomed in (0..MIN_INSERTS_HEIGHT_2).step_by(12) {
|
||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||
map.extract_if(|i, _| *i == doomed).for_each(drop);
|
||||
map.extract_if(.., |i, _| *i == doomed).for_each(drop);
|
||||
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_2 - 1);
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1136,7 +1160,7 @@ mod test_extract_if {
|
|||
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
||||
for sacred in (0..MIN_INSERTS_HEIGHT_2).step_by(12) {
|
||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||
map.extract_if(|i, _| *i != sacred).for_each(drop);
|
||||
map.extract_if(.., |i, _| *i != sacred).for_each(drop);
|
||||
assert!(map.keys().copied().eq(sacred..=sacred));
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1146,7 +1170,7 @@ mod test_extract_if {
|
|||
fn height_2_removing_all() {
|
||||
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
||||
let mut map = BTreeMap::from_iter(pairs);
|
||||
map.extract_if(|_, _| true).for_each(drop);
|
||||
map.extract_if(.., |_, _| true).for_each(drop);
|
||||
assert!(map.is_empty());
|
||||
map.check();
|
||||
}
|
||||
|
|
@ -1162,7 +1186,7 @@ mod test_extract_if {
|
|||
map.insert(b.spawn(Panic::InDrop), ());
|
||||
map.insert(c.spawn(Panic::Never), ());
|
||||
|
||||
catch_unwind(move || map.extract_if(|dummy, _| dummy.query(true)).for_each(drop))
|
||||
catch_unwind(move || map.extract_if(.., |dummy, _| dummy.query(true)).for_each(drop))
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(a.queried(), 1);
|
||||
|
|
@ -1185,7 +1209,7 @@ mod test_extract_if {
|
|||
map.insert(c.spawn(Panic::InQuery), ());
|
||||
|
||||
catch_unwind(AssertUnwindSafe(|| {
|
||||
map.extract_if(|dummy, _| dummy.query(true)).for_each(drop)
|
||||
map.extract_if(.., |dummy, _| dummy.query(true)).for_each(drop)
|
||||
}))
|
||||
.unwrap_err();
|
||||
|
||||
|
|
@ -1214,7 +1238,7 @@ mod test_extract_if {
|
|||
map.insert(c.spawn(Panic::InQuery), ());
|
||||
|
||||
{
|
||||
let mut it = map.extract_if(|dummy, _| dummy.query(true));
|
||||
let mut it = map.extract_if(.., |dummy, _| dummy.query(true));
|
||||
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
|
||||
// Iterator behavior after a panic is explicitly unspecified,
|
||||
// so this is just the current implementation:
|
||||
|
|
@ -1658,7 +1682,7 @@ fn assert_sync() {
|
|||
}
|
||||
|
||||
fn extract_if<T: Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
|
||||
v.extract_if(|_, _| false)
|
||||
v.extract_if(.., |_, _| false)
|
||||
}
|
||||
|
||||
fn iter<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
|
||||
|
|
@ -1727,7 +1751,7 @@ fn assert_send() {
|
|||
}
|
||||
|
||||
fn extract_if<T: Send + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
|
||||
v.extract_if(|_, _| false)
|
||||
v.extract_if(.., |_, _| false)
|
||||
}
|
||||
|
||||
fn iter<T: Send + Sync>(v: &BTreeMap<T, T>) -> impl Send + '_ {
|
||||
|
|
|
|||
|
|
@ -1109,7 +1109,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
T: Ord,
|
||||
F: FnMut(&T) -> bool,
|
||||
{
|
||||
self.extract_if(|v| !f(v)).for_each(drop);
|
||||
self.extract_if(.., |v| !f(v)).for_each(drop);
|
||||
}
|
||||
|
||||
/// Moves all elements from `other` into `self`, leaving `other` empty.
|
||||
|
|
@ -1187,7 +1187,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
BTreeSet { map: self.map.split_off(value) }
|
||||
}
|
||||
|
||||
/// Creates an iterator that visits all elements in ascending order and
|
||||
/// Creates an iterator that visits elements in the specified range in ascending order and
|
||||
/// uses a closure to determine if an element should be removed.
|
||||
///
|
||||
/// If the closure returns `true`, the element is removed from the set and
|
||||
|
|
@ -1208,18 +1208,25 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut set: BTreeSet<i32> = (0..8).collect();
|
||||
/// let evens: BTreeSet<_> = set.extract_if(|v| v % 2 == 0).collect();
|
||||
/// let evens: BTreeSet<_> = set.extract_if(.., |v| v % 2 == 0).collect();
|
||||
/// let odds = set;
|
||||
/// assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![0, 2, 4, 6]);
|
||||
/// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7]);
|
||||
///
|
||||
/// let mut map: BTreeSet<i32> = (0..8).collect();
|
||||
/// let low: BTreeSet<_> = map.extract_if(0..4, |_v| true).collect();
|
||||
/// let high = map;
|
||||
/// assert_eq!(low.into_iter().collect::<Vec<_>>(), [0, 1, 2, 3]);
|
||||
/// assert_eq!(high.into_iter().collect::<Vec<_>>(), [4, 5, 6, 7]);
|
||||
/// ```
|
||||
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||
pub fn extract_if<'a, F>(&'a mut self, pred: F) -> ExtractIf<'a, T, F, A>
|
||||
pub fn extract_if<'a, F, R>(&'a mut self, range: R, pred: F) -> ExtractIf<'a, T, R, F, A>
|
||||
where
|
||||
T: Ord,
|
||||
R: RangeBounds<T>,
|
||||
F: 'a + FnMut(&T) -> bool,
|
||||
{
|
||||
let (inner, alloc) = self.map.extract_if_inner();
|
||||
let (inner, alloc) = self.map.extract_if_inner(range);
|
||||
ExtractIf { pred, inner, alloc }
|
||||
}
|
||||
|
||||
|
|
@ -1554,17 +1561,18 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet<T, A> {
|
|||
pub struct ExtractIf<
|
||||
'a,
|
||||
T,
|
||||
R,
|
||||
F,
|
||||
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
|
||||
> {
|
||||
pred: F,
|
||||
inner: super::map::ExtractIfInner<'a, T, SetValZST>,
|
||||
inner: super::map::ExtractIfInner<'a, T, SetValZST, R>,
|
||||
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
|
||||
alloc: A,
|
||||
}
|
||||
|
||||
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||
impl<T, F, A> fmt::Debug for ExtractIf<'_, T, F, A>
|
||||
impl<T, R, F, A> fmt::Debug for ExtractIf<'_, T, R, F, A>
|
||||
where
|
||||
T: fmt::Debug,
|
||||
A: Allocator + Clone,
|
||||
|
|
@ -1577,8 +1585,10 @@ where
|
|||
}
|
||||
|
||||
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||
impl<'a, T, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, F, A>
|
||||
impl<'a, T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A>
|
||||
where
|
||||
T: PartialOrd,
|
||||
R: RangeBounds<T>,
|
||||
F: 'a + FnMut(&T) -> bool,
|
||||
{
|
||||
type Item = T;
|
||||
|
|
@ -1595,7 +1605,13 @@ where
|
|||
}
|
||||
|
||||
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||
impl<T, F, A: Allocator + Clone> FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&T) -> bool {}
|
||||
impl<T, R, F, A: Allocator + Clone> FusedIterator for ExtractIf<'_, T, R, F, A>
|
||||
where
|
||||
T: PartialOrd,
|
||||
R: RangeBounds<T>,
|
||||
F: FnMut(&T) -> bool,
|
||||
{
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Ord, A: Allocator + Clone> Extend<T> for BTreeSet<T, A> {
|
||||
|
|
|
|||
|
|
@ -368,8 +368,8 @@ fn test_extract_if() {
|
|||
let mut x = BTreeSet::from([1]);
|
||||
let mut y = BTreeSet::from([1]);
|
||||
|
||||
x.extract_if(|_| true).for_each(drop);
|
||||
y.extract_if(|_| false).for_each(drop);
|
||||
x.extract_if(.., |_| true).for_each(drop);
|
||||
y.extract_if(.., |_| false).for_each(drop);
|
||||
assert_eq!(x.len(), 0);
|
||||
assert_eq!(y.len(), 1);
|
||||
}
|
||||
|
|
@ -385,7 +385,7 @@ fn test_extract_if_drop_panic_leak() {
|
|||
set.insert(b.spawn(Panic::InDrop));
|
||||
set.insert(c.spawn(Panic::Never));
|
||||
|
||||
catch_unwind(move || set.extract_if(|dummy| dummy.query(true)).for_each(drop)).ok();
|
||||
catch_unwind(move || set.extract_if(.., |dummy| dummy.query(true)).for_each(drop)).ok();
|
||||
|
||||
assert_eq!(a.queried(), 1);
|
||||
assert_eq!(b.queried(), 1);
|
||||
|
|
@ -406,7 +406,7 @@ fn test_extract_if_pred_panic_leak() {
|
|||
set.insert(b.spawn(Panic::InQuery));
|
||||
set.insert(c.spawn(Panic::InQuery));
|
||||
|
||||
catch_unwind(AssertUnwindSafe(|| set.extract_if(|dummy| dummy.query(true)).for_each(drop)))
|
||||
catch_unwind(AssertUnwindSafe(|| set.extract_if(.., |dummy| dummy.query(true)).for_each(drop)))
|
||||
.ok();
|
||||
|
||||
assert_eq!(a.queried(), 1);
|
||||
|
|
@ -605,7 +605,7 @@ fn assert_sync() {
|
|||
}
|
||||
|
||||
fn extract_if<T: Sync + Ord>(v: &mut BTreeSet<T>) -> impl Sync + '_ {
|
||||
v.extract_if(|_| false)
|
||||
v.extract_if(.., |_| false)
|
||||
}
|
||||
|
||||
fn difference<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
|
||||
|
|
@ -644,7 +644,7 @@ fn assert_send() {
|
|||
}
|
||||
|
||||
fn extract_if<T: Send + Ord>(v: &mut BTreeSet<T>) -> impl Send + '_ {
|
||||
v.extract_if(|_| false)
|
||||
v.extract_if(.., |_| false)
|
||||
}
|
||||
|
||||
fn difference<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ pub fn clone_slim_100_and_clear(b: &mut Bencher) {
|
|||
#[bench]
|
||||
pub fn clone_slim_100_and_drain_all(b: &mut Bencher) {
|
||||
let src = slim_map(100);
|
||||
b.iter(|| src.clone().extract_if(|_, _| true).count())
|
||||
b.iter(|| src.clone().extract_if(.., |_, _| true).count())
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
@ -394,7 +394,7 @@ pub fn clone_slim_100_and_drain_half(b: &mut Bencher) {
|
|||
let src = slim_map(100);
|
||||
b.iter(|| {
|
||||
let mut map = src.clone();
|
||||
assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 100 / 2);
|
||||
assert_eq!(map.extract_if(.., |i, _| i % 2 == 0).count(), 100 / 2);
|
||||
assert_eq!(map.len(), 100 / 2);
|
||||
})
|
||||
}
|
||||
|
|
@ -457,7 +457,7 @@ pub fn clone_slim_10k_and_clear(b: &mut Bencher) {
|
|||
#[bench]
|
||||
pub fn clone_slim_10k_and_drain_all(b: &mut Bencher) {
|
||||
let src = slim_map(10_000);
|
||||
b.iter(|| src.clone().extract_if(|_, _| true).count())
|
||||
b.iter(|| src.clone().extract_if(.., |_, _| true).count())
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
@ -465,7 +465,7 @@ pub fn clone_slim_10k_and_drain_half(b: &mut Bencher) {
|
|||
let src = slim_map(10_000);
|
||||
b.iter(|| {
|
||||
let mut map = src.clone();
|
||||
assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 10_000 / 2);
|
||||
assert_eq!(map.extract_if(.., |i, _| i % 2 == 0).count(), 10_000 / 2);
|
||||
assert_eq!(map.len(), 10_000 / 2);
|
||||
})
|
||||
}
|
||||
|
|
@ -528,7 +528,7 @@ pub fn clone_fat_val_100_and_clear(b: &mut Bencher) {
|
|||
#[bench]
|
||||
pub fn clone_fat_val_100_and_drain_all(b: &mut Bencher) {
|
||||
let src = fat_val_map(100);
|
||||
b.iter(|| src.clone().extract_if(|_, _| true).count())
|
||||
b.iter(|| src.clone().extract_if(.., |_, _| true).count())
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
@ -536,7 +536,7 @@ pub fn clone_fat_val_100_and_drain_half(b: &mut Bencher) {
|
|||
let src = fat_val_map(100);
|
||||
b.iter(|| {
|
||||
let mut map = src.clone();
|
||||
assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 100 / 2);
|
||||
assert_eq!(map.extract_if(.., |i, _| i % 2 == 0).count(), 100 / 2);
|
||||
assert_eq!(map.len(), 100 / 2);
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ pub fn clone_100_and_clear(b: &mut Bencher) {
|
|||
#[bench]
|
||||
pub fn clone_100_and_drain_all(b: &mut Bencher) {
|
||||
let src = slim_set(100);
|
||||
b.iter(|| src.clone().extract_if(|_| true).count())
|
||||
b.iter(|| src.clone().extract_if(.., |_| true).count())
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
@ -77,7 +77,7 @@ pub fn clone_100_and_drain_half(b: &mut Bencher) {
|
|||
let src = slim_set(100);
|
||||
b.iter(|| {
|
||||
let mut set = src.clone();
|
||||
assert_eq!(set.extract_if(|i| i % 2 == 0).count(), 100 / 2);
|
||||
assert_eq!(set.extract_if(.., |i| i % 2 == 0).count(), 100 / 2);
|
||||
assert_eq!(set.len(), 100 / 2);
|
||||
})
|
||||
}
|
||||
|
|
@ -140,7 +140,7 @@ pub fn clone_10k_and_clear(b: &mut Bencher) {
|
|||
#[bench]
|
||||
pub fn clone_10k_and_drain_all(b: &mut Bencher) {
|
||||
let src = slim_set(10_000);
|
||||
b.iter(|| src.clone().extract_if(|_| true).count())
|
||||
b.iter(|| src.clone().extract_if(.., |_| true).count())
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
@ -148,7 +148,7 @@ pub fn clone_10k_and_drain_half(b: &mut Bencher) {
|
|||
let src = slim_set(10_000);
|
||||
b.iter(|| {
|
||||
let mut set = src.clone();
|
||||
assert_eq!(set.extract_if(|i| i % 2 == 0).count(), 10_000 / 2);
|
||||
assert_eq!(set.extract_if(.., |i| i % 2 == 0).count(), 10_000 / 2);
|
||||
assert_eq!(set.len(), 10_000 / 2);
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::ops::Range;
|
||||
|
||||
fn require_sync<T: Sync>(_: T) {}
|
||||
fn require_send_sync<T: Send + Sync>(_: T) {}
|
||||
|
||||
|
|
@ -55,7 +57,13 @@ fn test_btree_map() {
|
|||
|
||||
require_send_sync(async {
|
||||
let _v = None::<
|
||||
alloc::collections::btree_map::ExtractIf<'_, &u32, &u32, fn(&&u32, &mut &u32) -> bool>,
|
||||
alloc::collections::btree_map::ExtractIf<
|
||||
'_,
|
||||
&u32,
|
||||
&u32,
|
||||
Range<u32>,
|
||||
fn(&&u32, &mut &u32) -> bool,
|
||||
>,
|
||||
>;
|
||||
async {}.await;
|
||||
});
|
||||
|
|
@ -144,7 +152,9 @@ fn test_btree_set() {
|
|||
});
|
||||
|
||||
require_send_sync(async {
|
||||
let _v = None::<alloc::collections::btree_set::ExtractIf<'_, &u32, fn(&&u32) -> bool>>;
|
||||
let _v = None::<
|
||||
alloc::collections::btree_set::ExtractIf<'_, &u32, Range<u32>, fn(&&u32) -> bool>,
|
||||
>;
|
||||
async {}.await;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ macro_rules! int_impl {
|
|||
ActualT = $ActualT:ident,
|
||||
UnsignedT = $UnsignedT:ty,
|
||||
|
||||
// There are all for use *only* in doc comments.
|
||||
// These are all for use *only* in doc comments.
|
||||
// As such, they're all passed as literals -- passing them as a string
|
||||
// literal is fine if they need to be multiple code tokens.
|
||||
// In non-comments, use the associated constants rather than these.
|
||||
|
|
@ -1018,6 +1018,110 @@ macro_rules! int_impl {
|
|||
if b { overflow_panic::div() } else { a }
|
||||
}
|
||||
|
||||
/// Checked integer division without remainder. Computes `self / rhs`,
|
||||
/// returning `None` if `rhs == 0`, the division results in overflow,
|
||||
/// or `self % rhs != 0`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(exact_div)]
|
||||
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_exact_div(-1), Some(", stringify!($Max), "));")]
|
||||
#[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").checked_exact_div(2), None);")]
|
||||
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_exact_div(-1), None);")]
|
||||
#[doc = concat!("assert_eq!((1", stringify!($SelfT), ").checked_exact_div(0), None);")]
|
||||
/// ```
|
||||
#[unstable(
|
||||
feature = "exact_div",
|
||||
issue = "139911",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn checked_exact_div(self, rhs: Self) -> Option<Self> {
|
||||
if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: division by zero and overflow are checked above
|
||||
unsafe {
|
||||
if intrinsics::unlikely(intrinsics::unchecked_rem(self, rhs) != 0) {
|
||||
None
|
||||
} else {
|
||||
Some(intrinsics::exact_div(self, rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checked integer division without remainder. Computes `self / rhs`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `rhs == 0`, the division results in overflow,
|
||||
/// or `self % rhs != 0`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(exact_div)]
|
||||
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")]
|
||||
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), 2);")]
|
||||
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).exact_div(-1), ", stringify!($Max), ");")]
|
||||
/// ```
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(exact_div)]
|
||||
#[doc = concat!("let _ = 65", stringify!($SelfT), ".exact_div(2);")]
|
||||
/// ```
|
||||
/// ```should_panic
|
||||
/// #![feature(exact_div)]
|
||||
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.exact_div(-1);")]
|
||||
/// ```
|
||||
#[unstable(
|
||||
feature = "exact_div",
|
||||
issue = "139911",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn exact_div(self, rhs: Self) -> Self {
|
||||
match self.checked_exact_div(rhs) {
|
||||
Some(x) => x,
|
||||
None => panic!("Failed to divide without remainder"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Unchecked integer division without remainder. Computes `self / rhs`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This results in undefined behavior when `rhs == 0`, `self % rhs != 0`, or
|
||||
#[doc = concat!("`self == ", stringify!($SelfT), "::MIN && rhs == -1`,")]
|
||||
/// i.e. when [`checked_exact_div`](Self::checked_exact_div) would return `None`.
|
||||
#[unstable(
|
||||
feature = "exact_div",
|
||||
issue = "139911",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const unsafe fn unchecked_exact_div(self, rhs: Self) -> Self {
|
||||
assert_unsafe_precondition!(
|
||||
check_language_ub,
|
||||
concat!(stringify!($SelfT), "::unchecked_exact_div cannot overflow, divide by zero, or leave a remainder"),
|
||||
(
|
||||
lhs: $SelfT = self,
|
||||
rhs: $SelfT = rhs,
|
||||
) => rhs > 0 && lhs % rhs == 0 && (lhs != <$SelfT>::MIN || rhs != -1),
|
||||
);
|
||||
// SAFETY: Same precondition
|
||||
unsafe { intrinsics::exact_div(self, rhs) }
|
||||
}
|
||||
|
||||
/// Checked integer remainder. Computes `self % rhs`, returning `None` if
|
||||
/// `rhs == 0` or the division results in overflow.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1110,6 +1110,108 @@ macro_rules! uint_impl {
|
|||
self / rhs
|
||||
}
|
||||
|
||||
/// Checked integer division without remainder. Computes `self / rhs`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `rhs == 0` or `self % rhs != 0`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(exact_div)]
|
||||
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")]
|
||||
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), 2);")]
|
||||
/// ```
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(exact_div)]
|
||||
#[doc = concat!("let _ = 65", stringify!($SelfT), ".exact_div(2);")]
|
||||
/// ```
|
||||
#[unstable(
|
||||
feature = "exact_div",
|
||||
issue = "139911",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn checked_exact_div(self, rhs: Self) -> Option<Self> {
|
||||
if intrinsics::unlikely(rhs == 0) {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: division by zero is checked above
|
||||
unsafe {
|
||||
if intrinsics::unlikely(intrinsics::unchecked_rem(self, rhs) != 0) {
|
||||
None
|
||||
} else {
|
||||
Some(intrinsics::exact_div(self, rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checked integer division without remainder. Computes `self / rhs`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `rhs == 0` or `self % rhs != 0`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(exact_div)]
|
||||
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")]
|
||||
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), 2);")]
|
||||
/// ```
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(exact_div)]
|
||||
#[doc = concat!("let _ = 65", stringify!($SelfT), ".exact_div(2);")]
|
||||
/// ```
|
||||
#[unstable(
|
||||
feature = "exact_div",
|
||||
issue = "139911",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn exact_div(self, rhs: Self) -> Self {
|
||||
match self.checked_exact_div(rhs) {
|
||||
Some(x) => x,
|
||||
None => panic!("Failed to divide without remainder"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Unchecked integer division without remainder. Computes `self / rhs`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This results in undefined behavior when `rhs == 0` or `self % rhs != 0`,
|
||||
/// i.e. when [`checked_exact_div`](Self::checked_exact_div) would return `None`.
|
||||
#[unstable(
|
||||
feature = "exact_div",
|
||||
issue = "139911",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const unsafe fn unchecked_exact_div(self, rhs: Self) -> Self {
|
||||
assert_unsafe_precondition!(
|
||||
check_language_ub,
|
||||
concat!(stringify!($SelfT), "::unchecked_exact_div divide by zero or leave a remainder"),
|
||||
(
|
||||
lhs: $SelfT = self,
|
||||
rhs: $SelfT = rhs,
|
||||
) => rhs > 0 && lhs % rhs == 0,
|
||||
);
|
||||
// SAFETY: Same precondition
|
||||
unsafe { intrinsics::exact_div(self, rhs) }
|
||||
}
|
||||
|
||||
/// Checked integer remainder. Computes `self % rhs`, returning `None`
|
||||
/// if `rhs == 0`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -397,35 +397,7 @@ impl<T: ?Sized> *const T {
|
|||
if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
|
||||
}
|
||||
|
||||
/// Adds a signed offset to a pointer.
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
|
||||
/// "wrapping around"), must fit in an `isize`.
|
||||
///
|
||||
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space. Note that "range" here refers to a half-open range as usual in Rust,
|
||||
/// i.e., `self..result` for non-negative offsets and `result..self` for negative offsets.
|
||||
///
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// Consider using [`wrapping_offset`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
/// enables more aggressive compiler optimizations.
|
||||
///
|
||||
/// [`wrapping_offset`]: #method.wrapping_offset
|
||||
/// [allocated object]: crate::ptr#allocated-object
|
||||
#[doc = include_str!("./docs/offset.md")]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -905,38 +877,7 @@ impl<T: ?Sized> *const T {
|
|||
}
|
||||
}
|
||||
|
||||
/// Adds an unsigned offset to a pointer.
|
||||
///
|
||||
/// This can only move the pointer forward (or not move it). If you need to move forward or
|
||||
/// backward depending on the value, then you might want [`offset`](#method.offset) instead
|
||||
/// which takes a signed offset.
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
|
||||
/// "wrapping around"), must fit in an `isize`.
|
||||
///
|
||||
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// Consider using [`wrapping_add`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
/// enables more aggressive compiler optimizations.
|
||||
///
|
||||
/// [`wrapping_add`]: #method.wrapping_add
|
||||
/// [allocated object]: crate::ptr#allocated-object
|
||||
#[doc = include_str!("./docs/add.md")]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
32
library/core/src/ptr/docs/add.md
Normal file
32
library/core/src/ptr/docs/add.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
Adds an unsigned offset to a pointer.
|
||||
|
||||
This can only move the pointer forward (or not move it). If you need to move forward or
|
||||
backward depending on the value, then you might want [`offset`](#method.offset) instead
|
||||
which takes a signed offset.
|
||||
|
||||
`count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
offset of `3 * size_of::<T>()` bytes.
|
||||
|
||||
# Safety
|
||||
|
||||
If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
|
||||
* The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
|
||||
"wrapping around"), must fit in an `isize`.
|
||||
|
||||
* If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
|
||||
[allocated object], and the entire memory range between `self` and the result must be in
|
||||
bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
of the address space.
|
||||
|
||||
Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
safe.
|
||||
|
||||
Consider using [`wrapping_add`] instead if these constraints are
|
||||
difficult to satisfy. The only advantage of this method is that it
|
||||
enables more aggressive compiler optimizations.
|
||||
|
||||
[`wrapping_add`]: #method.wrapping_add
|
||||
[allocated object]: crate::ptr#allocated-object
|
||||
29
library/core/src/ptr/docs/offset.md
Normal file
29
library/core/src/ptr/docs/offset.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
Adds a signed offset to a pointer.
|
||||
|
||||
`count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
offset of `3 * size_of::<T>()` bytes.
|
||||
|
||||
# Safety
|
||||
|
||||
If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
|
||||
* The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
|
||||
"wrapping around"), must fit in an `isize`.
|
||||
|
||||
* If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
|
||||
[allocated object], and the entire memory range between `self` and the result must be in
|
||||
bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
of the address space. Note that "range" here refers to a half-open range as usual in Rust,
|
||||
i.e., `self..result` for non-negative offsets and `result..self` for negative offsets.
|
||||
|
||||
Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
safe.
|
||||
|
||||
Consider using [`wrapping_offset`] instead if these constraints are
|
||||
difficult to satisfy. The only advantage of this method is that it
|
||||
enables more aggressive compiler optimizations.
|
||||
|
||||
[`wrapping_offset`]: #method.wrapping_offset
|
||||
[allocated object]: crate::ptr#allocated-object
|
||||
|
|
@ -394,34 +394,7 @@ impl<T: ?Sized> *mut T {
|
|||
if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
|
||||
}
|
||||
|
||||
/// Adds a signed offset to a pointer.
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
|
||||
/// "wrapping around"), must fit in an `isize`.
|
||||
///
|
||||
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// Consider using [`wrapping_offset`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
/// enables more aggressive compiler optimizations.
|
||||
///
|
||||
/// [`wrapping_offset`]: #method.wrapping_offset
|
||||
/// [allocated object]: crate::ptr#allocated-object
|
||||
#[doc = include_str!("./docs/offset.md")]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -996,44 +969,13 @@ impl<T: ?Sized> *mut T {
|
|||
unsafe { (self as *const T).byte_offset_from_unsigned(origin) }
|
||||
}
|
||||
|
||||
/// Adds an unsigned offset to a pointer.
|
||||
///
|
||||
/// This can only move the pointer forward (or not move it). If you need to move forward or
|
||||
/// backward depending on the value, then you might want [`offset`](#method.offset) instead
|
||||
/// which takes a signed offset.
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
|
||||
/// "wrapping around"), must fit in an `isize`.
|
||||
///
|
||||
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// Consider using [`wrapping_add`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
/// enables more aggressive compiler optimizations.
|
||||
///
|
||||
/// [`wrapping_add`]: #method.wrapping_add
|
||||
/// [allocated object]: crate::ptr#allocated-object
|
||||
#[doc = include_str!("./docs/add.md")]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
/// let ptr: *const u8 = s.as_ptr();
|
||||
/// let mut s: String = "123".to_string();
|
||||
/// let ptr: *mut u8 = s.as_mut_ptr();
|
||||
///
|
||||
/// unsafe {
|
||||
/// assert_eq!('2', *ptr.add(1) as char);
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
timeout = 14400
|
||||
# 6 hours timeout for CI builds
|
||||
timeout = 21600
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ pub fn main() {
|
|||
test_all_refs(&mut 13, b.values_mut());
|
||||
|
||||
// Test forgetting the extractor.
|
||||
let mut d = b.extract_if(|_, i| *i < 30);
|
||||
let mut d = b.extract_if(.., |_, i| *i < 30);
|
||||
d.next().unwrap();
|
||||
mem::forget(d);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
- // MIR for `match_non_int_failed` before MatchBranchSimplification
|
||||
+ // MIR for `match_non_int_failed` after MatchBranchSimplification
|
||||
|
||||
fn match_non_int_failed(_1: char) -> u8 {
|
||||
let mut _0: u8;
|
||||
|
||||
bb0: {
|
||||
switchInt(copy _1) -> [97: bb1, 98: bb2, otherwise: bb3];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = const 97_u8;
|
||||
goto -> bb4;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_0 = const 98_u8;
|
||||
goto -> bb4;
|
||||
}
|
||||
|
||||
bb3: {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -627,6 +627,37 @@ fn match_i128_u128(i: EnumAi128) -> u128 {
|
|||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR matches_reduce_branches.match_non_int_failed.MatchBranchSimplification.diff
|
||||
#[custom_mir(dialect = "runtime")]
|
||||
fn match_non_int_failed(i: char) -> u8 {
|
||||
// CHECK-LABEL: fn match_non_int_failed(
|
||||
// CHECK: switchInt
|
||||
// CHECK: return
|
||||
mir! {
|
||||
{
|
||||
match i {
|
||||
'a' => bb1,
|
||||
'b' => bb2,
|
||||
_ => unreachable_bb,
|
||||
}
|
||||
}
|
||||
bb1 = {
|
||||
RET = 97;
|
||||
Goto(ret)
|
||||
}
|
||||
bb2 = {
|
||||
RET = 98;
|
||||
Goto(ret)
|
||||
}
|
||||
unreachable_bb = {
|
||||
Unreachable()
|
||||
}
|
||||
ret = {
|
||||
Return()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = foo(None);
|
||||
let _ = foo(Some(()));
|
||||
|
|
@ -664,4 +695,5 @@ fn main() {
|
|||
let _ = match_i128_u128(EnumAi128::A);
|
||||
|
||||
let _ = my_is_some(None);
|
||||
let _ = match_non_int_failed('a');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ fn main() {
|
|||
map.insert("c", ());
|
||||
|
||||
{
|
||||
let mut it = map.extract_if(|_, _| true);
|
||||
let mut it = map.extract_if(.., |_, _| true);
|
||||
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
|
||||
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
|
||||
assert!(matches!(result, Ok(None)));
|
||||
}
|
||||
|
||||
{
|
||||
let mut it = map.extract_if(|_, _| true);
|
||||
let mut it = map.extract_if(.., |_, _| true);
|
||||
catch_unwind(AssertUnwindSafe(|| while let Some(_) = it.next() {})).unwrap_err();
|
||||
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
|
||||
assert!(matches!(result, Ok(None)));
|
||||
|
|
|
|||
24
tests/ui/parser/match-arm-comma-typo-issue-140991.fixed
Normal file
24
tests/ui/parser/match-arm-comma-typo-issue-140991.fixed
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//@ run-rustfix
|
||||
|
||||
pub enum Foo {
|
||||
X, Y
|
||||
}
|
||||
|
||||
pub fn typo1(foo: Foo) -> Foo {
|
||||
use Foo::*;
|
||||
match foo {
|
||||
X => Y,
|
||||
Y => X, //~ ERROR expected one of
|
||||
}
|
||||
}
|
||||
|
||||
pub fn typo2(foo: Foo) -> Foo {
|
||||
use Foo::*;
|
||||
match foo {
|
||||
X => Y,
|
||||
Y => X, //~ ERROR expected one of
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() { }
|
||||
24
tests/ui/parser/match-arm-comma-typo-issue-140991.rs
Normal file
24
tests/ui/parser/match-arm-comma-typo-issue-140991.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//@ run-rustfix
|
||||
|
||||
pub enum Foo {
|
||||
X, Y
|
||||
}
|
||||
|
||||
pub fn typo1(foo: Foo) -> Foo {
|
||||
use Foo::*;
|
||||
match foo {
|
||||
X => Y.
|
||||
Y => X, //~ ERROR expected one of
|
||||
}
|
||||
}
|
||||
|
||||
pub fn typo2(foo: Foo) -> Foo {
|
||||
use Foo::*;
|
||||
match foo {
|
||||
X => Y/
|
||||
Y => X, //~ ERROR expected one of
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() { }
|
||||
26
tests/ui/parser/match-arm-comma-typo-issue-140991.stderr
Normal file
26
tests/ui/parser/match-arm-comma-typo-issue-140991.stderr
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
error: expected one of `(`, `,`, `.`, `::`, `?`, `}`, or an operator, found `=>`
|
||||
--> $DIR/match-arm-comma-typo-issue-140991.rs:11:11
|
||||
|
|
||||
LL | Y => X,
|
||||
| ^^ expected one of 7 possible tokens
|
||||
|
|
||||
help: you might have meant to write a `,` to end this `match` arm
|
||||
|
|
||||
LL - X => Y.
|
||||
LL + X => Y,
|
||||
|
|
||||
|
||||
error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, `}`, or an operator, found `=>`
|
||||
--> $DIR/match-arm-comma-typo-issue-140991.rs:19:11
|
||||
|
|
||||
LL | Y => X,
|
||||
| ^^ expected one of 8 possible tokens
|
||||
|
|
||||
help: you might have meant to write a `,` to end this `match` arm
|
||||
|
|
||||
LL - X => Y/
|
||||
LL + X => Y,
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
20
tests/ui/unsafe-binders/unused-lifetimes-2.fixed
Normal file
20
tests/ui/unsafe-binders/unused-lifetimes-2.fixed
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// regression test for #141758
|
||||
//@ run-rustfix
|
||||
//@ check-pass
|
||||
|
||||
#![warn(unused_lifetimes)]
|
||||
#![allow(incomplete_features, unused_imports, dead_code)]
|
||||
#![feature(unsafe_binders)]
|
||||
|
||||
use std::unsafe_binder::unwrap_binder;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct S([usize; 8]);
|
||||
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/141418>.
|
||||
pub fn by_value(_x: unsafe<'a> &'a S) -> usize {
|
||||
//~^ WARN lifetime parameter `'b` never used
|
||||
0
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
20
tests/ui/unsafe-binders/unused-lifetimes-2.rs
Normal file
20
tests/ui/unsafe-binders/unused-lifetimes-2.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// regression test for #141758
|
||||
//@ run-rustfix
|
||||
//@ check-pass
|
||||
|
||||
#![warn(unused_lifetimes)]
|
||||
#![allow(incomplete_features, unused_imports, dead_code)]
|
||||
#![feature(unsafe_binders)]
|
||||
|
||||
use std::unsafe_binder::unwrap_binder;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct S([usize; 8]);
|
||||
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/141418>.
|
||||
pub fn by_value(_x: unsafe<'a, 'b> &'a S) -> usize {
|
||||
//~^ WARN lifetime parameter `'b` never used
|
||||
0
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
16
tests/ui/unsafe-binders/unused-lifetimes-2.stderr
Normal file
16
tests/ui/unsafe-binders/unused-lifetimes-2.stderr
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
warning: lifetime parameter `'b` never used
|
||||
--> $DIR/unused-lifetimes-2.rs:15:32
|
||||
|
|
||||
LL | pub fn by_value(_x: unsafe<'a, 'b> &'a S) -> usize {
|
||||
| --^^
|
||||
| |
|
||||
| help: elide the unused lifetime
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/unused-lifetimes-2.rs:5:9
|
||||
|
|
||||
LL | #![warn(unused_lifetimes)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
20
tests/ui/unsafe-binders/unused-lifetimes.fixed
Normal file
20
tests/ui/unsafe-binders/unused-lifetimes.fixed
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// regression test for #141758
|
||||
//@ run-rustfix
|
||||
//@ check-pass
|
||||
|
||||
#![warn(unused_lifetimes)]
|
||||
#![allow(incomplete_features, unused_imports, dead_code)]
|
||||
#![feature(unsafe_binders)]
|
||||
|
||||
use std::unsafe_binder::unwrap_binder;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct S([usize; 8]);
|
||||
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/141418>.
|
||||
pub fn by_value(_x: S) -> usize {
|
||||
//~^ WARN lifetime parameter `'a` never used
|
||||
0
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
20
tests/ui/unsafe-binders/unused-lifetimes.rs
Normal file
20
tests/ui/unsafe-binders/unused-lifetimes.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// regression test for #141758
|
||||
//@ run-rustfix
|
||||
//@ check-pass
|
||||
|
||||
#![warn(unused_lifetimes)]
|
||||
#![allow(incomplete_features, unused_imports, dead_code)]
|
||||
#![feature(unsafe_binders)]
|
||||
|
||||
use std::unsafe_binder::unwrap_binder;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct S([usize; 8]);
|
||||
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/141418>.
|
||||
pub fn by_value(_x: unsafe<'a> S) -> usize {
|
||||
//~^ WARN lifetime parameter `'a` never used
|
||||
0
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
14
tests/ui/unsafe-binders/unused-lifetimes.stderr
Normal file
14
tests/ui/unsafe-binders/unused-lifetimes.stderr
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
warning: lifetime parameter `'a` never used
|
||||
--> $DIR/unused-lifetimes.rs:15:28
|
||||
|
|
||||
LL | pub fn by_value(_x: unsafe<'a> S) -> usize {
|
||||
| -------^^-- help: elide the unused lifetime
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/unused-lifetimes.rs:5:9
|
||||
|
|
||||
LL | #![warn(unused_lifetimes)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue