Auto merge of #61258 - Centril:rollup-l2mof9t, r=Centril

Rollup of 9 pull requests

Successful merges:

 - #61084 (Clarify docs for unreachable! macro)
 - #61220 (Added error message for E0284)
 - #61227 (Use .await syntax instead of await!)
 - #61230 (avoid creating Boxes of uninitalized values in RawVec)
 - #61237 (Updated the Iterator docs with information about overriding methods.)
 - #61241 (Check place iterative)
 - #61242 (Make dest_needs_borrow iterate instead of recurse)
 - #61247 (Make eval_place iterate instead of recurse)
 - #61248 (Use Place::local)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-05-28 11:50:14 +00:00
commit 7da118581c
15 changed files with 168 additions and 110 deletions

View File

@ -395,11 +395,10 @@ impl<T: Clone> Clone for Box<T> {
#[stable(feature = "box_slice_clone", since = "1.3.0")]
impl Clone for Box<str> {
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<T: Copy> 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()
}
}
}

View File

@ -685,12 +685,14 @@ impl<T, A: Alloc> RawVec<T, A> {
impl<T> RawVec<T, Global> {
/// 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<T, Global>` 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);

View File

@ -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")]

View File

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

View File

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

View File

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

View File

@ -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<bool, ()> {
let results = [Ok(true), Ok(false), Err(())].iter().cloned();
let v: Vec<bool> = results.collect()?;
// Do things with v...
Ok(true)
}
```
Here we have an iterator `results` over `Result<bool, ()>`.
Hence, `results.collect()` can return any type implementing
`FromIterator<Result<bool, ()>>`. On the other hand, the
`?` operator can accept any type implementing `Try`.
The author of this code probably wants `collect()` to return a
`Result<Vec<bool>, ()>`, but the compiler can't be sure
that there isn't another type `T` implementing both `Try` and
`FromIterator<Result<bool, ()>>` in scope such that
`T::Ok == Vec<bool>`. 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<bool, ()> {
let results = [Ok(true), Ok(false), Err(())].iter().cloned();
let v = {
let temp: Result<Vec<bool>, ()> = 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

View File

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

View File

@ -296,47 +296,50 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
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<Const<'tcx>> {

View File

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

View File

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

View File

@ -12,3 +12,4 @@ LL | trait Foo: Iterator<Item = i32> {}
error: aborting due to previous error
For more information about this error, try `rustc --explain E0284`.

View File

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

View File

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

View File

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