mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-30 05:51:58 +00:00
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:
commit
7da118581c
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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")]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
///
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
);
|
||||
|
@ -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>> {
|
||||
|
@ -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) {
|
||||
|
@ -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()))
|
||||
|
@ -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`.
|
||||
|
@ -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`.
|
||||
|
@ -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`.
|
||||
|
@ -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`.
|
||||
|
Loading…
Reference in New Issue
Block a user