From 8700f697ee3098111325a6b6bccfda959551ae90 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 13 Mar 2022 13:39:20 +0800 Subject: [PATCH 01/12] 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 bf031b423c2e5..2eee4c5d5e526 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, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, GeneratorSubsts}; use rustc_target::abi::VariantIdx; use rustc_index::vec::{Idx, IndexVec}; @@ -322,6 +322,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), }; @@ -387,7 +390,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) } @@ -459,49 +462,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 e69bf6eca90ef..955b583fd2682 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1887,8 +1887,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, @@ -1897,6 +1896,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 802a59abe5faf..217db18c15c1a 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -353,7 +353,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 5fca8143f06af568e064fc7b1496acbee2df7f58 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 13 Mar 2022 14:41:44 +0800 Subject: [PATCH 02/12] 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 8340a0b360ef7..a3d57d3dea709 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 dc4d10f699c75..0d85f02e76a78 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -722,6 +722,7 @@ symbols! { gen_future, gen_kill, generator, + generator_clone, generator_return, generator_state, generators, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 955b583fd2682..1260698d1cff4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1897,35 +1897,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 0451205ce686c0b9784b44dd9bfab8c70c615eb0 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Mon, 14 Mar 2022 10:24:10 +0800 Subject: [PATCH 03/12] 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 1260698d1cff4..b05f0fa07b8ff 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1917,23 +1917,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 0e8c69e0f8eaaafb0e40b00277965e05da285b93 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Fri, 18 Mar 2022 14:24:54 +0800 Subject: [PATCH 04/12] 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 b05f0fa07b8ff..bbc2c7bd9055e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1917,18 +1917,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 43f42d2fd756738e95e295c86f2403a220c507d3 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Mon, 21 Mar 2022 12:56:22 +0800 Subject: [PATCH 05/12] 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 a3d57d3dea709..72f88f37dfb9f 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -150,6 +150,8 @@ declare_features! ( (active, allow_internal_unstable, "1.0.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), /// Allows using the `rust-intrinsic`'s "ABI". (active, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. @@ -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 960bdcc3bb2f3e254af2f0389b4b36c2c9c0ca70 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Mon, 21 Mar 2022 12:57:06 +0800 Subject: [PATCH 06/12] 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 2eee4c5d5e526..e1f692a925c67 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, Ty, TyCtxt, GeneratorSubsts}; +use rustc_middle::ty::{self, GeneratorSubsts, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; use rustc_index::vec::{Idx, IndexVec}; @@ -484,20 +484,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 } @@ -505,11 +497,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); @@ -523,11 +511,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); @@ -564,7 +548,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 bbc2c7bd9055e..8d520b4508fbf 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1898,11 +1898,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 @@ -1926,14 +1928,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 217db18c15c1a..36810260f6938 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -353,10 +353,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 c32400f9921839c17d9a8d79af1f6764d03ed4cb Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Mon, 21 Mar 2022 13:57:10 +0800 Subject: [PATCH 07/12] 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 cf917689a3ddfb49007a447a24e7abb85f0d2257 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 27 Mar 2022 15:50:40 +0800 Subject: [PATCH 08/12] 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 72f88f37dfb9f..2168d4ddf958c 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -150,8 +150,6 @@ declare_features! ( (active, allow_internal_unstable, "1.0.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), /// Allows using the `rust-intrinsic`'s "ABI". (active, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. @@ -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 251b92aabded74a9a823b58bdab6a334f9606b09 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 10 Apr 2022 14:04:44 +0800 Subject: [PATCH 09/12] 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 e1f692a925c67..b2c152ec7018c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -473,7 +473,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); @@ -489,6 +500,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 0cccb999bc720dc9219ece1e226d76eba55033a9 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 10 Apr 2022 14:05:31 +0800 Subject: [PATCH 10/12] 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 b2c152ec7018c..f6efc0a93f4ba 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -535,10 +535,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, @@ -546,6 +544,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 8d520b4508fbf..21ae0b756efe9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1902,15 +1902,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 { @@ -1920,31 +1920,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 2688d751f435f6bd89be9dbf79d3f9408cea0d6a Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 10 Apr 2022 15:04:04 +0800 Subject: [PATCH 11/12] 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 69168f1c9a766c31093f3801cc3ec5df90a9450c Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 10 Apr 2022 15:28:31 +0800 Subject: [PATCH 12/12] 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