Skip to content

Commit 8a8f91b

Browse files
committed
Generalize tuple_like_shim's code to be useful for enums
1 parent dfd244d commit 8a8f91b

File tree

1 file changed

+39
-24
lines changed

1 file changed

+39
-24
lines changed

src/librustc_mir/shim.rs

+39-24
Original file line numberDiff line numberDiff line change
@@ -297,18 +297,22 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
297297
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
298298
let is_copy = !self_ty.moves_by_default(tcx, tcx.param_env(def_id), builder.span);
299299

300+
let dest = Place::Local(RETURN_PLACE);
301+
let src = Place::Local(Local::new(1+0)).deref();
302+
300303
match self_ty.sty {
301304
_ if is_copy => builder.copy_shim(),
302305
ty::TyArray(ty, len) => {
303306
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
304-
builder.array_shim(ty, len)
307+
builder.array_shim(dest, src, ty, len)
305308
}
306309
ty::TyClosure(def_id, substs) => {
307310
builder.tuple_like_shim(
308-
&substs.upvar_tys(def_id, tcx).collect::<Vec<_>>()
311+
dest, src,
312+
substs.upvar_tys(def_id, tcx)
309313
)
310314
}
311-
ty::TyTuple(tys, _) => builder.tuple_like_shim(&**tys),
315+
ty::TyTuple(tys, _) => builder.tuple_like_shim(dest, src, tys.iter().cloned()),
312316
_ => {
313317
bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty)
314318
}
@@ -382,6 +386,14 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
382386
})
383387
}
384388

389+
/// Gives the index of an upcoming BasicBlock, with an offset.
390+
/// offset=0 will give you the index of the next BasicBlock,
391+
/// offset=1 will give the index of the next-to-next block,
392+
/// offset=-1 will give you the index of the last-created block
393+
fn block_index_offset(&mut self, offset: usize) -> BasicBlock {
394+
BasicBlock::new(self.blocks.len() + offset)
395+
}
396+
385397
fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
386398
Statement {
387399
source_info: self.source_info(),
@@ -502,11 +514,9 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
502514
}
503515
}
504516

505-
fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
517+
fn array_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, ty: Ty<'tcx>, len: u64) {
506518
let tcx = self.tcx;
507519
let span = self.span;
508-
let src = Place::Local(Local::new(1+0)).deref();
509-
let dest = Place::Local(RETURN_PLACE);
510520

511521
let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
512522
let end = self.make_place(Mutability::Not, tcx.types.usize);
@@ -616,42 +626,47 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
616626
self.block(vec![], TerminatorKind::Resume, true);
617627
}
618628

619-
fn tuple_like_shim(&mut self, tys: &[ty::Ty<'tcx>]) {
620-
let rcvr = Place::Local(Local::new(1+0)).deref();
621-
622-
let mut previous_place = None;
623-
let return_place = Place::Local(RETURN_PLACE);
624-
for (i, ity) in tys.iter().enumerate() {
629+
fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>,
630+
src: Place<'tcx>, tys: I)
631+
where I: Iterator<Item = ty::Ty<'tcx>> {
632+
let mut previous_field = None;
633+
for (i, ity) in tys.enumerate() {
625634
let field = Field::new(i);
626-
let rcvr_field = rcvr.clone().field(field, *ity);
635+
let src_field = src.clone().field(field, ity);
636+
637+
let dest_field = dest.clone().field(field, ity);
627638

628-
let place = return_place.clone().field(field, *ity);
639+
// #(2i + 1) is the cleanup block for the previous clone operation
640+
let cleanup_block = self.block_index_offset(1);
641+
// #(2i + 2) is the next cloning block
642+
// (or the Return terminator if this is the last block)
643+
let next_block = self.block_index_offset(2);
629644

630645
// BB #(2i)
631-
// `returns[i] = Clone::clone(&rcvr.i);`
646+
// `dest.i = Clone::clone(&src.i);`
632647
// Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
633648
self.make_clone_call(
634-
place.clone(),
635-
rcvr_field,
636-
*ity,
637-
BasicBlock::new(2 * i + 2),
638-
BasicBlock::new(2 * i + 1),
649+
dest_field.clone(),
650+
src_field,
651+
ity,
652+
next_block,
653+
cleanup_block,
639654
);
640655

641656
// BB #(2i + 1) (cleanup)
642-
if let Some(previous_place) = previous_place.take() {
657+
if let Some((previous_field, previous_cleanup)) = previous_field.take() {
643658
// Drop previous field and goto previous cleanup block.
644659
self.block(vec![], TerminatorKind::Drop {
645-
location: previous_place,
646-
target: BasicBlock::new(2 * i - 1),
660+
location: previous_field,
661+
target: previous_cleanup,
647662
unwind: None,
648663
}, true);
649664
} else {
650665
// Nothing to drop, just resume.
651666
self.block(vec![], TerminatorKind::Resume, true);
652667
}
653668

654-
previous_place = Some(place);
669+
previous_field = Some((dest_field, cleanup_block));
655670
}
656671

657672
self.block(vec![], TerminatorKind::Return, false);

0 commit comments

Comments
 (0)