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:
bors 2025-05-30 22:14:00 +00:00
commit 0b00e6847b
31 changed files with 716 additions and 217 deletions

View file

@ -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 }}

View file

@ -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();

View file

@ -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(

View file

@ -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,

View file

@ -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> {

View file

@ -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 + '_ {

View file

@ -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> {

View file

@ -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 + '_ {

View file

@ -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);
})
}

View file

@ -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);
})
}

View file

@ -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;
});

View file

@ -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.
///

View file

@ -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`.
///

View file

@ -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
///

View 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

View 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

View file

@ -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);

View file

@ -1 +1,2 @@
timeout = 14400
# 6 hours timeout for CI builds
timeout = 21600

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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');
}

View file

@ -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)));

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

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

View 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

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

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

View 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

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

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

View 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