diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index bf8f5b8b91a1e..76b660fba685c 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -395,11 +395,10 @@ impl Clone for Box { #[stable(feature = "box_slice_clone", since = "1.3.0")] impl Clone for Box { fn clone(&self) -> Self { - let len = self.len(); - let buf = RawVec::with_capacity(len); + // this makes a copy of the data + let buf: Box<[u8]> = self.as_bytes().into(); unsafe { - ptr::copy_nonoverlapping(self.as_ptr(), buf.ptr(), len); - from_boxed_utf8_unchecked(buf.into_box()) + from_boxed_utf8_unchecked(buf) } } } @@ -546,9 +545,12 @@ impl From<&[T]> for Box<[T]> { /// println!("{:?}", boxed_slice); /// ``` fn from(slice: &[T]) -> Box<[T]> { - let mut boxed = unsafe { RawVec::with_capacity(slice.len()).into_box() }; - boxed.copy_from_slice(slice); - boxed + let len = slice.len(); + let buf = RawVec::with_capacity(len); + unsafe { + ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len); + buf.into_box() + } } } diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index d1fc5ac3b30d4..0454a56443579 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -685,12 +685,14 @@ impl RawVec { impl RawVec { /// Converts the entire buffer into `Box<[T]>`. /// - /// While it is not *strictly* Undefined Behavior to call - /// this procedure while some of the RawVec is uninitialized, - /// it certainly makes it trivial to trigger it. - /// /// Note that this will correctly reconstitute any `cap` changes /// that may have been performed. (see description of type for details) + /// + /// # Undefined Behavior + /// + /// All elements of `RawVec` must be initialized. Notice that + /// the rules around uninitialized boxed values are not finalized yet, + /// but until they are, it is advisable to avoid them. pub unsafe fn into_box(self) -> Box<[T]> { // NOTE: not calling `cap()` here, actually using the real `cap` field! let slice = slice::from_raw_parts_mut(self.ptr(), self.cap); diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index 3f76ac20192ba..0492fd709b8dc 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -21,7 +21,7 @@ use crate::task::{Context, Poll}; /// task. /// /// When using a future, you generally won't call `poll` directly, but instead -/// `await!` the value. +/// `.await` the value. #[doc(spotlight)] #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 1601357d3b054..6eccb9d1ea86d 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -140,6 +140,11 @@ //! call `next()` on your iterator, until it reaches `None`. Let's go over that //! next. //! +//! Also note that `Iterator` provides a default implementation of methods such as `nth` and `fold` +//! which call `next` internally. However, it is also possible to write a custom implementation of +//! methods like `nth` and `fold` if an iterator can compute them more efficiently without calling +//! `next`. +//! //! # for Loops and IntoIterator //! //! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 38c7c9bc4d086..d0fdd79473e67 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -964,6 +964,7 @@ pub trait Iterator { /// Creates an iterator that skips the first `n` elements. /// /// After they have been consumed, the rest of the elements are yielded. + /// Rather than overriding this method directly, instead override the `nth` method. /// /// # Examples /// diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index d2ee9b11b3640..9dfa09cf8a512 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -445,9 +445,10 @@ macro_rules! writeln { /// * Iterators that dynamically terminate. /// /// If the determination that the code is unreachable proves incorrect, the -/// program immediately terminates with a [`panic!`]. The function [`unreachable_unchecked`], -/// which belongs to the [`std::hint`] module, informs the compiler to -/// optimize the code out of the release version entirely. +/// program immediately terminates with a [`panic!`]. +/// +/// The unsafe counterpart of this macro is the [`unreachable_unchecked`] function, which +/// will cause undefined behavior if the code is reached. /// /// [`panic!`]: ../std/macro.panic.html /// [`unreachable_unchecked`]: ../std/hint/fn.unreachable_unchecked.html diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index a1bfd417566ad..6243e911bd5fd 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -1207,6 +1207,51 @@ fn main() { ``` "##, +E0284: r##" +This error occurs when the compiler is unable to unambiguously infer the +return type of a function or method which is generic on return type, such +as the `collect` method for `Iterator`s. + +For example: + +```compile_fail,E0284 +fn foo() -> Result { + let results = [Ok(true), Ok(false), Err(())].iter().cloned(); + let v: Vec = results.collect()?; + // Do things with v... + Ok(true) +} +``` + +Here we have an iterator `results` over `Result`. +Hence, `results.collect()` can return any type implementing +`FromIterator>`. On the other hand, the +`?` operator can accept any type implementing `Try`. + +The author of this code probably wants `collect()` to return a +`Result, ()>`, but the compiler can't be sure +that there isn't another type `T` implementing both `Try` and +`FromIterator>` in scope such that +`T::Ok == Vec`. Hence, this code is ambiguous and an error +is returned. + +To resolve this error, use a concrete type for the intermediate expression: + +``` +fn foo() -> Result { + let results = [Ok(true), Ok(false), Err(())].iter().cloned(); + let v = { + let temp: Result, ()> = results.collect(); + temp? + }; + // Do things with v... + Ok(true) +} +``` + +Note that the type of `v` can now be inferred from the type of `temp`. +"##, + E0308: r##" This error occurs when the compiler was unable to infer the concrete type of a variable. It can occur for several cases, the most common of which is a @@ -2158,7 +2203,6 @@ register_diagnostics! { E0278, // requirement is not satisfied E0279, // requirement is not satisfied E0280, // requirement is not satisfied - E0284, // cannot resolve type // E0285, // overflow evaluation builtin bounds // E0296, // replaced with a generic attribute input check // E0300, // unexpanded macro diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index a0b504a99de9a..07a9f294fb68c 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -528,13 +528,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }) => { // Not projected from the implicit `self` in a closure. debug_assert!( - match *base { - Place::Base(PlaceBase::Local(local)) => local == Local::new(1), - Place::Projection(box Projection { - ref base, - elem: ProjectionElem::Deref, - }) => *base == Place::Base(PlaceBase::Local(Local::new(1))), - _ => false, + match base.local() { + Some(local) => local == Local::new(1), + None => false, }, "Unexpected capture place" ); diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index ce854518db3d3..11022be097cfd 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -296,47 +296,50 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option> { trace!("eval_place(place={:?})", place); - match *place { - Place::Base(PlaceBase::Local(loc)) => self.places[loc].clone(), - Place::Projection(ref proj) => match proj.elem { - ProjectionElem::Field(field, _) => { - trace!("field proj on {:?}", proj.base); - let base = self.eval_place(&proj.base, source_info)?; + place.iterate(|place_base, place_projection| { + let mut eval = match place_base { + PlaceBase::Local(loc) => self.places[*loc].clone()?, + PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted), ..}) => { + let generics = self.tcx.generics_of(self.source.def_id()); + if generics.requires_monomorphization(self.tcx) { + // FIXME: can't handle code with generics + return None; + } + let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id()); + let instance = Instance::new(self.source.def_id(), substs); + let cid = GlobalId { + instance, + promoted: Some(*promoted), + }; + // cannot use `const_eval` here, because that would require having the MIR + // for the current function available, but we're producing said MIR right now let res = self.use_ecx(source_info, |this| { - this.ecx.operand_field(base, field.index() as u64) + let mir = &this.promoted[*promoted]; + eval_promoted(this.tcx, cid, mir, this.param_env) })?; - Some(res) - }, - // We could get more projections by using e.g., `operand_projection`, - // but we do not even have the stack frame set up properly so - // an `Index` projection would throw us off-track. - _ => None, - }, - Place::Base( - PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted), ..}) - ) => { - let generics = self.tcx.generics_of(self.source.def_id()); - if generics.requires_monomorphization(self.tcx) { - // FIXME: can't handle code with generics - return None; + trace!("evaluated promoted {:?} to {:?}", promoted, res); + res.into() } - let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id()); - let instance = Instance::new(self.source.def_id(), substs); - let cid = GlobalId { - instance, - promoted: Some(promoted), - }; - // cannot use `const_eval` here, because that would require having the MIR - // for the current function available, but we're producing said MIR right now - let res = self.use_ecx(source_info, |this| { - let mir = &this.promoted[promoted]; - eval_promoted(this.tcx, cid, mir, this.param_env) - })?; - trace!("evaluated promoted {:?} to {:?}", promoted, res); - Some(res.into()) - }, - _ => None, - } + _ => return None, + }; + + for proj in place_projection { + match proj.elem { + ProjectionElem::Field(field, _) => { + trace!("field proj on {:?}", proj.base); + eval = self.use_ecx(source_info, |this| { + this.ecx.operand_field(eval, field.index() as u64) + })?; + }, + // We could get more projections by using e.g., `operand_projection`, + // but we do not even have the stack frame set up properly so + // an `Index` projection would throw us off-track. + _ => return None, + } + } + + Some(eval) + }) } fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 24ec3219a2e7b..782af3024ad2c 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -440,19 +440,22 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // writes to `i`. To prevent this we need to create a temporary // borrow of the place and pass the destination as `*temp` instead. fn dest_needs_borrow(place: &Place<'_>) -> bool { - match *place { - Place::Projection(ref p) => { - match p.elem { + place.iterate(|place_base, place_projection| { + for proj in place_projection { + match proj.elem { ProjectionElem::Deref | - ProjectionElem::Index(_) => true, - _ => dest_needs_borrow(&p.base) + ProjectionElem::Index(_) => return true, + _ => {} } } - // Static variables need a borrow because the callee - // might modify the same static. - Place::Base(PlaceBase::Static(_)) => true, - _ => false - } + + match place_base { + // Static variables need a borrow because the callee + // might modify the same static. + PlaceBase::Static(_) => true, + _ => false + } + }) } let dest = if dest_needs_borrow(&destination.0) { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index e1d41ba4fc509..a1e2d0683d380 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -136,10 +136,10 @@ fn check_rvalue( ) -> McfResult { match rvalue { Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => { - check_operand(tcx, mir, operand, span) + check_operand(operand, span) } Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => { - check_place(tcx, mir, place, span) + check_place(place, span) } Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc::ty::cast::CastTy; @@ -153,11 +153,11 @@ fn check_rvalue( (CastTy::RPtr(_), CastTy::Float) => bug!(), (CastTy::RPtr(_), CastTy::Int(_)) => bug!(), (CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(), - _ => check_operand(tcx, mir, operand, span), + _ => check_operand(operand, span), } } Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _) => { - check_operand(tcx, mir, operand, span) + check_operand(operand, span) } Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _) | Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), _, _) | @@ -171,8 +171,8 @@ fn check_rvalue( )), // binops are fine on integers Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { - check_operand(tcx, mir, lhs, span)?; - check_operand(tcx, mir, rhs, span)?; + check_operand(lhs, span)?; + check_operand(rhs, span)?; let ty = lhs.ty(mir, tcx); if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) @@ -191,7 +191,7 @@ fn check_rvalue( Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(mir, tcx); if ty.is_integral() || ty.is_bool() { - check_operand(tcx, mir, operand, span) + check_operand(operand, span) } else { Err(( span, @@ -201,7 +201,7 @@ fn check_rvalue( } Rvalue::Aggregate(_, operands) => { for operand in operands { - check_operand(tcx, mir, operand, span)?; + check_operand(operand, span)?; } Ok(()) } @@ -216,11 +216,11 @@ fn check_statement( let span = statement.source_info.span; match &statement.kind { StatementKind::Assign(place, rval) => { - check_place(tcx, mir, place, span)?; + check_place(place, span)?; check_rvalue(tcx, mir, rval, span) } - StatementKind::FakeRead(_, place) => check_place(tcx, mir, place, span), + StatementKind::FakeRead(_, place) => check_place(place, span), // just an assignment StatementKind::SetDiscriminant { .. } => Ok(()), @@ -239,43 +239,40 @@ fn check_statement( } fn check_operand( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a Mir<'tcx>, operand: &Operand<'tcx>, span: Span, ) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => { - check_place(tcx, mir, place, span) + check_place(place, span) } Operand::Constant(_) => Ok(()), } } -fn check_place( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a Mir<'tcx>, - place: &Place<'tcx>, - span: Span, -) -> McfResult { - match place { - Place::Base(PlaceBase::Local(_)) => Ok(()), - // promoteds are always fine, they are essentially constants - Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) => Ok(()), - Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. })) => - Err((span, "cannot access `static` items in const fn".into())), - Place::Projection(proj) => { +fn check_place(place: &Place<'tcx>, span: Span) -> McfResult { + place.iterate(|place_base, place_projection| { + for proj in place_projection { match proj.elem { - | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } - | ProjectionElem::Deref | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - check_place(tcx, mir, &proj.base, span) - } - | ProjectionElem::Downcast(..) => { - Err((span, "`match` or `if let` in `const fn` is unstable".into())) + ProjectionElem::Downcast(..) => { + return Err((span, "`match` or `if let` in `const fn` is unstable".into())); } + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Deref + | ProjectionElem::Field(..) + | ProjectionElem::Index(_) => {} } } - } + + match place_base { + PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. }) => { + Err((span, "cannot access `static` items in const fn".into())) + } + PlaceBase::Local(_) + | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => Ok(()), + } + }) } fn check_terminator( @@ -290,11 +287,11 @@ fn check_terminator( | TerminatorKind::Resume => Ok(()), TerminatorKind::Drop { location, .. } => { - check_place(tcx, mir, location, span) + check_place(location, span) } TerminatorKind::DropAndReplace { location, value, .. } => { - check_place(tcx, mir, location, span)?; - check_operand(tcx, mir, value, span) + check_place(location, span)?; + check_operand(value, span) }, TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } => Err(( @@ -346,10 +343,10 @@ fn check_terminator( )), } - check_operand(tcx, mir, func, span)?; + check_operand(func, span)?; for arg in args { - check_operand(tcx, mir, arg, span)?; + check_operand(arg, span)?; } Ok(()) } else { @@ -363,7 +360,7 @@ fn check_terminator( msg: _, target: _, cleanup: _, - } => check_operand(tcx, mir, cond, span), + } => check_operand(cond, span), TerminatorKind::FalseUnwind { .. } => { Err((span, "loops are not allowed in const fn".into())) diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr index fced38caaba91..a26ee23894f6d 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr @@ -12,3 +12,4 @@ LL | trait Foo: Iterator {} error: aborting due to previous error +For more information about this error, try `rustc --explain E0284`. diff --git a/src/test/ui/associated-types/associated-types-unconstrained.stderr b/src/test/ui/associated-types/associated-types-unconstrained.stderr index 26e5a6a503c6f..da14a69ae306a 100644 --- a/src/test/ui/associated-types/associated-types-unconstrained.stderr +++ b/src/test/ui/associated-types/associated-types-unconstrained.stderr @@ -6,3 +6,4 @@ LL | let x: isize = Foo::bar(); error: aborting due to previous error +For more information about this error, try `rustc --explain E0284`. diff --git a/src/test/ui/issues/issue-12028.stderr b/src/test/ui/issues/issue-12028.stderr index b9e2e80492b37..64694c7a8d0b6 100644 --- a/src/test/ui/issues/issue-12028.stderr +++ b/src/test/ui/issues/issue-12028.stderr @@ -6,3 +6,4 @@ LL | self.input_stream(&mut stream); error: aborting due to previous error +For more information about this error, try `rustc --explain E0284`. diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr index 2a1bdf57a88cb..f62a540572c93 100644 --- a/src/test/ui/question-mark-type-infer.stderr +++ b/src/test/ui/question-mark-type-infer.stderr @@ -6,3 +6,4 @@ LL | l.iter().map(f).collect()? error: aborting due to previous error +For more information about this error, try `rustc --explain E0284`.