]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #91030 - estebank:trait-bounds-are-tricky-2, r=oli-obk
authorbors <bors@rust-lang.org>
Thu, 24 Mar 2022 10:24:54 +0000 (10:24 +0000)
committerbors <bors@rust-lang.org>
Thu, 24 Mar 2022 10:24:54 +0000 (10:24 +0000)
Properly track `ImplObligations`

Instead of probing for all possible `impl`s that could have caused an
`ImplObligation`, keep track of its `DefId` and obligation spans for
accurate error reporting.

Follow to #89580. Addresses #89418.

47 files changed:
.gitmodules
Cargo.lock
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_middle/Cargo.toml
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_trait_selection/src/traits/misc.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_traits/Cargo.toml
compiler/rustc_traits/src/chalk/db.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/coherence/builtin.rs
library/alloc/src/collections/binary_heap.rs
library/alloc/src/vec/in_place_collect.rs [new file with mode: 0644]
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/mod.rs
library/alloc/src/vec/source_iter_marker.rs [deleted file]
library/core/src/iter/adapters/mod.rs
library/core/src/iter/traits/marker.rs
src/llvm-project
src/test/rustdoc/auto-trait-not-send.rs [new file with mode: 0644]
src/test/ui/async-await/async-block-control-flow-static-semantics.rs
src/test/ui/async-await/async-block-control-flow-static-semantics.stderr
src/test/ui/async-await/generator-desc.stderr
src/test/ui/async-await/issue-67252-unnamed-future.stderr
src/test/ui/async-await/issue-68112.stderr
src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr
src/test/ui/async-await/partial-drop-partial-reinit.stderr
src/test/ui/chalkify/bugs/async.stderr
src/test/ui/coherence/deep-bad-copy-reason.rs [new file with mode: 0644]
src/test/ui/coherence/deep-bad-copy-reason.stderr [new file with mode: 0644]
src/test/ui/consts/const-deref-ptr.stderr
src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
src/test/ui/consts/offset_ub.stderr
src/test/ui/error-codes/E0396-fixed.stderr
src/test/ui/generic-associated-types/bugs/issue-89008.stderr
src/test/ui/impl-trait/issue-55872-2.rs
src/test/ui/impl-trait/issue-55872-2.stderr
src/test/ui/impl-trait/issues/issue-78722.stderr
src/test/ui/pattern/non-structural-match-types.stderr
src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs [new file with mode: 0644]
src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr [new file with mode: 0644]
src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
src/test/ui/union/union-copy.stderr

index 9f54ed5bdab6d3abf747a47bc63c1931d10ce862..21bce3c7fa06b410d50b1157db2e2f3706235897 100644 (file)
@@ -34,7 +34,7 @@
 [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
index 48518008b7d45f77f5cf6a581023f29b580e5f9a..80f0a0b8b5ba3c3464ac08440d37c6541b3cf4d0 100644 (file)
@@ -515,9 +515,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[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",
@@ -527,9 +527,9 @@ dependencies = [
 
 [[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",
@@ -540,9 +540,9 @@ dependencies = [
 
 [[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",
@@ -551,9 +551,9 @@ dependencies = [
 
 [[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",
index 6397fcaaf8d10844823f6990034488f4eeb25173..871b7578abdc31e9bc3c358ff2bfd922299f9359 100644 (file)
@@ -427,22 +427,12 @@ fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
             }
         }
 
-        // 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 {
index b1334410237e769c2cd4b2816bd8159dc5e4fd69..9cfc5f5b444dfe9bcf199c3a679aa4e780b3df8f 100644 (file)
@@ -29,7 +29,7 @@ rustc_index = { path = "../rustc_index" }
 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" }
index a575f27ad3860206028497b52a38ec2ea2928d50..fa2dad5ce25f054b05067cfdb7c3def2c772a9c8 100644 (file)
@@ -41,6 +41,7 @@
 #![feature(new_uninit)]
 #![feature(nll)]
 #![feature(once_cell)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
index 00cb9907d95a5dae0aebd50fa3f6e2cced010ef1..5cfd9a5edfb19433adc7f512d26c6beff547ed09 100644 (file)
@@ -896,44 +896,48 @@ fn pretty_print_opaque_impl_type(
             );
 
             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;
index 08308253ced5f15ef837f53e73bd1be6653318b1..b83b0bf1ca52eea50331e7aa1f89d254b47c7c5c 100644 (file)
@@ -11,7 +11,7 @@
 
 #[derive(Clone)]
 pub enum CopyImplementationError<'tcx> {
-    InfrigingFields(Vec<&'tcx ty::FieldDef>),
+    InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>),
     NotAnAdt,
     HasDestructor,
 }
@@ -67,7 +67,7 @@ pub fn can_type_implement_copy<'tcx>(
                 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) => {
index c15afa33d2b982d10f117b6b1c4aab4675a103cc..3a5bca492965e939110754549917a0af72d5c9a8 100644 (file)
@@ -1266,7 +1266,7 @@ fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
         // 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;
         }
 
@@ -1283,7 +1283,7 @@ fn check_candidate_cache(
         // 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();
index 25f228c78903181197beb7765456177f287e5a91..67f878df31cb545bae51629fb464773c91f13402 100644 (file)
@@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" }
 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" }
index 9b85242e90a71ff5a8c6487c1f0314522dd6d284..6424b907478764ce6698c23112d3234732a1485d 100644 (file)
@@ -100,6 +100,8 @@ fn trait_datum(
         &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);
 
@@ -119,25 +121,27 @@ fn trait_datum(
 
         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
         };
@@ -232,6 +236,28 @@ fn adt_repr(
         })
     }
 
+    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>>,
@@ -540,6 +566,7 @@ fn well_known_trait_id(
             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)
     }
index c16be38d5fc3d2c5f86a3bf701a8d68cd3ff74a6..1c4fbbbb9bfaf8a71882a6009153043a650ab5c2 100644 (file)
@@ -17,7 +17,7 @@
 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};
@@ -1275,7 +1275,9 @@ fn check_struct_pat_fields(
             .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,
index ef59df0dc88f3556341be2ee33d131a481aa2989..3135e9996ab8b8a7dc798dd604ac8ed09c7bfda3 100644 (file)
@@ -91,8 +91,40 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                 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();
         }
index e6c3d38dab3a29603ba1e54c30f9e72c0e7d1f0c..ef5bef0253a569b2cbcc60d277a1b3ad8217d55c 100644 (file)
 
 use crate::collections::TryReserveError;
 use crate::slice;
-use crate::vec::{self, AsIntoIter, Vec};
+use crate::vec::{self, AsVecIntoIter, Vec};
 
 use super::SpecExtend;
 
@@ -1401,6 +1401,8 @@ fn is_empty(&self) -> bool {
 #[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> {
@@ -1416,7 +1418,7 @@ unsafe fn as_inner(&mut self) -> &mut Self::Source {
 #[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> {
diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs
new file mode 100644 (file)
index 0000000..282af8c
--- /dev/null
@@ -0,0 +1,302 @@
+//! 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>;
+}
index f985fb78465b9a459ce72547e61123a521c793cc..f17b8d71b3a1a23815d56e7fc15c3187d3a602cc 100644 (file)
@@ -1,3 +1,5 @@
+#[cfg(not(no_global_oom_handling))]
+use super::AsVecIntoIter;
 use crate::alloc::{Allocator, Global};
 use crate::raw_vec::RawVec;
 use core::fmt;
@@ -97,6 +99,9 @@ fn as_raw_mut_slice(&mut self) -> *mut [T] {
     /// (&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();
@@ -323,6 +328,8 @@ fn drop(&mut self) {
     }
 }
 
+// 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> {}
@@ -338,14 +345,8 @@ unsafe fn as_inner(&mut self) -> &mut Self::Source {
     }
 }
 
-// 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> {
index 5131168db0c82bb972889c2dc630fd5bf3405786..9a66e69bdc0615e7a6191d38370617802bb7b12d 100644 (file)
@@ -96,7 +96,7 @@
 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;
 
diff --git a/library/alloc/src/vec/source_iter_marker.rs b/library/alloc/src/vec/source_iter_marker.rs
deleted file mode 100644 (file)
index 6e78534..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-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
-    }
-}
index d82fde4752020226796f4046a1e9a63d2280f952..4500b44b7e9aff39ccd2589d1cd0f8f7c68c23d1 100644 (file)
 /// 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:
index 844459d77cd9661691bfc19ad944131b39f6ac3a..da753745740d70cfd376f46f747a9b4bd6810f0e 100644 (file)
@@ -51,6 +51,10 @@ unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {}
 /// 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
index c8eccf626fb5bb851b2ade93af8851ca1523807f..9168e236c548d1d0e9938ee6dd4cdbd308fdfd72 160000 (submodule)
@@ -1 +1 @@
-Subproject commit c8eccf626fb5bb851b2ade93af8851ca1523807f
+Subproject commit 9168e236c548d1d0e9938ee6dd4cdbd308fdfd72
diff --git a/src/test/rustdoc/auto-trait-not-send.rs b/src/test/rustdoc/auto-trait-not-send.rs
new file mode 100644 (file)
index 0000000..7bd4f6d
--- /dev/null
@@ -0,0 +1,8 @@
+#![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 {}
index e3832767203bbb6c5845b92ffbfc456d5ee71a87..f6c6f90a39378ad316b5ab9dc3915914b2094f88 100644 (file)
@@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 {
         return 0u8;
     };
     let _: &dyn Future<Output = ()> = &block;
-    //~^ 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() {
index fe864c65b7cf24ca510d7366305295ad7dc021a0..919904ce3b6a2fd64d19593e47a6288b29531d10 100644 (file)
@@ -31,7 +31,7 @@ LL | |
 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 = ()> = &block;
@@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 {
    |    |
    |    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 = ()> = &block;
index 4a45d8d2a942344a55427e35341450aec65e3478..79834ed7ec1a8fb08d64c5cbdbba08c9a13536ad 100644 (file)
@@ -46,8 +46,8 @@ LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
    |                                           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
 
index f32e074d75d620a1656a053b5c2745b79e677a79..19b90f1d878c71ef92d1675d684bd33c39f39a7f 100644 (file)
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 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
    |
index a8c2ebe12fa1837eff54e5529e839d9cb079fec7..9682a7055e93c4fd16fdd7748c7e87d1853553ea 100644 (file)
@@ -44,13 +44,13 @@ LL |     require_send(send_fut);
    = 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
    |
index b4d2006480390302ff4c02886bf3cfcdae3fc3dc..cf023bd0f9705f6a223ada47cbe5045b417b1676 100644 (file)
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 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
    |
index 2097642eb24abb5d6d9fc91939c589e281f5d1e7..a83b1d660c34cfb093860520095068a5e83ca7e6 100644 (file)
@@ -14,7 +14,7 @@ LL | async fn foo() {
    = 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
index 7a86561bcb9ce14728c2742aeb3bcdf9bbb69ba8..3d62f059f37cdbc6e29b0081c36eaf676dda7eee 100644 (file)
@@ -28,7 +28,7 @@ note: required by a bound in `from_generator`
 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 {
diff --git a/src/test/ui/coherence/deep-bad-copy-reason.rs b/src/test/ui/coherence/deep-bad-copy-reason.rs
new file mode 100644 (file)
index 0000000..80bbe38
--- /dev/null
@@ -0,0 +1,40 @@
+#![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, ()>>();
+}
diff --git a/src/test/ui/coherence/deep-bad-copy-reason.stderr b/src/test/ui/coherence/deep-bad-copy-reason.stderr
new file mode 100644 (file)
index 0000000..295538c
--- /dev/null
@@ -0,0 +1,18 @@
+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`.
index 316843889c683ae765112752fe4dfa9cc8d89acd..7606afdc4ff6c7fcb0b96e66aae6c475c3f4fd6c 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer
   --> $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
 
index 44fa437806b15b325c12bbbe60698c4e4cb5a87b..df8a80be72cb5dd80ec2ffc5f0ae38875799b183 100644 (file)
@@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed
   --> $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
 
index 2a489e8b69c8f70a7fe2a9b8c327cd9289ae7ac4..f8c9dca566b93975278849a26b0279f401ccf64d 100644 (file)
@@ -296,7 +296,7 @@ error[E0080]: could not evaluate static initializer
   --> $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
index ff850d2dbe9a0aa2cb072ade07eefda59c98d110..ded007ce2813979b39d47cf5674c39998867cbbe 100644 (file)
@@ -296,7 +296,7 @@ error[E0080]: could not evaluate static initializer
   --> $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
index 7d6716787aad5513cd25e51a7f4431a5182afb4f..9c1733e827d1963e9b5efe9850fb7c8f15f5e584 100644 (file)
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 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();
index 237950a30e841ba7fc56eb040446d91cf9775354..e774e38931377953bd97bcc48ad787dc59fbd862 100644 (file)
@@ -130,7 +130,7 @@ error[E0080]: evaluation of constant value failed
 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
@@ -158,7 +158,7 @@ error[E0080]: evaluation of constant value failed
 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
index 91997fcf0f901c66fe733d8a7246832cf3182b65..3eb291f0f7014b654f4c5ea926f8ba2aed7b2136 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $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
 
index c2687ca540153c7bcc87aa5e8cea8788b130e023..3e607d4004e8510faee45646dcaba96535e78ce2 100644 (file)
@@ -1,4 +1,4 @@
-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>;
index 17a6a85787442cf8489e2bb712af3a57c4362ac6..1841d7b3d372d6cdc2067a6760a540313227d8e2 100644 (file)
@@ -12,7 +12,7 @@ impl<S> Bar for S {
     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 {}
     }
 }
index b76b564dfb139352cd83be0a07b8d560c69b0d0d..76122e60c4cb6eb5d952811a6b57e669c788bb89 100644 (file)
@@ -1,8 +1,8 @@
-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
index 130678de2370cd47ed6978b7c50ef91a15a443d9..86bde9a0cddab967e843d72c87f133d05165caef 100644 (file)
@@ -15,7 +15,7 @@ LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
    |                                           ------------------------------- 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
index 31168e29eb82fc583e800d035bd4e2d329c527ed..91fed81eaeff6927e99aada93a1603a4ade43b93 100644 (file)
@@ -4,7 +4,7 @@ error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:22]` cannot be used
 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 {} } => {},
diff --git a/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs b/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs
new file mode 100644 (file)
index 0000000..c30b8a1
--- /dev/null
@@ -0,0 +1,12 @@
+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]
+}
diff --git a/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr b/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr
new file mode 100644 (file)
index 0000000..16f7514
--- /dev/null
@@ -0,0 +1,24 @@
+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`.
index 550ed4b03b03937d2fe73fbff637f155ea662c48..7ef4895249cec7218f08a5836b9dd9edc0d817c2 100644 (file)
@@ -81,7 +81,7 @@ LL |   pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
    |                                             ------------------------------- 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 {
index 0f47bae7f0fede41ce85502fd44f2445c782ba57..279808dd55bb4dea18fbaa79ccbbcc66d351fb9b 100644 (file)
@@ -6,6 +6,12 @@ LL |     a: std::mem::ManuallyDrop<String>
 ...
 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