From 613cc9bb45a35949ca0df5ba5139b986e31ca673 Mon Sep 17 00:00:00 2001 From: pierwill Date: Thu, 17 Dec 2020 11:39:39 -0800 Subject: [PATCH 01/35] Edit rustc_ast::ast::FieldPat docs Punctuation fixes. --- compiler/rustc_ast/src/ast.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 220bbed7e78b6..20f98d390960e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -636,16 +636,16 @@ impl Pat { } } -/// A single field in a struct pattern +/// A single field in a struct pattern. /// -/// Patterns like the fields of Foo `{ x, ref y, ref mut z }` -/// are treated the same as` x: x, y: ref y, z: ref mut z`, -/// except is_shorthand is true +/// Patterns like the fields of `Foo { x, ref y, ref mut z }` +/// are treated the same as `x: x, y: ref y, z: ref mut z`, +/// except when `is_shorthand` is true. #[derive(Clone, Encodable, Decodable, Debug)] pub struct FieldPat { - /// The identifier for the field + /// The identifier for the field. pub ident: Ident, - /// The pattern the field is destructured to + /// The pattern the field is destructured to. pub pat: P, pub is_shorthand: bool, pub attrs: AttrVec, From 7ac02bddc7349fb2268c88e0adc4a0f1854fb531 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 26 Dec 2020 23:07:11 -0500 Subject: [PATCH 02/35] Don't give an error when creating a file for the first time Previously, `os.remove` would always give a FileNotFound error the first time you called it, causing bootstrap to make unnecessary copies. This now only calls `remove()` if the file exists, avoiding the unnecessary error. --- src/bootstrap/bootstrap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 97f40815b87b4..b8bae69d06330 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -351,11 +351,13 @@ def output(filepath): with open(tmp, 'w') as f: yield f try: - os.remove(filepath) # PermissionError/OSError on Win32 if in use - os.rename(tmp, filepath) + if os.path.exists(filepath): + os.remove(filepath) # PermissionError/OSError on Win32 if in use except OSError: shutil.copy2(tmp, filepath) os.remove(tmp) + return + os.rename(tmp, filepath) class RustBuild(object): From 122e91c4fbba35a2331647f89a4f49e668e0cd88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Dec 2020 19:35:16 +0100 Subject: [PATCH 03/35] promotion: factor some common code into validate_ref --- .../rustc_mir/src/transform/promote_consts.rs | 107 ++++++++---------- 1 file changed, 50 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 8d5ed747c3f8f..6791d7b1ba0c7 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -309,49 +309,26 @@ impl<'tcx> Validator<'_, 'tcx> { let statement = &self.body[loc.block].statements[loc.statement_index]; match &statement.kind { StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => { - match kind { - BorrowKind::Shared | BorrowKind::Mut { .. } => {} - - // FIXME(eddyb) these aren't promoted here but *could* - // be promoted as part of a larger value because - // `validate_rvalue` doesn't check them, need to - // figure out what is the intended behavior. - BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable), - } - // We can only promote interior borrows of promotable temps (non-temps // don't get promoted anyway). self.validate_local(place.local)?; + // The reference operation itself must be promotable. + // (Needs to come after `validate_local` to avoid ICEs.) + self.validate_ref(*kind, place)?; + + // We do not check all the projections (they do not get promoted anyway), + // but we do stay away from promoting anything involving a dereference. if place.projection.contains(&ProjectionElem::Deref) { return Err(Unpromotable); } - if self.qualif_local::(place.local) { - return Err(Unpromotable); - } - // FIXME(eddyb) this duplicates part of `validate_rvalue`. - let has_mut_interior = - self.qualif_local::(place.local); - if has_mut_interior { + // We cannot promote things that need dropping, since the promoted value + // would not get dropped. + if self.qualif_local::(place.local) { return Err(Unpromotable); } - if let BorrowKind::Mut { .. } = kind { - let ty = place.ty(self.body, self.tcx).ty; - - // In theory, any zero-sized value could be borrowed - // mutably without consequences. However, only &mut [] - // is allowed right now. - if let ty::Array(_, len) = ty.kind() { - match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) => {} - _ => return Err(Unpromotable), - } - } else { - return Err(Unpromotable); - } - } Ok(()) } @@ -572,6 +549,39 @@ impl<'tcx> Validator<'_, 'tcx> { } } + fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> { + match kind { + // Reject these borrow types just to be safe. + // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase. + BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable), + + BorrowKind::Shared => { + let has_mut_interior = self.qualif_local::(place.local); + if has_mut_interior { + return Err(Unpromotable); + } + } + + BorrowKind::Mut { .. } => { + let ty = place.ty(self.body, self.tcx).ty; + + // In theory, any zero-sized value could be borrowed + // mutably without consequences. However, only &mut [] + // is allowed right now. + if let ty::Array(_, len) = ty.kind() { + match len.try_eval_usize(self.tcx, self.param_env) { + Some(0) => {} + _ => return Err(Unpromotable), + } + } else { + return Err(Unpromotable); + } + } + } + + Ok(()) + } + fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match *rvalue { Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { @@ -640,37 +650,20 @@ impl<'tcx> Validator<'_, 'tcx> { } Rvalue::Ref(_, kind, place) => { - if let BorrowKind::Mut { .. } = kind { - let ty = place.ty(self.body, self.tcx).ty; - - // In theory, any zero-sized value could be borrowed - // mutably without consequences. However, only &mut [] - // is allowed right now. - if let ty::Array(_, len) = ty.kind() { - match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) => {} - _ => return Err(Unpromotable), - } - } else { - return Err(Unpromotable); - } - } - // Special-case reborrows to be more like a copy of the reference. - let mut place = place.as_ref(); - if let [proj_base @ .., ProjectionElem::Deref] = &place.projection { - let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; + let mut place_simplified = place.as_ref(); + if let [proj_base @ .., ProjectionElem::Deref] = &place_simplified.projection { + let base_ty = Place::ty_from(place_simplified.local, proj_base, self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind() { - place = PlaceRef { local: place.local, projection: proj_base }; + place_simplified = PlaceRef { local: place_simplified.local, projection: proj_base }; } } - self.validate_place(place)?; + self.validate_place(place_simplified)?; - let has_mut_interior = self.qualif_local::(place.local); - if has_mut_interior { - return Err(Unpromotable); - } + // Check that the reference is fine (using the original place!). + // (Needs to come after `validate_local` to avoid ICEs.) + self.validate_ref(*kind, place)?; Ok(()) } From c177e68015c0915aee333540f29d1673fe6ffdd5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Dec 2020 22:44:04 +0100 Subject: [PATCH 04/35] merge two match'es for more exhaustiveness --- .../rustc_mir/src/transform/promote_consts.rs | 80 ++++++++++--------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 6791d7b1ba0c7..7cb80c78c8d2b 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -90,7 +90,7 @@ pub enum TempState { impl TempState { pub fn is_promotable(&self) -> bool { debug!("is_promotable: self={:?}", self); - matches!(self, TempState::Defined { .. } ) + matches!(self, TempState::Defined { .. }) } } @@ -329,7 +329,6 @@ impl<'tcx> Validator<'_, 'tcx> { return Err(Unpromotable); } - Ok(()) } _ => bug!(), @@ -583,18 +582,33 @@ impl<'tcx> Validator<'_, 'tcx> { } fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { - match *rvalue { - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { - let operand_ty = operand.ty(self.body, self.tcx); - let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { - // ptr-to-int casts are not possible in consts and thus not promotable - return Err(Unpromotable); + match rvalue { + Rvalue::Use(operand) | Rvalue::Repeat(operand, _) | Rvalue::UnaryOp(_, operand) => { + self.validate_operand(operand)?; + } + + Rvalue::Discriminant(place) | Rvalue::Len(place) => self.validate_place(place.as_ref())?, + + Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), + + Rvalue::Cast(kind, operand, cast_ty) => { + if matches!(kind, CastKind::Misc) { + let operand_ty = operand.ty(self.body, self.tcx); + let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); + let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); + if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { + // ptr-to-int casts are not possible in consts and thus not promotable + return Err(Unpromotable); + } + // int-to-ptr casts are fine, they just use the integer value at pointer type. } + + self.validate_operand(operand)?; } - Rvalue::BinaryOp(op, ref lhs, _) => { + Rvalue::BinaryOp(op, lhs, rhs) + | Rvalue::CheckedBinaryOp(op, lhs, rhs) => { + let op = *op; if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { assert!( op == BinOp::Eq @@ -609,29 +623,17 @@ impl<'tcx> Validator<'_, 'tcx> { // raw pointer operations are not allowed inside consts and thus not promotable return Err(Unpromotable); } - } - - Rvalue::NullaryOp(NullOp::Box, _) => return Err(Unpromotable), - - // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous. - _ => {} - } - - match rvalue { - Rvalue::ThreadLocalRef(_) => Err(Unpromotable), - - Rvalue::NullaryOp(..) => Ok(()), - Rvalue::Discriminant(place) | Rvalue::Len(place) => self.validate_place(place.as_ref()), + // FIXME: reject operations that can fail -- namely, division and modulo. - Rvalue::Use(operand) - | Rvalue::Repeat(operand, _) - | Rvalue::UnaryOp(_, operand) - | Rvalue::Cast(_, operand, _) => self.validate_operand(operand), - - Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { self.validate_operand(lhs)?; - self.validate_operand(rhs) + self.validate_operand(rhs)?; + } + + Rvalue::NullaryOp(op, _) => { + if matches!(op, NullOp::Box) { + return Err(Unpromotable); + } } Rvalue::AddressOf(_, place) => { @@ -646,16 +648,18 @@ impl<'tcx> Validator<'_, 'tcx> { }); } } - Err(Unpromotable) + return Err(Unpromotable); } Rvalue::Ref(_, kind, place) => { // Special-case reborrows to be more like a copy of the reference. let mut place_simplified = place.as_ref(); if let [proj_base @ .., ProjectionElem::Deref] = &place_simplified.projection { - let base_ty = Place::ty_from(place_simplified.local, proj_base, self.body, self.tcx).ty; + let base_ty = + Place::ty_from(place_simplified.local, proj_base, self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind() { - place_simplified = PlaceRef { local: place_simplified.local, projection: proj_base }; + place_simplified = + PlaceRef { local: place_simplified.local, projection: proj_base }; } } @@ -664,18 +668,16 @@ impl<'tcx> Validator<'_, 'tcx> { // Check that the reference is fine (using the original place!). // (Needs to come after `validate_local` to avoid ICEs.) self.validate_ref(*kind, place)?; - - Ok(()) } - Rvalue::Aggregate(_, ref operands) => { + Rvalue::Aggregate(_, operands) => { for o in operands { self.validate_operand(o)?; } - - Ok(()) } } + + Ok(()) } fn validate_call( From 4a90a58c34cdc47e51b3b6ae54c6da7578498866 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Dec 2020 23:29:16 +0100 Subject: [PATCH 05/35] make more matches exhaustive --- .../rustc_mir/src/transform/promote_consts.rs | 61 +++++++++++++------ 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 7cb80c78c8d2b..71a1d57fec33e 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -583,11 +583,15 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match rvalue { - Rvalue::Use(operand) | Rvalue::Repeat(operand, _) | Rvalue::UnaryOp(_, operand) => { + Rvalue::Use(operand) + | Rvalue::Repeat(operand, _) + | Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => { self.validate_operand(operand)?; } - Rvalue::Discriminant(place) | Rvalue::Len(place) => self.validate_place(place.as_ref())?, + Rvalue::Discriminant(place) | Rvalue::Len(place) => { + self.validate_place(place.as_ref())? + } Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), @@ -606,35 +610,52 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(operand)?; } - Rvalue::BinaryOp(op, lhs, rhs) - | Rvalue::CheckedBinaryOp(op, lhs, rhs) => { + Rvalue::BinaryOp(op, lhs, rhs) | Rvalue::CheckedBinaryOp(op, lhs, rhs) => { let op = *op; if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { - assert!( - op == BinOp::Eq - || op == BinOp::Ne - || op == BinOp::Le - || op == BinOp::Lt - || op == BinOp::Ge - || op == BinOp::Gt - || op == BinOp::Offset - ); - // raw pointer operations are not allowed inside consts and thus not promotable + assert!(matches!( + op, + BinOp::Eq + | BinOp::Ne + | BinOp::Le + | BinOp::Lt + | BinOp::Ge + | BinOp::Gt + | BinOp::Offset + )); return Err(Unpromotable); } - // FIXME: reject operations that can fail -- namely, division and modulo. + match op { + // FIXME: reject operations that can fail -- namely, division and modulo. + BinOp::Eq + | BinOp::Ne + | BinOp::Le + | BinOp::Lt + | BinOp::Ge + | BinOp::Gt + | BinOp::Offset + | BinOp::Add + | BinOp::Sub + | BinOp::Mul + | BinOp::Div + | BinOp::Rem + | BinOp::BitXor + | BinOp::BitAnd + | BinOp::BitOr + | BinOp::Shl + | BinOp::Shr => {} + } self.validate_operand(lhs)?; self.validate_operand(rhs)?; } - Rvalue::NullaryOp(op, _) => { - if matches!(op, NullOp::Box) { - return Err(Unpromotable); - } - } + Rvalue::NullaryOp(op, _) => match op { + NullOp::Box => return Err(Unpromotable), + NullOp::SizeOf => {} + }, Rvalue::AddressOf(_, place) => { // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is From 5182776c6ceded22b79adc43e275b6b02111fe5b Mon Sep 17 00:00:00 2001 From: C Date: Fri, 4 Dec 2020 23:50:05 +0000 Subject: [PATCH 06/35] refactor: moving vec.rs to vec/mod.rs --- library/alloc/src/{vec.rs => vec/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename library/alloc/src/{vec.rs => vec/mod.rs} (100%) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec/mod.rs similarity index 100% rename from library/alloc/src/vec.rs rename to library/alloc/src/vec/mod.rs From 434e5d142204d9b3019cfedc049d39b0affd08e7 Mon Sep 17 00:00:00 2001 From: C Date: Fri, 4 Dec 2020 23:58:11 +0000 Subject: [PATCH 07/35] refactor: moving DrainFilter into drain_filter.rs --- library/alloc/src/vec/drain_filter.rs | 143 ++++++++++++++++++++++++++ library/alloc/src/vec/mod.rs | 143 +------------------------- 2 files changed, 148 insertions(+), 138 deletions(-) create mode 100644 library/alloc/src/vec/drain_filter.rs diff --git a/library/alloc/src/vec/drain_filter.rs b/library/alloc/src/vec/drain_filter.rs new file mode 100644 index 0000000000000..9d898c7c756c2 --- /dev/null +++ b/library/alloc/src/vec/drain_filter.rs @@ -0,0 +1,143 @@ +use core::ptr::{self}; +use core::slice::{self}; +use crate::alloc::{Allocator, Global}; + +use super::{Vec}; + +/// An iterator which uses a closure to determine if an element should be removed. +/// +/// This struct is created by [`Vec::drain_filter`]. +/// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// #![feature(drain_filter)] +/// +/// let mut v = vec![0, 1, 2]; +/// let iter: std::vec::DrainFilter<_, _> = v.drain_filter(|x| *x % 2 == 0); +/// ``` +#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +#[derive(Debug)] +pub struct DrainFilter< + 'a, + T, + F, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> where + F: FnMut(&mut T) -> bool, +{ + pub(super) vec: &'a mut Vec, + /// The index of the item that will be inspected by the next call to `next`. + pub(super) idx: usize, + /// The number of items that have been drained (removed) thus far. + pub(super) del: usize, + /// The original length of `vec` prior to draining. + pub(super) old_len: usize, + /// The filter test predicate. + pub(super) pred: F, + /// A flag that indicates a panic has occurred in the filter test predicate. + /// This is used as a hint in the drop implementation to prevent consumption + /// of the remainder of the `DrainFilter`. Any unprocessed items will be + /// backshifted in the `vec`, but no further items will be dropped or + /// tested by the filter predicate. + pub(super) panic_flag: bool, +} + +impl DrainFilter<'_, T, F, A> + where + F: FnMut(&mut T) -> bool, +{ + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn allocator(&self) -> &A { + self.vec.allocator() + } +} + +#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +impl Iterator for DrainFilter<'_, T, F, A> + where + F: FnMut(&mut T) -> bool, +{ + type Item = T; + + fn next(&mut self) -> Option { + unsafe { + while self.idx < self.old_len { + let i = self.idx; + let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); + self.panic_flag = true; + let drained = (self.pred)(&mut v[i]); + self.panic_flag = false; + // Update the index *after* the predicate is called. If the index + // is updated prior and the predicate panics, the element at this + // index would be leaked. + self.idx += 1; + if drained { + self.del += 1; + return Some(ptr::read(&v[i])); + } else if self.del > 0 { + let del = self.del; + let src: *const T = &v[i]; + let dst: *mut T = &mut v[i - del]; + ptr::copy_nonoverlapping(src, dst, 1); + } + } + None + } + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.old_len - self.idx)) + } +} + +#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +impl Drop for DrainFilter<'_, T, F, A> + where + F: FnMut(&mut T) -> bool, +{ + fn drop(&mut self) { + struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator> + where + F: FnMut(&mut T) -> bool, + { + drain: &'b mut DrainFilter<'a, T, F, A>, + } + + impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A> + where + F: FnMut(&mut T) -> bool, + { + fn drop(&mut self) { + unsafe { + if self.drain.idx < self.drain.old_len && self.drain.del > 0 { + // This is a pretty messed up state, and there isn't really an + // obviously right thing to do. We don't want to keep trying + // to execute `pred`, so we just backshift all the unprocessed + // elements and tell the vec that they still exist. The backshift + // is required to prevent a double-drop of the last successfully + // drained item prior to a panic in the predicate. + let ptr = self.drain.vec.as_mut_ptr(); + let src = ptr.add(self.drain.idx); + let dst = src.sub(self.drain.del); + let tail_len = self.drain.old_len - self.drain.idx; + src.copy_to(dst, tail_len); + } + self.drain.vec.set_len(self.drain.old_len - self.drain.del); + } + } + } + + let backshift = BackshiftOnDrop { drain: self }; + + // Attempt to consume any remaining elements if the filter predicate + // has not yet panicked. We'll backshift any remaining elements + // whether we've already panicked or if the consumption here panics. + if !backshift.drain.panic_flag { + backshift.drain.for_each(drop); + } + } +} \ No newline at end of file diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index c9fa41138cd41..2fb1fe0d5cbd8 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -74,6 +74,11 @@ use crate::boxed::Box; use crate::collections::TryReserveError; use crate::raw_vec::RawVec; +#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +pub use self::drain_filter::DrainFilter; + +mod drain_filter; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -3585,141 +3590,3 @@ impl Drain<'_, T, A> { self.tail_start = new_tail_start; } } - -/// An iterator which uses a closure to determine if an element should be removed. -/// -/// This struct is created by [`Vec::drain_filter`]. -/// See its documentation for more. -/// -/// # Example -/// -/// ``` -/// #![feature(drain_filter)] -/// -/// let mut v = vec![0, 1, 2]; -/// let iter: std::vec::DrainFilter<_, _> = v.drain_filter(|x| *x % 2 == 0); -/// ``` -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -#[derive(Debug)] -pub struct DrainFilter< - 'a, - T, - F, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> where - F: FnMut(&mut T) -> bool, -{ - vec: &'a mut Vec, - /// The index of the item that will be inspected by the next call to `next`. - idx: usize, - /// The number of items that have been drained (removed) thus far. - del: usize, - /// The original length of `vec` prior to draining. - old_len: usize, - /// The filter test predicate. - pred: F, - /// A flag that indicates a panic has occurred in the filter test predicate. - /// This is used as a hint in the drop implementation to prevent consumption - /// of the remainder of the `DrainFilter`. Any unprocessed items will be - /// backshifted in the `vec`, but no further items will be dropped or - /// tested by the filter predicate. - panic_flag: bool, -} - -impl DrainFilter<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ - /// Returns a reference to the underlying allocator. - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub fn allocator(&self) -> &A { - self.vec.allocator() - } -} - -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Iterator for DrainFilter<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ - type Item = T; - - fn next(&mut self) -> Option { - unsafe { - while self.idx < self.old_len { - let i = self.idx; - let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); - self.panic_flag = true; - let drained = (self.pred)(&mut v[i]); - self.panic_flag = false; - // Update the index *after* the predicate is called. If the index - // is updated prior and the predicate panics, the element at this - // index would be leaked. - self.idx += 1; - if drained { - self.del += 1; - return Some(ptr::read(&v[i])); - } else if self.del > 0 { - let del = self.del; - let src: *const T = &v[i]; - let dst: *mut T = &mut v[i - del]; - ptr::copy_nonoverlapping(src, dst, 1); - } - } - None - } - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(self.old_len - self.idx)) - } -} - -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Drop for DrainFilter<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ - fn drop(&mut self) { - struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator> - where - F: FnMut(&mut T) -> bool, - { - drain: &'b mut DrainFilter<'a, T, F, A>, - } - - impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A> - where - F: FnMut(&mut T) -> bool, - { - fn drop(&mut self) { - unsafe { - if self.drain.idx < self.drain.old_len && self.drain.del > 0 { - // This is a pretty messed up state, and there isn't really an - // obviously right thing to do. We don't want to keep trying - // to execute `pred`, so we just backshift all the unprocessed - // elements and tell the vec that they still exist. The backshift - // is required to prevent a double-drop of the last successfully - // drained item prior to a panic in the predicate. - let ptr = self.drain.vec.as_mut_ptr(); - let src = ptr.add(self.drain.idx); - let dst = src.sub(self.drain.del); - let tail_len = self.drain.old_len - self.drain.idx; - src.copy_to(dst, tail_len); - } - self.drain.vec.set_len(self.drain.old_len - self.drain.del); - } - } - } - - let backshift = BackshiftOnDrop { drain: self }; - - // Attempt to consume any remaining elements if the filter predicate - // has not yet panicked. We'll backshift any remaining elements - // whether we've already panicked or if the consumption here panics. - if !backshift.drain.panic_flag { - backshift.drain.for_each(drop); - } - } -} From 17593f258b5bc8a4778df35bf9a82950738b70e8 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 00:04:32 +0000 Subject: [PATCH 08/35] refactor: moving Splice into splice.rs --- library/alloc/src/vec/mod.rs | 133 ++------------------------------ library/alloc/src/vec/splice.rs | 133 ++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 128 deletions(-) create mode 100644 library/alloc/src/vec/splice.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 2fb1fe0d5cbd8..924b04a8fe1c8 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -79,6 +79,11 @@ pub use self::drain_filter::DrainFilter; mod drain_filter; +#[stable(feature = "vec_splice", since = "1.21.0")] +pub use self::splice::Splice; + +mod splice; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -3462,131 +3467,3 @@ unsafe impl TrustedLen for Drain<'_, T, A> {} #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Drain<'_, T, A> {} - -/// A splicing iterator for `Vec`. -/// -/// This struct is created by [`Vec::splice()`]. -/// See its documentation for more. -/// -/// # Example -/// -/// ``` -/// let mut v = vec![0, 1, 2]; -/// let new = [7, 8]; -/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned()); -/// ``` -#[derive(Debug)] -#[stable(feature = "vec_splice", since = "1.21.0")] -pub struct Splice< - 'a, - I: Iterator + 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, -> { - drain: Drain<'a, I::Item, A>, - replace_with: I, -} - -#[stable(feature = "vec_splice", since = "1.21.0")] -impl Iterator for Splice<'_, I, A> { - type Item = I::Item; - - fn next(&mut self) -> Option { - self.drain.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.drain.size_hint() - } -} - -#[stable(feature = "vec_splice", since = "1.21.0")] -impl DoubleEndedIterator for Splice<'_, I, A> { - fn next_back(&mut self) -> Option { - self.drain.next_back() - } -} - -#[stable(feature = "vec_splice", since = "1.21.0")] -impl ExactSizeIterator for Splice<'_, I, A> {} - -#[stable(feature = "vec_splice", since = "1.21.0")] -impl Drop for Splice<'_, I, A> { - fn drop(&mut self) { - self.drain.by_ref().for_each(drop); - - unsafe { - if self.drain.tail_len == 0 { - self.drain.vec.as_mut().extend(self.replace_with.by_ref()); - return; - } - - // First fill the range left by drain(). - if !self.drain.fill(&mut self.replace_with) { - return; - } - - // There may be more elements. Use the lower bound as an estimate. - // FIXME: Is the upper bound a better guess? Or something else? - let (lower_bound, _upper_bound) = self.replace_with.size_hint(); - if lower_bound > 0 { - self.drain.move_tail(lower_bound); - if !self.drain.fill(&mut self.replace_with) { - return; - } - } - - // Collect any remaining elements. - // This is a zero-length vector which does not allocate if `lower_bound` was exact. - let mut collected = self.replace_with.by_ref().collect::>().into_iter(); - // Now we have an exact count. - if collected.len() > 0 { - self.drain.move_tail(collected.len()); - let filled = self.drain.fill(&mut collected); - debug_assert!(filled); - debug_assert_eq!(collected.len(), 0); - } - } - // Let `Drain::drop` move the tail back if necessary and restore `vec.len`. - } -} - -/// Private helper methods for `Splice::drop` -impl Drain<'_, T, A> { - /// The range from `self.vec.len` to `self.tail_start` contains elements - /// that have been moved out. - /// Fill that range as much as possible with new elements from the `replace_with` iterator. - /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.) - unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { - let vec = unsafe { self.vec.as_mut() }; - let range_start = vec.len; - let range_end = self.tail_start; - let range_slice = unsafe { - slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start) - }; - - for place in range_slice { - if let Some(new_item) = replace_with.next() { - unsafe { ptr::write(place, new_item) }; - vec.len += 1; - } else { - return false; - } - } - true - } - - /// Makes room for inserting more elements before the tail. - unsafe fn move_tail(&mut self, additional: usize) { - let vec = unsafe { self.vec.as_mut() }; - let len = self.tail_start + self.tail_len; - vec.buf.reserve(len, additional); - - let new_tail_start = self.tail_start + additional; - unsafe { - let src = vec.as_ptr().add(self.tail_start); - let dst = vec.as_mut_ptr().add(new_tail_start); - ptr::copy(src, dst, self.tail_len); - } - self.tail_start = new_tail_start; - } -} diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs new file mode 100644 index 0000000000000..86b2fa0968ef2 --- /dev/null +++ b/library/alloc/src/vec/splice.rs @@ -0,0 +1,133 @@ +use crate::alloc::{Allocator, Global}; +use core::ptr::{self}; +use core::slice::{self}; + +use super::{Vec, Drain}; + +/// A splicing iterator for `Vec`. +/// +/// This struct is created by [`Vec::splice()`]. +/// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// let mut v = vec![0, 1, 2]; +/// let new = [7, 8]; +/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned()); +/// ``` +#[derive(Debug)] +#[stable(feature = "vec_splice", since = "1.21.0")] +pub struct Splice< + 'a, + I: Iterator + 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, +> { + pub(super) drain: Drain<'a, I::Item, A>, + pub(super) replace_with: I, +} + +#[stable(feature = "vec_splice", since = "1.21.0")] +impl Iterator for Splice<'_, I, A> { + type Item = I::Item; + + fn next(&mut self) -> Option { + self.drain.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.drain.size_hint() + } +} + +#[stable(feature = "vec_splice", since = "1.21.0")] +impl DoubleEndedIterator for Splice<'_, I, A> { + fn next_back(&mut self) -> Option { + self.drain.next_back() + } +} + +#[stable(feature = "vec_splice", since = "1.21.0")] +impl ExactSizeIterator for Splice<'_, I, A> {} + +#[stable(feature = "vec_splice", since = "1.21.0")] +impl Drop for Splice<'_, I, A> { + fn drop(&mut self) { + self.drain.by_ref().for_each(drop); + + unsafe { + if self.drain.tail_len == 0 { + self.drain.vec.as_mut().extend(self.replace_with.by_ref()); + return; + } + + // First fill the range left by drain(). + if !self.drain.fill(&mut self.replace_with) { + return; + } + + // There may be more elements. Use the lower bound as an estimate. + // FIXME: Is the upper bound a better guess? Or something else? + let (lower_bound, _upper_bound) = self.replace_with.size_hint(); + if lower_bound > 0 { + self.drain.move_tail(lower_bound); + if !self.drain.fill(&mut self.replace_with) { + return; + } + } + + // Collect any remaining elements. + // This is a zero-length vector which does not allocate if `lower_bound` was exact. + let mut collected = self.replace_with.by_ref().collect::>().into_iter(); + // Now we have an exact count. + if collected.len() > 0 { + self.drain.move_tail(collected.len()); + let filled = self.drain.fill(&mut collected); + debug_assert!(filled); + debug_assert_eq!(collected.len(), 0); + } + } + // Let `Drain::drop` move the tail back if necessary and restore `vec.len`. + } +} + +/// Private helper methods for `Splice::drop` +impl Drain<'_, T, A> { + /// The range from `self.vec.len` to `self.tail_start` contains elements + /// that have been moved out. + /// Fill that range as much as possible with new elements from the `replace_with` iterator. + /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.) + unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { + let vec = unsafe { self.vec.as_mut() }; + let range_start = vec.len; + let range_end = self.tail_start; + let range_slice = unsafe { + slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start) + }; + + for place in range_slice { + if let Some(new_item) = replace_with.next() { + unsafe { ptr::write(place, new_item) }; + vec.len += 1; + } else { + return false; + } + } + true + } + + /// Makes room for inserting more elements before the tail. + unsafe fn move_tail(&mut self, additional: usize) { + let vec = unsafe { self.vec.as_mut() }; + let len = self.tail_start + self.tail_len; + vec.buf.reserve(len, additional); + + let new_tail_start = self.tail_start + additional; + unsafe { + let src = vec.as_ptr().add(self.tail_start); + let dst = vec.as_mut_ptr().add(new_tail_start); + ptr::copy(src, dst, self.tail_len); + } + self.tail_start = new_tail_start; + } +} \ No newline at end of file From 6bf9608f9fd22c10f8ba37b416b6a0d4431ef59a Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 00:12:42 +0000 Subject: [PATCH 09/35] refactor: moving Drain into drain.rs --- library/alloc/src/vec/drain.rs | 157 +++++++++++++++++++++++++++++++++ library/alloc/src/vec/mod.rs | 152 ++----------------------------- 2 files changed, 162 insertions(+), 147 deletions(-) create mode 100644 library/alloc/src/vec/drain.rs diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs new file mode 100644 index 0000000000000..e61f17a1c3018 --- /dev/null +++ b/library/alloc/src/vec/drain.rs @@ -0,0 +1,157 @@ +use crate::alloc::{Allocator, Global}; +use core::iter::{ + FusedIterator, TrustedLen, +}; +use core::mem::{self}; +use core::ptr::{self, NonNull}; +use core::slice::{self}; +use core::fmt; + +use super::{Vec}; + +/// A draining iterator for `Vec`. +/// +/// This `struct` is created by [`Vec::drain`]. +/// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// let mut v = vec![0, 1, 2]; +/// let iter: std::vec::Drain<_> = v.drain(..); +/// ``` +#[stable(feature = "drain", since = "1.6.0")] +pub struct Drain< + 'a, + T: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, +> { + /// Index of tail to preserve + pub(super) tail_start: usize, + /// Length of tail + pub(super) tail_len: usize, + /// Current remaining range to remove + pub(super) iter: slice::Iter<'a, T>, + pub(super) vec: NonNull>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for Drain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() + } +} + +impl<'a, T, A: Allocator> Drain<'a, T, A> { + /// Returns the remaining items of this iterator as a slice. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec!['a', 'b', 'c']; + /// let mut drain = vec.drain(..); + /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']); + /// let _ = drain.next().unwrap(); + /// assert_eq!(drain.as_slice(), &['b', 'c']); + /// ``` + #[stable(feature = "vec_drain_as_slice", since = "1.46.0")] + pub fn as_slice(&self) -> &[T] { + self.iter.as_slice() + } + + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn allocator(&self) -> &A { + unsafe { self.vec.as_ref().allocator() } + } +} + +#[stable(feature = "vec_drain_as_slice", since = "1.46.0")] +impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +#[stable(feature = "drain", since = "1.6.0")] +unsafe impl Sync for Drain<'_, T, A> {} +#[stable(feature = "drain", since = "1.6.0")] +unsafe impl Send for Drain<'_, T, A> {} + +#[stable(feature = "drain", since = "1.6.0")] +impl Iterator for Drain<'_, T, A> { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|elt| unsafe { ptr::read(elt as *const _) }) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl DoubleEndedIterator for Drain<'_, T, A> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) }) + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl Drop for Drain<'_, T, A> { + fn drop(&mut self) { + /// Continues dropping the remaining elements in the `Drain`, then moves back the + /// un-`Drain`ed elements to restore the original `Vec`. + struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>); + + impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { + fn drop(&mut self) { + // Continue the same loop we have below. If the loop already finished, this does + // nothing. + self.0.for_each(drop); + + if self.0.tail_len > 0 { + unsafe { + let source_vec = self.0.vec.as_mut(); + // memmove back untouched tail, update to new length + let start = source_vec.len(); + let tail = self.0.tail_start; + if tail != start { + let src = source_vec.as_ptr().add(tail); + let dst = source_vec.as_mut_ptr().add(start); + ptr::copy(src, dst, self.0.tail_len); + } + source_vec.set_len(start + self.0.tail_len); + } + } + } + } + + // exhaust self first + while let Some(item) = self.next() { + let guard = DropGuard(self); + drop(item); + mem::forget(guard); + } + + // Drop a `DropGuard` to move back the non-drained tail of `self`. + DropGuard(self); + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl ExactSizeIterator for Drain<'_, T, A> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Drain<'_, T, A> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Drain<'_, T, A> {} diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 924b04a8fe1c8..1553e367c87ec 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -84,6 +84,11 @@ pub use self::splice::Splice; mod splice; +#[stable(feature = "drain", since = "1.6.0")] +pub use self::drain::Drain; + +mod drain; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -3320,150 +3325,3 @@ impl AsIntoIter for IntoIter { self } } - -/// A draining iterator for `Vec`. -/// -/// This `struct` is created by [`Vec::drain`]. -/// See its documentation for more. -/// -/// # Example -/// -/// ``` -/// let mut v = vec![0, 1, 2]; -/// let iter: std::vec::Drain<_> = v.drain(..); -/// ``` -#[stable(feature = "drain", since = "1.6.0")] -pub struct Drain< - 'a, - T: 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, -> { - /// Index of tail to preserve - tail_start: usize, - /// Length of tail - tail_len: usize, - /// Current remaining range to remove - iter: slice::Iter<'a, T>, - vec: NonNull>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for Drain<'_, T, A> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() - } -} - -impl<'a, T, A: Allocator> Drain<'a, T, A> { - /// Returns the remaining items of this iterator as a slice. - /// - /// # Examples - /// - /// ``` - /// let mut vec = vec!['a', 'b', 'c']; - /// let mut drain = vec.drain(..); - /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']); - /// let _ = drain.next().unwrap(); - /// assert_eq!(drain.as_slice(), &['b', 'c']); - /// ``` - #[stable(feature = "vec_drain_as_slice", since = "1.46.0")] - pub fn as_slice(&self) -> &[T] { - self.iter.as_slice() - } - - /// Returns a reference to the underlying allocator. - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub fn allocator(&self) -> &A { - unsafe { self.vec.as_ref().allocator() } - } -} - -#[stable(feature = "vec_drain_as_slice", since = "1.46.0")] -impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> { - fn as_ref(&self) -> &[T] { - self.as_slice() - } -} - -#[stable(feature = "drain", since = "1.6.0")] -unsafe impl Sync for Drain<'_, T, A> {} -#[stable(feature = "drain", since = "1.6.0")] -unsafe impl Send for Drain<'_, T, A> {} - -#[stable(feature = "drain", since = "1.6.0")] -impl Iterator for Drain<'_, T, A> { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(elt as *const _) }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl DoubleEndedIterator for Drain<'_, T, A> { - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) }) - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl Drop for Drain<'_, T, A> { - fn drop(&mut self) { - /// Continues dropping the remaining elements in the `Drain`, then moves back the - /// un-`Drain`ed elements to restore the original `Vec`. - struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>); - - impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { - fn drop(&mut self) { - // Continue the same loop we have below. If the loop already finished, this does - // nothing. - self.0.for_each(drop); - - if self.0.tail_len > 0 { - unsafe { - let source_vec = self.0.vec.as_mut(); - // memmove back untouched tail, update to new length - let start = source_vec.len(); - let tail = self.0.tail_start; - if tail != start { - let src = source_vec.as_ptr().add(tail); - let dst = source_vec.as_mut_ptr().add(start); - ptr::copy(src, dst, self.0.tail_len); - } - source_vec.set_len(start + self.0.tail_len); - } - } - } - } - - // exhaust self first - while let Some(item) = self.next() { - let guard = DropGuard(self); - drop(item); - mem::forget(guard); - } - - // Drop a `DropGuard` to move back the non-drained tail of `self`. - DropGuard(self); - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl ExactSizeIterator for Drain<'_, T, A> { - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Drain<'_, T, A> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_, T, A> {} From 2580822b919257c8b7c81d3343c43733c216e26c Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 00:17:25 +0000 Subject: [PATCH 10/35] refactor: moved Vec impl Cow into cow.rs --- library/alloc/src/vec/cow.rs | 35 ++++++++++++++++++++++++++++++++++ library/alloc/src/vec/mod.rs | 37 ++---------------------------------- 2 files changed, 37 insertions(+), 35 deletions(-) create mode 100644 library/alloc/src/vec/cow.rs diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs new file mode 100644 index 0000000000000..15942f9892d1c --- /dev/null +++ b/library/alloc/src/vec/cow.rs @@ -0,0 +1,35 @@ +use crate::borrow::Cow; +use core::iter::{FromIterator}; + +use super::{Vec}; + +#[stable(feature = "cow_from_vec", since = "1.8.0")] +impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { + fn from(s: &'a [T]) -> Cow<'a, [T]> { + Cow::Borrowed(s) + } +} + +#[stable(feature = "cow_from_vec", since = "1.8.0")] +impl<'a, T: Clone> From> for Cow<'a, [T]> { + fn from(v: Vec) -> Cow<'a, [T]> { + Cow::Owned(v) + } +} + +#[stable(feature = "cow_from_vec_ref", since = "1.28.0")] +impl<'a, T: Clone> From<&'a Vec> for Cow<'a, [T]> { + fn from(v: &'a Vec) -> Cow<'a, [T]> { + Cow::Borrowed(v.as_slice()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> FromIterator for Cow<'a, [T]> + where + T: Clone, +{ + fn from_iter>(it: I) -> Cow<'a, [T]> { + Cow::Owned(FromIterator::from_iter(it)) + } +} \ No newline at end of file diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1553e367c87ec..8d3f8b0bfd89a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -89,6 +89,8 @@ pub use self::drain::Drain; mod drain; +mod cow; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -3013,41 +3015,6 @@ impl TryFrom> for [T; N] { } } -//////////////////////////////////////////////////////////////////////////////// -// Clone-on-write -//////////////////////////////////////////////////////////////////////////////// - -#[stable(feature = "cow_from_vec", since = "1.8.0")] -impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { - fn from(s: &'a [T]) -> Cow<'a, [T]> { - Cow::Borrowed(s) - } -} - -#[stable(feature = "cow_from_vec", since = "1.8.0")] -impl<'a, T: Clone> From> for Cow<'a, [T]> { - fn from(v: Vec) -> Cow<'a, [T]> { - Cow::Owned(v) - } -} - -#[stable(feature = "cow_from_vec_ref", since = "1.28.0")] -impl<'a, T: Clone> From<&'a Vec> for Cow<'a, [T]> { - fn from(v: &'a Vec) -> Cow<'a, [T]> { - Cow::Borrowed(v.as_slice()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> FromIterator for Cow<'a, [T]> -where - T: Clone, -{ - fn from_iter>(it: I) -> Cow<'a, [T]> { - Cow::Owned(FromIterator::from_iter(it)) - } -} - //////////////////////////////////////////////////////////////////////////////// // Iterators //////////////////////////////////////////////////////////////////////////////// From 93613901d004ccf0b8a240bf328559a4128ac3b2 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 00:45:20 +0000 Subject: [PATCH 11/35] refactor: moved IntoIter into into_iter.rs --- library/alloc/src/vec/into_iter.rs | 270 +++++++++++++++++++++++++++++ library/alloc/src/vec/mod.rs | 270 +---------------------------- 2 files changed, 276 insertions(+), 264 deletions(-) create mode 100644 library/alloc/src/vec/into_iter.rs diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs new file mode 100644 index 0000000000000..623792a631612 --- /dev/null +++ b/library/alloc/src/vec/into_iter.rs @@ -0,0 +1,270 @@ +use crate::alloc::{Allocator, Global}; +use crate::raw_vec::RawVec; +use core::marker::PhantomData; +use core::intrinsics::{arith_offset}; +use core::mem::{self}; +use core::fmt; +use core::ptr::{self, NonNull}; +use core::slice::{self}; +use core::iter::{ + FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess, +}; + +/// An iterator that moves out of a vector. +/// +/// This `struct` is created by the `into_iter` method on [`Vec`] (provided +/// by the [`IntoIterator`] trait). +/// +/// # Example +/// +/// ``` +/// let v = vec![0, 1, 2]; +/// let iter: std::vec::IntoIter<_> = v.into_iter(); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + pub(super) buf: NonNull, + pub(super) phantom: PhantomData, + pub(super) cap: usize, + pub(super) alloc: A, + pub(super) ptr: *const T, + pub(super) end: *const T, +} + +#[stable(feature = "vec_intoiter_debug", since = "1.13.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("IntoIter").field(&self.as_slice()).finish() + } +} + +impl IntoIter { + /// Returns the remaining items of this iterator as a slice. + /// + /// # Examples + /// + /// ``` + /// let vec = vec!['a', 'b', 'c']; + /// let mut into_iter = vec.into_iter(); + /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + /// let _ = into_iter.next().unwrap(); + /// assert_eq!(into_iter.as_slice(), &['b', 'c']); + /// ``` + #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")] + pub fn as_slice(&self) -> &[T] { + unsafe { slice::from_raw_parts(self.ptr, self.len()) } + } + + /// Returns the remaining items of this iterator as a mutable slice. + /// + /// # Examples + /// + /// ``` + /// let vec = vec!['a', 'b', 'c']; + /// let mut into_iter = vec.into_iter(); + /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + /// into_iter.as_mut_slice()[2] = 'z'; + /// assert_eq!(into_iter.next().unwrap(), 'a'); + /// assert_eq!(into_iter.next().unwrap(), 'b'); + /// assert_eq!(into_iter.next().unwrap(), 'z'); + /// ``` + #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")] + pub fn as_mut_slice(&mut self) -> &mut [T] { + unsafe { &mut *self.as_raw_mut_slice() } + } + + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn allocator(&self) -> &A { + &self.alloc + } + + fn as_raw_mut_slice(&mut self) -> *mut [T] { + ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) + } + + pub(super) fn drop_remaining(&mut self) { + unsafe { + ptr::drop_in_place(self.as_mut_slice()); + } + self.ptr = self.end; + } + + /// Relinquishes the backing allocation, equivalent to + /// `ptr::write(&mut self, Vec::new().into_iter())` + pub(super) fn forget_allocation(&mut self) { + self.cap = 0; + self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) }; + self.ptr = self.buf.as_ptr(); + self.end = self.buf.as_ptr(); + } +} + +#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] +impl AsRef<[T]> for IntoIter { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for IntoIter {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for IntoIter {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + if self.ptr as *const _ == self.end { + None + } else if mem::size_of::() == 0 { + // purposefully don't use 'ptr.offset' because for + // vectors with 0-size elements this would return the + // same pointer. + self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T }; + + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } else { + let old = self.ptr; + self.ptr = unsafe { self.ptr.offset(1) }; + + Some(unsafe { ptr::read(old) }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let exact = if mem::size_of::() == 0 { + (self.end as usize).wrapping_sub(self.ptr as usize) + } else { + unsafe { self.end.offset_from(self.ptr) as usize } + }; + (exact, Some(exact)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must guarantee that `i` is in bounds of the + // `Vec`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)` + // is guaranteed to pointer to an element of the `Vec` and + // thus guaranteed to be valid to dereference. + // + // Also note the implementation of `Self: TrustedRandomAccess` requires + // that `T: Copy` so reading elements from the buffer doesn't invalidate + // them for `Drop`. + unsafe { + if mem::size_of::() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + if self.end == self.ptr { + None + } else if mem::size_of::() == 0 { + // See above for why 'ptr.offset' isn't used + self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T }; + + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } else { + self.end = unsafe { self.end.offset(-1) }; + + Some(unsafe { ptr::read(self.end) }) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter { + fn is_empty(&self) -> bool { + self.ptr == self.end + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IntoIter {} + +#[doc(hidden)] +#[unstable(issue = "none", feature = "std_internals")] +// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr +// and thus we can't implement drop-handling +unsafe impl TrustedRandomAccess for IntoIter + where + T: Copy, +{ + fn may_have_side_effect() -> bool { + false + } +} + +#[stable(feature = "vec_into_iter_clone", since = "1.8.0")] +impl Clone for IntoIter { + #[cfg(not(test))] + fn clone(&self) -> Self { + self.as_slice().to_vec_in(self.alloc.clone()).into_iter() + } + #[cfg(test)] + fn clone(&self) -> Self { + crate::slice::to_vec(self.as_slice(), self.alloc.clone()).into_iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter { + fn drop(&mut self) { + struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter); + + impl Drop for DropGuard<'_, T, A> { + fn drop(&mut self) { + unsafe { + // `IntoIter::alloc` is not used anymore after this + let alloc = ptr::read(&self.0.alloc); + // RawVec handles deallocation + let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); + } + } + } + + let guard = DropGuard(self); + // destroy the remaining elements + unsafe { + ptr::drop_in_place(guard.0.as_raw_mut_slice()); + } + // now `guard` will be dropped and do the rest + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for IntoIter {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for IntoIter { + type Source = Self; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut Self::Source { + self + } +} diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 8d3f8b0bfd89a..b6508bfea0818 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -60,7 +60,7 @@ use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::{arith_offset, assume}; use core::iter::{ - FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess, + FromIterator, InPlaceIterable, SourceIter, TrustedLen, }; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, MaybeUninit}; @@ -91,6 +91,11 @@ mod drain; mod cow; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::into_iter::IntoIter; + +mod into_iter; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -3015,269 +3020,6 @@ impl TryFrom> for [T; N] { } } -//////////////////////////////////////////////////////////////////////////////// -// Iterators -//////////////////////////////////////////////////////////////////////////////// - -/// An iterator that moves out of a vector. -/// -/// This `struct` is created by the `into_iter` method on [`Vec`] (provided -/// by the [`IntoIterator`] trait). -/// -/// # Example -/// -/// ``` -/// let v = vec![0, 1, 2]; -/// let iter: std::vec::IntoIter<_> = v.into_iter(); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter< - T, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> { - buf: NonNull, - phantom: PhantomData, - cap: usize, - alloc: A, - ptr: *const T, - end: *const T, -} - -#[stable(feature = "vec_intoiter_debug", since = "1.13.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("IntoIter").field(&self.as_slice()).finish() - } -} - -impl IntoIter { - /// Returns the remaining items of this iterator as a slice. - /// - /// # Examples - /// - /// ``` - /// let vec = vec!['a', 'b', 'c']; - /// let mut into_iter = vec.into_iter(); - /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); - /// let _ = into_iter.next().unwrap(); - /// assert_eq!(into_iter.as_slice(), &['b', 'c']); - /// ``` - #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")] - pub fn as_slice(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.ptr, self.len()) } - } - - /// Returns the remaining items of this iterator as a mutable slice. - /// - /// # Examples - /// - /// ``` - /// let vec = vec!['a', 'b', 'c']; - /// let mut into_iter = vec.into_iter(); - /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); - /// into_iter.as_mut_slice()[2] = 'z'; - /// assert_eq!(into_iter.next().unwrap(), 'a'); - /// assert_eq!(into_iter.next().unwrap(), 'b'); - /// assert_eq!(into_iter.next().unwrap(), 'z'); - /// ``` - #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")] - pub fn as_mut_slice(&mut self) -> &mut [T] { - unsafe { &mut *self.as_raw_mut_slice() } - } - - /// Returns a reference to the underlying allocator. - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub fn allocator(&self) -> &A { - &self.alloc - } - - fn as_raw_mut_slice(&mut self) -> *mut [T] { - ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) - } - - fn drop_remaining(&mut self) { - unsafe { - ptr::drop_in_place(self.as_mut_slice()); - } - self.ptr = self.end; - } - - /// Relinquishes the backing allocation, equivalent to - /// `ptr::write(&mut self, Vec::new().into_iter())` - fn forget_allocation(&mut self) { - self.cap = 0; - self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) }; - self.ptr = self.buf.as_ptr(); - self.end = self.buf.as_ptr(); - } -} - -#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] -impl AsRef<[T]> for IntoIter { - fn as_ref(&self) -> &[T] { - self.as_slice() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for IntoIter {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for IntoIter {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - if self.ptr as *const _ == self.end { - None - } else if mem::size_of::() == 0 { - // purposefully don't use 'ptr.offset' because for - // vectors with 0-size elements this would return the - // same pointer. - self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T }; - - // Make up a value of this ZST. - Some(unsafe { mem::zeroed() }) - } else { - let old = self.ptr; - self.ptr = unsafe { self.ptr.offset(1) }; - - Some(unsafe { ptr::read(old) }) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let exact = if mem::size_of::() == 0 { - (self.end as usize).wrapping_sub(self.ptr as usize) - } else { - unsafe { self.end.offset_from(self.ptr) as usize } - }; - (exact, Some(exact)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must guarantee that `i` is in bounds of the - // `Vec`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)` - // is guaranteed to pointer to an element of the `Vec` and - // thus guaranteed to be valid to dereference. - // - // Also note the implementation of `Self: TrustedRandomAccess` requires - // that `T: Copy` so reading elements from the buffer doesn't invalidate - // them for `Drop`. - unsafe { - if mem::size_of::() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - if self.end == self.ptr { - None - } else if mem::size_of::() == 0 { - // See above for why 'ptr.offset' isn't used - self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T }; - - // Make up a value of this ZST. - Some(unsafe { mem::zeroed() }) - } else { - self.end = unsafe { self.end.offset(-1) }; - - Some(unsafe { ptr::read(self.end) }) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { - fn is_empty(&self) -> bool { - self.ptr == self.end - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IntoIter {} - -#[doc(hidden)] -#[unstable(issue = "none", feature = "std_internals")] -// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr -// and thus we can't implement drop-handling -unsafe impl TrustedRandomAccess for IntoIter -where - T: Copy, -{ - fn may_have_side_effect() -> bool { - false - } -} - -#[stable(feature = "vec_into_iter_clone", since = "1.8.0")] -impl Clone for IntoIter { - #[cfg(not(test))] - fn clone(&self) -> Self { - self.as_slice().to_vec_in(self.alloc.clone()).into_iter() - } - #[cfg(test)] - fn clone(&self) -> Self { - crate::slice::to_vec(self.as_slice(), self.alloc.clone()).into_iter() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter { - fn drop(&mut self) { - struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter); - - impl Drop for DropGuard<'_, T, A> { - fn drop(&mut self) { - unsafe { - // `IntoIter::alloc` is not used anymore after this - let alloc = ptr::read(&self.0.alloc); - // RawVec handles deallocation - let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); - } - } - } - - let guard = DropGuard(self); - // destroy the remaining elements - unsafe { - ptr::drop_in_place(guard.0.as_raw_mut_slice()); - } - // now `guard` will be dropped and do the rest - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for IntoIter {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for IntoIter { - type Source = Self; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut Self::Source { - self - } -} - // internal helper trait for in-place iteration specialization. #[rustc_specialization_trait] pub(crate) trait AsIntoIter { From 2a1248976a00429994d5965bb31d6dcc1b7dcd68 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 00:47:54 +0000 Subject: [PATCH 12/35] refactor: moving AsIntoIter into into_iter.rs --- library/alloc/src/vec/into_iter.rs | 15 +++++++++++++++ library/alloc/src/vec/mod.rs | 16 +--------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 623792a631612..c4330df4ad95b 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -268,3 +268,18 @@ unsafe impl SourceIter for IntoIter { self } } + +// internal helper trait for in-place iteration specialization. +#[rustc_specialization_trait] +pub(crate) trait AsIntoIter { + type Item; + fn as_into_iter(&mut self) -> &mut IntoIter; +} + +impl AsIntoIter for IntoIter { + type Item = T; + + fn as_into_iter(&mut self) -> &mut IntoIter { + self + } +} diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b6508bfea0818..1f410e3c02842 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -93,6 +93,7 @@ mod cow; #[stable(feature = "rust1", since = "1.0.0")] pub use self::into_iter::IntoIter; +pub (crate) use self::into_iter::AsIntoIter; mod into_iter; @@ -3019,18 +3020,3 @@ impl TryFrom> for [T; N] { Ok(array) } } - -// internal helper trait for in-place iteration specialization. -#[rustc_specialization_trait] -pub(crate) trait AsIntoIter { - type Item; - fn as_into_iter(&mut self) -> &mut IntoIter; -} - -impl AsIntoIter for IntoIter { - type Item = T; - - fn as_into_iter(&mut self) -> &mut IntoIter { - self - } -} From 840c4e2873476a7d6101f71e4f63b3024245ccd1 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 00:52:48 +0000 Subject: [PATCH 13/35] refactor: moved IsZero into is_zero.rs --- library/alloc/src/vec/is_zero.rs | 71 ++++++++++++++++++++++++++++++ library/alloc/src/vec/mod.rs | 74 ++------------------------------ 2 files changed, 75 insertions(+), 70 deletions(-) create mode 100644 library/alloc/src/vec/is_zero.rs diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs new file mode 100644 index 0000000000000..961f6ca171b11 --- /dev/null +++ b/library/alloc/src/vec/is_zero.rs @@ -0,0 +1,71 @@ +use crate::boxed::Box; + +#[rustc_specialization_trait] +pub(super) unsafe trait IsZero { + /// Whether this value is zero + fn is_zero(&self) -> bool; +} + +macro_rules! impl_is_zero { + ($t:ty, $is_zero:expr) => { + unsafe impl IsZero for $t { + #[inline] + fn is_zero(&self) -> bool { + $is_zero(*self) + } + } + }; +} + +impl_is_zero!(i16, |x| x == 0); +impl_is_zero!(i32, |x| x == 0); +impl_is_zero!(i64, |x| x == 0); +impl_is_zero!(i128, |x| x == 0); +impl_is_zero!(isize, |x| x == 0); + +impl_is_zero!(u16, |x| x == 0); +impl_is_zero!(u32, |x| x == 0); +impl_is_zero!(u64, |x| x == 0); +impl_is_zero!(u128, |x| x == 0); +impl_is_zero!(usize, |x| x == 0); + +impl_is_zero!(bool, |x| x == false); +impl_is_zero!(char, |x| x == '\0'); + +impl_is_zero!(f32, |x: f32| x.to_bits() == 0); +impl_is_zero!(f64, |x: f64| x.to_bits() == 0); + +unsafe impl IsZero for *const T { + #[inline] + fn is_zero(&self) -> bool { + (*self).is_null() + } +} + +unsafe impl IsZero for *mut T { + #[inline] + fn is_zero(&self) -> bool { + (*self).is_null() + } +} + +// `Option<&T>` and `Option>` are guaranteed to represent `None` as null. +// For fat pointers, the bytes that would be the pointer metadata in the `Some` +// variant are padding in the `None` variant, so ignoring them and +// zero-initializing instead is ok. +// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of +// `SpecFromElem`. + +unsafe impl IsZero for Option<&T> { + #[inline] + fn is_zero(&self) -> bool { + self.is_none() + } +} + +unsafe impl IsZero for Option> { + #[inline] + fn is_zero(&self) -> bool { + self.is_none() + } +} \ No newline at end of file diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1f410e3c02842..69fcfaa6a7ecf 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -97,6 +97,10 @@ pub (crate) use self::into_iter::AsIntoIter; mod into_iter; +use self::is_zero::IsZero; + +mod is_zero; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -2042,76 +2046,6 @@ impl SpecFromElem for T { } } -#[rustc_specialization_trait] -unsafe trait IsZero { - /// Whether this value is zero - fn is_zero(&self) -> bool; -} - -macro_rules! impl_is_zero { - ($t:ty, $is_zero:expr) => { - unsafe impl IsZero for $t { - #[inline] - fn is_zero(&self) -> bool { - $is_zero(*self) - } - } - }; -} - -impl_is_zero!(i16, |x| x == 0); -impl_is_zero!(i32, |x| x == 0); -impl_is_zero!(i64, |x| x == 0); -impl_is_zero!(i128, |x| x == 0); -impl_is_zero!(isize, |x| x == 0); - -impl_is_zero!(u16, |x| x == 0); -impl_is_zero!(u32, |x| x == 0); -impl_is_zero!(u64, |x| x == 0); -impl_is_zero!(u128, |x| x == 0); -impl_is_zero!(usize, |x| x == 0); - -impl_is_zero!(bool, |x| x == false); -impl_is_zero!(char, |x| x == '\0'); - -impl_is_zero!(f32, |x: f32| x.to_bits() == 0); -impl_is_zero!(f64, |x: f64| x.to_bits() == 0); - -unsafe impl IsZero for *const T { - #[inline] - fn is_zero(&self) -> bool { - (*self).is_null() - } -} - -unsafe impl IsZero for *mut T { - #[inline] - fn is_zero(&self) -> bool { - (*self).is_null() - } -} - -// `Option<&T>` and `Option>` are guaranteed to represent `None` as null. -// For fat pointers, the bytes that would be the pointer metadata in the `Some` -// variant are padding in the `None` variant, so ignoring them and -// zero-initializing instead is ok. -// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of -// `SpecFromElem`. - -unsafe impl IsZero for Option<&T> { - #[inline] - fn is_zero(&self) -> bool { - self.is_none() - } -} - -unsafe impl IsZero for Option> { - #[inline] - fn is_zero(&self) -> bool { - self.is_none() - } -} - //////////////////////////////////////////////////////////////////////////////// // Common trait implementations for Vec //////////////////////////////////////////////////////////////////////////////// From 5ac6709b95bb0cce4cffa9bd87d241928bc7f3f6 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 01:04:06 +0000 Subject: [PATCH 14/35] refactor: moving SourceIterMarker into source_iter_marker.rs --- library/alloc/src/vec/mod.rs | 107 +------------------ library/alloc/src/vec/source_iter_marker.rs | 110 ++++++++++++++++++++ 2 files changed, 113 insertions(+), 104 deletions(-) create mode 100644 library/alloc/src/vec/source_iter_marker.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 69fcfaa6a7ecf..bd71d7004b993 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -60,7 +60,7 @@ use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::{arith_offset, assume}; use core::iter::{ - FromIterator, InPlaceIterable, SourceIter, TrustedLen, + FromIterator, TrustedLen, }; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, MaybeUninit}; @@ -101,6 +101,8 @@ use self::is_zero::IsZero; mod is_zero; +mod source_iter_marker; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -2356,109 +2358,6 @@ impl SpecFromIter> for Vec { } } -fn write_in_place_with_drop( - src_end: *const T, -) -> impl FnMut(InPlaceDrop, T) -> Result, !> { - move |mut sink, item| { - unsafe { - // the InPlaceIterable contract cannot be verified precisely here since - // try_fold has an exclusive reference to the source pointer - // all we can do is check if it's still in range - debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation"); - ptr::write(sink.dst, item); - sink.dst = sink.dst.add(1); - } - Ok(sink) - } -} - -/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the -/// source allocation, i.e. executing the pipeline in place. -/// -/// The SourceIter parent trait is necessary for the specializing function to access the allocation -/// which is to be reused. But it is not sufficient for the specialization to be valid. See -/// additional bounds on the impl. -#[rustc_unsafe_specialization_marker] -trait SourceIterMarker: SourceIter {} - -// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of -// Adapter>> (all owned by core/std). Additional bounds -// on the adapter implementations (beyond `impl Trait for Adapter`) only depend on other -// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator). -// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which -// several other specializations already depend on. -impl SourceIterMarker for T where T: SourceIter + InPlaceIterable {} - -impl SpecFromIter for Vec -where - I: Iterator + SourceIterMarker, -{ - default fn from_iter(mut iterator: I) -> Self { - // Additional requirements which cannot expressed via trait bounds. We rely on const eval - // instead: - // a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic - // b) size match as required by Alloc contract - // c) alignments match as required by Alloc contract - if mem::size_of::() == 0 - || mem::size_of::() - != mem::size_of::<<::Source as AsIntoIter>::Item>() - || mem::align_of::() - != mem::align_of::<<::Source as AsIntoIter>::Item>() - { - // fallback to more generic implementations - return SpecFromIterNested::from_iter(iterator); - } - - let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe { - let inner = iterator.as_inner().as_into_iter(); - ( - inner.buf.as_ptr(), - inner.ptr, - inner.buf.as_ptr() as *mut T, - inner.end as *const T, - inner.cap, - ) - }; - - // use try-fold since - // - it vectorizes better for some iterator adapters - // - unlike most internal iteration methods, it only takes a &mut self - // - it lets us thread the write pointer through its innards and get it back in the end - let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf }; - let sink = iterator - .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end)) - .unwrap(); - // iteration succeeded, don't drop head - let dst = ManuallyDrop::new(sink).dst; - - let src = unsafe { iterator.as_inner().as_into_iter() }; - // check if SourceIter contract was upheld - // caveat: if they weren't we may not even make it to this point - debug_assert_eq!(src_buf, src.buf.as_ptr()); - // check InPlaceIterable contract. This is only possible if the iterator advanced the - // source pointer at all. If it uses unchecked access via TrustedRandomAccess - // then the source pointer will stay in its initial position and we can't use it as reference - if src.ptr != src_ptr { - debug_assert!( - dst as *const _ <= src.ptr, - "InPlaceIterable contract violation, write pointer advanced beyond read pointer" - ); - } - - // drop any remaining values at the tail of the source - src.drop_remaining(); - // but prevent drop of the allocation itself once IntoIter goes out of scope - src.forget_allocation(); - - let vec = unsafe { - let len = dst.offset_from(dst_buf) as usize; - Vec::from_raw_parts(dst_buf, len, cap) - }; - - vec - } -} - impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec where I: Iterator, diff --git a/library/alloc/src/vec/source_iter_marker.rs b/library/alloc/src/vec/source_iter_marker.rs new file mode 100644 index 0000000000000..eb3ae01a47e9b --- /dev/null +++ b/library/alloc/src/vec/source_iter_marker.rs @@ -0,0 +1,110 @@ +use core::iter::{ + InPlaceIterable, SourceIter, +}; +use core::mem::{self, ManuallyDrop}; +use core::ptr::{self}; + +use super::{Vec, InPlaceDrop, AsIntoIter, SpecFromIter, SpecFromIterNested}; + +/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the +/// source allocation, i.e. executing the pipeline in place. +/// +/// The SourceIter parent trait is necessary for the specializing function to access the allocation +/// which is to be reused. But it is not sufficient for the specialization to be valid. See +/// additional bounds on the impl. +#[rustc_unsafe_specialization_marker] +pub (super) trait SourceIterMarker: SourceIter {} + +// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of +// Adapter>> (all owned by core/std). Additional bounds +// on the adapter implementations (beyond `impl Trait for Adapter`) only depend on other +// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator). +// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which +// several other specializations already depend on. +impl SourceIterMarker for T where T: SourceIter + InPlaceIterable {} + +impl SpecFromIter for Vec + where + I: Iterator + SourceIterMarker, +{ + default fn from_iter(mut iterator: I) -> Self { + // Additional requirements which cannot expressed via trait bounds. We rely on const eval + // instead: + // a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic + // b) size match as required by Alloc contract + // c) alignments match as required by Alloc contract + if mem::size_of::() == 0 + || mem::size_of::() + != mem::size_of::<<::Source as AsIntoIter>::Item>() + || mem::align_of::() + != mem::align_of::<<::Source as AsIntoIter>::Item>() + { + // fallback to more generic implementations + return SpecFromIterNested::from_iter(iterator); + } + + let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe { + let inner = iterator.as_inner().as_into_iter(); + ( + inner.buf.as_ptr(), + inner.ptr, + inner.buf.as_ptr() as *mut T, + inner.end as *const T, + inner.cap, + ) + }; + + // use try-fold since + // - it vectorizes better for some iterator adapters + // - unlike most internal iteration methods, it only takes a &mut self + // - it lets us thread the write pointer through its innards and get it back in the end + let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf }; + let sink = iterator + .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end)) + .unwrap(); + // iteration succeeded, don't drop head + let dst = ManuallyDrop::new(sink).dst; + + let src = unsafe { iterator.as_inner().as_into_iter() }; + // check if SourceIter contract was upheld + // caveat: if they weren't we may not even make it to this point + debug_assert_eq!(src_buf, src.buf.as_ptr()); + // check InPlaceIterable contract. This is only possible if the iterator advanced the + // source pointer at all. If it uses unchecked access via TrustedRandomAccess + // then the source pointer will stay in its initial position and we can't use it as reference + if src.ptr != src_ptr { + debug_assert!( + dst as *const _ <= src.ptr, + "InPlaceIterable contract violation, write pointer advanced beyond read pointer" + ); + } + + // drop any remaining values at the tail of the source + src.drop_remaining(); + // but prevent drop of the allocation itself once IntoIter goes out of scope + src.forget_allocation(); + + let vec = unsafe { + let len = dst.offset_from(dst_buf) as usize; + Vec::from_raw_parts(dst_buf, len, cap) + }; + + vec + } +} + +fn write_in_place_with_drop( + src_end: *const T, +) -> impl FnMut(InPlaceDrop, T) -> Result, !> { + move |mut sink, item| { + unsafe { + // the InPlaceIterable contract cannot be verified precisely here since + // try_fold has an exclusive reference to the source pointer + // all we can do is check if it's still in range + debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation"); + ptr::write(sink.dst, item); + sink.dst = sink.dst.add(1); + } + Ok(sink) + } +} From dc46013248ecb8b0d3d29581c1734dd2ecd42b0d Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 01:07:34 +0000 Subject: [PATCH 15/35] refactor: moved PartialEq into partial_eq --- library/alloc/src/vec/mod.rs | 41 ++------------------------- library/alloc/src/vec/partial_eq.rs | 43 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 39 deletions(-) create mode 100644 library/alloc/src/vec/partial_eq.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index bd71d7004b993..a862a979d3b6a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -103,6 +103,8 @@ mod is_zero; mod source_iter_marker; +mod partial_eq; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -2615,45 +2617,6 @@ impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { } } -macro_rules! __impl_slice_eq1 { - ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => { - #[$stability] - impl PartialEq<$rhs> for $lhs - where - T: PartialEq, - $($ty: $bound)? - { - #[inline] - fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } - #[inline] - fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] } - } - } -} - -__impl_slice_eq1! { [A: Allocator] Vec, Vec, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: Allocator] Vec, &[U], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: Allocator] Vec, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: Allocator] &[T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } -__impl_slice_eq1! { [A: Allocator] &mut [T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } -__impl_slice_eq1! { [A: Allocator] Vec, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } -__impl_slice_eq1! { [A: Allocator] [T], Vec, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } -__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, [U; N], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] } - -// NOTE: some less important impls are omitted to reduce code bloat -// FIXME(Centril): Reconsider this? -//__impl_slice_eq1! { [const N: usize] Vec, &mut [B; N], } -//__impl_slice_eq1! { [const N: usize] [A; N], Vec, } -//__impl_slice_eq1! { [const N: usize] &[A; N], Vec, } -//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec, } -//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], } -//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], } -//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], } - /// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Vec { diff --git a/library/alloc/src/vec/partial_eq.rs b/library/alloc/src/vec/partial_eq.rs new file mode 100644 index 0000000000000..617f04044399e --- /dev/null +++ b/library/alloc/src/vec/partial_eq.rs @@ -0,0 +1,43 @@ +use crate::alloc::{Allocator}; +use crate::borrow::Cow; + +use super::{Vec}; + +macro_rules! __impl_slice_eq1 { + ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => { + #[$stability] + impl PartialEq<$rhs> for $lhs + where + T: PartialEq, + $($ty: $bound)? + { + #[inline] + fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } + #[inline] + fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] } + } + } +} + +__impl_slice_eq1! { [A: Allocator] Vec, Vec, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, &[U], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] &[T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } +__impl_slice_eq1! { [A: Allocator] &mut [T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } +__impl_slice_eq1! { [A: Allocator] [T], Vec, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } +__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, [U; N], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] } + +// NOTE: some less important impls are omitted to reduce code bloat +// FIXME(Centril): Reconsider this? +//__impl_slice_eq1! { [const N: usize] Vec, &mut [B; N], } +//__impl_slice_eq1! { [const N: usize] [A; N], Vec, } +//__impl_slice_eq1! { [const N: usize] &[A; N], Vec, } +//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec, } +//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], } +//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], } +//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], } From a2f4bc0d181f6aaee7b43fc37e7f16bd400d6b2c Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 01:14:31 +0000 Subject: [PATCH 16/35] refactor: moved SpecFromElem to spec_from_elem.rs --- library/alloc/src/vec/mod.rs | 59 ++---------------------- library/alloc/src/vec/spec_from_elem.rs | 60 +++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 55 deletions(-) create mode 100644 library/alloc/src/vec/spec_from_elem.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a862a979d3b6a..ae1736d8d3c4d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -105,6 +105,10 @@ mod source_iter_marker; mod partial_eq; +use self::spec_from_elem::SpecFromElem; + +mod spec_from_elem; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -1995,61 +1999,6 @@ pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec< ::from_elem(elem, n, alloc) } -// Specialization trait used for Vec::from_elem -trait SpecFromElem: Sized { - fn from_elem(elem: Self, n: usize, alloc: A) -> Vec; -} - -impl SpecFromElem for T { - default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { - let mut v = Vec::with_capacity_in(n, alloc); - v.extend_with(n, ExtendElement(elem)); - v - } -} - -impl SpecFromElem for i8 { - #[inline] - fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { - if elem == 0 { - return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; - } - unsafe { - let mut v = Vec::with_capacity_in(n, alloc); - ptr::write_bytes(v.as_mut_ptr(), elem as u8, n); - v.set_len(n); - v - } - } -} - -impl SpecFromElem for u8 { - #[inline] - fn from_elem(elem: u8, n: usize, alloc: A) -> Vec { - if elem == 0 { - return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; - } - unsafe { - let mut v = Vec::with_capacity_in(n, alloc); - ptr::write_bytes(v.as_mut_ptr(), elem, n); - v.set_len(n); - v - } - } -} - -impl SpecFromElem for T { - #[inline] - fn from_elem(elem: T, n: usize, alloc: A) -> Vec { - if elem.is_zero() { - return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; - } - let mut v = Vec::with_capacity_in(n, alloc); - v.extend_with(n, ExtendElement(elem)); - v - } -} - //////////////////////////////////////////////////////////////////////////////// // Common trait implementations for Vec //////////////////////////////////////////////////////////////////////////////// diff --git a/library/alloc/src/vec/spec_from_elem.rs b/library/alloc/src/vec/spec_from_elem.rs new file mode 100644 index 0000000000000..ef89054ea1320 --- /dev/null +++ b/library/alloc/src/vec/spec_from_elem.rs @@ -0,0 +1,60 @@ +use crate::alloc::{Allocator}; +use crate::raw_vec::RawVec; +use core::ptr::{self}; + +use super::{Vec, IsZero, ExtendElement}; + +// Specialization trait used for Vec::from_elem +pub(super) trait SpecFromElem: Sized { + fn from_elem(elem: Self, n: usize, alloc: A) -> Vec; +} + +impl SpecFromElem for T { + default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { + let mut v = Vec::with_capacity_in(n, alloc); + v.extend_with(n, ExtendElement(elem)); + v + } +} + +impl SpecFromElem for i8 { + #[inline] + fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { + if elem == 0 { + return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; + } + unsafe { + let mut v = Vec::with_capacity_in(n, alloc); + ptr::write_bytes(v.as_mut_ptr(), elem as u8, n); + v.set_len(n); + v + } + } +} + +impl SpecFromElem for u8 { + #[inline] + fn from_elem(elem: u8, n: usize, alloc: A) -> Vec { + if elem == 0 { + return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; + } + unsafe { + let mut v = Vec::with_capacity_in(n, alloc); + ptr::write_bytes(v.as_mut_ptr(), elem, n); + v.set_len(n); + v + } + } +} + +impl SpecFromElem for T { + #[inline] + fn from_elem(elem: T, n: usize, alloc: A) -> Vec { + if elem.is_zero() { + return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; + } + let mut v = Vec::with_capacity_in(n, alloc); + v.extend_with(n, ExtendElement(elem)); + v + } +} \ No newline at end of file From a3f3fc5aedc9636ea580d8241746e06db6031270 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 01:21:51 +0000 Subject: [PATCH 17/35] refactor: moved SetLenOnDrop to set_len_on_drop --- library/alloc/src/vec/mod.rs | 33 +++--------------------- library/alloc/src/vec/set_len_on_drop.rs | 28 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 library/alloc/src/vec/set_len_on_drop.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ae1736d8d3c4d..62ca5b950ce84 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -109,6 +109,10 @@ use self::spec_from_elem::SpecFromElem; mod spec_from_elem; +use self::set_len_on_drop::SetLenOnDrop; + +mod set_len_on_drop; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -1911,35 +1915,6 @@ impl Vec { } } -// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. -// -// The idea is: The length field in SetLenOnDrop is a local variable -// that the optimizer will see does not alias with any stores through the Vec's data -// pointer. This is a workaround for alias analysis issue #32155 -struct SetLenOnDrop<'a> { - len: &'a mut usize, - local_len: usize, -} - -impl<'a> SetLenOnDrop<'a> { - #[inline] - fn new(len: &'a mut usize) -> Self { - SetLenOnDrop { local_len: *len, len } - } - - #[inline] - fn increment_len(&mut self, increment: usize) { - self.local_len += increment; - } -} - -impl Drop for SetLenOnDrop<'_> { - #[inline] - fn drop(&mut self) { - *self.len = self.local_len; - } -} - impl Vec { /// Removes consecutive repeated elements in the vector according to the /// [`PartialEq`] trait implementation. diff --git a/library/alloc/src/vec/set_len_on_drop.rs b/library/alloc/src/vec/set_len_on_drop.rs new file mode 100644 index 0000000000000..8b66bc8121296 --- /dev/null +++ b/library/alloc/src/vec/set_len_on_drop.rs @@ -0,0 +1,28 @@ +// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. +// +// The idea is: The length field in SetLenOnDrop is a local variable +// that the optimizer will see does not alias with any stores through the Vec's data +// pointer. This is a workaround for alias analysis issue #32155 +pub(super) struct SetLenOnDrop<'a> { + len: &'a mut usize, + local_len: usize, +} + +impl<'a> SetLenOnDrop<'a> { + #[inline] + pub(super) fn new(len: &'a mut usize) -> Self { + SetLenOnDrop { local_len: *len, len } + } + + #[inline] + pub(super) fn increment_len(&mut self, increment: usize) { + self.local_len += increment; + } +} + +impl Drop for SetLenOnDrop<'_> { + #[inline] + fn drop(&mut self) { + *self.len = self.local_len; + } +} From 9e08ce7190dd63afc3e5a12f89134c760566513a Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 01:26:52 +0000 Subject: [PATCH 18/35] refactor: moved InPlaceDrop into in_place_drop.rs --- library/alloc/src/vec/in_place_drop.rs | 24 ++++++++++++++++++++++++ library/alloc/src/vec/mod.rs | 26 ++++---------------------- 2 files changed, 28 insertions(+), 22 deletions(-) create mode 100644 library/alloc/src/vec/in_place_drop.rs diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs new file mode 100644 index 0000000000000..3a0ecc529c006 --- /dev/null +++ b/library/alloc/src/vec/in_place_drop.rs @@ -0,0 +1,24 @@ +use core::ptr::{self}; +use core::slice::{self}; + +// A helper struct for in-place iteration that drops the destination slice of iteration, +// i.e. the head. The source slice (the tail) is dropped by IntoIter. +pub (super) struct InPlaceDrop { + pub (super) inner: *mut T, + pub (super) dst: *mut T, +} + +impl InPlaceDrop { + fn len(&self) -> usize { + unsafe { self.dst.offset_from(self.inner) as usize } + } +} + +impl Drop for InPlaceDrop { + #[inline] + fn drop(&mut self) { + unsafe { + ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len())); + } + } +} diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 62ca5b950ce84..08a920a9c6072 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -113,6 +113,10 @@ use self::set_len_on_drop::SetLenOnDrop; mod set_len_on_drop; +use self::in_place_drop::InPlaceDrop; + +mod in_place_drop; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -2233,28 +2237,6 @@ where } } -// A helper struct for in-place iteration that drops the destination slice of iteration, -// i.e. the head. The source slice (the tail) is dropped by IntoIter. -struct InPlaceDrop { - inner: *mut T, - dst: *mut T, -} - -impl InPlaceDrop { - fn len(&self) -> usize { - unsafe { self.dst.offset_from(self.inner) as usize } - } -} - -impl Drop for InPlaceDrop { - #[inline] - fn drop(&mut self) { - unsafe { - ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len())); - } - } -} - impl SpecFromIter> for Vec { fn from_iter(iterator: IntoIter) -> Self { // A common case is passing a vector into a function which immediately From 56d82b3dcc73e227dd2fa4dd4a8ef8d96ce75805 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 01:30:20 +0000 Subject: [PATCH 19/35] refactor: moved SpecFromIterNested to spec_from_iter_nested.rs --- library/alloc/src/vec/mod.rs | 56 ++----------------- .../alloc/src/vec/spec_from_iter_nested.rs | 56 +++++++++++++++++++ 2 files changed, 60 insertions(+), 52 deletions(-) create mode 100644 library/alloc/src/vec/spec_from_iter_nested.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 08a920a9c6072..438246ab4cb31 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -117,6 +117,10 @@ use self::in_place_drop::InPlaceDrop; mod in_place_drop; +use self::spec_from_iter_nested::SpecFromIterNested; + +mod spec_from_iter_nested; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -2176,58 +2180,6 @@ trait SpecFromIter { fn from_iter(iter: I) -> Self; } -/// Another specialization trait for Vec::from_iter -/// necessary to manually prioritize overlapping specializations -/// see [`SpecFromIter`] for details. -trait SpecFromIterNested { - fn from_iter(iter: I) -> Self; -} - -impl SpecFromIterNested for Vec -where - I: Iterator, -{ - default fn from_iter(mut iterator: I) -> Self { - // Unroll the first iteration, as the vector is going to be - // expanded on this iteration in every case when the iterable is not - // empty, but the loop in extend_desugared() is not going to see the - // vector being full in the few subsequent loop iterations. - // So we get better branch prediction. - let mut vector = match iterator.next() { - None => return Vec::new(), - Some(element) => { - let (lower, _) = iterator.size_hint(); - let mut vector = Vec::with_capacity(lower.saturating_add(1)); - unsafe { - ptr::write(vector.as_mut_ptr(), element); - vector.set_len(1); - } - vector - } - }; - // must delegate to spec_extend() since extend() itself delegates - // to spec_from for empty Vecs - as SpecExtend>::spec_extend(&mut vector, iterator); - vector - } -} - -impl SpecFromIterNested for Vec -where - I: TrustedLen, -{ - fn from_iter(iterator: I) -> Self { - let mut vector = match iterator.size_hint() { - (_, Some(upper)) => Vec::with_capacity(upper), - _ => Vec::new(), - }; - // must delegate to spec_extend() since extend() itself delegates - // to spec_from for empty Vecs - vector.spec_extend(iterator); - vector - } -} - impl SpecFromIter for Vec where I: Iterator, diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs new file mode 100644 index 0000000000000..0da42844c96ce --- /dev/null +++ b/library/alloc/src/vec/spec_from_iter_nested.rs @@ -0,0 +1,56 @@ +use core::ptr::{self}; +use core::iter::{TrustedLen}; + +use super::{Vec, SpecExtend}; + +/// Another specialization trait for Vec::from_iter +/// necessary to manually prioritize overlapping specializations +/// see [`SpecFromIter`] for details. +pub(super) trait SpecFromIterNested { + fn from_iter(iter: I) -> Self; +} + +impl SpecFromIterNested for Vec + where + I: Iterator, +{ + default fn from_iter(mut iterator: I) -> Self { + // Unroll the first iteration, as the vector is going to be + // expanded on this iteration in every case when the iterable is not + // empty, but the loop in extend_desugared() is not going to see the + // vector being full in the few subsequent loop iterations. + // So we get better branch prediction. + let mut vector = match iterator.next() { + None => return Vec::new(), + Some(element) => { + let (lower, _) = iterator.size_hint(); + let mut vector = Vec::with_capacity(lower.saturating_add(1)); + unsafe { + ptr::write(vector.as_mut_ptr(), element); + vector.set_len(1); + } + vector + } + }; + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs + as SpecExtend>::spec_extend(&mut vector, iterator); + vector + } +} + +impl SpecFromIterNested for Vec + where + I: TrustedLen, +{ + fn from_iter(iterator: I) -> Self { + let mut vector = match iterator.size_hint() { + (_, Some(upper)) => Vec::with_capacity(upper), + _ => Vec::new(), + }; + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs + vector.spec_extend(iterator); + vector + } +} From d24a27797df96bb1dbc886f0997138965c5d7b50 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 01:37:10 +0000 Subject: [PATCH 20/35] refactor: moving SpecFromIter into spec_from_iter.rs --- library/alloc/src/vec/mod.rs | 96 +----------------------- library/alloc/src/vec/spec_from_iter.rs | 98 +++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 92 deletions(-) create mode 100644 library/alloc/src/vec/spec_from_iter.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 438246ab4cb31..dfb837d54f5f7 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -121,6 +121,10 @@ use self::spec_from_iter_nested::SpecFromIterNested; mod spec_from_iter_nested; +use self::spec_from_iter::SpecFromIter; + +mod spec_from_iter; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -2156,98 +2160,6 @@ impl Extend for Vec { } } -/// Specialization trait used for Vec::from_iter -/// -/// ## The delegation graph: -/// -/// ```text -/// +-------------+ -/// |FromIterator | -/// +-+-----------+ -/// | -/// v -/// +-+-------------------------------+ +---------------------+ -/// |SpecFromIter +---->+SpecFromIterNested | -/// |where I: | | |where I: | -/// | Iterator (default)----------+ | | Iterator (default) | -/// | vec::IntoIter | | | TrustedLen | -/// | SourceIterMarker---fallback-+ | | | -/// | slice::Iter | | | -/// | Iterator | +---------------------+ -/// +---------------------------------+ -/// ``` -trait SpecFromIter { - fn from_iter(iter: I) -> Self; -} - -impl SpecFromIter for Vec -where - I: Iterator, -{ - default fn from_iter(iterator: I) -> Self { - SpecFromIterNested::from_iter(iterator) - } -} - -impl SpecFromIter> for Vec { - fn from_iter(iterator: IntoIter) -> Self { - // A common case is passing a vector into a function which immediately - // re-collects into a vector. We can short circuit this if the IntoIter - // has not been advanced at all. - // When it has been advanced We can also reuse the memory and move the data to the front. - // But we only do so when the resulting Vec wouldn't have more unused capacity - // than creating it through the generic FromIterator implementation would. That limitation - // is not strictly necessary as Vec's allocation behavior is intentionally unspecified. - // But it is a conservative choice. - let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr; - if !has_advanced || iterator.len() >= iterator.cap / 2 { - unsafe { - let it = ManuallyDrop::new(iterator); - if has_advanced { - ptr::copy(it.ptr, it.buf.as_ptr(), it.len()); - } - return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap); - } - } - - let mut vec = Vec::new(); - // must delegate to spec_extend() since extend() itself delegates - // to spec_from for empty Vecs - vec.spec_extend(iterator); - vec - } -} - -impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec -where - I: Iterator, - T: Clone, -{ - default fn from_iter(iterator: I) -> Self { - SpecFromIter::from_iter(iterator.cloned()) - } -} - -// This utilizes `iterator.as_slice().to_vec()` since spec_extend -// must take more steps to reason about the final capacity + length -// and thus do more work. `to_vec()` directly allocates the correct amount -// and fills it exactly. -impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec { - #[cfg(not(test))] - fn from_iter(iterator: slice::Iter<'a, T>) -> Self { - iterator.as_slice().to_vec() - } - - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is - // required for this method definition, is not available. Instead use the - // `slice::to_vec` function which is only available with cfg(test) - // NB see the slice::hack module in slice.rs for more information - #[cfg(test)] - fn from_iter(iterator: slice::Iter<'a, T>) -> Self { - crate::slice::to_vec(iterator.as_slice(), Global) - } -} - // Specialization trait used for Vec::extend trait SpecExtend { fn spec_extend(&mut self, iter: I); diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs new file mode 100644 index 0000000000000..bf07fc97f8943 --- /dev/null +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -0,0 +1,98 @@ +use crate::alloc::Global; +use core::mem::{ManuallyDrop}; +use core::ptr::{self}; +use core::slice::{self}; + +use super::{Vec, IntoIter, SpecFromIterNested, SpecExtend}; + +/// Specialization trait used for Vec::from_iter +/// +/// ## The delegation graph: +/// +/// ```text +/// +-------------+ +/// |FromIterator | +/// +-+-----------+ +/// | +/// v +/// +-+-------------------------------+ +---------------------+ +/// |SpecFromIter +---->+SpecFromIterNested | +/// |where I: | | |where I: | +/// | Iterator (default)----------+ | | Iterator (default) | +/// | vec::IntoIter | | | TrustedLen | +/// | SourceIterMarker---fallback-+ | | | +/// | slice::Iter | | | +/// | Iterator | +---------------------+ +/// +---------------------------------+ +/// ``` +pub(super) trait SpecFromIter { + fn from_iter(iter: I) -> Self; +} + +impl SpecFromIter for Vec + where + I: Iterator, +{ + default fn from_iter(iterator: I) -> Self { + SpecFromIterNested::from_iter(iterator) + } +} + +impl SpecFromIter> for Vec { + fn from_iter(iterator: IntoIter) -> Self { + // A common case is passing a vector into a function which immediately + // re-collects into a vector. We can short circuit this if the IntoIter + // has not been advanced at all. + // When it has been advanced We can also reuse the memory and move the data to the front. + // But we only do so when the resulting Vec wouldn't have more unused capacity + // than creating it through the generic FromIterator implementation would. That limitation + // is not strictly necessary as Vec's allocation behavior is intentionally unspecified. + // But it is a conservative choice. + let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr; + if !has_advanced || iterator.len() >= iterator.cap / 2 { + unsafe { + let it = ManuallyDrop::new(iterator); + if has_advanced { + ptr::copy(it.ptr, it.buf.as_ptr(), it.len()); + } + return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap); + } + } + + let mut vec = Vec::new(); + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs + vec.spec_extend(iterator); + vec + } +} + +impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec + where + I: Iterator, + T: Clone, +{ + default fn from_iter(iterator: I) -> Self { + SpecFromIter::from_iter(iterator.cloned()) + } +} + +// This utilizes `iterator.as_slice().to_vec()` since spec_extend +// must take more steps to reason about the final capacity + length +// and thus do more work. `to_vec()` directly allocates the correct amount +// and fills it exactly. +impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec { + #[cfg(not(test))] + fn from_iter(iterator: slice::Iter<'a, T>) -> Self { + iterator.as_slice().to_vec() + } + + // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is + // required for this method definition, is not available. Instead use the + // `slice::to_vec` function which is only available with cfg(test) + // NB see the slice::hack module in slice.rs for more information + #[cfg(test)] + fn from_iter(iterator: slice::Iter<'a, T>) -> Self { + crate::slice::to_vec(iterator.as_slice(), Global) + } +} From bd49a60f2943c313adae8582f266b875c9b7eaa9 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 01:41:44 +0000 Subject: [PATCH 21/35] refactor: moved SpecExtend into spec_extend.rs --- library/alloc/src/vec/mod.rs | 84 ++-------------------------- library/alloc/src/vec/spec_extend.rs | 82 +++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 79 deletions(-) create mode 100644 library/alloc/src/vec/spec_extend.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index dfb837d54f5f7..32470941755a7 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -59,9 +59,7 @@ use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::{arith_offset, assume}; -use core::iter::{ - FromIterator, TrustedLen, -}; +use core::iter::{FromIterator}; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; @@ -125,6 +123,10 @@ use self::spec_from_iter::SpecFromIter; mod spec_from_iter; +use self::spec_extend::SpecExtend; + +mod spec_extend; + /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples @@ -2160,82 +2162,6 @@ impl Extend for Vec { } } -// Specialization trait used for Vec::extend -trait SpecExtend { - fn spec_extend(&mut self, iter: I); -} - -impl SpecExtend for Vec -where - I: Iterator, -{ - default fn spec_extend(&mut self, iter: I) { - self.extend_desugared(iter) - } -} - -impl SpecExtend for Vec -where - I: TrustedLen, -{ - default fn spec_extend(&mut self, iterator: I) { - // This is the case for a TrustedLen iterator. - let (low, high) = iterator.size_hint(); - if let Some(high_value) = high { - debug_assert_eq!( - low, - high_value, - "TrustedLen iterator's size hint is not exact: {:?}", - (low, high) - ); - } - if let Some(additional) = high { - self.reserve(additional); - unsafe { - let mut ptr = self.as_mut_ptr().add(self.len()); - let mut local_len = SetLenOnDrop::new(&mut self.len); - iterator.for_each(move |element| { - ptr::write(ptr, element); - ptr = ptr.offset(1); - // NB can't overflow since we would have had to alloc the address space - local_len.increment_len(1); - }); - } - } else { - self.extend_desugared(iterator) - } - } -} - -impl SpecExtend> for Vec { - fn spec_extend(&mut self, mut iterator: IntoIter) { - unsafe { - self.append_elements(iterator.as_slice() as _); - } - iterator.ptr = iterator.end; - } -} - -impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec -where - I: Iterator, - T: Clone, -{ - default fn spec_extend(&mut self, iterator: I) { - self.spec_extend(iterator.cloned()) - } -} - -impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec -where - T: Copy, -{ - fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { - let slice = iterator.as_slice(); - unsafe { self.append_elements(slice) }; - } -} - impl Vec { // leaf method to which various SpecFrom/SpecExtend implementations delegate when // they have no further optimizations to apply diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs new file mode 100644 index 0000000000000..6959733d0744a --- /dev/null +++ b/library/alloc/src/vec/spec_extend.rs @@ -0,0 +1,82 @@ +use crate::alloc::{Allocator}; +use core::iter::{TrustedLen}; +use core::slice::{self}; +use core::ptr::{self}; + +use super::{Vec, IntoIter, SetLenOnDrop}; + +// Specialization trait used for Vec::extend +pub(super) trait SpecExtend { + fn spec_extend(&mut self, iter: I); +} + +impl SpecExtend for Vec + where + I: Iterator, +{ + default fn spec_extend(&mut self, iter: I) { + self.extend_desugared(iter) + } +} + +impl SpecExtend for Vec + where + I: TrustedLen, +{ + default fn spec_extend(&mut self, iterator: I) { + // This is the case for a TrustedLen iterator. + let (low, high) = iterator.size_hint(); + if let Some(high_value) = high { + debug_assert_eq!( + low, + high_value, + "TrustedLen iterator's size hint is not exact: {:?}", + (low, high) + ); + } + if let Some(additional) = high { + self.reserve(additional); + unsafe { + let mut ptr = self.as_mut_ptr().add(self.len()); + let mut local_len = SetLenOnDrop::new(&mut self.len); + iterator.for_each(move |element| { + ptr::write(ptr, element); + ptr = ptr.offset(1); + // NB can't overflow since we would have had to alloc the address space + local_len.increment_len(1); + }); + } + } else { + self.extend_desugared(iterator) + } + } +} + +impl SpecExtend> for Vec { + fn spec_extend(&mut self, mut iterator: IntoIter) { + unsafe { + self.append_elements(iterator.as_slice() as _); + } + iterator.ptr = iterator.end; + } +} + +impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec + where + I: Iterator, + T: Clone, +{ + default fn spec_extend(&mut self, iterator: I) { + self.spec_extend(iterator.cloned()) + } +} + +impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec + where + T: Copy, +{ + fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { + let slice = iterator.as_slice(); + unsafe { self.append_elements(slice) }; + } +} From 6002b280f119a12631da0d1bb7e6adad53cefc95 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 01:42:29 +0000 Subject: [PATCH 22/35] refactor: removing // ignore-tidy-filelength --- library/alloc/src/vec/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 32470941755a7..2947c6a299f4a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1,4 +1,3 @@ -// ignore-tidy-filelength //! A contiguous growable array type with heap-allocated contents, written //! `Vec`. //! From 2de8356f60a7a9800809ab60e813fcfd4a7accf2 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 01:44:07 +0000 Subject: [PATCH 23/35] style: applying Rust style --- library/alloc/src/vec/cow.rs | 10 +++---- library/alloc/src/vec/drain.rs | 8 +++--- library/alloc/src/vec/drain_filter.rs | 26 +++++++++---------- library/alloc/src/vec/in_place_drop.rs | 6 ++--- library/alloc/src/vec/into_iter.rs | 16 +++++------- library/alloc/src/vec/is_zero.rs | 2 +- library/alloc/src/vec/mod.rs | 4 +-- library/alloc/src/vec/partial_eq.rs | 4 +-- library/alloc/src/vec/source_iter_marker.rs | 16 +++++------- library/alloc/src/vec/spec_extend.rs | 26 +++++++++---------- library/alloc/src/vec/spec_from_elem.rs | 6 ++--- library/alloc/src/vec/spec_from_iter.rs | 14 +++++----- .../alloc/src/vec/spec_from_iter_nested.rs | 12 ++++----- library/alloc/src/vec/splice.rs | 4 +-- 14 files changed, 74 insertions(+), 80 deletions(-) diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 15942f9892d1c..73d15d3064789 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -1,7 +1,7 @@ use crate::borrow::Cow; -use core::iter::{FromIterator}; +use core::iter::FromIterator; -use super::{Vec}; +use super::Vec; #[stable(feature = "cow_from_vec", since = "1.8.0")] impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { @@ -26,10 +26,10 @@ impl<'a, T: Clone> From<&'a Vec> for Cow<'a, [T]> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> FromIterator for Cow<'a, [T]> - where - T: Clone, +where + T: Clone, { fn from_iter>(it: I) -> Cow<'a, [T]> { Cow::Owned(FromIterator::from_iter(it)) } -} \ No newline at end of file +} diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs index e61f17a1c3018..fb32d144f872c 100644 --- a/library/alloc/src/vec/drain.rs +++ b/library/alloc/src/vec/drain.rs @@ -1,13 +1,11 @@ use crate::alloc::{Allocator, Global}; -use core::iter::{ - FusedIterator, TrustedLen, -}; +use core::fmt; +use core::iter::{FusedIterator, TrustedLen}; use core::mem::{self}; use core::ptr::{self, NonNull}; use core::slice::{self}; -use core::fmt; -use super::{Vec}; +use super::Vec; /// A draining iterator for `Vec`. /// diff --git a/library/alloc/src/vec/drain_filter.rs b/library/alloc/src/vec/drain_filter.rs index 9d898c7c756c2..3c37c92ae44b0 100644 --- a/library/alloc/src/vec/drain_filter.rs +++ b/library/alloc/src/vec/drain_filter.rs @@ -1,8 +1,8 @@ +use crate::alloc::{Allocator, Global}; use core::ptr::{self}; use core::slice::{self}; -use crate::alloc::{Allocator, Global}; -use super::{Vec}; +use super::Vec; /// An iterator which uses a closure to determine if an element should be removed. /// @@ -45,8 +45,8 @@ pub struct DrainFilter< } impl DrainFilter<'_, T, F, A> - where - F: FnMut(&mut T) -> bool, +where + F: FnMut(&mut T) -> bool, { /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] @@ -58,8 +58,8 @@ impl DrainFilter<'_, T, F, A> #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] impl Iterator for DrainFilter<'_, T, F, A> - where - F: FnMut(&mut T) -> bool, +where + F: FnMut(&mut T) -> bool, { type Item = T; @@ -96,20 +96,20 @@ impl Iterator for DrainFilter<'_, T, F, A> #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] impl Drop for DrainFilter<'_, T, F, A> - where - F: FnMut(&mut T) -> bool, +where + F: FnMut(&mut T) -> bool, { fn drop(&mut self) { struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator> - where - F: FnMut(&mut T) -> bool, + where + F: FnMut(&mut T) -> bool, { drain: &'b mut DrainFilter<'a, T, F, A>, } impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A> - where - F: FnMut(&mut T) -> bool, + where + F: FnMut(&mut T) -> bool, { fn drop(&mut self) { unsafe { @@ -140,4 +140,4 @@ impl Drop for DrainFilter<'_, T, F, A> backshift.drain.for_each(drop); } } -} \ No newline at end of file +} diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs index 3a0ecc529c006..354d25c2389fb 100644 --- a/library/alloc/src/vec/in_place_drop.rs +++ b/library/alloc/src/vec/in_place_drop.rs @@ -3,9 +3,9 @@ use core::slice::{self}; // A helper struct for in-place iteration that drops the destination slice of iteration, // i.e. the head. The source slice (the tail) is dropped by IntoIter. -pub (super) struct InPlaceDrop { - pub (super) inner: *mut T, - pub (super) dst: *mut T, +pub(super) struct InPlaceDrop { + pub(super) inner: *mut T, + pub(super) dst: *mut T, } impl InPlaceDrop { diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index c4330df4ad95b..1788690d96b8f 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -1,14 +1,12 @@ use crate::alloc::{Allocator, Global}; use crate::raw_vec::RawVec; +use core::fmt; +use core::intrinsics::arith_offset; +use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess}; use core::marker::PhantomData; -use core::intrinsics::{arith_offset}; use core::mem::{self}; -use core::fmt; use core::ptr::{self, NonNull}; use core::slice::{self}; -use core::iter::{ - FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess, -}; /// An iterator that moves out of a vector. /// @@ -156,8 +154,8 @@ impl Iterator for IntoIter { } unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item - where - Self: TrustedRandomAccess, + where + Self: TrustedRandomAccess, { // SAFETY: the caller must guarantee that `i` is in bounds of the // `Vec`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)` @@ -211,8 +209,8 @@ unsafe impl TrustedLen for IntoIter {} // T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr // and thus we can't implement drop-handling unsafe impl TrustedRandomAccess for IntoIter - where - T: Copy, +where + T: Copy, { fn may_have_side_effect() -> bool { false diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index 961f6ca171b11..b5739970b6ea4 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -68,4 +68,4 @@ unsafe impl IsZero for Option> { fn is_zero(&self) -> bool { self.is_none() } -} \ No newline at end of file +} diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 2947c6a299f4a..2a83eb33fe3ec 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -58,7 +58,7 @@ use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::{arith_offset, assume}; -use core::iter::{FromIterator}; +use core::iter::FromIterator; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; @@ -88,9 +88,9 @@ mod drain; mod cow; +pub(crate) use self::into_iter::AsIntoIter; #[stable(feature = "rust1", since = "1.0.0")] pub use self::into_iter::IntoIter; -pub (crate) use self::into_iter::AsIntoIter; mod into_iter; diff --git a/library/alloc/src/vec/partial_eq.rs b/library/alloc/src/vec/partial_eq.rs index 617f04044399e..ff90b6caf4601 100644 --- a/library/alloc/src/vec/partial_eq.rs +++ b/library/alloc/src/vec/partial_eq.rs @@ -1,7 +1,7 @@ -use crate::alloc::{Allocator}; +use crate::alloc::Allocator; use crate::borrow::Cow; -use super::{Vec}; +use super::Vec; macro_rules! __impl_slice_eq1 { ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => { diff --git a/library/alloc/src/vec/source_iter_marker.rs b/library/alloc/src/vec/source_iter_marker.rs index eb3ae01a47e9b..8c0e95559fa15 100644 --- a/library/alloc/src/vec/source_iter_marker.rs +++ b/library/alloc/src/vec/source_iter_marker.rs @@ -1,10 +1,8 @@ -use core::iter::{ - InPlaceIterable, SourceIter, -}; +use core::iter::{InPlaceIterable, SourceIter}; use core::mem::{self, ManuallyDrop}; use core::ptr::{self}; -use super::{Vec, InPlaceDrop, AsIntoIter, SpecFromIter, SpecFromIterNested}; +use super::{AsIntoIter, InPlaceDrop, SpecFromIter, SpecFromIterNested, Vec}; /// Specialization marker for collecting an iterator pipeline into a Vec while reusing the /// source allocation, i.e. executing the pipeline in place. @@ -13,7 +11,7 @@ use super::{Vec, InPlaceDrop, AsIntoIter, SpecFromIter, SpecFromIterNested}; /// which is to be reused. But it is not sufficient for the specialization to be valid. See /// additional bounds on the impl. #[rustc_unsafe_specialization_marker] -pub (super) trait SourceIterMarker: SourceIter {} +pub(super) trait SourceIterMarker: SourceIter {} // The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of // Adapter>> (all owned by core/std). Additional bounds @@ -24,8 +22,8 @@ pub (super) trait SourceIterMarker: SourceIter {} impl SourceIterMarker for T where T: SourceIter + InPlaceIterable {} impl SpecFromIter for Vec - where - I: Iterator + SourceIterMarker, +where + I: Iterator + SourceIterMarker, { default fn from_iter(mut iterator: I) -> Self { // Additional requirements which cannot expressed via trait bounds. We rely on const eval @@ -35,9 +33,9 @@ impl SpecFromIter for Vec // c) alignments match as required by Alloc contract if mem::size_of::() == 0 || mem::size_of::() - != mem::size_of::<<::Source as AsIntoIter>::Item>() + != mem::size_of::<<::Source as AsIntoIter>::Item>() || mem::align_of::() - != mem::align_of::<<::Source as AsIntoIter>::Item>() + != mem::align_of::<<::Source as AsIntoIter>::Item>() { // fallback to more generic implementations return SpecFromIterNested::from_iter(iterator); diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index 6959733d0744a..b6186a7ebaf73 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -1,9 +1,9 @@ -use crate::alloc::{Allocator}; -use core::iter::{TrustedLen}; -use core::slice::{self}; +use crate::alloc::Allocator; +use core::iter::TrustedLen; use core::ptr::{self}; +use core::slice::{self}; -use super::{Vec, IntoIter, SetLenOnDrop}; +use super::{IntoIter, SetLenOnDrop, Vec}; // Specialization trait used for Vec::extend pub(super) trait SpecExtend { @@ -11,8 +11,8 @@ pub(super) trait SpecExtend { } impl SpecExtend for Vec - where - I: Iterator, +where + I: Iterator, { default fn spec_extend(&mut self, iter: I) { self.extend_desugared(iter) @@ -20,8 +20,8 @@ impl SpecExtend for Vec } impl SpecExtend for Vec - where - I: TrustedLen, +where + I: TrustedLen, { default fn spec_extend(&mut self, iterator: I) { // This is the case for a TrustedLen iterator. @@ -62,9 +62,9 @@ impl SpecExtend> for Vec { } impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec - where - I: Iterator, - T: Clone, +where + I: Iterator, + T: Clone, { default fn spec_extend(&mut self, iterator: I) { self.spec_extend(iterator.cloned()) @@ -72,8 +72,8 @@ impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec } impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec - where - T: Copy, +where + T: Copy, { fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { let slice = iterator.as_slice(); diff --git a/library/alloc/src/vec/spec_from_elem.rs b/library/alloc/src/vec/spec_from_elem.rs index ef89054ea1320..de610174783c4 100644 --- a/library/alloc/src/vec/spec_from_elem.rs +++ b/library/alloc/src/vec/spec_from_elem.rs @@ -1,8 +1,8 @@ -use crate::alloc::{Allocator}; +use crate::alloc::Allocator; use crate::raw_vec::RawVec; use core::ptr::{self}; -use super::{Vec, IsZero, ExtendElement}; +use super::{ExtendElement, IsZero, Vec}; // Specialization trait used for Vec::from_elem pub(super) trait SpecFromElem: Sized { @@ -57,4 +57,4 @@ impl SpecFromElem for T { v.extend_with(n, ExtendElement(elem)); v } -} \ No newline at end of file +} diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index bf07fc97f8943..4349d1582102d 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -1,9 +1,9 @@ use crate::alloc::Global; -use core::mem::{ManuallyDrop}; +use core::mem::ManuallyDrop; use core::ptr::{self}; use core::slice::{self}; -use super::{Vec, IntoIter, SpecFromIterNested, SpecExtend}; +use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec}; /// Specialization trait used for Vec::from_iter /// @@ -30,8 +30,8 @@ pub(super) trait SpecFromIter { } impl SpecFromIter for Vec - where - I: Iterator, +where + I: Iterator, { default fn from_iter(iterator: I) -> Self { SpecFromIterNested::from_iter(iterator) @@ -68,9 +68,9 @@ impl SpecFromIter> for Vec { } impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec - where - I: Iterator, - T: Clone, +where + I: Iterator, + T: Clone, { default fn from_iter(iterator: I) -> Self { SpecFromIter::from_iter(iterator.cloned()) diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs index 0da42844c96ce..6abd4ff2a3f0a 100644 --- a/library/alloc/src/vec/spec_from_iter_nested.rs +++ b/library/alloc/src/vec/spec_from_iter_nested.rs @@ -1,7 +1,7 @@ +use core::iter::TrustedLen; use core::ptr::{self}; -use core::iter::{TrustedLen}; -use super::{Vec, SpecExtend}; +use super::{SpecExtend, Vec}; /// Another specialization trait for Vec::from_iter /// necessary to manually prioritize overlapping specializations @@ -11,8 +11,8 @@ pub(super) trait SpecFromIterNested { } impl SpecFromIterNested for Vec - where - I: Iterator, +where + I: Iterator, { default fn from_iter(mut iterator: I) -> Self { // Unroll the first iteration, as the vector is going to be @@ -40,8 +40,8 @@ impl SpecFromIterNested for Vec } impl SpecFromIterNested for Vec - where - I: TrustedLen, +where + I: TrustedLen, { fn from_iter(iterator: I) -> Self { let mut vector = match iterator.size_hint() { diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs index 86b2fa0968ef2..0a27b5b62ecf5 100644 --- a/library/alloc/src/vec/splice.rs +++ b/library/alloc/src/vec/splice.rs @@ -2,7 +2,7 @@ use crate::alloc::{Allocator, Global}; use core::ptr::{self}; use core::slice::{self}; -use super::{Vec, Drain}; +use super::{Drain, Vec}; /// A splicing iterator for `Vec`. /// @@ -130,4 +130,4 @@ impl Drain<'_, T, A> { } self.tail_start = new_tail_start; } -} \ No newline at end of file +} From 80f10d7aa7b3e3bf9a47de6ef2a9f4439d993c48 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 13:27:03 +0000 Subject: [PATCH 24/35] fix: moved import into #[cfg(test)] --- library/alloc/src/vec/spec_from_iter.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index 4349d1582102d..bbfcc68daeff4 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -1,4 +1,3 @@ -use crate::alloc::Global; use core::mem::ManuallyDrop; use core::ptr::{self}; use core::slice::{self}; @@ -93,6 +92,6 @@ impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec { // NB see the slice::hack module in slice.rs for more information #[cfg(test)] fn from_iter(iterator: slice::Iter<'a, T>) -> Self { - crate::slice::to_vec(iterator.as_slice(), Global) + crate::slice::to_vec(iterator.as_slice(), crate::alloc::Global) } } From f7a6f0cae3f6850ad84b8fa6ba6b9f06ae94c27d Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 13:47:27 +0000 Subject: [PATCH 25/35] docs: fixing references --- library/alloc/src/vec/into_iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 1788690d96b8f..99ecec648ad95 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -10,7 +10,7 @@ use core::slice::{self}; /// An iterator that moves out of a vector. /// -/// This `struct` is created by the `into_iter` method on [`Vec`] (provided +/// This `struct` is created by the `into_iter` method on [`super::Vec`] (provided /// by the [`IntoIterator`] trait). /// /// # Example From 206b2ca61ee467d65f674ab83d13a57fe15c7252 Mon Sep 17 00:00:00 2001 From: C Date: Sat, 5 Dec 2020 14:21:50 +0000 Subject: [PATCH 26/35] test: updated expected Vec src path --- src/test/ui/associated-types/defaults-wf.stderr | 2 +- src/test/ui/bad/bad-sized.stderr | 2 +- src/test/ui/issues/issue-20433.stderr | 2 +- src/test/ui/lint/lint-const-item-mutation.stderr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/associated-types/defaults-wf.stderr b/src/test/ui/associated-types/defaults-wf.stderr index 4c43e6a182dc9..d4fa5be742ff3 100644 --- a/src/test/ui/associated-types/defaults-wf.stderr +++ b/src/test/ui/associated-types/defaults-wf.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | type Ty = Vec<[u8]>; | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - ::: $SRC_DIR/alloc/src/vec.rs:LL:COL + ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL | LL | pub struct Vec { | - required by this bound in `Vec` diff --git a/src/test/ui/bad/bad-sized.stderr b/src/test/ui/bad/bad-sized.stderr index 60a5bb9f78666..260d78b543a4c 100644 --- a/src/test/ui/bad/bad-sized.stderr +++ b/src/test/ui/bad/bad-sized.stderr @@ -15,7 +15,7 @@ error[E0277]: the size for values of type `dyn Trait` cannot be known at compila LL | let x: Vec = Vec::new(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - ::: $SRC_DIR/alloc/src/vec.rs:LL:COL + ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL | LL | pub struct Vec { | - required by this bound in `Vec` diff --git a/src/test/ui/issues/issue-20433.stderr b/src/test/ui/issues/issue-20433.stderr index 3f7226c79bf2a..5fed02164b5b7 100644 --- a/src/test/ui/issues/issue-20433.stderr +++ b/src/test/ui/issues/issue-20433.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation LL | fn iceman(c: Vec<[i32]>) {} | ^^^^^^^^^^ doesn't have a size known at compile-time | - ::: $SRC_DIR/alloc/src/vec.rs:LL:COL + ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL | LL | pub struct Vec { | - required by this bound in `Vec` diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr index 74505eeb987c6..3973af540c81f 100644 --- a/src/test/ui/lint/lint-const-item-mutation.stderr +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -107,7 +107,7 @@ LL | VEC.push(0); = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: mutable reference created due to call to this method - --> $SRC_DIR/alloc/src/vec.rs:LL:COL + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL | LL | / pub fn push(&mut self, value: T) { LL | | // This will panic or abort if we would allocate > isize::MAX bytes From 51cec58040780975903e42fee6d30427b3f2cd15 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Dec 2020 16:32:38 +0100 Subject: [PATCH 27/35] fix a comment --- compiler/rustc_mir/src/transform/promote_consts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 71a1d57fec33e..ea92e23e9bffb 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -687,7 +687,7 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_place(place_simplified)?; // Check that the reference is fine (using the original place!). - // (Needs to come after `validate_local` to avoid ICEs.) + // (Needs to come after `validate_place` to avoid ICEs.) self.validate_ref(*kind, place)?; } From 81685e9ad8f80634f0dfd7c1afcab74ba1c78a59 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Tue, 29 Dec 2020 15:42:41 -0500 Subject: [PATCH 28/35] Do not create dangling &T in Weak::drop --- library/alloc/src/rc.rs | 2 +- library/alloc/src/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 73d12f0a5f45d..57df28a15c85a 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2042,7 +2042,7 @@ impl Drop for Weak { // the strong pointers have disappeared. if inner.weak() == 0 { unsafe { - Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); } } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 7c03345aba507..85c0a9f085729 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1927,7 +1927,7 @@ impl Drop for Weak { if inner.weak.fetch_sub(1, Release) == 1 { acquire!(inner.weak); - unsafe { Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } + unsafe { Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())) } } } } From 95aed7ab3b38f908d357ee5e433946639fff6b03 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Dec 2020 22:46:17 +0100 Subject: [PATCH 29/35] Miri: make size/align_of_val work for dangling raw ptrs --- compiler/rustc_mir/src/interpret/intrinsics.rs | 6 ++++-- compiler/rustc_mir/src/interpret/validity.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 474e1f8e577f8..03f3bd3494936 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -141,9 +141,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } sym::min_align_of_val | sym::size_of_val => { - let place = self.deref_operand(args[0])?; + // Avoid `deref_operand` -- this is not a deref, the ptr does not have to be + // dereferencable! + let place = self.ref_to_mplace(self.read_immediate(args[0])?)?; let (size, align) = self - .size_and_align_of(place.meta, place.layout)? + .size_and_align_of_mplace(place)? .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?; let result = match intrinsic_name { diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 57aec0953b8c2..aff80dddfdfe6 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -391,7 +391,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' } // Make sure this is dereferenceable and all. let size_and_align = try_validation!( - self.ecx.size_and_align_of(place.meta, place.layout), + self.ecx.size_and_align_of_mplace(place), self.path, err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg }, ); From f76bae924438fbf4a885fd8827d43499ab5d1f68 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Dec 2020 14:29:33 +0100 Subject: [PATCH 30/35] CTFE: test size/align_of_val_raw on dangling pointers --- library/core/src/mem/mod.rs | 6 ++++-- src/test/ui/consts/const-size_of_val-align_of_val.rs | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index e84014c68a676..70c3fded692d9 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -374,7 +374,8 @@ pub const fn size_of_val(val: &T) -> usize { /// ``` #[inline] #[unstable(feature = "layout_for_ptr", issue = "69835")] -pub unsafe fn size_of_val_raw(val: *const T) -> usize { +#[rustc_const_unstable(feature = "const_size_of_val_raw", issue = "46571")] +pub const unsafe fn size_of_val_raw(val: *const T) -> usize { intrinsics::size_of_val(val) } @@ -505,7 +506,8 @@ pub const fn align_of_val(val: &T) -> usize { /// ``` #[inline] #[unstable(feature = "layout_for_ptr", issue = "69835")] -pub unsafe fn align_of_val_raw(val: *const T) -> usize { +#[rustc_const_unstable(feature = "const_align_of_val_raw", issue = "46571")] +pub const unsafe fn align_of_val_raw(val: *const T) -> usize { intrinsics::min_align_of_val(val) } diff --git a/src/test/ui/consts/const-size_of_val-align_of_val.rs b/src/test/ui/consts/const-size_of_val-align_of_val.rs index e8e6f1d390099..5c0d7d94d64f1 100644 --- a/src/test/ui/consts/const-size_of_val-align_of_val.rs +++ b/src/test/ui/consts/const-size_of_val-align_of_val.rs @@ -1,6 +1,7 @@ // run-pass #![feature(const_size_of_val, const_align_of_val)] +#![feature(const_size_of_val_raw, const_align_of_val_raw, layout_for_ptr)] use std::mem; @@ -32,6 +33,9 @@ const ALIGN_OF_UGH: usize = mem::align_of_val(&UGH); const SIZE_OF_SLICE: usize = mem::size_of_val("foobar".as_bytes()); +const SIZE_OF_DANGLING: usize = unsafe { mem::size_of_val_raw(0x100 as *const i32) }; +const ALIGN_OF_DANGLING: usize = unsafe { mem::align_of_val_raw(0x100 as *const i16) }; + fn main() { assert_eq!(SIZE_OF_FOO, mem::size_of::()); assert_eq!(SIZE_OF_BAR, mem::size_of::()); @@ -41,5 +45,8 @@ fn main() { assert_eq!(ALIGN_OF_BAR, mem::align_of::()); assert_eq!(ALIGN_OF_UGH, mem::align_of::()); + assert_eq!(SIZE_OF_DANGLING, mem::size_of::()); + assert_eq!(ALIGN_OF_DANGLING, mem::align_of::()); + assert_eq!(SIZE_OF_SLICE, "foobar".len()); } From edeac1778cbab28bb1d141e90e7ae6dc2eb97e60 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 29 Dec 2020 20:28:08 -0500 Subject: [PATCH 31/35] Rename kw::Invalid -> kw::Empty See https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Is.20there.20a.20symbol.20for.20the.20empty.20string.3F/near/220054471 for context. --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_builtin_macros/src/llvm_asm.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 4 ++-- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_lint/src/context.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 10 +++++----- compiler/rustc_mir_build/src/build/mod.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 6 +++--- compiler/rustc_passes/src/liveness.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_resolve/src/build_reduced_graph.rs | 6 +++--- compiler/rustc_resolve/src/def_collector.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 6 +++--- compiler/rustc_resolve/src/macros.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 4 ++-- compiler/rustc_span/src/symbol.rs | 8 ++++---- compiler/rustc_typeck/src/check/expr.rs | 4 ++-- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 2 +- src/librustdoc/clean/mod.rs | 4 ++-- src/librustdoc/html/render/mod.rs | 6 +++--- src/tools/clippy/clippy_lints/src/lifetimes.rs | 2 +- 27 files changed, 46 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2e1b5a74a7b7e..9dc6d6c98c753 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1716,7 +1716,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } self.arena.alloc_from_iter(inputs.iter().map(|param| match param.pat.kind { PatKind::Ident(_, ident, _) => ident, - _ => Ident::new(kw::Invalid, param.pat.span), + _ => Ident::new(kw::Empty, param.pat.span), })) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 686300c7c5fec..f9eb69bb43815 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -184,7 +184,7 @@ impl<'a> AstValidator<'a> { } fn check_lifetime(&self, ident: Ident) { - let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid]; + let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names"); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index dcb6e115eda05..333a396a0b4fc 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2787,7 +2787,7 @@ impl<'a> State<'a> { self.print_explicit_self(&eself); } else { let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind { - ident.name == kw::Invalid + ident.name == kw::Empty } else { false }; diff --git a/compiler/rustc_builtin_macros/src/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs index db73fdbe24ff5..5f2b1c34d2b68 100644 --- a/compiler/rustc_builtin_macros/src/llvm_asm.rs +++ b/compiler/rustc_builtin_macros/src/llvm_asm.rs @@ -93,7 +93,7 @@ fn parse_inline_asm<'a>( }) .unwrap_or(tts.len()); let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect()); - let mut asm = kw::Invalid; + let mut asm = kw::Empty; let mut asm_str_style = None; let mut outputs = Vec::new(); let mut inputs = Vec::new(); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index d5b2cbaa55843..f1eae605da018 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -170,7 +170,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // (after #67586 gets fixed). None } else { - let name = kw::Invalid; + let name = kw::Empty; let decl = &self.mir.local_decls[local]; let dbg_var = if full_debug_info { self.adjusted_span_and_dbg_scope(decl.source_info).map( @@ -204,7 +204,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None } else { Some(match whole_local_var.or(fallback_var) { - Some(var) if var.name != kw::Invalid => var.name.to_string(), + Some(var) if var.name != kw::Empty => var.name.to_string(), _ => format!("{:?}", local), }) }; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2abebbd030387..b18d75dc6a30c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -28,7 +28,7 @@ pub struct Lifetime { pub span: Span, /// Either "`'a`", referring to a named lifetime definition, - /// or "``" (i.e., `kw::Invalid`), for elision placeholders. + /// or "``" (i.e., `kw::Empty`), for elision placeholders. /// /// HIR lowering inserts these placeholders in type paths that /// refer to type definitions needing lifetime parameters, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index fa943d0d748a3..a8371274f61f8 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -868,7 +868,7 @@ impl EarlyLintPass for AnonymousParameters { if let ast::AssocItemKind::Fn(_, ref sig, _, _) = it.kind { for arg in sig.decl.inputs.iter() { if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind { - if ident.name == kw::Invalid { + if ident.name == kw::Empty { cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| { let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index bfeef4904893a..ea4f7daec43d1 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -728,7 +728,7 @@ impl<'tcx> LateContext<'tcx> { /// Check if a `DefId`'s path matches the given absolute type path usage. /// - /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; + /// Anonymous scopes such as `extern` imports are matched with `kw::Empty`; /// inherent `impl` blocks are matched with the name of the type. /// /// Instead of using this method, it is often preferable to instead use diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index fe29f9d177f92..744fdc83a91ec 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -132,7 +132,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { impl Collector<'tcx> { fn register_native_lib(&mut self, span: Option, lib: NativeLib) { - if lib.name.as_ref().map(|&s| s == kw::Invalid).unwrap_or(false) { + if lib.name.as_ref().map(|&s| s == kw::Empty).unwrap_or(false) { match span { Some(span) => { struct_span_err!( diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 598e28c1a3ab0..09d5b10210312 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -379,7 +379,7 @@ impl<'hir> Map<'hir> { pub fn body_param_names(&self, id: BodyId) -> impl Iterator + 'hir { self.body(id).params.iter().map(|arg| match arg.pat.kind { PatKind::Binding(_, _, ident, _) => ident, - _ => Ident::new(kw::Invalid, rustc_span::DUMMY_SP), + _ => Ident::new(kw::Empty, rustc_span::DUMMY_SP), }) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 9b178d9d2bd00..893572785f76b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1481,7 +1481,7 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { // FIXME(eddyb) `name` should never be empty, but it // currently is for `extern { ... }` "foreign modules". let name = disambiguated_data.data.name(); - if name != DefPathDataName::Named(kw::Invalid) { + if name != DefPathDataName::Named(kw::Empty) { if !self.empty_path { write!(self, "::")?; } @@ -1608,14 +1608,14 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { match *region { ty::ReEarlyBound(ref data) => { - data.name != kw::Invalid && data.name != kw::UnderscoreLifetime + data.name != kw::Empty && data.name != kw::UnderscoreLifetime } ty::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { - if name != kw::Invalid && name != kw::UnderscoreLifetime { + if name != kw::Empty && name != kw::UnderscoreLifetime { return true; } } @@ -1685,7 +1685,7 @@ impl FmtPrinter<'_, '_, F> { // `explain_region()` or `note_and_explain_region()`. match *region { ty::ReEarlyBound(ref data) => { - if data.name != kw::Invalid { + if data.name != kw::Empty { p!(write("{}", data.name)); return Ok(self); } @@ -1694,7 +1694,7 @@ impl FmtPrinter<'_, '_, F> { | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { - if name != kw::Invalid && name != kw::UnderscoreLifetime { + if name != kw::Empty && name != kw::UnderscoreLifetime { p!(write("{}", name)); return Ok(self); } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e041464381220..996615995259d 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -854,7 +854,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut mutability = Mutability::Not; // FIXME(project-rfc-2229#8): Store more precise information - let mut name = kw::Invalid; + let mut name = kw::Empty; if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) { if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { name = ident.name; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 634cce403df96..c6669f0468296 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -494,7 +494,7 @@ impl<'a> Parser<'a> { let polarity = self.parse_polarity(); // Parse both types and traits as a type, then reinterpret if necessary. - let err_path = |span| ast::Path::from_ident(Ident::new(kw::Invalid, span)); + let err_path = |span| ast::Path::from_ident(Ident::new(kw::Empty, span)); let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt) { let span = self.prev_token.span.between(self.token.span); @@ -1699,7 +1699,7 @@ impl<'a> Parser<'a> { // Skip every token until next possible arg or end. p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); // Create a placeholder argument for proper arg count (issue #34264). - Ok(dummy_arg(Ident::new(kw::Invalid, lo.to(p.prev_token.span)))) + Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)))) }); // ...now that we've parsed the first argument, `self` is no longer allowed. first_param = false; @@ -1759,7 +1759,7 @@ impl<'a> Parser<'a> { } match ty { Ok(ty) => { - let ident = Ident::new(kw::Invalid, self.prev_token.span); + let ident = Ident::new(kw::Empty, self.prev_token.span); let bm = BindingMode::ByValue(Mutability::Not); let pat = self.mk_pat_ident(ty.span, bm, ident); (pat, ty) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 86ce35c6d9909..b6f631300905e 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1385,7 +1385,7 @@ impl<'tcx> Liveness<'_, 'tcx> { fn should_warn(&self, var: Variable) -> Option { let name = self.ir.variable_name(var); - if name == kw::Invalid { + if name == kw::Empty { return None; } let name: &str = &name.as_str(); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 3b4249a93e1fb..b13377bb2b1d5 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -959,7 +959,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { in_update_syntax: bool, ) { // definition of the field - let ident = Ident::new(kw::Invalid, use_ctxt); + let ident = Ident::new(kw::Empty, use_ctxt); let current_hir = self.current_item.unwrap(); let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, current_hir).1; if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 06e9969697d09..6657201aaebdd 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -342,7 +342,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let field_names = vdata .fields() .iter() - .map(|field| respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))) + .map(|field| respan(field.span, field.ident.map_or(kw::Empty, |ident| ident.name))) .collect(); self.insert_field_names(def_id, field_names); } @@ -527,7 +527,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // HACK(eddyb) unclear how good this is, but keeping `$crate` // in `source` breaks `src/test/compile-fail/import-crate-var.rs`, // while the current crate doesn't have a valid `crate_name`. - if crate_name != kw::Invalid { + if crate_name != kw::Empty { // `crate_name` should not be interpreted as relative. module_path.push(Segment { ident: Ident { name: kw::PathRoot, span: source.ident.span }, @@ -656,7 +656,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &'b Item) { - if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Invalid { + if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Empty { // Fake crate root item from expand. return; } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 69773ba1d7221..48bce88439424 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -74,7 +74,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { // information we encapsulate into, the better let def_data = match &i.kind { ItemKind::Impl { .. } => DefPathData::Impl, - ItemKind::Mod(..) if i.ident.name == kw::Invalid => { + ItemKind::Mod(..) if i.ident.name == kw::Empty => { // Fake crate root item from expand. return visit::walk_item(self, i); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b13462587bc61..e45d7223849b9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1641,7 +1641,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } // Record as bound if it's valid: - let ident_valid = ident.name != kw::Invalid; + let ident_valid = ident.name != kw::Empty; if ident_valid { bindings.last_mut().unwrap().1.insert(ident); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5c79cfa9c1dba..c2780b46f6cfb 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1182,12 +1182,12 @@ impl<'a> Resolver<'a> { ) -> Resolver<'a> { let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }; let root_def_id = root_local_def_id.to_def_id(); - let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid); + let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty); let graph_root = arenas.alloc_module(ModuleData { no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude), ..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span) }); - let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid); + let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty); let empty_module = arenas.alloc_module(ModuleData { no_implicit_prelude: true, ..ModuleData::new( @@ -1797,7 +1797,7 @@ impl<'a> Resolver<'a> { ribs: &[Rib<'a>], ) -> Option> { assert!(ns == TypeNS || ns == ValueNS); - if ident.name == kw::Invalid { + if ident.name == kw::Empty { return Some(LexicalScopeBinding::Res(Res::Err)); } let (general_span, normalized_span) = if ident.name == kw::SelfUpper { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c8dbe68512857..5ad7c83ca36af 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -160,7 +160,7 @@ impl<'a> ResolverExpand for Resolver<'a> { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); match self.resolve_crate_root(ident).kind { - ModuleKind::Def(.., name) if name != kw::Invalid => name, + ModuleKind::Def(.., name) if name != kw::Empty => name, _ => kw::Crate, } }); diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 0f82db1d05aa1..fdc0d225bb82d 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1065,7 +1065,7 @@ pub fn decode_syntax_context< parent: SyntaxContext::root(), opaque: SyntaxContext::root(), opaque_and_semitransparent: SyntaxContext::root(), - dollar_crate_name: kw::Invalid, + dollar_crate_name: kw::Empty, }); let mut ctxts = outer_ctxts.lock(); let new_len = raw_id as usize + 1; @@ -1092,7 +1092,7 @@ pub fn decode_syntax_context< ctxt_data, ); // Make sure nothing weird happening while `decode_data` was running - assert_eq!(dummy.dollar_crate_name, kw::Invalid); + assert_eq!(dummy.dollar_crate_name, kw::Empty); }); Ok(new_ctxt) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 99a523c3f3bb4..d324465c895fb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -25,7 +25,7 @@ symbols! { Keywords { // Special reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. - Invalid: "", + Empty: "", PathRoot: "{{root}}", DollarCrate: "$crate", Underscore: "_", @@ -1273,7 +1273,7 @@ impl Ident { #[inline] pub fn invalid() -> Ident { - Ident::with_dummy_span(kw::Invalid) + Ident::with_dummy_span(kw::Empty) } /// Maps a string to an identifier with a dummy span. @@ -1470,7 +1470,7 @@ impl Symbol { } pub fn is_empty(self) -> bool { - self == kw::Invalid + self == kw::Empty } /// This method is supposed to be used in error messages, so it's expected to be @@ -1654,7 +1654,7 @@ impl Symbol { /// Returns `true` if this symbol can be a raw identifier. pub fn can_be_raw(self) -> bool { - self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword() + self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword() } } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index ec0e039b5d29d..93eb2cfc72a80 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -883,7 +883,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(method) } Err(error) => { - if segment.ident.name != kw::Invalid { + if segment.ident.name != kw::Empty { self.report_extended_method_error(segment, span, args, rcvr_t, error); } Err(()) @@ -1547,7 +1547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return field_ty; } - if field.name == kw::Invalid { + if field.name == kw::Empty { } else if self.method_exists(field, expr_t, expr.hir_id, true) { self.ban_take_value_of_method(expr, expr_t, field); } else if !expr_t.is_primitive_ty() { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 41a403a010ee6..2a8b77da44fc4 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -914,7 +914,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), _ => Err(ErrorReported), }; - if item_name.name != kw::Invalid { + if item_name.name != kw::Empty { if let Some(mut e) = self.report_method_error( span, ty, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dd96178cdb700..657b8d3879f8c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -941,7 +941,7 @@ impl<'a> Clean for (&'a [hir::Ty<'a>], &'a [Ident]) { .iter() .enumerate() .map(|(i, ty)| { - let mut name = self.1.get(i).map(|ident| ident.name).unwrap_or(kw::Invalid); + let mut name = self.1.get(i).map(|ident| ident.name).unwrap_or(kw::Empty); if name.is_empty() { name = kw::Underscore; } @@ -1000,7 +1000,7 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { .iter() .map(|t| Argument { type_: t.clean(cx), - name: names.next().map(|i| i.name).unwrap_or(kw::Invalid), + name: names.next().map(|i| i.name).unwrap_or(kw::Empty), }) .collect(), }, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 185df60735fd4..a6ac3bdb714f6 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2086,8 +2086,8 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl (true, false) => return Ordering::Greater, } } - let lhs = i1.name.unwrap_or(kw::Invalid).as_str(); - let rhs = i2.name.unwrap_or(kw::Invalid).as_str(); + let lhs = i1.name.unwrap_or(kw::Empty).as_str(); + let rhs = i2.name.unwrap_or(kw::Empty).as_str(); compare_names(&lhs, &rhs) } @@ -4206,7 +4206,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache: ty: \"{ty}\", \ relpath: \"{path}\"\ }};", - name = it.name.unwrap_or(kw::Invalid), + name = it.name.unwrap_or(kw::Empty), ty = it.type_(), path = relpath ); diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 4d737b3f49b03..e84c8b4e5b3e0 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -501,7 +501,7 @@ impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker { // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { - if lifetime.name.ident().name != kw::Invalid && lifetime.name.ident().name != kw::StaticLifetime { + if lifetime.name.ident().name != kw::Empty && lifetime.name.ident().name != kw::StaticLifetime { self.lifetimes_used_in_body = true; } } From 78498d0d45351c3f9b17c186506d214a8c384368 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 30 Dec 2020 15:59:44 +0100 Subject: [PATCH 32/35] Add regression test for #80062 --- src/test/ui/const-generics/issues/issue-80062.rs | 10 ++++++++++ src/test/ui/const-generics/issues/issue-80062.stderr | 11 +++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-80062.rs create mode 100644 src/test/ui/const-generics/issues/issue-80062.stderr diff --git a/src/test/ui/const-generics/issues/issue-80062.rs b/src/test/ui/const-generics/issues/issue-80062.rs new file mode 100644 index 0000000000000..56dc53298fb35 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-80062.rs @@ -0,0 +1,10 @@ +// Regression test for issue #80062 (fixed by `min_const_generics`) + +fn sof() -> T { unimplemented!() } + +fn test() { + let _: [u8; sof::()]; + //~^ ERROR generic parameters may not be used in const operations +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-80062.stderr b/src/test/ui/const-generics/issues/issue-80062.stderr new file mode 100644 index 0000000000000..aad8907bda2d0 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-80062.stderr @@ -0,0 +1,11 @@ +error: generic parameters may not be used in const operations + --> $DIR/issue-80062.rs:6:23 + | +LL | let _: [u8; sof::()]; + | ^ cannot perform const operation using `T` + | + = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions + +error: aborting due to previous error + From 16834a8f52853be76cf4a96de120042f2a4a96a2 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 30 Dec 2020 15:35:02 +0000 Subject: [PATCH 33/35] Fix rustdoc link in vec/into_iter.rs. --- library/alloc/src/vec/into_iter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 99ecec648ad95..f131d06bb18f9 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -10,8 +10,8 @@ use core::slice::{self}; /// An iterator that moves out of a vector. /// -/// This `struct` is created by the `into_iter` method on [`super::Vec`] (provided -/// by the [`IntoIterator`] trait). +/// This `struct` is created by the `into_iter` method on [`Vec`](super::Vec) +/// (provided by the [`IntoIterator`] trait). /// /// # Example /// From 7786a6b3341862a69a1083ee60edfd89644b57ab Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 21 Aug 2020 21:56:40 +0200 Subject: [PATCH 34/35] Add Iterator::intersperse --- library/core/src/iter/adapters/intersperse.rs | 76 +++++++++++++++++ library/core/src/iter/adapters/mod.rs | 4 + library/core/src/iter/mod.rs | 2 + library/core/src/iter/traits/iterator.rs | 24 +++++- library/core/tests/iter.rs | 82 +++++++++++++++++++ library/core/tests/lib.rs | 1 + src/librustdoc/clean/utils.rs | 1 - src/librustdoc/lib.rs | 1 + 8 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 library/core/src/iter/adapters/intersperse.rs diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs new file mode 100644 index 0000000000000..4656a725a3c61 --- /dev/null +++ b/library/core/src/iter/adapters/intersperse.rs @@ -0,0 +1,76 @@ +use super::Peekable; + +/// An iterator adapter that places a separator between all elements. +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")] +#[derive(Debug, Clone)] +pub struct Intersperse +where + I::Item: Clone, +{ + separator: I::Item, + iter: Peekable, + needs_sep: bool, +} + +impl Intersperse +where + I::Item: Clone, +{ + pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self { + Self { iter: iter.peekable(), separator, needs_sep: false } + } +} + +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")] +impl Iterator for Intersperse +where + I: Iterator, + I::Item: Clone, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.needs_sep && self.iter.peek().is_some() { + self.needs_sep = false; + Some(self.separator.clone()) + } else { + self.needs_sep = true; + self.iter.next() + } + } + + fn fold(mut self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + let mut accum = init; + + // Use `peek()` first to avoid calling `next()` on an empty iterator. + if !self.needs_sep || self.iter.peek().is_some() { + if let Some(x) = self.iter.next() { + accum = f(accum, x); + } + } + + let element = &self.separator; + + self.iter.fold(accum, |mut accum, x| { + accum = f(accum, element.clone()); + accum = f(accum, x); + accum + }) + } + + fn size_hint(&self) -> (usize, Option) { + let (lo, hi) = self.iter.size_hint(); + let next_is_elem = !self.needs_sep; + let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo); + let hi = match hi { + Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi), + None => None, + }; + (lo, hi) + } +} diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index b8d3430f91099..550b7c2959772 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -11,6 +11,7 @@ mod filter_map; mod flatten; mod fuse; mod inspect; +mod intersperse; mod map; mod map_while; mod peekable; @@ -41,6 +42,9 @@ pub use self::flatten::Flatten; #[stable(feature = "iter_copied", since = "1.36.0")] pub use self::copied::Copied; +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")] +pub use self::intersperse::Intersperse; + #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] pub use self::map_while::MapWhile; diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 3e74637b49f1c..e771b2737921b 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -395,6 +395,8 @@ pub use self::adapters::Cloned; pub use self::adapters::Copied; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::adapters::Flatten; +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")] +pub use self::adapters::Intersperse; #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] pub use self::adapters::MapWhile; #[unstable(feature = "inplace_iteration", issue = "none")] diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 7ba16f89284e1..47a49b19dd4bb 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -8,7 +8,7 @@ use crate::ops::{Add, ControlFlow, Try}; use super::super::TrustedRandomAccess; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; -use super::super::{FromIterator, Product, Sum, Zip}; +use super::super::{FromIterator, Intersperse, Product, Sum, Zip}; use super::super::{ Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, }; @@ -569,6 +569,28 @@ pub trait Iterator { Zip::new(self, other.into_iter()) } + /// Places a copy of `separator` between all elements. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_intersperse)] + /// + /// let hello = ["Hello", "World"].iter().copied().intersperse(" ").collect::(); + /// assert_eq!(hello, "Hello World"); + /// ``` + #[inline] + #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")] + fn intersperse(self, separator: Self::Item) -> Intersperse + where + Self: Sized, + Self::Item: Clone, + { + Intersperse::new(self, separator) + } + /// Takes a closure and creates an iterator which calls that closure on each /// element. /// diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index ec4b49da384c3..7376e7848eff5 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -3505,3 +3505,85 @@ pub fn extend_for_unit() { } assert_eq!(x, 5); } + +#[test] +fn test_intersperse() { + let xs = ["a", "", "b", "c"]; + let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect(); + let text: String = v.concat(); + assert_eq!(text, "a, , b, c".to_string()); + + let ys = [0, 1, 2, 3]; + let mut it = ys[..0].iter().map(|x| *x).intersperse(1); + assert!(it.next() == None); +} + +#[test] +fn test_intersperse_size_hint() { + let xs = ["a", "", "b", "c"]; + let mut iter = xs.iter().map(|x| x.clone()).intersperse(", "); + assert_eq!(iter.size_hint(), (7, Some(7))); + + assert_eq!(iter.next(), Some("a")); + assert_eq!(iter.size_hint(), (6, Some(6))); + assert_eq!(iter.next(), Some(", ")); + assert_eq!(iter.size_hint(), (5, Some(5))); + + assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0))); +} + +#[test] +fn test_fold_specialization_intersperse() { + let mut iter = (1..2).intersperse(0); + iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); + + let mut iter = (1..3).intersperse(0); + iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); + + let mut iter = (1..4).intersperse(0); + iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); +} + +#[test] +fn test_try_fold_specialization_intersperse_ok() { + let mut iter = (1..2).intersperse(0); + iter.clone().try_for_each(|x| { + assert_eq!(Some(x), iter.next()); + Some(()) + }); + + let mut iter = (1..3).intersperse(0); + iter.clone().try_for_each(|x| { + assert_eq!(Some(x), iter.next()); + Some(()) + }); + + let mut iter = (1..4).intersperse(0); + iter.clone().try_for_each(|x| { + assert_eq!(Some(x), iter.next()); + Some(()) + }); +} + +#[test] +fn test_try_fold_specialization_intersperse_err() { + let orig_iter = ["a", "b"].iter().copied().intersperse("-"); + + // Abort after the first item. + let mut iter = orig_iter.clone(); + iter.try_for_each(|_| None::<()>); + assert_eq!(iter.next(), Some("-")); + assert_eq!(iter.next(), Some("b")); + assert_eq!(iter.next(), None); + + // Abort after the second item. + let mut iter = orig_iter.clone(); + iter.try_for_each(|item| if item == "-" { None } else { Some(()) }); + assert_eq!(iter.next(), Some("b")); + assert_eq!(iter.next(), None); + + // Abort after the third item. + let mut iter = orig_iter.clone(); + iter.try_for_each(|item| if item == "b" { None } else { Some(()) }); + assert_eq!(iter.next(), None); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 9e8ec7060216b..fba3294e0bbdb 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -51,6 +51,7 @@ #![feature(array_value_iter)] #![feature(iter_advance_by)] #![feature(iter_partition_in_place)] +#![feature(iter_intersperse)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] #![feature(cmp_min_max_by)] diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 2cde0c209ee9b..a6c090c6576ef 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -8,7 +8,6 @@ use crate::clean::{ }; use crate::core::DocContext; -use itertools::Itertools; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e8bf664d45c4d..7ed64c5813fcd 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -17,6 +17,7 @@ #![feature(type_ascription)] #![feature(split_inclusive)] #![feature(str_split_once)] +#![feature(iter_intersperse)] #![recursion_limit = "256"] #[macro_use] From 40bbb7fad4b3ce6b8738ed2d524388b23d58100e Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 28 Nov 2020 15:55:07 -0800 Subject: [PATCH 35/35] Add tracking issue --- library/core/src/iter/adapters/intersperse.rs | 4 ++-- library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/iter/mod.rs | 2 +- library/core/src/iter/traits/iterator.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index 4656a725a3c61..362326725490f 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -1,7 +1,7 @@ use super::Peekable; /// An iterator adapter that places a separator between all elements. -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] #[derive(Debug, Clone)] pub struct Intersperse where @@ -21,7 +21,7 @@ where } } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl Iterator for Intersperse where I: Iterator, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 550b7c2959772..7dfbf32cea7b8 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -42,7 +42,7 @@ pub use self::flatten::Flatten; #[stable(feature = "iter_copied", since = "1.36.0")] pub use self::copied::Copied; -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::intersperse::Intersperse; #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index e771b2737921b..569de719d03d6 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -395,7 +395,7 @@ pub use self::adapters::Cloned; pub use self::adapters::Copied; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::adapters::Flatten; -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::adapters::Intersperse; #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] pub use self::adapters::MapWhile; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 47a49b19dd4bb..633175702d870 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -582,7 +582,7 @@ pub trait Iterator { /// assert_eq!(hello, "Hello World"); /// ``` #[inline] - #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "none")] + #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] fn intersperse(self, separator: Self::Item) -> Intersperse where Self: Sized,