[submodule "src/llvm-project"]
path = src/llvm-project
url = https://github.com/rust-lang/llvm-project.git
- branch = rustc/14.0-2022-02-09
+ branch = rustc/14.0-2022-03-22
[submodule "src/doc/embedded-book"]
path = src/doc/embedded-book
url = https://github.com/rust-embedded/book.git
[[package]]
name = "chalk-derive"
-version = "0.76.0"
+version = "0.80.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58c24b8052ea1e3adbb6f9ab7ba5fcc18b9d12591c042de4c833f709ce81e0e0"
+checksum = "d0001adf0cf12361e08b65e1898ea138f8f77d8f5177cbf29b6b3b3532252bd6"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "chalk-engine"
-version = "0.76.0"
+version = "0.80.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eca186b6ea9af798312f4b568fd094c82e7946ac08be5dc5fea22decc6d2ed8"
+checksum = "c44ee96f2d67cb5193d1503f185db1abad9933a1c6e6b4169c176f90baecd393"
dependencies = [
"chalk-derive",
"chalk-ir",
[[package]]
name = "chalk-ir"
-version = "0.76.0"
+version = "0.80.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cad5c3f1edd4b4a2c9bda24ae558ceb4f88336f88f944c2e35d0bfeb13c818"
+checksum = "92d8a95548f23618fda86426e4304e563ec2bb7ba0216139f0748d63c107b5f1"
dependencies = [
"bitflags",
"chalk-derive",
[[package]]
name = "chalk-solve"
-version = "0.76.0"
+version = "0.80.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94533188d3452bc72cbd5618d166f45fc7646b674ad3fe9667d557bc25236dee"
+checksum = "f37f492dacfafe2e21319b80827da2779932909bb392f0cc86b2bd5c07c1b4e1"
dependencies = [
"chalk-derive",
"chalk-ir",
}
}
- // Extract from the pointer an `Option<AllocId>` and an offset, which is relative to the
- // allocation or (if that is `None`) an absolute address.
- let ptr_or_addr = if size.bytes() == 0 {
- // Let's see what we can do, but don't throw errors if there's nothing there.
- self.ptr_try_get_alloc(ptr)
- } else {
- // A "real" access, we insist on getting an `AllocId`.
- Ok(self.ptr_get_alloc(ptr)?)
- };
- Ok(match ptr_or_addr {
+ Ok(match self.ptr_try_get_alloc(ptr) {
Err(addr) => {
- // No memory is actually being accessed.
- debug_assert!(size.bytes() == 0);
- // Must be non-null.
- if addr == 0 {
- throw_ub!(DanglingIntPointer(0, msg))
+ // We couldn't get a proper allocation. This is only okay if the access size is 0,
+ // and the address is not null.
+ if size.bytes() > 0 || addr == 0 {
+ throw_ub!(DanglingIntPointer(addr, msg));
}
// Must be aligned.
if let Some(align) = align {
rustc_serialize = { path = "../rustc_serialize" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.76.0"
+chalk-ir = "0.80.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
rustc_session = { path = "../rustc_session" }
rustc_type_ir = { path = "../rustc_type_ir" }
#![feature(new_uninit)]
#![feature(nll)]
#![feature(once_cell)]
+#![feature(let_chains)]
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(trusted_len)]
);
if !generics.is_empty() || !assoc_items.is_empty() {
- p!("<");
let mut first = true;
for ty in generics {
- if !first {
+ if first {
+ p!("<");
+ first = false;
+ } else {
p!(", ");
}
p!(print(trait_ref.rebind(*ty)));
- first = false;
}
for (assoc_item_def_id, term) in assoc_items {
- if !first {
+ // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
+ if let Some(ty) = term.skip_binder().ty() &&
+ let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = ty.kind() &&
+ Some(*item_def_id) == self.tcx().lang_items().generator_return() {
+ continue;
+ }
+
+ if first {
+ p!("<");
+ first = false;
+ } else {
p!(", ");
}
+
p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).name));
match term.skip_binder() {
Term::Ty(ty) => {
- // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
- if matches!(
- ty.kind(), ty::Projection(ty::ProjectionTy { item_def_id, .. })
- if Some(*item_def_id) == self.tcx().lang_items().generator_return()
- ) {
- p!("[async output]")
- } else {
- p!(print(ty))
- }
+ p!(print(ty))
}
Term::Const(c) => {
p!(print(c));
}
};
-
- first = false;
}
- p!(">");
+ if !first {
+ p!(">");
+ }
}
first = false;
#[derive(Clone)]
pub enum CopyImplementationError<'tcx> {
- InfrigingFields(Vec<&'tcx ty::FieldDef>),
+ InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>),
NotAnAdt,
HasDestructor,
}
match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) {
Ok(ty) => {
if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
- infringing.push(field);
+ infringing.push((field, ty));
}
}
Err(errors) => {
// the master cache. Since coherence executes pretty quickly,
// it's not worth going to more trouble to increase the
// hit-rate, I don't think.
- if self.intercrate {
+ if self.intercrate || self.allow_negative_impls {
return false;
}
// mode, so don't do any caching. In particular, we might
// re-use the same `InferCtxt` with both an intercrate
// and non-intercrate `SelectionContext`
- if self.intercrate {
+ if self.intercrate || self.allow_negative_impls {
return None;
}
let tcx = self.tcx();
rustc_index = { path = "../rustc_index" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.76.0"
-chalk-engine = "0.76.0"
-chalk-solve = "0.76.0"
+chalk-ir = "0.80.0"
+chalk-engine = "0.80.0"
+chalk-solve = "0.80.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
rustc_infer = { path = "../rustc_infer" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
&self,
trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
) -> Arc<chalk_solve::rust_ir::TraitDatum<RustInterner<'tcx>>> {
+ use chalk_solve::rust_ir::WellKnownTrait::*;
+
let def_id = trait_id.0;
let trait_def = self.interner.tcx.trait_def(def_id);
let lang_items = self.interner.tcx.lang_items();
let well_known = if lang_items.sized_trait() == Some(def_id) {
- Some(chalk_solve::rust_ir::WellKnownTrait::Sized)
+ Some(Sized)
} else if lang_items.copy_trait() == Some(def_id) {
- Some(chalk_solve::rust_ir::WellKnownTrait::Copy)
+ Some(Copy)
} else if lang_items.clone_trait() == Some(def_id) {
- Some(chalk_solve::rust_ir::WellKnownTrait::Clone)
+ Some(Clone)
} else if lang_items.drop_trait() == Some(def_id) {
- Some(chalk_solve::rust_ir::WellKnownTrait::Drop)
+ Some(Drop)
} else if lang_items.fn_trait() == Some(def_id) {
- Some(chalk_solve::rust_ir::WellKnownTrait::Fn)
+ Some(Fn)
} else if lang_items.fn_once_trait() == Some(def_id) {
- Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce)
+ Some(FnOnce)
} else if lang_items.fn_mut_trait() == Some(def_id) {
- Some(chalk_solve::rust_ir::WellKnownTrait::FnMut)
+ Some(FnMut)
} else if lang_items.unsize_trait() == Some(def_id) {
- Some(chalk_solve::rust_ir::WellKnownTrait::Unsize)
+ Some(Unsize)
} else if lang_items.unpin_trait() == Some(def_id) {
- Some(chalk_solve::rust_ir::WellKnownTrait::Unpin)
+ Some(Unpin)
} else if lang_items.coerce_unsized_trait() == Some(def_id) {
- Some(chalk_solve::rust_ir::WellKnownTrait::CoerceUnsized)
+ Some(CoerceUnsized)
+ } else if lang_items.dispatch_from_dyn_trait() == Some(def_id) {
+ Some(DispatchFromDyn)
} else {
None
};
})
}
+ fn adt_size_align(
+ &self,
+ adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
+ ) -> Arc<chalk_solve::rust_ir::AdtSizeAlign> {
+ let tcx = self.interner.tcx;
+ let did = adt_id.0.did();
+
+ // Grab the ADT and the param we might need to calculate its layout
+ let param_env = tcx.param_env(did);
+ let adt_ty = tcx.type_of(did);
+
+ // The ADT is a 1-zst if it's a ZST and its alignment is 1.
+ // Mark the ADT as _not_ a 1-zst if there was a layout error.
+ let one_zst = if let Ok(layout) = tcx.layout_of(param_env.and(adt_ty)) {
+ layout.is_zst() && layout.align.abi.bytes() == 1
+ } else {
+ false
+ };
+
+ Arc::new(chalk_solve::rust_ir::AdtSizeAlign::from_one_zst(one_zst))
+ }
+
fn fn_def_datum(
&self,
fn_def_id: chalk_ir::FnDefId<RustInterner<'tcx>>,
Unpin => lang_items.unpin_trait(),
CoerceUnsized => lang_items.coerce_unsized_trait(),
DiscriminantKind => lang_items.discriminant_kind_trait(),
+ DispatchFromDyn => lang_items.dispatch_from_dyn_trait(),
};
def_id.map(chalk_ir::TraitId)
}
use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::{Span, Spanned};
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, MultiSpan, DUMMY_SP};
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::{ObligationCause, Pattern};
.filter(|(_, ident)| !used_fields.contains_key(ident))
.collect::<Vec<_>>();
- let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) {
+ let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered())
+ && !inexistent_fields.iter().any(|field| field.name == kw::Underscore)
+ {
Some(self.error_inexistent_fields(
adt.variant_descr(),
&inexistent_fields,
E0204,
"the trait `Copy` may not be implemented for this type"
);
- for span in fields.iter().map(|f| tcx.def_span(f.did)) {
- err.span_label(span, "this field does not implement `Copy`");
+ for (field, ty) in fields {
+ let field_span = tcx.def_span(field.did);
+ err.span_label(field_span, "this field does not implement `Copy`");
+ // Spin up a new FulfillmentContext, so we can get the _precise_ reason
+ // why this field does not implement Copy. This is useful because sometimes
+ // it is not immediately clear why Copy is not implemented for a field, since
+ // all we point at is the field itself.
+ tcx.infer_ctxt().enter(|infcx| {
+ let mut fulfill_cx = traits::FulfillmentContext::new_ignoring_regions();
+ fulfill_cx.register_bound(
+ &infcx,
+ param_env,
+ ty,
+ tcx.lang_items().copy_trait().unwrap(),
+ traits::ObligationCause::dummy_with_span(field_span),
+ );
+ for error in fulfill_cx.select_all_or_error(&infcx) {
+ let error_predicate = error.obligation.predicate;
+ // Only note if it's not the root obligation, otherwise it's trivial and
+ // should be self-explanatory (i.e. a field literally doesn't implement Copy).
+
+ // FIXME: This error could be more descriptive, especially if the error_predicate
+ // contains a foreign type or if it's a deeply nested type...
+ if error_predicate != error.root_obligation.predicate {
+ err.span_note(
+ error.obligation.cause.span,
+ &format!(
+ "the `Copy` impl for `{}` requires that `{}`",
+ ty, error_predicate
+ ),
+ );
+ }
+ }
+ });
}
err.emit();
}
use crate::collections::TryReserveError;
use crate::slice;
-use crate::vec::{self, AsIntoIter, Vec};
+use crate::vec::{self, AsVecIntoIter, Vec};
use super::SpecExtend;
#[stable(feature = "fused", since = "1.26.0")]
impl<T> FusedIterator for IntoIter<T> {}
+// In addition to the SAFETY invariants of the following three unsafe traits
+// also refer to the vec::in_place_collect module documentation to get an overview
#[unstable(issue = "none", feature = "inplace_iteration")]
#[doc(hidden)]
unsafe impl<T> SourceIter for IntoIter<T> {
#[doc(hidden)]
unsafe impl<I> InPlaceIterable for IntoIter<I> {}
-impl<I> AsIntoIter for IntoIter<I> {
+unsafe impl<I> AsVecIntoIter for IntoIter<I> {
type Item = I;
fn as_into_iter(&mut self) -> &mut vec::IntoIter<Self::Item> {
--- /dev/null
+//! Inplace iterate-and-collect specialization for `Vec`
+//!
+//! Note: This documents Vec internals, some of the following sections explain implementation
+//! details and are best read together with the source of this module.
+//!
+//! The specialization in this module applies to iterators in the shape of
+//! `source.adapter().adapter().adapter().collect::<Vec<U>>()`
+//! where `source` is an owning iterator obtained from [`Vec<T>`], [`Box<[T]>`][box] (by conversion to `Vec`)
+//! or [`BinaryHeap<T>`], the adapters each consume one or more items per step
+//! (represented by [`InPlaceIterable`]), provide transitive access to `source` (via [`SourceIter`])
+//! and thus the underlying allocation. And finally the layouts of `T` and `U` must
+//! have the same size and alignment, this is currently ensured via const eval instead of trait bounds
+//! in the specialized [`SpecFromIter`] implementation.
+//!
+//! [`BinaryHeap<T>`]: crate::collections::BinaryHeap
+//! [box]: crate::boxed::Box
+//!
+//! By extension some other collections which use `collect::<Vec<_>>()` internally in their
+//! `FromIterator` implementation benefit from this too.
+//!
+//! Access to the underlying source goes through a further layer of indirection via the private
+//! trait [`AsVecIntoIter`] to hide the implementation detail that other collections may use
+//! `vec::IntoIter` internally.
+//!
+//! In-place iteration depends on the interaction of several unsafe traits, implementation
+//! details of multiple parts in the iterator pipeline and often requires holistic reasoning
+//! across multiple structs since iterators are executed cooperatively rather than having
+//! a central evaluator/visitor struct executing all iterator components.
+//!
+//! # Reading from and writing to the same allocation
+//!
+//! By its nature collecting in place means that the reader and writer side of the iterator
+//! use the same allocation. Since `try_fold()` (used in [`SpecInPlaceCollect`]) takes a
+//! reference to the iterator for the duration of the iteration that means we can't interleave
+//! the step of reading a value and getting a reference to write to. Instead raw pointers must be
+//! used on the reader and writer side.
+//!
+//! That writes never clobber a yet-to-be-read item is ensured by the [`InPlaceIterable`] requirements.
+//!
+//! # Layout constraints
+//!
+//! [`Allocator`] requires that `allocate()` and `deallocate()` have matching alignment and size.
+//! Additionally this specialization doesn't make sense for ZSTs as there is no reallocation to
+//! avoid and it would make pointer arithmetic more difficult.
+//!
+//! [`Allocator`]: core::alloc::Allocator
+//!
+//! # Drop- and panic-safety
+//!
+//! Iteration can panic, requiring dropping the already written parts but also the remainder of
+//! the source. Iteration can also leave some source items unconsumed which must be dropped.
+//! All those drops in turn can panic which then must either leak the allocation or abort to avoid
+//! double-drops.
+//!
+//! This is handled by the [`InPlaceDrop`] guard for sink items (`U`) and by
+//! [`vec::IntoIter::forget_allocation_drop_remaining()`] for remaining source items (`T`).
+//!
+//! [`vec::IntoIter::forget_allocation_drop_remaining()`]: super::IntoIter::forget_allocation_drop_remaining()
+//!
+//! # O(1) collect
+//!
+//! The main iteration itself is further specialized when the iterator implements
+//! [`TrustedRandomAccessNoCoerce`] to let the optimizer see that it is a counted loop with a single
+//! [induction variable]. This can turn some iterators into a noop, i.e. it reduces them from O(n) to
+//! O(1). This particular optimization is quite fickle and doesn't always work, see [#79308]
+//!
+//! [#79308]: https://github.com/rust-lang/rust/issues/79308
+//! [induction variable]: https://en.wikipedia.org/wiki/Induction_variable
+//!
+//! Since unchecked accesses through that trait do not advance the read pointer of `IntoIter`
+//! this would interact unsoundly with the requirements about dropping the tail described above.
+//! But since the normal `Drop` implementation of `IntoIter` would suffer from the same problem it
+//! is only correct for `TrustedRandomAccessNoCoerce` to be implemented when the items don't
+//! have a destructor. Thus that implicit requirement also makes the specialization safe to use for
+//! in-place collection.
+//! Note that this safety concern is about the correctness of `impl Drop for IntoIter`,
+//! not the guarantees of `InPlaceIterable`.
+//!
+//! # Adapter implementations
+//!
+//! The invariants for adapters are documented in [`SourceIter`] and [`InPlaceIterable`], but
+//! getting them right can be rather subtle for multiple, sometimes non-local reasons.
+//! For example `InPlaceIterable` would be valid to implement for [`Peekable`], except
+//! that it is stateful, cloneable and `IntoIter`'s clone implementation shortens the underlying
+//! allocation which means if the iterator has been peeked and then gets cloned there no longer is
+//! enough room, thus breaking an invariant ([#85322]).
+//!
+//! [#85322]: https://github.com/rust-lang/rust/issues/85322
+//! [`Peekable`]: core::iter::Peekable
+//!
+//!
+//! # Examples
+//!
+//! Some cases that are optimized by this specialization, more can be found in the `Vec`
+//! benchmarks:
+//!
+//! ```rust
+//! # #[allow(dead_code)]
+//! /// Converts a usize vec into an isize one.
+//! pub fn cast(vec: Vec<usize>) -> Vec<isize> {
+//! // Does not allocate, free or panic. On optlevel>=2 it does not loop.
+//! // Of course this particular case could and should be written with `into_raw_parts` and
+//! // `from_raw_parts` instead.
+//! vec.into_iter().map(|u| u as isize).collect()
+//! }
+//! ```
+//!
+//! ```rust
+//! # #[allow(dead_code)]
+//! /// Drops remaining items in `src` and if the layouts of `T` and `U` match it
+//! /// returns an empty Vec backed by the original allocation. Otherwise it returns a new
+//! /// empty vec.
+//! pub fn recycle_allocation<T, U>(src: Vec<T>) -> Vec<U> {
+//! src.into_iter().filter_map(|_| None).collect()
+//! }
+//! ```
+//!
+//! ```rust
+//! let vec = vec![13usize; 1024];
+//! let _ = vec.into_iter()
+//! .enumerate()
+//! .filter_map(|(idx, val)| if idx % 2 == 0 { Some(val+idx) } else {None})
+//! .collect::<Vec<_>>();
+//!
+//! // is equivalent to the following, but doesn't require bounds checks
+//!
+//! let mut vec = vec![13usize; 1024];
+//! let mut write_idx = 0;
+//! for idx in 0..vec.len() {
+//! if idx % 2 == 0 {
+//! vec[write_idx] = vec[idx] + idx;
+//! write_idx += 1;
+//! }
+//! }
+//! vec.truncate(write_idx);
+//! ```
+use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce};
+use core::mem::{self, ManuallyDrop};
+use core::ptr::{self};
+
+use super::{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.
+#[rustc_unsafe_specialization_marker]
+pub(super) trait InPlaceIterableMarker {}
+
+impl<T> InPlaceIterableMarker for T where T: InPlaceIterable {}
+
+impl<T, I> SpecFromIter<T, I> for Vec<T>
+where
+ I: Iterator<Item = T> + SourceIter<Source: AsVecIntoIter> + InPlaceIterableMarker,
+{
+ default fn from_iter(mut iterator: I) -> Self {
+ // See "Layout constraints" section in the module documentation. We rely on const
+ // optimization here since these conditions currently cannot be expressed as trait bounds
+ if mem::size_of::<T>() == 0
+ || mem::size_of::<T>()
+ != mem::size_of::<<<I as SourceIter>::Source as AsVecIntoIter>::Item>()
+ || mem::align_of::<T>()
+ != mem::align_of::<<<I as SourceIter>::Source as AsVecIntoIter>::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,
+ )
+ };
+
+ let len = SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end);
+
+ let src = unsafe { iterator.as_inner().as_into_iter() };
+ // check if SourceIter contract was upheld
+ // caveat: if they weren't we might 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!(
+ unsafe { dst_buf.add(len) as *const _ } <= src.ptr,
+ "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
+ );
+ }
+
+ // Drop any remaining values at the tail of the source but prevent drop of the allocation
+ // itself once IntoIter goes out of scope.
+ // If the drop panics then we also leak any elements collected into dst_buf.
+ //
+ // Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce
+ // contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the
+ // module documenttation why this is ok anyway.
+ src.forget_allocation_drop_remaining();
+
+ let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) };
+
+ vec
+ }
+}
+
+fn write_in_place_with_drop<T>(
+ src_end: *const T,
+) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
+ 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);
+ // Since this executes user code which can panic we have to bump the pointer
+ // after each step.
+ sink.dst = sink.dst.add(1);
+ }
+ Ok(sink)
+ }
+}
+
+/// Helper trait to hold specialized implementations of the in-place iterate-collect loop
+trait SpecInPlaceCollect<T, I>: Iterator<Item = T> {
+ /// Collects an iterator (`self`) into the destination buffer (`dst`) and returns the number of items
+ /// collected. `end` is the last writable element of the allocation and used for bounds checks.
+ ///
+ /// This method is specialized and one of its implementations makes use of
+ /// `Iterator::__iterator_get_unchecked` calls with a `TrustedRandomAccessNoCoerce` bound
+ /// on `I` which means the caller of this method must take the safety conditions
+ /// of that trait into consideration.
+ fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize;
+}
+
+impl<T, I> SpecInPlaceCollect<T, I> for I
+where
+ I: Iterator<Item = T>,
+{
+ #[inline]
+ default fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
+ // 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 =
+ self.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(end)).unwrap();
+ // iteration succeeded, don't drop head
+ unsafe { ManuallyDrop::new(sink).dst.offset_from(dst_buf) as usize }
+ }
+}
+
+impl<T, I> SpecInPlaceCollect<T, I> for I
+where
+ I: Iterator<Item = T> + TrustedRandomAccessNoCoerce,
+{
+ #[inline]
+ fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
+ let len = self.size();
+ let mut drop_guard = InPlaceDrop { inner: dst_buf, dst: dst_buf };
+ for i in 0..len {
+ // Safety: InplaceIterable contract guarantees that for every element we read
+ // one slot in the underlying storage will have been freed up and we can immediately
+ // write back the result.
+ unsafe {
+ let dst = dst_buf.offset(i as isize);
+ debug_assert!(dst as *const _ <= end, "InPlaceIterable contract violation");
+ ptr::write(dst, self.__iterator_get_unchecked(i));
+ // Since this executes user code which can panic we have to bump the pointer
+ // after each step.
+ drop_guard.dst = dst.add(1);
+ }
+ }
+ mem::forget(drop_guard);
+ len
+ }
+}
+
+/// Internal helper trait for in-place iteration specialization.
+///
+/// Currently this is only implemented by [`vec::IntoIter`] - returning a reference to itself - and
+/// [`binary_heap::IntoIter`] which returns a reference to its inner representation.
+///
+/// Since this is an internal trait it hides the implementation detail `binary_heap::IntoIter`
+/// uses `vec::IntoIter` internally.
+///
+/// [`vec::IntoIter`]: super::IntoIter
+/// [`binary_heap::IntoIter`]: crate::collections::binary_heap::IntoIter
+///
+/// # Safety
+///
+/// In-place iteration relies on implementation details of `vec::IntoIter`, most importantly that
+/// it does not create references to the whole allocation during iteration, only raw pointers
+#[rustc_specialization_trait]
+pub(crate) unsafe trait AsVecIntoIter {
+ type Item;
+ fn as_into_iter(&mut self) -> &mut super::IntoIter<Self::Item>;
+}
+#[cfg(not(no_global_oom_handling))]
+use super::AsVecIntoIter;
use crate::alloc::{Allocator, Global};
use crate::raw_vec::RawVec;
use core::fmt;
/// (&mut into_iter).for_each(core::mem::drop);
/// unsafe { core::ptr::write(&mut into_iter, Vec::new().into_iter()); }
/// ```
+ ///
+ /// This method is used by in-place iteration, refer to the vec::in_place_collect
+ /// documentation for an overview.
#[cfg(not(no_global_oom_handling))]
pub(super) fn forget_allocation_drop_remaining(&mut self) {
let remaining = self.as_raw_mut_slice();
}
}
+// In addition to the SAFETY invariants of the following three unsafe traits
+// also refer to the vec::in_place_collect module documentation to get an overview
#[unstable(issue = "none", feature = "inplace_iteration")]
#[doc(hidden)]
unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {}
}
}
-// 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<Self::Item>;
-}
-
-impl<T> AsIntoIter for IntoIter<T> {
+#[cfg(not(no_global_oom_handling))]
+unsafe impl<T> AsVecIntoIter for IntoIter<T> {
type Item = T;
fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item> {
mod cow;
#[cfg(not(no_global_oom_handling))]
-pub(crate) use self::into_iter::AsIntoIter;
+pub(crate) use self::in_place_collect::AsVecIntoIter;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::into_iter::IntoIter;
mod is_zero;
#[cfg(not(no_global_oom_handling))]
-mod source_iter_marker;
+mod in_place_collect;
mod partial_eq;
+++ /dev/null
-use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce};
-use core::mem::{self, ManuallyDrop};
-use core::ptr::{self};
-
-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.
-#[rustc_unsafe_specialization_marker]
-pub(super) trait InPlaceIterableMarker {}
-
-impl<T> InPlaceIterableMarker for T where T: InPlaceIterable {}
-
-impl<T, I> SpecFromIter<T, I> for Vec<T>
-where
- I: Iterator<Item = T> + SourceIter<Source: AsIntoIter> + InPlaceIterableMarker,
-{
- 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::<T>() == 0
- || mem::size_of::<T>()
- != mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
- || mem::align_of::<T>()
- != mem::align_of::<<<I as SourceIter>::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,
- )
- };
-
- let len = SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end);
-
- let src = unsafe { iterator.as_inner().as_into_iter() };
- // check if SourceIter contract was upheld
- // caveat: if they weren't we might 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!(
- unsafe { dst_buf.add(len) as *const _ } <= src.ptr,
- "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
- );
- }
-
- // drop any remaining values at the tail of the source
- // but prevent drop of the allocation itself once IntoIter goes out of scope
- // if the drop panics then we also leak any elements collected into dst_buf
- //
- // FIXME: Since `SpecInPlaceCollect::collect_in_place` above might use
- // `__iterator_get_unchecked` internally, this call might be operating on
- // a `vec::IntoIter` with incorrect internal state regarding which elements
- // have already been “consumed”. However, the `TrustedRandomIteratorNoCoerce`
- // implementation of `vec::IntoIter` is only present if the `Vec` elements
- // don’t have a destructor, so it doesn’t matter if elements are “dropped multiple times”
- // in this case.
- // This argument technically currently lacks justification from the `# Safety` docs for
- // `SourceIter`/`InPlaceIterable` and/or `TrustedRandomAccess`, so it might be possible that
- // someone could inadvertently create new library unsoundness
- // involving this `.forget_allocation_drop_remaining()` call.
- src.forget_allocation_drop_remaining();
-
- let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) };
-
- vec
- }
-}
-
-fn write_in_place_with_drop<T>(
- src_end: *const T,
-) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
- 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);
- // Since this executes user code which can panic we have to bump the pointer
- // after each step.
- sink.dst = sink.dst.add(1);
- }
- Ok(sink)
- }
-}
-
-/// Helper trait to hold specialized implementations of the in-place iterate-collect loop
-trait SpecInPlaceCollect<T, I>: Iterator<Item = T> {
- /// Collects an iterator (`self`) into the destination buffer (`dst`) and returns the number of items
- /// collected. `end` is the last writable element of the allocation and used for bounds checks.
- ///
- /// This method is specialized and one of its implementations makes use of
- /// `Iterator::__iterator_get_unchecked` calls with a `TrustedRandomAccessNoCoerce` bound
- /// on `I` which means the caller of this method must take the safety conditions
- /// of that trait into consideration.
- fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize;
-}
-
-impl<T, I> SpecInPlaceCollect<T, I> for I
-where
- I: Iterator<Item = T>,
-{
- #[inline]
- default fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
- // 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 =
- self.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(end)).unwrap();
- // iteration succeeded, don't drop head
- unsafe { ManuallyDrop::new(sink).dst.offset_from(dst_buf) as usize }
- }
-}
-
-impl<T, I> SpecInPlaceCollect<T, I> for I
-where
- I: Iterator<Item = T> + TrustedRandomAccessNoCoerce,
-{
- #[inline]
- fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
- let len = self.size();
- let mut drop_guard = InPlaceDrop { inner: dst_buf, dst: dst_buf };
- for i in 0..len {
- // Safety: InplaceIterable contract guarantees that for every element we read
- // one slot in the underlying storage will have been freed up and we can immediately
- // write back the result.
- unsafe {
- let dst = dst_buf.offset(i as isize);
- debug_assert!(dst as *const _ <= end, "InPlaceIterable contract violation");
- ptr::write(dst, self.__iterator_get_unchecked(i));
- // Since this executes user code which can panic we have to bump the pointer
- // after each step.
- drop_guard.dst = dst.add(1);
- }
- }
- mem::forget(drop_guard);
- len
- }
-}
/// The trait is unsafe because implementers must uphold additional safety properties.
/// See [`as_inner`] for details.
///
+/// The primary use of this trait is in-place iteration. Refer to the [`vec::in_place_collect`]
+/// module documentation for more information.
+///
+/// [`vec::in_place_collect`]: ../../../../alloc/vec/in_place_collect/index.html
+///
/// # Examples
///
/// Retrieving a partially consumed source:
/// in its place, assuming structural constraints of the source allow such an insertion.
/// In other words this trait indicates that an iterator pipeline can be collected in place.
///
+/// The primary use of this trait is in-place iteration. Refer to the [`vec::in_place_collect`]
+/// module documentation for more information.
+///
+/// [`vec::in_place_collect`]: ../../../../alloc/vec/in_place_collect/index.html
/// [`SourceIter`]: crate::iter::SourceIter
/// [`next()`]: Iterator::next
/// [`try_fold()`]: Iterator::try_fold
-Subproject commit c8eccf626fb5bb851b2ade93af8851ca1523807f
+Subproject commit 9168e236c548d1d0e9938ee6dd4cdbd308fdfd72
--- /dev/null
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Foo.html'
+// @has - '//*[@id="impl-Send"]' 'impl !Send for Foo'
+// @has - '//*[@id="impl-Sync"]' 'impl !Sync for Foo'
+pub struct Foo(*const i8);
+pub trait Whatever: Send {}
+impl<T: Send + ?Sized> Whatever for T {}
return 0u8;
};
let _: &dyn Future<Output = ()> = █
- //~^ ERROR type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
+ //~^ ERROR type mismatch resolving `<impl Future as Future>::Output == ()`
}
fn no_break_in_async_block() {
LL | | }
| |_^ expected `u8`, found `()`
-error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
+error[E0271]: type mismatch resolving `<impl Future as Future>::Output == ()`
--> $DIR/async-block-control-flow-static-semantics.rs:26:39
|
LL | let _: &dyn Future<Output = ()> = █
| |
| implicitly returns `()` as its body has no tail or `return` expression
-error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
+error[E0271]: type mismatch resolving `<impl Future as Future>::Output == ()`
--> $DIR/async-block-control-flow-static-semantics.rs:17:39
|
LL | let _: &dyn Future<Output = ()> = █
| the expected opaque type
| the found opaque type
|
- = note: expected opaque type `impl Future<Output = [async output]>` (`async` closure body)
- found opaque type `impl Future<Output = [async output]>` (`async` closure body)
+ = note: expected opaque type `impl Future` (`async` closure body)
+ found opaque type `impl Future` (`async` closure body)
error: aborting due to 3 previous errors
LL | spawn(async {
| ^^^^^ future created by async block is not `Send`
|
- = help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `*mut ()`
+ = help: within `impl Future`, the trait `Send` is not implemented for `*mut ()`
note: future is not `Send` as this value is used across an await
--> $DIR/issue-67252-unnamed-future.rs:20:16
|
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
- = note: required because it appears within the type `impl Future<Output = [async output]>`
+ = note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `{ResumeTy, impl Future<Output = Arc<RefCell<i32>>>, (), i32, Ready<i32>}`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
- = note: required because it appears within the type `impl Future<Output = [async output]>`
+ = note: required because it appears within the type `impl Future`
note: required by a bound in `require_send`
--> $DIR/issue-68112.rs:11:25
|
LL | assert_send(async {
| ^^^^^^^^^^^ future created by async block is not `Send`
|
- = help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `*const u8`
+ = help: within `impl Future`, the trait `Send` is not implemented for `*const u8`
note: future is not `Send` as this value is used across an await
--> $DIR/issue-65436-raw-ptr-not-send.rs:14:35
|
= note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future<Output = ()>, ()}`
= note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>`
- = note: required because it appears within the type `impl Future<Output = [async output]>`
+ = note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future<Output = ()>`
note: required by a bound in `gimme_send`
--> $DIR/partial-drop-partial-reinit.rs:10:18
LL | T: Generator<ResumeTy, Yield = ()>,
| ^^^^^^^^^^ required by this bound in `from_generator`
-error[E0280]: the requirement `<impl Future<Output = [async output]> as Future>::Output == u32` is not satisfied
+error[E0280]: the requirement `<impl Future as Future>::Output == u32` is not satisfied
--> $DIR/async.rs:7:25
|
LL | async fn foo(x: u32) -> u32 {
--- /dev/null
+#![feature(extern_types)]
+
+extern "Rust" {
+ type OpaqueListContents;
+}
+
+pub struct ListS<T> {
+ len: usize,
+ data: [T; 0],
+ opaque: OpaqueListContents,
+}
+
+pub struct Interned<'a, T>(&'a T);
+
+impl<'a, T> Clone for Interned<'a, T> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<'a, T> Copy for Interned<'a, T> {}
+
+pub struct List<'tcx, T>(Interned<'tcx, ListS<T>>);
+//~^ NOTE this field does not implement `Copy`
+//~| NOTE the `Copy` impl for `Interned<'tcx, ListS<T>>` requires that `OpaqueListContents: Sized`
+
+impl<'tcx, T> Clone for List<'tcx, T> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<'tcx, T> Copy for List<'tcx, T> {}
+//~^ ERROR the trait `Copy` may not be implemented for this type
+
+fn assert_is_copy<T: Copy>() {}
+
+fn main() {
+ assert_is_copy::<List<'static, ()>>();
+}
--- /dev/null
+error[E0204]: the trait `Copy` may not be implemented for this type
+ --> $DIR/deep-bad-copy-reason.rs:33:15
+ |
+LL | pub struct List<'tcx, T>(Interned<'tcx, ListS<T>>);
+ | ------------------------ this field does not implement `Copy`
+...
+LL | impl<'tcx, T> Copy for List<'tcx, T> {}
+ | ^^^^
+ |
+note: the `Copy` impl for `Interned<'tcx, ListS<T>>` requires that `OpaqueListContents: Sized`
+ --> $DIR/deep-bad-copy-reason.rs:23:26
+ |
+LL | pub struct List<'tcx, T>(Interned<'tcx, ListS<T>>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0204`.
--> $DIR/const-deref-ptr.rs:4:29
|
LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0xdeadbeef is not a valid pointer
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0xdeadbeef is not a valid pointer
error: aborting due to previous error
--> $DIR/const_raw_ptr_ops2.rs:7:26
|
LL | const Z2: i32 = unsafe { *(42 as *const i32) };
- | ^^^^^^^^^^^^^^^^^^^ 0x2a is not a valid pointer
+ | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a is not a valid pointer
error[E0080]: evaluation of constant value failed
--> $DIR/const_raw_ptr_ops2.rs:9:26
|
LL | const Z3: i32 = unsafe { *(44 as *const i32) };
- | ^^^^^^^^^^^^^^^^^^^ 0x2c is not a valid pointer
+ | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2c is not a valid pointer
error: aborting due to 2 previous errors
--> $DIR/ub-wide-ptr.rs:135:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer
error[E0080]: could not evaluate static initializer
--> $DIR/ub-wide-ptr.rs:139:5
--> $DIR/ub-wide-ptr.rs:135:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer
error[E0080]: could not evaluate static initializer
--> $DIR/ub-wide-ptr.rs:139:5
LL | Some(&mut *(42 as *mut i32))
| ^^^^^^^^^^^^^^^^^^^^^^
| |
- | 0x2a is not a valid pointer
+ | dereferencing pointer failed: 0x2a is not a valid pointer
| inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:13:10
...
LL | const A: Option<&mut i32> = helper();
LL | unsafe { intrinsics::offset(self, count) as *mut T }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | 0x1 is not a valid pointer
+ | pointer arithmetic failed: 0x1 is not a valid pointer
| inside `ptr::mut_ptr::<impl *mut u8>::offset` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
|
::: $DIR/offset_ub.rs:19:42
LL | unsafe { intrinsics::offset(self, count) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | 0x7f..f is not a valid pointer
+ | pointer arithmetic failed: 0x7f..f is not a valid pointer
| inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
::: $DIR/offset_ub.rs:25:47
--> $DIR/E0396-fixed.rs:5:28
|
LL | const VALUE: u8 = unsafe { *REG_ADDR };
- | ^^^^^^^^^ 0x5f3759df is not a valid pointer
+ | ^^^^^^^^^ dereferencing pointer failed: 0x5f3759df is not a valid pointer
error: aborting due to previous error
-error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == impl Stream<Item = Repr>`
+error[E0271]: type mismatch resolving `<impl Future as Future>::Output == impl Stream<Item = Repr>`
--> $DIR/issue-89008.rs:39:43
|
LL | type LineStream<'a, Repr> = impl Stream<Item = Repr>;
type E = impl std::marker::Copy;
fn foo<T>() -> Self::E {
//~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- //~| ERROR the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
+ //~| ERROR the trait bound `impl Future: Copy` is not satisfied
async {}
}
}
-error[E0277]: the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
+error[E0277]: the trait bound `impl Future: Copy` is not satisfied
--> $DIR/issue-55872-2.rs:13:20
|
LL | fn foo<T>() -> Self::E {
- | ^^^^^^^ the trait `Copy` is not implemented for `impl Future<Output = [async output]>`
+ | ^^^^^^^ the trait `Copy` is not implemented for `impl Future`
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> $DIR/issue-55872-2.rs:13:28
| ------------------------------- the found opaque type
|
= note: expected opaque type `impl Future<Output = u8>`
- found opaque type `impl Future<Output = [async output]>`
+ found opaque type `impl Future`
= note: distinct uses of `impl Trait` result in different opaque types
error: aborting due to previous error
LL | const { || {} } => {},
| ^^^^^^^^^^^^^^^
-error: `impl Future<Output = [async output]>` cannot be used in patterns
+error: `impl Future` cannot be used in patterns
--> $DIR/non-structural-match-types.rs:12:9
|
LL | const { async {} } => {},
--- /dev/null
+enum Foo {
+ Bar { bar: bool },
+ Other,
+}
+
+fn main() {
+ let foo = Some(Foo::Other);
+
+ if let Some(Foo::Bar {_}) = foo {}
+ //~^ ERROR expected identifier, found reserved identifier `_`
+ //~| ERROR pattern does not mention field `bar` [E0027]
+}
--- /dev/null
+error: expected identifier, found reserved identifier `_`
+ --> $DIR/struct-enum-ignoring-field-with-underscore.rs:9:27
+ |
+LL | if let Some(Foo::Bar {_}) = foo {}
+ | ^ expected identifier, found reserved identifier
+
+error[E0027]: pattern does not mention field `bar`
+ --> $DIR/struct-enum-ignoring-field-with-underscore.rs:9:17
+ |
+LL | if let Some(Foo::Bar {_}) = foo {}
+ | ^^^^^^^^^^^^ missing field `bar`
+ |
+help: include the missing field in the pattern
+ |
+LL | if let Some(Foo::Bar {_, bar }) = foo {}
+ | ~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+ |
+LL | if let Some(Foo::Bar {_, .. }) = foo {}
+ | ~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
| ------------------------------- the found opaque type
|
= note: expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>`
- found opaque type `impl Future<Output = [async output]>`
+ found opaque type `impl Future`
help: you need to pin and box this expression
|
LL ~ Box::pin(async {
...
LL | impl Copy for W {}
| ^^^^
+ |
+note: the `Copy` impl for `ManuallyDrop<String>` requires that `String: Copy`
+ --> $DIR/union-copy.rs:8:5
+ |
+LL | a: std::mem::ManuallyDrop<String>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error