@@ -21,7 +21,8 @@ use rustc::middle::dataflow::DataFlowOperator;
2121use rustc:: middle:: dataflow:: KillFrom ;
2222use rustc:: middle:: expr_use_visitor as euv;
2323use rustc:: middle:: expr_use_visitor:: MutateMode ;
24- use rustc:: ty:: TyCtxt ;
24+ use rustc:: middle:: mem_categorization as mc;
25+ use rustc:: ty:: { self , TyCtxt } ;
2526use rustc:: util:: nodemap:: { FnvHashMap , NodeSet } ;
2627
2728use std:: cell:: RefCell ;
@@ -364,6 +365,32 @@ impl<'a, 'tcx> MoveData<'tcx> {
364365 lp : Rc < LoanPath < ' tcx > > ,
365366 id : ast:: NodeId ,
366367 kind : MoveKind ) {
368+ // Moving one union field automatically moves all its fields.
369+ if let LpExtend ( ref base_lp, mutbl, LpInterior ( opt_variant_id, interior) ) = lp. kind {
370+ if let ty:: TyUnion ( ref adt_def, _) = base_lp. ty . sty {
371+ for field in & adt_def. struct_variant ( ) . fields {
372+ let field = InteriorKind :: InteriorField ( mc:: NamedField ( field. name ) ) ;
373+ let field_ty = if field == interior {
374+ lp. ty
375+ } else {
376+ tcx. types . err // Doesn't matter
377+ } ;
378+ let sibling_lp_kind = LpExtend ( base_lp. clone ( ) , mutbl,
379+ LpInterior ( opt_variant_id, field) ) ;
380+ let sibling_lp = Rc :: new ( LoanPath :: new ( sibling_lp_kind, field_ty) ) ;
381+ self . add_move_helper ( tcx, sibling_lp, id, kind) ;
382+ }
383+ return ;
384+ }
385+ }
386+
387+ self . add_move_helper ( tcx, lp. clone ( ) , id, kind) ;
388+ }
389+
390+ fn add_move_helper ( & self , tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
391+ lp : Rc < LoanPath < ' tcx > > ,
392+ id : ast:: NodeId ,
393+ kind : MoveKind ) {
367394 debug ! ( "add_move(lp={:?}, id={}, kind={:?})" ,
368395 lp,
369396 id,
@@ -393,6 +420,34 @@ impl<'a, 'tcx> MoveData<'tcx> {
393420 span : Span ,
394421 assignee_id : ast:: NodeId ,
395422 mode : euv:: MutateMode ) {
423+ // Assigning to one union field automatically assigns to all its fields.
424+ if let LpExtend ( ref base_lp, mutbl, LpInterior ( opt_variant_id, interior) ) = lp. kind {
425+ if let ty:: TyUnion ( ref adt_def, _) = base_lp. ty . sty {
426+ for field in & adt_def. struct_variant ( ) . fields {
427+ let field = InteriorKind :: InteriorField ( mc:: NamedField ( field. name ) ) ;
428+ let field_ty = if field == interior {
429+ lp. ty
430+ } else {
431+ tcx. types . err // Doesn't matter
432+ } ;
433+ let sibling_lp_kind = LpExtend ( base_lp. clone ( ) , mutbl,
434+ LpInterior ( opt_variant_id, field) ) ;
435+ let sibling_lp = Rc :: new ( LoanPath :: new ( sibling_lp_kind, field_ty) ) ;
436+ self . add_assignment_helper ( tcx, sibling_lp, assign_id, span, assignee_id, mode) ;
437+ }
438+ return ;
439+ }
440+ }
441+
442+ self . add_assignment_helper ( tcx, lp. clone ( ) , assign_id, span, assignee_id, mode) ;
443+ }
444+
445+ pub fn add_assignment_helper ( & self , tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
446+ lp : Rc < LoanPath < ' tcx > > ,
447+ assign_id : ast:: NodeId ,
448+ span : Span ,
449+ assignee_id : ast:: NodeId ,
450+ mode : euv:: MutateMode ) {
396451 debug ! ( "add_assignment(lp={:?}, assign_id={}, assignee_id={}" ,
397452 lp, assign_id, assignee_id) ;
398453
0 commit comments