@@ -313,6 +313,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
313
313
)
314
314
}
315
315
ty:: TyTuple ( tys, _) => builder. tuple_like_shim ( dest, src, tys. iter ( ) . cloned ( ) ) ,
316
+ ty:: TyAdt ( adt, substs) => builder. enum_shim ( adt, substs, dest, src) ,
316
317
_ => {
317
318
bug ! ( "clone shim for `{:?}` which is not `Copy` and is not an aggregate" , self_ty)
318
319
}
@@ -671,6 +672,62 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
671
672
672
673
self . block ( vec ! [ ] , TerminatorKind :: Return , false ) ;
673
674
}
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
+ }
674
731
}
675
732
676
733
/// Build a "call" shim for `def_id`. The shim calls the
0 commit comments