From 2c0bc9444eea8677a307c2440b2f206911d5bbbe Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 13 Mar 2022 13:39:20 +0800 Subject: [PATCH 01/14] implement Copy/Clone for generators --- compiler/rustc_mir_transform/src/shim.rs | 129 +++++++++++++----- .../src/traits/select/mod.rs | 36 ++++- compiler/rustc_ty_utils/src/instance.rs | 5 +- 3 files changed, 135 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 2b21fbe0a617f..0be2cbb2094a7 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -4,7 +4,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, GeneratorSubsts}; use rustc_target::abi::VariantIdx; use rustc_index::vec::{Idx, IndexVec}; @@ -323,6 +323,9 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys()) } ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()), + ty::Generator(gen_def_id, substs, hir::Movability::Movable) => { + builder.generator_shim(dest, src, *gen_def_id, substs.as_generator()) + } _ => bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty), }; @@ -388,7 +391,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { /// offset=0 will give you the index of the next BasicBlock, /// offset=1 will give the index of the next-to-next block, /// offset=-1 will give you the index of the last-created block - fn block_index_offset(&mut self, offset: usize) -> BasicBlock { + fn block_index_offset(&self, offset: usize) -> BasicBlock { BasicBlock::new(self.blocks.len() + offset) } @@ -461,49 +464,111 @@ impl<'tcx> CloneShimBuilder<'tcx> { ); } - fn tuple_like_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I) + fn clone_fields( + &mut self, + dest: Place<'tcx>, + src: Place<'tcx>, + target: BasicBlock, + mut unwind: BasicBlock, + tys: I, + ) -> BasicBlock where I: IntoIterator>, { - let mut previous_field = None; for (i, ity) in tys.into_iter().enumerate() { let field = Field::new(i); let src_field = self.tcx.mk_place_field(src, field, ity); let dest_field = self.tcx.mk_place_field(dest, field, ity); - // #(2i + 1) is the cleanup block for the previous clone operation - let cleanup_block = self.block_index_offset(1); - // #(2i + 2) is the next cloning block - // (or the Return terminator if this is the last block) + let next_unwind = self.block_index_offset(1); let next_block = self.block_index_offset(2); + self.make_clone_call(dest_field, src_field, ity, next_block, unwind); + self.block( + vec![], + TerminatorKind::Drop { + place: dest_field, + target: unwind, + unwind: None, + }, + true, + ); + unwind = next_unwind; + } + self.block( + vec![], + TerminatorKind::Goto { target }, + false, + ); + unwind + } - // BB #(2i) - // `dest.i = Clone::clone(&src.i);` - // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens. - self.make_clone_call(dest_field, src_field, ity, next_block, cleanup_block); - - // BB #(2i + 1) (cleanup) - if let Some((previous_field, previous_cleanup)) = previous_field.take() { - // Drop previous field and goto previous cleanup block. - self.block( - vec![], - TerminatorKind::Drop { - place: previous_field, - target: previous_cleanup, - unwind: None, - }, - true, - ); - } else { - // Nothing to drop, just resume. - self.block(vec![], TerminatorKind::Resume, true); - } + fn tuple_like_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I) + where + I: IntoIterator>, + { + self.block( + vec![], + TerminatorKind::Goto { target: self.block_index_offset(3) }, + false, + ); + let unwind = self.block(vec![], TerminatorKind::Resume, true); + let target = self.block(vec![], TerminatorKind::Return, false); - previous_field = Some((dest_field, cleanup_block)); - } + let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, tys); + } - self.block(vec![], TerminatorKind::Return, false); + fn generator_shim( + &mut self, + dest: Place<'tcx>, + src: Place<'tcx>, + gen_def_id: DefId, + substs: GeneratorSubsts<'tcx>, + ) { + self.block( + vec![], + TerminatorKind::Goto { target: self.block_index_offset(3) }, + false, + ); + let unwind = self.block(vec![], TerminatorKind::Resume, true); + // This will get overwritten with a switch once we know the target blocks + let switch = self.block(vec![], TerminatorKind::Unreachable, false); + let unwind = self.clone_fields(dest, src, switch, unwind, substs.upvar_tys()); + let target = self.block(vec![], TerminatorKind::Return, false); + let unreachable = self.block(vec![], TerminatorKind::Unreachable, false); + let mut cases = Vec::with_capacity(substs.state_tys(gen_def_id, self.tcx).count()); + for (index, state_tys) in substs.state_tys(gen_def_id, self.tcx).enumerate() { + let variant_index = VariantIdx::new(index); + let dest = self.tcx.mk_place_downcast_unnamed(dest, variant_index); + let src = self.tcx.mk_place_downcast_unnamed(src, variant_index); + let start_block = self.block_index_offset(0); + let clone_block = self.block_index_offset(1); + cases.push((index as u128, start_block)); + self.block( + vec![self.make_statement(StatementKind::SetDiscriminant { + place: Box::new(Place::return_place()), + variant_index, + })], + TerminatorKind::Goto { target: clone_block }, + false, + ); + let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, state_tys); + } + let discr_ty = substs.discr_ty(self.tcx); + let temp = self.make_place(Mutability::Mut, discr_ty); + let rvalue = Rvalue::Discriminant(src); + let statement = self.make_statement(StatementKind::Assign(Box::new((temp, rvalue)))); + match &mut self.blocks[switch] { + BasicBlockData { statements, terminator: Some(Terminator { kind, .. }), .. } => { + statements.push(statement); + *kind = TerminatorKind::SwitchInt { + discr: Operand::Move(temp), + switch_ty: discr_ty, + targets: SwitchTargets::new(cases.into_iter(), unreachable), + }; + }, + BasicBlockData { terminator: None, .. } => unreachable!(), + } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5da8cfab0b13b..592c6c8e05564 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1928,8 +1928,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Dynamic(..) | ty::Str | ty::Slice(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) + | ty::Generator(_, _, hir::Movability::Static) | ty::Foreign(..) | ty::Ref(_, _, hir::Mutability::Mut) => None, @@ -1938,6 +1937,39 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Where(obligation.predicate.rebind(tys.iter().collect())) } + ty::Generator(_, substs, hir::Movability::Movable) => { + let resolved_upvars = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); + let resolved_witness = self.infcx.shallow_resolve(substs.as_generator().witness()); + if { + matches!(resolved_upvars.kind(), ty::Infer(ty::TyVar(_))) || + matches!(resolved_witness.kind(), ty::Infer(ty::TyVar(_))) + } { + // Not yet resolved. + Ambiguous + } else { + let mut all = substs.as_generator().upvar_tys().collect::>(); + all.push(substs.as_generator().witness()); + Where(obligation.predicate.rebind(all)) + } + } + + ty::GeneratorWitness(binder) => { + let tys = binder.no_bound_vars().unwrap(); + let mut iter = tys.iter(); + loop { + let ty = match iter.next() { + Some(ty) => ty, + Option::None => { + break Where(obligation.predicate.rebind(tys.to_vec())) + }, + }; + let resolved = self.infcx.shallow_resolve(ty); + if matches!(resolved.kind(), ty::Infer(ty::TyVar(_))) { + break Ambiguous; + } + } + } + ty::Closure(_, substs) => { // (*) binder moved here let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index b55302de2a733..87eca3d388b43 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -263,7 +263,10 @@ fn resolve_associated_item<'tcx>( let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env); match self_ty.kind() { _ if is_copy => (), - ty::Closure(..) | ty::Tuple(..) => {} + ty::Generator(..) | + ty::GeneratorWitness(..) | + ty::Closure(..) | + ty::Tuple(..) => {}, _ => return Ok(None), }; From 0228c073e07bc36ab4dbb88ab7f3cbdf00832d59 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 13 Mar 2022 14:41:44 +0800 Subject: [PATCH 02/14] add generator_clone feature gate --- compiler/rustc_feature/src/active.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + .../src/traits/select/mod.rs | 56 +++++++++++-------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 98258834bd589..0168587fbce44 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -396,6 +396,8 @@ declare_features! ( (active, fn_align, "1.53.0", Some(82232), None), /// Allows defining generators. (active, generators, "1.21.0", Some(43122), None), + /// Allows generators to be cloned. + (active, generator_clone, "1.60.0", None, None), /// Infer generic args for both consts and types. (active, generic_arg_infer, "1.55.0", Some(85077), None), /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9c3d99deae06d..5bddcd3481974 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -763,6 +763,7 @@ symbols! { gen_future, gen_kill, generator, + generator_clone, generator_state, generators, generic_arg_infer, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 592c6c8e05564..0e7483847e3c4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1938,35 +1938,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::Generator(_, substs, hir::Movability::Movable) => { - let resolved_upvars = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); - let resolved_witness = self.infcx.shallow_resolve(substs.as_generator().witness()); - if { - matches!(resolved_upvars.kind(), ty::Infer(ty::TyVar(_))) || - matches!(resolved_witness.kind(), ty::Infer(ty::TyVar(_))) - } { - // Not yet resolved. - Ambiguous + if self.tcx().features().generator_clone { + let resolved_upvars = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); + let resolved_witness = self.infcx.shallow_resolve(substs.as_generator().witness()); + if { + matches!(resolved_upvars.kind(), ty::Infer(ty::TyVar(_))) || + matches!(resolved_witness.kind(), ty::Infer(ty::TyVar(_))) + } { + // Not yet resolved. + Ambiguous + } else { + let mut all = substs.as_generator().upvar_tys().collect::>(); + all.push(substs.as_generator().witness()); + Where(obligation.predicate.rebind(all)) + } } else { - let mut all = substs.as_generator().upvar_tys().collect::>(); - all.push(substs.as_generator().witness()); - Where(obligation.predicate.rebind(all)) + None } } ty::GeneratorWitness(binder) => { - let tys = binder.no_bound_vars().unwrap(); - let mut iter = tys.iter(); - loop { - let ty = match iter.next() { - Some(ty) => ty, - Option::None => { - break Where(obligation.predicate.rebind(tys.to_vec())) - }, - }; - let resolved = self.infcx.shallow_resolve(ty); - if matches!(resolved.kind(), ty::Infer(ty::TyVar(_))) { - break Ambiguous; - } + match binder.no_bound_vars() { + Some(tys) => { + let mut iter = tys.iter(); + loop { + let ty = match iter.next() { + Some(ty) => ty, + Option::None => { + break Where(obligation.predicate.rebind(tys.to_vec())) + }, + }; + let resolved = self.infcx.shallow_resolve(ty); + if matches!(resolved.kind(), ty::Infer(ty::TyVar(_))) { + break Ambiguous; + } + } + }, + Option::None => None, } } From a5cb3cca5ed28ccf865e7dbe74262e9744427bbe Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Mon, 14 Mar 2022 10:24:10 +0800 Subject: [PATCH 03/14] loosen restriction on when GeneratorWitness: Clone --- .../src/traits/select/mod.rs | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 0e7483847e3c4..5f9f9847b2382 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1958,23 +1958,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::GeneratorWitness(binder) => { - match binder.no_bound_vars() { - Some(tys) => { - let mut iter = tys.iter(); - loop { - let ty = match iter.next() { - Some(ty) => ty, - Option::None => { - break Where(obligation.predicate.rebind(tys.to_vec())) - }, - }; - let resolved = self.infcx.shallow_resolve(ty); - if matches!(resolved.kind(), ty::Infer(ty::TyVar(_))) { - break Ambiguous; - } - } - }, - Option::None => None, + let tys = self.tcx().erase_late_bound_regions(binder); + let mut iter = tys.iter(); + loop { + let ty = match iter.next() { + Some(ty) => ty, + Option::None => { + break Where(obligation.predicate.rebind(tys.to_vec())) + }, + }; + let resolved = self.infcx.shallow_resolve(ty); + if matches!(resolved.kind(), ty::Infer(ty::TyVar(_))) { + break Ambiguous; + } } } From c1f1bc6e8ff357bbff604d6db3d220bf29900179 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Fri, 18 Mar 2022 14:24:54 +0800 Subject: [PATCH 04/14] fix GeneratorWitness: Clone check --- .../src/traits/select/mod.rs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5f9f9847b2382..3499c64a1db0a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1958,18 +1958,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::GeneratorWitness(binder) => { - let tys = self.tcx().erase_late_bound_regions(binder); - let mut iter = tys.iter(); + let witness_tys = binder.skip_binder(); + let mut iter = witness_tys.iter(); loop { - let ty = match iter.next() { - Some(ty) => ty, + match iter.next() { + Some(witness_ty) => { + let resolved = self.infcx.shallow_resolve(witness_ty); + if matches!(resolved.kind(), ty::Infer(ty::TyVar(_))) { + break Ambiguous; + } + }, Option::None => { - break Where(obligation.predicate.rebind(tys.to_vec())) + // (*) binder moved here + let all_vars = self.tcx().mk_bound_variable_kinds( + obligation.predicate.bound_vars().iter().chain(binder.bound_vars().iter()) + ); + break Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars)); }, - }; - let resolved = self.infcx.shallow_resolve(ty); - if matches!(resolved.kind(), ty::Infer(ty::TyVar(_))) { - break Ambiguous; } } } From 8aa30dd3cb18e4e6a1a5940addd8e744ab8d3eef Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Mon, 21 Mar 2022 12:56:22 +0800 Subject: [PATCH 05/14] move generator_clone feature definition Move it to the list of features with no tracking issue, since it has no tracking issue. --- compiler/rustc_feature/src/active.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 0168587fbce44..0000eabb66587 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -152,6 +152,8 @@ declare_features! ( (active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None), /// Allows identifying the `compiler_builtins` crate. (active, compiler_builtins, "1.13.0", None, None), + /// Allows generators to be cloned. + (active, generator_clone, "1.60.0", None, None), /// Outputs useful `assert!` messages (active, generic_assert, "1.63.0", None, None), /// Allows using the `rust-intrinsic`'s "ABI". @@ -396,8 +398,6 @@ declare_features! ( (active, fn_align, "1.53.0", Some(82232), None), /// Allows defining generators. (active, generators, "1.21.0", Some(43122), None), - /// Allows generators to be cloned. - (active, generator_clone, "1.60.0", None, None), /// Infer generic args for both consts and types. (active, generic_arg_infer, "1.55.0", Some(85077), None), /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). From 22f4bbb20f373b0c3d47788f58c95d60656918f2 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Mon, 21 Mar 2022 12:57:06 +0800 Subject: [PATCH 06/14] Apply formatting fixes --- compiler/rustc_mir_transform/src/shim.rs | 28 ++++--------------- .../src/traits/select/mod.rs | 25 +++++++++++------ compiler/rustc_ty_utils/src/instance.rs | 8 +++--- 3 files changed, 27 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 0be2cbb2094a7..3a43932f50cb5 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -4,7 +4,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, GeneratorSubsts}; +use rustc_middle::ty::{self, EarlyBinder, GeneratorSubsts, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; use rustc_index::vec::{Idx, IndexVec}; @@ -486,20 +486,12 @@ impl<'tcx> CloneShimBuilder<'tcx> { self.make_clone_call(dest_field, src_field, ity, next_block, unwind); self.block( vec![], - TerminatorKind::Drop { - place: dest_field, - target: unwind, - unwind: None, - }, + TerminatorKind::Drop { place: dest_field, target: unwind, unwind: None }, true, ); unwind = next_unwind; } - self.block( - vec![], - TerminatorKind::Goto { target }, - false, - ); + self.block(vec![], TerminatorKind::Goto { target }, false); unwind } @@ -507,11 +499,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { where I: IntoIterator>, { - self.block( - vec![], - TerminatorKind::Goto { target: self.block_index_offset(3) }, - false, - ); + self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false); let unwind = self.block(vec![], TerminatorKind::Resume, true); let target = self.block(vec![], TerminatorKind::Return, false); @@ -525,11 +513,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { gen_def_id: DefId, substs: GeneratorSubsts<'tcx>, ) { - self.block( - vec![], - TerminatorKind::Goto { target: self.block_index_offset(3) }, - false, - ); + self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false); let unwind = self.block(vec![], TerminatorKind::Resume, true); // This will get overwritten with a switch once we know the target blocks let switch = self.block(vec![], TerminatorKind::Unreachable, false); @@ -566,7 +550,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { switch_ty: discr_ty, targets: SwitchTargets::new(cases.into_iter(), unreachable), }; - }, + } BasicBlockData { terminator: None, .. } => unreachable!(), } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3499c64a1db0a..b5e7a8b562ea6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1939,11 +1939,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Generator(_, substs, hir::Movability::Movable) => { if self.tcx().features().generator_clone { - let resolved_upvars = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); - let resolved_witness = self.infcx.shallow_resolve(substs.as_generator().witness()); + let resolved_upvars = + self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); + let resolved_witness = + self.infcx.shallow_resolve(substs.as_generator().witness()); if { - matches!(resolved_upvars.kind(), ty::Infer(ty::TyVar(_))) || - matches!(resolved_witness.kind(), ty::Infer(ty::TyVar(_))) + matches!(resolved_upvars.kind(), ty::Infer(ty::TyVar(_))) + || matches!(resolved_witness.kind(), ty::Infer(ty::TyVar(_))) } { // Not yet resolved. Ambiguous @@ -1967,14 +1969,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if matches!(resolved.kind(), ty::Infer(ty::TyVar(_))) { break Ambiguous; } - }, + } Option::None => { // (*) binder moved here let all_vars = self.tcx().mk_bound_variable_kinds( - obligation.predicate.bound_vars().iter().chain(binder.bound_vars().iter()) + obligation + .predicate + .bound_vars() + .iter() + .chain(binder.bound_vars().iter()), ); - break Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars)); - }, + break Where(ty::Binder::bind_with_vars( + witness_tys.to_vec(), + all_vars, + )); + } } } } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 87eca3d388b43..edf47403c0d65 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -263,10 +263,10 @@ fn resolve_associated_item<'tcx>( let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env); match self_ty.kind() { _ if is_copy => (), - ty::Generator(..) | - ty::GeneratorWitness(..) | - ty::Closure(..) | - ty::Tuple(..) => {}, + ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Closure(..) + | ty::Tuple(..) => {} _ => return Ok(None), }; From fa6dbcf20da11e3af4d8d6494e58d1b5a60b39ab Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Mon, 21 Mar 2022 13:57:10 +0800 Subject: [PATCH 07/14] Add feature gate tests for generator_clone --- src/test/ui/generator/clone-impl-static.rs | 17 ++ .../ui/generator/clone-impl-static.stderr | 31 ++++ src/test/ui/generator/clone-impl.rs | 73 ++++++++ src/test/ui/generator/clone-impl.stderr | 163 ++++++++++++++++++ 4 files changed, 284 insertions(+) create mode 100644 src/test/ui/generator/clone-impl-static.rs create mode 100644 src/test/ui/generator/clone-impl-static.stderr create mode 100644 src/test/ui/generator/clone-impl.rs create mode 100644 src/test/ui/generator/clone-impl.stderr diff --git a/src/test/ui/generator/clone-impl-static.rs b/src/test/ui/generator/clone-impl-static.rs new file mode 100644 index 0000000000000..55ed0f281e050 --- /dev/null +++ b/src/test/ui/generator/clone-impl-static.rs @@ -0,0 +1,17 @@ +// gate-test-generator_clone +// Verifies that static generators cannot be cloned/copied. + +#![feature(generators, generator_clone)] + +fn main() { + let gen = static move || { + yield; + }; + check_copy(&gen); + //~^ ERROR Copy` is not satisfied + check_clone(&gen); + //~^ ERROR Clone` is not satisfied +} + +fn check_copy(_x: &T) {} +fn check_clone(_x: &T) {} diff --git a/src/test/ui/generator/clone-impl-static.stderr b/src/test/ui/generator/clone-impl-static.stderr new file mode 100644 index 0000000000000..cc15c4afd7793 --- /dev/null +++ b/src/test/ui/generator/clone-impl-static.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `[static generator@$DIR/clone-impl-static.rs:7:15: 9:6]: Copy` is not satisfied + --> $DIR/clone-impl-static.rs:10:16 + | +LL | check_copy(&gen); + | ---------- ^^^^ the trait `Copy` is not implemented for `[static generator@$DIR/clone-impl-static.rs:7:15: 9:6]` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_copy` + --> $DIR/clone-impl-static.rs:16:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `[static generator@$DIR/clone-impl-static.rs:7:15: 9:6]: Clone` is not satisfied + --> $DIR/clone-impl-static.rs:12:17 + | +LL | check_clone(&gen); + | ----------- ^^^^ the trait `Clone` is not implemented for `[static generator@$DIR/clone-impl-static.rs:7:15: 9:6]` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_clone` + --> $DIR/clone-impl-static.rs:17:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generator/clone-impl.rs b/src/test/ui/generator/clone-impl.rs new file mode 100644 index 0000000000000..cbfd65a530998 --- /dev/null +++ b/src/test/ui/generator/clone-impl.rs @@ -0,0 +1,73 @@ +// gate-test-generator_clone +// Verifies that non-static generators can be cloned/copied if all their upvars and locals held +// across awaits can be cloned/copied. + +#![feature(generators, generator_clone)] + +struct NonClone; + +fn main() { + let copyable: u32 = 123; + let clonable_0: Vec = Vec::new(); + let clonable_1: Vec = Vec::new(); + let non_clonable: NonClone = NonClone; + + let gen_copy_0 = move || { + yield; + drop(copyable); + }; + check_copy(&gen_copy_0); + check_clone(&gen_copy_0); + let gen_copy_1 = move || { + /* + let v = vec!['a']; + let n = NonClone; + drop(v); + drop(n); + */ + yield; + let v = vec!['a']; + let n = NonClone; + drop(n); + drop(copyable); + }; + check_copy(&gen_copy_1); + check_clone(&gen_copy_1); + let gen_clone_0 = move || { + let v = vec!['a']; + yield; + drop(v); + drop(clonable_0); + }; + check_copy(&gen_clone_0); + //~^ ERROR the trait bound `Vec: Copy` is not satisfied + //~| ERROR the trait bound `Vec: Copy` is not satisfied + check_clone(&gen_clone_0); + let gen_clone_1 = move || { + let v = vec!['a']; + /* + let n = NonClone; + drop(n); + */ + yield; + let n = NonClone; + drop(n); + drop(v); + drop(clonable_1); + }; + check_copy(&gen_clone_1); + //~^ ERROR the trait bound `Vec: Copy` is not satisfied + //~| ERROR the trait bound `Vec: Copy` is not satisfied + check_clone(&gen_clone_1); + let gen_non_clone = move || { + yield; + drop(non_clonable); + }; + check_copy(&gen_non_clone); + //~^ ERROR the trait bound `NonClone: Copy` is not satisfied + check_clone(&gen_non_clone); + //~^ ERROR the trait bound `NonClone: Clone` is not satisfied +} + +fn check_copy(_x: &T) {} +fn check_clone(_x: &T) {} diff --git a/src/test/ui/generator/clone-impl.stderr b/src/test/ui/generator/clone-impl.stderr new file mode 100644 index 0000000000000..407927fb3bc24 --- /dev/null +++ b/src/test/ui/generator/clone-impl.stderr @@ -0,0 +1,163 @@ +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:36:23: 41:6]` + --> $DIR/clone-impl.rs:42:5 + | +LL | let gen_clone_0 = move || { + | _______________________- +LL | | let v = vec!['a']; +LL | | yield; +LL | | drop(v); +LL | | drop(clonable_0); +LL | | }; + | |_____- within this `[generator@$DIR/clone-impl.rs:36:23: 41:6]` +LL | check_copy(&gen_clone_0); + | ^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:36:23: 41:6]`, the trait `Copy` is not implemented for `Vec` + | +note: captured value does not implement `Copy` + --> $DIR/clone-impl.rs:40:14 + | +LL | drop(clonable_0); + | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` +note: required by a bound in `check_copy` + --> $DIR/clone-impl.rs:72:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:36:23: 41:6]` + --> $DIR/clone-impl.rs:42:5 + | +LL | let gen_clone_0 = move || { + | _______________________- +LL | | let v = vec!['a']; +LL | | yield; +LL | | drop(v); +LL | | drop(clonable_0); +LL | | }; + | |_____- within this `[generator@$DIR/clone-impl.rs:36:23: 41:6]` +LL | check_copy(&gen_clone_0); + | ^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:36:23: 41:6]`, the trait `Copy` is not implemented for `Vec` + | +note: generator does not implement `Copy` as this value is used across a yield + --> $DIR/clone-impl.rs:38:9 + | +LL | let v = vec!['a']; + | - has type `Vec` which does not implement `Copy` +LL | yield; + | ^^^^^ yield occurs here, with `v` maybe used later +... +LL | }; + | - `v` is later dropped here +note: required by a bound in `check_copy` + --> $DIR/clone-impl.rs:72:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:46:23: 57:6]` + --> $DIR/clone-impl.rs:58:5 + | +LL | let gen_clone_1 = move || { + | _______________________- +LL | | let v = vec!['a']; +LL | | /* +LL | | let n = NonClone; +... | +LL | | drop(clonable_1); +LL | | }; + | |_____- within this `[generator@$DIR/clone-impl.rs:46:23: 57:6]` +LL | check_copy(&gen_clone_1); + | ^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:46:23: 57:6]`, the trait `Copy` is not implemented for `Vec` + | +note: captured value does not implement `Copy` + --> $DIR/clone-impl.rs:56:14 + | +LL | drop(clonable_1); + | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` +note: required by a bound in `check_copy` + --> $DIR/clone-impl.rs:72:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:46:23: 57:6]` + --> $DIR/clone-impl.rs:58:5 + | +LL | let gen_clone_1 = move || { + | _______________________- +LL | | let v = vec!['a']; +LL | | /* +LL | | let n = NonClone; +... | +LL | | drop(clonable_1); +LL | | }; + | |_____- within this `[generator@$DIR/clone-impl.rs:46:23: 57:6]` +LL | check_copy(&gen_clone_1); + | ^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:46:23: 57:6]`, the trait `Copy` is not implemented for `Vec` + | +note: generator does not implement `Copy` as this value is used across a yield + --> $DIR/clone-impl.rs:52:9 + | +LL | let v = vec!['a']; + | - has type `Vec` which does not implement `Copy` +... +LL | yield; + | ^^^^^ yield occurs here, with `v` maybe used later +... +LL | }; + | - `v` is later dropped here +note: required by a bound in `check_copy` + --> $DIR/clone-impl.rs:72:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:62:25: 65:6]` + --> $DIR/clone-impl.rs:66:5 + | +LL | let gen_non_clone = move || { + | _________________________- +LL | | yield; +LL | | drop(non_clonable); +LL | | }; + | |_____- within this `[generator@$DIR/clone-impl.rs:62:25: 65:6]` +LL | check_copy(&gen_non_clone); + | ^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:62:25: 65:6]`, the trait `Copy` is not implemented for `NonClone` + | +note: captured value does not implement `Copy` + --> $DIR/clone-impl.rs:64:14 + | +LL | drop(non_clonable); + | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy` +note: required by a bound in `check_copy` + --> $DIR/clone-impl.rs:72:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `[generator@$DIR/clone-impl.rs:62:25: 65:6]` + --> $DIR/clone-impl.rs:68:5 + | +LL | let gen_non_clone = move || { + | _________________________- +LL | | yield; +LL | | drop(non_clonable); +LL | | }; + | |_____- within this `[generator@$DIR/clone-impl.rs:62:25: 65:6]` +... +LL | check_clone(&gen_non_clone); + | ^^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:62:25: 65:6]`, the trait `Clone` is not implemented for `NonClone` + | +note: captured value does not implement `Clone` + --> $DIR/clone-impl.rs:64:14 + | +LL | drop(non_clonable); + | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone` +note: required by a bound in `check_clone` + --> $DIR/clone-impl.rs:73:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. From 1bc9453aa8a8ec07b4a32b201612b149b762fccd Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 27 Mar 2022 15:50:40 +0800 Subject: [PATCH 08/14] Add tracking issue number to feature(generator_clone) --- compiler/rustc_feature/src/active.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 0000eabb66587..c2cc4d7923b73 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -152,8 +152,6 @@ declare_features! ( (active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None), /// Allows identifying the `compiler_builtins` crate. (active, compiler_builtins, "1.13.0", None, None), - /// Allows generators to be cloned. - (active, generator_clone, "1.60.0", None, None), /// Outputs useful `assert!` messages (active, generic_assert, "1.63.0", None, None), /// Allows using the `rust-intrinsic`'s "ABI". @@ -396,6 +394,8 @@ declare_features! ( (active, ffi_returns_twice, "1.34.0", Some(58314), None), /// Allows using `#[repr(align(...))]` on function items (active, fn_align, "1.53.0", Some(82232), None), + /// Allows generators to be cloned. + (active, generator_clone, "1.60.0", Some(95360), None), /// Allows defining generators. (active, generators, "1.21.0", Some(43122), None), /// Infer generic args for both consts and types. From 543023c249c89477a5cd9fd39d942b49c2d9d30e Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 10 Apr 2022 14:04:44 +0800 Subject: [PATCH 09/14] Add some comments to generator clone shim code --- compiler/rustc_mir_transform/src/shim.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 3a43932f50cb5..f5083438b0c05 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -475,7 +475,18 @@ impl<'tcx> CloneShimBuilder<'tcx> { where I: IntoIterator>, { + // For an iterator of length n, create 2*n + 1 blocks. for (i, ity) in tys.into_iter().enumerate() { + // Each iteration creates two blocks, referred to here as block 2*i and block 2*i + 1. + // + // Block 2*i attempts to clone the field. If successful it branches to 2*i + 2 (the + // next clone block). If unsuccessful it branches to the previous unwind block, which + // is initially the `unwind` argument passed to this function. + // + // Block 2*i + 1 is the unwind block for this iteration. It drops the cloned value + // created by block 2*i. We store this block in `unwind` so that the next clone block + // will unwind to it if cloning fails. + let field = Field::new(i); let src_field = self.tcx.mk_place_field(src, field, ity); @@ -491,6 +502,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { ); unwind = next_unwind; } + // If all clones succeed then we end up here. self.block(vec![], TerminatorKind::Goto { target }, false); unwind } From 62112f4dc1b8bb9e148a3907c15c50b9ead42c7c Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 10 Apr 2022 14:05:31 +0800 Subject: [PATCH 10/14] minor fixups as per PR feedback --- compiler/rustc_mir_transform/src/shim.rs | 5 +-- .../src/traits/select/mod.rs | 44 +++++++------------ 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index f5083438b0c05..8821362002943 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -537,10 +537,8 @@ impl<'tcx> CloneShimBuilder<'tcx> { let variant_index = VariantIdx::new(index); let dest = self.tcx.mk_place_downcast_unnamed(dest, variant_index); let src = self.tcx.mk_place_downcast_unnamed(src, variant_index); - let start_block = self.block_index_offset(0); let clone_block = self.block_index_offset(1); - cases.push((index as u128, start_block)); - self.block( + let start_block = self.block( vec![self.make_statement(StatementKind::SetDiscriminant { place: Box::new(Place::return_place()), variant_index, @@ -548,6 +546,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { TerminatorKind::Goto { target: clone_block }, false, ); + cases.push((index as u128, start_block)); let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, state_tys); } let discr_ty = substs.discr_ty(self.tcx); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b5e7a8b562ea6..3ab9b7f4083b8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1943,15 +1943,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); let resolved_witness = self.infcx.shallow_resolve(substs.as_generator().witness()); - if { - matches!(resolved_upvars.kind(), ty::Infer(ty::TyVar(_))) - || matches!(resolved_witness.kind(), ty::Infer(ty::TyVar(_))) - } { + if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() { // Not yet resolved. Ambiguous } else { - let mut all = substs.as_generator().upvar_tys().collect::>(); - all.push(substs.as_generator().witness()); + let all = substs + .as_generator() + .upvar_tys() + .chain(iter::once(substs.as_generator().witness())) + .collect::>(); Where(obligation.predicate.rebind(all)) } } else { @@ -1961,31 +1961,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::GeneratorWitness(binder) => { let witness_tys = binder.skip_binder(); - let mut iter = witness_tys.iter(); - loop { - match iter.next() { - Some(witness_ty) => { - let resolved = self.infcx.shallow_resolve(witness_ty); - if matches!(resolved.kind(), ty::Infer(ty::TyVar(_))) { - break Ambiguous; - } - } - Option::None => { - // (*) binder moved here - let all_vars = self.tcx().mk_bound_variable_kinds( - obligation - .predicate - .bound_vars() - .iter() - .chain(binder.bound_vars().iter()), - ); - break Where(ty::Binder::bind_with_vars( - witness_tys.to_vec(), - all_vars, - )); - } + for witness_ty in witness_tys.iter() { + let resolved = self.infcx.shallow_resolve(witness_ty); + if resolved.is_ty_var() { + return Ambiguous; } } + // (*) binder moved here + let all_vars = self.tcx().mk_bound_variable_kinds( + obligation.predicate.bound_vars().iter().chain(binder.bound_vars().iter()), + ); + Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars)) } ty::Closure(_, substs) => { From d9a17229dcde2366c9a3fd300682f596318192c4 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 10 Apr 2022 15:04:04 +0800 Subject: [PATCH 11/14] test async diagnostics for feature(generator_clone) --- src/test/ui/generator/clone-impl-async.rs | 71 ++++++++ src/test/ui/generator/clone-impl-async.stderr | 171 ++++++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 src/test/ui/generator/clone-impl-async.rs create mode 100644 src/test/ui/generator/clone-impl-async.stderr diff --git a/src/test/ui/generator/clone-impl-async.rs b/src/test/ui/generator/clone-impl-async.rs new file mode 100644 index 0000000000000..97cbd9d9fb599 --- /dev/null +++ b/src/test/ui/generator/clone-impl-async.rs @@ -0,0 +1,71 @@ +// edition:2021 +// gate-test-generator_clone +// Verifies that feature(generator_clone) doesn't allow async blocks to be cloned/copied. + +#![feature(generators, generator_clone)] + +use std::future::ready; + +struct NonClone; + +fn main() { + let inner_non_clone = async { + let non_clone = NonClone; + let () = ready(()).await; + drop(non_clone); + }; + check_copy(&inner_non_clone); + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied + check_clone(&inner_non_clone); + //~^ ERROR the trait bound `impl Future: Clone` is not satisfied + + let non_clone = NonClone; + let outer_non_clone = async move { + drop(non_clone); + }; + check_copy(&outer_non_clone); + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied + check_clone(&outer_non_clone); + //~^ ERROR the trait bound `impl Future: Clone` is not satisfied + + let maybe_copy_clone = async move {}; + check_copy(&maybe_copy_clone); + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied + check_clone(&maybe_copy_clone); + //~^ ERROR the trait bound `impl Future: Clone` is not satisfied + + let inner_non_clone_fn = the_inner_non_clone_fn(); + check_copy(&inner_non_clone_fn); + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied + check_clone(&inner_non_clone_fn); + //~^ ERROR the trait bound `impl Future: Clone` is not satisfied + + let outer_non_clone_fn = the_outer_non_clone_fn(NonClone); + check_copy(&outer_non_clone_fn); + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied + check_clone(&outer_non_clone_fn); + //~^ ERROR the trait bound `impl Future: Clone` is not satisfied + + let maybe_copy_clone_fn = the_maybe_copy_clone_fn(); + check_copy(&maybe_copy_clone_fn); + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied + check_clone(&maybe_copy_clone_fn); + //~^ ERROR the trait bound `impl Future: Clone` is not satisfied +} + +async fn the_inner_non_clone_fn() { + let non_clone = NonClone; + let () = ready(()).await; + drop(non_clone); +} + +async fn the_outer_non_clone_fn(non_clone: NonClone) { + let () = ready(()).await; + drop(non_clone); +} + +async fn the_maybe_copy_clone_fn() { +} + +fn check_copy(_x: &T) {} +fn check_clone(_x: &T) {} diff --git a/src/test/ui/generator/clone-impl-async.stderr b/src/test/ui/generator/clone-impl-async.stderr new file mode 100644 index 0000000000000..6246d773f35b9 --- /dev/null +++ b/src/test/ui/generator/clone-impl-async.stderr @@ -0,0 +1,171 @@ +error[E0277]: the trait bound `impl Future: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:17:16 + | +LL | check_copy(&inner_non_clone); + | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_copy` + --> $DIR/clone-impl-async.rs:70:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `impl Future: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:19:17 + | +LL | check_clone(&inner_non_clone); + | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_clone` + --> $DIR/clone-impl-async.rs:71:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error[E0277]: the trait bound `impl Future: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:26:16 + | +LL | check_copy(&outer_non_clone); + | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_copy` + --> $DIR/clone-impl-async.rs:70:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `impl Future: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:28:17 + | +LL | check_clone(&outer_non_clone); + | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_clone` + --> $DIR/clone-impl-async.rs:71:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error[E0277]: the trait bound `impl Future: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:32:16 + | +LL | check_copy(&maybe_copy_clone); + | ---------- ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_copy` + --> $DIR/clone-impl-async.rs:70:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `impl Future: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:34:17 + | +LL | check_clone(&maybe_copy_clone); + | ----------- ^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_clone` + --> $DIR/clone-impl-async.rs:71:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error[E0277]: the trait bound `impl Future: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:38:16 + | +LL | check_copy(&inner_non_clone_fn); + | ---------- ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_copy` + --> $DIR/clone-impl-async.rs:70:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `impl Future: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:40:17 + | +LL | check_clone(&inner_non_clone_fn); + | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_clone` + --> $DIR/clone-impl-async.rs:71:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error[E0277]: the trait bound `impl Future: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:44:16 + | +LL | check_copy(&outer_non_clone_fn); + | ---------- ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_copy` + --> $DIR/clone-impl-async.rs:70:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `impl Future: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:46:17 + | +LL | check_clone(&outer_non_clone_fn); + | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_clone` + --> $DIR/clone-impl-async.rs:71:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error[E0277]: the trait bound `impl Future: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:50:16 + | +LL | check_copy(&maybe_copy_clone_fn); + | ---------- ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_copy` + --> $DIR/clone-impl-async.rs:70:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `impl Future: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:52:17 + | +LL | check_clone(&maybe_copy_clone_fn); + | ----------- ^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check_clone` + --> $DIR/clone-impl-async.rs:71:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0277`. From 9cd008f51463792398c83e1765252f5597ec992a Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 10 Apr 2022 15:28:31 +0800 Subject: [PATCH 12/14] fix tests after rebase --- src/test/ui/generator/clone-impl-async.rs | 12 +++++----- src/test/ui/generator/clone-impl-async.stderr | 24 +++++++++---------- src/test/ui/generator/clone-impl.stderr | 8 +++++++ 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/test/ui/generator/clone-impl-async.rs b/src/test/ui/generator/clone-impl-async.rs index 97cbd9d9fb599..83c51526b7b09 100644 --- a/src/test/ui/generator/clone-impl-async.rs +++ b/src/test/ui/generator/clone-impl-async.rs @@ -15,24 +15,24 @@ fn main() { drop(non_clone); }; check_copy(&inner_non_clone); - //~^ ERROR the trait bound `impl Future: Copy` is not satisfied + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied check_clone(&inner_non_clone); - //~^ ERROR the trait bound `impl Future: Clone` is not satisfied + //~^ ERROR the trait bound `impl Future: Clone` is not satisfied let non_clone = NonClone; let outer_non_clone = async move { drop(non_clone); }; check_copy(&outer_non_clone); - //~^ ERROR the trait bound `impl Future: Copy` is not satisfied + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied check_clone(&outer_non_clone); - //~^ ERROR the trait bound `impl Future: Clone` is not satisfied + //~^ ERROR the trait bound `impl Future: Clone` is not satisfied let maybe_copy_clone = async move {}; check_copy(&maybe_copy_clone); - //~^ ERROR the trait bound `impl Future: Copy` is not satisfied + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied check_clone(&maybe_copy_clone); - //~^ ERROR the trait bound `impl Future: Clone` is not satisfied + //~^ ERROR the trait bound `impl Future: Clone` is not satisfied let inner_non_clone_fn = the_inner_non_clone_fn(); check_copy(&inner_non_clone_fn); diff --git a/src/test/ui/generator/clone-impl-async.stderr b/src/test/ui/generator/clone-impl-async.stderr index 6246d773f35b9..cbb58d2af18e7 100644 --- a/src/test/ui/generator/clone-impl-async.stderr +++ b/src/test/ui/generator/clone-impl-async.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `impl Future: Copy` is not satisfied +error[E0277]: the trait bound `impl Future: Copy` is not satisfied --> $DIR/clone-impl-async.rs:17:16 | LL | check_copy(&inner_non_clone); - | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` + | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` | | | required by a bound introduced by this call | @@ -12,11 +12,11 @@ note: required by a bound in `check_copy` LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `impl Future: Clone` is not satisfied +error[E0277]: the trait bound `impl Future: Clone` is not satisfied --> $DIR/clone-impl-async.rs:19:17 | LL | check_clone(&inner_non_clone); - | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` + | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` | | | required by a bound introduced by this call | @@ -26,11 +26,11 @@ note: required by a bound in `check_clone` LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` -error[E0277]: the trait bound `impl Future: Copy` is not satisfied +error[E0277]: the trait bound `impl Future: Copy` is not satisfied --> $DIR/clone-impl-async.rs:26:16 | LL | check_copy(&outer_non_clone); - | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` + | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` | | | required by a bound introduced by this call | @@ -40,11 +40,11 @@ note: required by a bound in `check_copy` LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `impl Future: Clone` is not satisfied +error[E0277]: the trait bound `impl Future: Clone` is not satisfied --> $DIR/clone-impl-async.rs:28:17 | LL | check_clone(&outer_non_clone); - | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` + | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` | | | required by a bound introduced by this call | @@ -54,11 +54,11 @@ note: required by a bound in `check_clone` LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` -error[E0277]: the trait bound `impl Future: Copy` is not satisfied +error[E0277]: the trait bound `impl Future: Copy` is not satisfied --> $DIR/clone-impl-async.rs:32:16 | LL | check_copy(&maybe_copy_clone); - | ---------- ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` + | ---------- ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` | | | required by a bound introduced by this call | @@ -68,11 +68,11 @@ note: required by a bound in `check_copy` LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `impl Future: Clone` is not satisfied +error[E0277]: the trait bound `impl Future: Clone` is not satisfied --> $DIR/clone-impl-async.rs:34:17 | LL | check_clone(&maybe_copy_clone); - | ----------- ^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` + | ----------- ^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` | | | required by a bound introduced by this call | diff --git a/src/test/ui/generator/clone-impl.stderr b/src/test/ui/generator/clone-impl.stderr index 407927fb3bc24..e097250cca86f 100644 --- a/src/test/ui/generator/clone-impl.stderr +++ b/src/test/ui/generator/clone-impl.stderr @@ -133,6 +133,10 @@ note: required by a bound in `check_copy` | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` +help: consider annotating `NonClone` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `[generator@$DIR/clone-impl.rs:62:25: 65:6]` --> $DIR/clone-impl.rs:68:5 @@ -157,6 +161,10 @@ note: required by a bound in `check_clone` | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` +help: consider annotating `NonClone` with `#[derive(Clone)]` + | +LL | #[derive(Clone)] + | error: aborting due to 6 previous errors From 0f367a9be89c58087e6a3373125a230698287ed9 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sun, 11 Sep 2022 13:57:41 +0800 Subject: [PATCH 13/14] Use current rustc version. --- compiler/rustc_feature/src/active.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index c2cc4d7923b73..5377ebde1683f 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -395,7 +395,7 @@ declare_features! ( /// Allows using `#[repr(align(...))]` on function items (active, fn_align, "1.53.0", Some(82232), None), /// Allows generators to be cloned. - (active, generator_clone, "1.60.0", Some(95360), None), + (active, generator_clone, "CURRENT_RUSTC_VERSION", Some(95360), None), /// Allows defining generators. (active, generators, "1.21.0", Some(43122), None), /// Infer generic args for both consts and types. From 4e9bcb5d54d8cba113ebd9c94d293f376ac040ef Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sun, 11 Sep 2022 14:21:40 +0800 Subject: [PATCH 14/14] Update unit test outputs --- .../ui/generator/clone-impl-static.stderr | 8 +- src/test/ui/generator/clone-impl.stderr | 123 +++++++----------- 2 files changed, 51 insertions(+), 80 deletions(-) diff --git a/src/test/ui/generator/clone-impl-static.stderr b/src/test/ui/generator/clone-impl-static.stderr index cc15c4afd7793..cbadf6f156a9f 100644 --- a/src/test/ui/generator/clone-impl-static.stderr +++ b/src/test/ui/generator/clone-impl-static.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `[static generator@$DIR/clone-impl-static.rs:7:15: 9:6]: Copy` is not satisfied +error[E0277]: the trait bound `[static generator@$DIR/clone-impl-static.rs:7:15: 7:29]: Copy` is not satisfied --> $DIR/clone-impl-static.rs:10:16 | LL | check_copy(&gen); - | ---------- ^^^^ the trait `Copy` is not implemented for `[static generator@$DIR/clone-impl-static.rs:7:15: 9:6]` + | ---------- ^^^^ the trait `Copy` is not implemented for `[static generator@$DIR/clone-impl-static.rs:7:15: 7:29]` | | | required by a bound introduced by this call | @@ -12,11 +12,11 @@ note: required by a bound in `check_copy` LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `[static generator@$DIR/clone-impl-static.rs:7:15: 9:6]: Clone` is not satisfied +error[E0277]: the trait bound `[static generator@$DIR/clone-impl-static.rs:7:15: 7:29]: Clone` is not satisfied --> $DIR/clone-impl-static.rs:12:17 | LL | check_clone(&gen); - | ----------- ^^^^ the trait `Clone` is not implemented for `[static generator@$DIR/clone-impl-static.rs:7:15: 9:6]` + | ----------- ^^^^ the trait `Clone` is not implemented for `[static generator@$DIR/clone-impl-static.rs:7:15: 7:29]` | | | required by a bound introduced by this call | diff --git a/src/test/ui/generator/clone-impl.stderr b/src/test/ui/generator/clone-impl.stderr index e097250cca86f..a92646b198cf4 100644 --- a/src/test/ui/generator/clone-impl.stderr +++ b/src/test/ui/generator/clone-impl.stderr @@ -1,16 +1,11 @@ -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:36:23: 41:6]` - --> $DIR/clone-impl.rs:42:5 - | -LL | let gen_clone_0 = move || { - | _______________________- -LL | | let v = vec!['a']; -LL | | yield; -LL | | drop(v); -LL | | drop(clonable_0); -LL | | }; - | |_____- within this `[generator@$DIR/clone-impl.rs:36:23: 41:6]` -LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:36:23: 41:6]`, the trait `Copy` is not implemented for `Vec` +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:36:23: 36:30]` + --> $DIR/clone-impl.rs:42:16 + | +LL | let gen_clone_0 = move || { + | ------- within this `[generator@$DIR/clone-impl.rs:36:23: 36:30]` +... +LL | check_copy(&gen_clone_0); + | ^^^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:36:23: 36:30]`, the trait `Copy` is not implemented for `Vec` | note: captured value does not implement `Copy` --> $DIR/clone-impl.rs:40:14 @@ -23,19 +18,14 @@ note: required by a bound in `check_copy` LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:36:23: 41:6]` - --> $DIR/clone-impl.rs:42:5 - | -LL | let gen_clone_0 = move || { - | _______________________- -LL | | let v = vec!['a']; -LL | | yield; -LL | | drop(v); -LL | | drop(clonable_0); -LL | | }; - | |_____- within this `[generator@$DIR/clone-impl.rs:36:23: 41:6]` -LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:36:23: 41:6]`, the trait `Copy` is not implemented for `Vec` +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:36:23: 36:30]` + --> $DIR/clone-impl.rs:42:16 + | +LL | let gen_clone_0 = move || { + | ------- within this `[generator@$DIR/clone-impl.rs:36:23: 36:30]` +... +LL | check_copy(&gen_clone_0); + | ^^^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:36:23: 36:30]`, the trait `Copy` is not implemented for `Vec` | note: generator does not implement `Copy` as this value is used across a yield --> $DIR/clone-impl.rs:38:9 @@ -53,20 +43,14 @@ note: required by a bound in `check_copy` LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:46:23: 57:6]` - --> $DIR/clone-impl.rs:58:5 - | -LL | let gen_clone_1 = move || { - | _______________________- -LL | | let v = vec!['a']; -LL | | /* -LL | | let n = NonClone; -... | -LL | | drop(clonable_1); -LL | | }; - | |_____- within this `[generator@$DIR/clone-impl.rs:46:23: 57:6]` -LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:46:23: 57:6]`, the trait `Copy` is not implemented for `Vec` +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:46:23: 46:30]` + --> $DIR/clone-impl.rs:58:16 + | +LL | let gen_clone_1 = move || { + | ------- within this `[generator@$DIR/clone-impl.rs:46:23: 46:30]` +... +LL | check_copy(&gen_clone_1); + | ^^^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:46:23: 46:30]`, the trait `Copy` is not implemented for `Vec` | note: captured value does not implement `Copy` --> $DIR/clone-impl.rs:56:14 @@ -79,20 +63,14 @@ note: required by a bound in `check_copy` LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:46:23: 57:6]` - --> $DIR/clone-impl.rs:58:5 - | -LL | let gen_clone_1 = move || { - | _______________________- -LL | | let v = vec!['a']; -LL | | /* -LL | | let n = NonClone; -... | -LL | | drop(clonable_1); -LL | | }; - | |_____- within this `[generator@$DIR/clone-impl.rs:46:23: 57:6]` -LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:46:23: 57:6]`, the trait `Copy` is not implemented for `Vec` +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:46:23: 46:30]` + --> $DIR/clone-impl.rs:58:16 + | +LL | let gen_clone_1 = move || { + | ------- within this `[generator@$DIR/clone-impl.rs:46:23: 46:30]` +... +LL | check_copy(&gen_clone_1); + | ^^^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:46:23: 46:30]`, the trait `Copy` is not implemented for `Vec` | note: generator does not implement `Copy` as this value is used across a yield --> $DIR/clone-impl.rs:52:9 @@ -111,17 +89,14 @@ note: required by a bound in `check_copy` LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:62:25: 65:6]` - --> $DIR/clone-impl.rs:66:5 - | -LL | let gen_non_clone = move || { - | _________________________- -LL | | yield; -LL | | drop(non_clonable); -LL | | }; - | |_____- within this `[generator@$DIR/clone-impl.rs:62:25: 65:6]` -LL | check_copy(&gen_non_clone); - | ^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:62:25: 65:6]`, the trait `Copy` is not implemented for `NonClone` +error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `[generator@$DIR/clone-impl.rs:62:25: 62:32]` + --> $DIR/clone-impl.rs:66:16 + | +LL | let gen_non_clone = move || { + | ------- within this `[generator@$DIR/clone-impl.rs:62:25: 62:32]` +... +LL | check_copy(&gen_non_clone); + | ^^^^^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:62:25: 62:32]`, the trait `Copy` is not implemented for `NonClone` | note: captured value does not implement `Copy` --> $DIR/clone-impl.rs:64:14 @@ -138,18 +113,14 @@ help: consider annotating `NonClone` with `#[derive(Copy)]` LL | #[derive(Copy)] | -error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `[generator@$DIR/clone-impl.rs:62:25: 65:6]` - --> $DIR/clone-impl.rs:68:5 - | -LL | let gen_non_clone = move || { - | _________________________- -LL | | yield; -LL | | drop(non_clonable); -LL | | }; - | |_____- within this `[generator@$DIR/clone-impl.rs:62:25: 65:6]` +error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `[generator@$DIR/clone-impl.rs:62:25: 62:32]` + --> $DIR/clone-impl.rs:68:17 + | +LL | let gen_non_clone = move || { + | ------- within this `[generator@$DIR/clone-impl.rs:62:25: 62:32]` ... -LL | check_clone(&gen_non_clone); - | ^^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:62:25: 65:6]`, the trait `Clone` is not implemented for `NonClone` +LL | check_clone(&gen_non_clone); + | ^^^^^^^^^^^^^^ within `[generator@$DIR/clone-impl.rs:62:25: 62:32]`, the trait `Clone` is not implemented for `NonClone` | note: captured value does not implement `Clone` --> $DIR/clone-impl.rs:64:14