mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 21:47:04 +00:00
Auto merge of #101673 - crlf0710:generator_clone, r=oli-obk
Allow generators to impl Clone/Copy Revives #95137. It's a pity that the original pr didn't land because the implementation is almost complete! All credits goes to `@canndrew,` and i just resolved the merge conflicts and updated the feature gate version number. r? `@oli-obk`
This commit is contained in:
commit
6f0c4a6c5c
@ -394,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, "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.
|
||||
|
@ -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, GeneratorSubsts, Ty, TyCtxt};
|
||||
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,106 @@ impl<'tcx> CloneShimBuilder<'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
|
||||
fn clone_fields<I>(
|
||||
&mut self,
|
||||
dest: Place<'tcx>,
|
||||
src: Place<'tcx>,
|
||||
target: BasicBlock,
|
||||
mut unwind: BasicBlock,
|
||||
tys: I,
|
||||
) -> BasicBlock
|
||||
where
|
||||
I: IntoIterator<Item = Ty<'tcx>>,
|
||||
{
|
||||
let mut previous_field = None;
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
previous_field = Some((dest_field, cleanup_block));
|
||||
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;
|
||||
}
|
||||
// If all clones succeed then we end up here.
|
||||
self.block(vec![], TerminatorKind::Goto { target }, false);
|
||||
unwind
|
||||
}
|
||||
|
||||
self.block(vec![], TerminatorKind::Return, false);
|
||||
fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
|
||||
where
|
||||
I: IntoIterator<Item = Ty<'tcx>>,
|
||||
{
|
||||
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);
|
||||
|
||||
let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, tys);
|
||||
}
|
||||
|
||||
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 clone_block = self.block_index_offset(1);
|
||||
let start_block = self.block(
|
||||
vec![self.make_statement(StatementKind::SetDiscriminant {
|
||||
place: Box::new(Place::return_place()),
|
||||
variant_index,
|
||||
})],
|
||||
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);
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -763,6 +763,7 @@ symbols! {
|
||||
gen_future,
|
||||
gen_kill,
|
||||
generator,
|
||||
generator_clone,
|
||||
generator_state,
|
||||
generators,
|
||||
generic_arg_infer,
|
||||
|
@ -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,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
Where(obligation.predicate.rebind(tys.iter().collect()))
|
||||
}
|
||||
|
||||
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());
|
||||
if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() {
|
||||
// Not yet resolved.
|
||||
Ambiguous
|
||||
} else {
|
||||
let all = substs
|
||||
.as_generator()
|
||||
.upvar_tys()
|
||||
.chain(iter::once(substs.as_generator().witness()))
|
||||
.collect::<Vec<_>>();
|
||||
Where(obligation.predicate.rebind(all))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
ty::GeneratorWitness(binder) => {
|
||||
let witness_tys = binder.skip_binder();
|
||||
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) => {
|
||||
// (*) binder moved here
|
||||
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
|
||||
|
@ -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),
|
||||
};
|
||||
|
||||
|
71
src/test/ui/generator/clone-impl-async.rs
Normal file
71
src/test/ui/generator/clone-impl-async.rs
Normal file
@ -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<Output = ()>: Copy` is not satisfied
|
||||
check_clone(&inner_non_clone);
|
||||
//~^ ERROR the trait bound `impl Future<Output = ()>: 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<Output = ()>: Copy` is not satisfied
|
||||
check_clone(&outer_non_clone);
|
||||
//~^ ERROR the trait bound `impl Future<Output = ()>: Clone` is not satisfied
|
||||
|
||||
let maybe_copy_clone = async move {};
|
||||
check_copy(&maybe_copy_clone);
|
||||
//~^ ERROR the trait bound `impl Future<Output = ()>: Copy` is not satisfied
|
||||
check_clone(&maybe_copy_clone);
|
||||
//~^ ERROR the trait bound `impl Future<Output = ()>: 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<Output = ()>: Copy` is not satisfied
|
||||
check_clone(&inner_non_clone_fn);
|
||||
//~^ ERROR the trait bound `impl Future<Output = ()>: 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<Output = ()>: Copy` is not satisfied
|
||||
check_clone(&outer_non_clone_fn);
|
||||
//~^ ERROR the trait bound `impl Future<Output = ()>: 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<Output = ()>: Copy` is not satisfied
|
||||
check_clone(&maybe_copy_clone_fn);
|
||||
//~^ ERROR the trait bound `impl Future<Output = ()>: 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<T: Copy>(_x: &T) {}
|
||||
fn check_clone<T: Clone>(_x: &T) {}
|
171
src/test/ui/generator/clone-impl-async.stderr
Normal file
171
src/test/ui/generator/clone-impl-async.stderr
Normal file
@ -0,0 +1,171 @@
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Copy>(_x: &T) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Clone>(_x: &T) {}
|
||||
| ^^^^^ required by this bound in `check_clone`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Copy>(_x: &T) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Clone>(_x: &T) {}
|
||||
| ^^^^^ required by this bound in `check_clone`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Copy>(_x: &T) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Clone>(_x: &T) {}
|
||||
| ^^^^^ required by this bound in `check_clone`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Copy>(_x: &T) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Clone>(_x: &T) {}
|
||||
| ^^^^^ required by this bound in `check_clone`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Copy>(_x: &T) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Clone>(_x: &T) {}
|
||||
| ^^^^^ required by this bound in `check_clone`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: Copy>(_x: &T) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
|
||||
error[E0277]: the trait bound `impl Future<Output = ()>: 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<Output = ()>`
|
||||
| |
|
||||
| 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<T: 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`.
|
17
src/test/ui/generator/clone-impl-static.rs
Normal file
17
src/test/ui/generator/clone-impl-static.rs
Normal file
@ -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<T: Copy>(_x: &T) {}
|
||||
fn check_clone<T: Clone>(_x: &T) {}
|
31
src/test/ui/generator/clone-impl-static.stderr
Normal file
31
src/test/ui/generator/clone-impl-static.stderr
Normal file
@ -0,0 +1,31 @@
|
||||
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: 7:29]`
|
||||
| |
|
||||
| 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<T: Copy>(_x: &T) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
|
||||
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: 7:29]`
|
||||
| |
|
||||
| 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<T: 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`.
|
73
src/test/ui/generator/clone-impl.rs
Normal file
73
src/test/ui/generator/clone-impl.rs
Normal file
@ -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<u32> = Vec::new();
|
||||
let clonable_1: Vec<u32> = 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<u32>: Copy` is not satisfied
|
||||
//~| ERROR the trait bound `Vec<char>: 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<u32>: Copy` is not satisfied
|
||||
//~| ERROR the trait bound `Vec<char>: 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<T: Copy>(_x: &T) {}
|
||||
fn check_clone<T: Clone>(_x: &T) {}
|
142
src/test/ui/generator/clone-impl.stderr
Normal file
142
src/test/ui/generator/clone-impl.stderr
Normal file
@ -0,0 +1,142 @@
|
||||
error[E0277]: the trait bound `Vec<u32>: 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<u32>`
|
||||
|
|
||||
note: captured value does not implement `Copy`
|
||||
--> $DIR/clone-impl.rs:40:14
|
||||
|
|
||||
LL | drop(clonable_0);
|
||||
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
|
||||
note: required by a bound in `check_copy`
|
||||
--> $DIR/clone-impl.rs:72:18
|
||||
|
|
||||
LL | fn check_copy<T: Copy>(_x: &T) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
|
||||
error[E0277]: the trait bound `Vec<char>: 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<char>`
|
||||
|
|
||||
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<char>` 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<T: Copy>(_x: &T) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
|
||||
error[E0277]: the trait bound `Vec<u32>: 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<u32>`
|
||||
|
|
||||
note: captured value does not implement `Copy`
|
||||
--> $DIR/clone-impl.rs:56:14
|
||||
|
|
||||
LL | drop(clonable_1);
|
||||
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
|
||||
note: required by a bound in `check_copy`
|
||||
--> $DIR/clone-impl.rs:72:18
|
||||
|
|
||||
LL | fn check_copy<T: Copy>(_x: &T) {}
|
||||
| ^^^^ required by this bound in `check_copy`
|
||||
|
||||
error[E0277]: the trait bound `Vec<char>: 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<char>`
|
||||
|
|
||||
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<char>` 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<T: 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: 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
|
||||
|
|
||||
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<T: 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: 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: 62:32]`, 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<T: 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
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user