Skip to content

Commit 84558e8

Browse files
committed
Add enum shim
1 parent f58f1be commit 84558e8

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

src/librustc_mir/shim.rs

+57
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
313313
)
314314
}
315315
ty::TyTuple(tys, _) => builder.tuple_like_shim(dest, src, tys.iter().cloned()),
316+
ty::TyAdt(adt, substs) => builder.enum_shim(adt, substs, dest, src),
316317
_ => {
317318
bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty)
318319
}
@@ -671,6 +672,62 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
671672

672673
self.block(vec![], TerminatorKind::Return, false);
673674
}
675+
676+
fn enum_shim(&mut self, adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>,
677+
dest: Place<'tcx>, src: Place<'tcx>) {
678+
use rustc::ty::util::IntTypeExt;
679+
if !adt.is_enum() {
680+
bug!("We only make Clone shims for enum ADTs");
681+
}
682+
// should be u128 maybe?
683+
let discr_ty = adt.repr.discr_type().to_ty(self.tcx);
684+
let discr = self.make_place(Mutability::Not, discr_ty);
685+
686+
let assign_discr = self.make_statement(
687+
StatementKind::Assign(
688+
discr.clone(),
689+
Rvalue::Discriminant(src.clone())
690+
)
691+
);
692+
// insert dummy first block
693+
let entry_block = self.block(vec![], TerminatorKind::Abort, false);
694+
let switch = self.make_enum_match(adt, substs, discr, dest, src);
695+
696+
let source_info = self.source_info();
697+
self.blocks[entry_block].statements = vec![assign_discr];
698+
self.blocks[entry_block].terminator = Some(Terminator { source_info, kind: switch });
699+
}
700+
701+
fn make_enum_match(&mut self, adt: &'tcx ty::AdtDef,
702+
substs: &'tcx Substs<'tcx>,
703+
discr: Place<'tcx>,
704+
dest: Place<'tcx>,
705+
receiver: Place<'tcx>) -> TerminatorKind<'tcx> {
706+
707+
let mut values = vec![];
708+
let mut targets = vec![];
709+
for (idx, variant) in adt.variants.iter().enumerate() {
710+
values.push(adt.discriminant_for_variant(self.tcx, idx));
711+
712+
let src_variant = receiver.clone().downcast(adt, idx);
713+
let dest_variant = dest.clone().downcast(adt, idx);
714+
715+
// next block created will be the target
716+
targets.push(self.block_index_offset(0));
717+
// the borrow
718+
let tcx = self.tcx;
719+
let iter = variant.fields.iter().map(|field| field.ty(tcx, substs));
720+
self.tuple_like_shim(src_variant, dest_variant, iter);
721+
}
722+
// the nonexistant extra case
723+
targets.push(self.block(vec![], TerminatorKind::Abort, true));
724+
TerminatorKind::SwitchInt {
725+
discr: Operand::Move(discr),
726+
switch_ty: self.tcx.types.usize,
727+
values: From::from(values),
728+
targets,
729+
}
730+
}
674731
}
675732

676733
/// Build a "call" shim for `def_id`. The shim calls the

0 commit comments

Comments
 (0)