@@ -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