@@ -5,7 +5,7 @@ use rustc_errors::struct_span_err;
55use  rustc_hir as  hir; 
66use  rustc_middle:: mir:: BorrowKind ; 
77use  rustc_middle:: thir:: * ; 
8- use  rustc_middle:: ty:: { self ,  ParamEnv ,  TyCtxt } ; 
8+ use  rustc_middle:: ty:: { self ,  ParamEnv ,  Ty ,   TyCtxt } ; 
99use  rustc_session:: lint:: builtin:: { UNSAFE_OP_IN_UNSAFE_FN ,  UNUSED_UNSAFE } ; 
1010use  rustc_session:: lint:: Level ; 
1111use  rustc_span:: def_id:: { DefId ,  LocalDefId } ; 
@@ -27,7 +27,9 @@ struct UnsafetyVisitor<'a, 'tcx> {
2727    /// The `#[target_feature]` attributes of the body. Used for checking 
2828/// calls to functions with `#[target_feature]` (RFC 2396). 
2929body_target_features :  & ' tcx  Vec < Symbol > , 
30-     in_possible_lhs_union_assign :  bool , 
30+     /// When inside the LHS of an assignment to a field, this is the type 
31+ /// of the LHS and the span of the assignment expression. 
32+ assignment_info :  Option < ( Ty < ' tcx > ,  Span ) > , 
3133    in_union_destructure :  bool , 
3234    param_env :  ParamEnv < ' tcx > , 
3335    inside_adt :  bool , 
@@ -287,7 +289,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
287289    } 
288290
289291    fn  visit_expr ( & mut  self ,  expr :  & Expr < ' tcx > )  { 
290-         // could we be in a  the LHS of an assignment of  a union ? 
292+         // could we be in the LHS of an assignment to  a field ? 
291293        match  expr. kind  { 
292294            ExprKind :: Field  {  .. } 
293295            | ExprKind :: VarRef  {  .. } 
@@ -329,7 +331,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
329331            | ExprKind :: InlineAsm  {  .. } 
330332            | ExprKind :: LlvmInlineAsm  {  .. } 
331333            | ExprKind :: LogicalOp  {  .. } 
332-             | ExprKind :: Use  {  .. }  => self . in_possible_lhs_union_assign  = false , 
334+             | ExprKind :: Use  {  .. }  => { 
335+                 // We don't need to save the old value and restore it 
336+                 // because all the place expressions can't have more 
337+                 // than one child. 
338+                 self . assignment_info  = None ; 
339+             } 
333340        } ; 
334341        match  expr. kind  { 
335342            ExprKind :: Scope  {  value,  lint_level :  LintLevel :: Explicit ( hir_id) ,  region_scope :  _ }  => { 
@@ -409,32 +416,42 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
409416                self . safety_context  = closure_visitor. safety_context ; 
410417            } 
411418            ExprKind :: Field  {  lhs,  .. }  => { 
412-                 // assigning to union field is okay for AccessToUnionField 
413-                 if  let  ty:: Adt ( adt_def,  _)  = & self . thir [ lhs] . ty . kind ( )  { 
419+                 let  lhs =  & self . thir [ lhs ] ; 
420+                 if  let  ty:: Adt ( adt_def,  _)  = lhs. ty . kind ( )  { 
414421                    if  adt_def. is_union ( )  { 
415-                         if  self . in_possible_lhs_union_assign  { 
416-                             // FIXME: trigger AssignToDroppingUnionField unsafety if needed 
422+                         if  let  Some ( ( assigned_ty,  assignment_span) )  = self . assignment_info  { 
423+                             // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. 
424+                             if  !( assigned_ty
425+                                 . ty_adt_def ( ) 
426+                                 . map_or ( false ,  |adt| adt. is_manually_drop ( ) ) 
427+                                 || assigned_ty
428+                                     . is_copy_modulo_regions ( self . tcx . at ( expr. span ) ,  self . param_env ) ) 
429+                             { 
430+                                 self . requires_unsafe ( assignment_span,  AssignToDroppingUnionField ) ; 
431+                             }  else  { 
432+                                 // write to non-drop union field, safe 
433+                             } 
417434                        }  else  { 
418435                            self . requires_unsafe ( expr. span ,  AccessToUnionField ) ; 
419436                        } 
420437                    } 
421438                } 
422439            } 
423440            ExprKind :: Assign  {  lhs,  rhs }  | ExprKind :: AssignOp  {  lhs,  rhs,  .. }  => { 
441+                 let  lhs = & self . thir [ lhs] ; 
424442                // First, check whether we are mutating a layout constrained field 
425443                let  mut  visitor = LayoutConstrainedPlaceVisitor :: new ( self . thir ,  self . tcx ) ; 
426-                 visit:: walk_expr ( & mut  visitor,  & self . thir [ lhs] ) ; 
444+                 visit:: walk_expr ( & mut  visitor,  lhs) ; 
427445                if  visitor. found  { 
428446                    self . requires_unsafe ( expr. span ,  MutationOfLayoutConstrainedField ) ; 
429447                } 
430448
431449                // Second, check for accesses to union fields 
432450                // don't have any special handling for AssignOp since it causes a read *and* write to lhs 
433451                if  matches ! ( expr. kind,  ExprKind :: Assign  {  .. } )  { 
434-                     // assigning to a union is safe, check here so it doesn't get treated as a read later 
435-                     self . in_possible_lhs_union_assign  = true ; 
436-                     visit:: walk_expr ( self ,  & self . thir ( ) [ lhs] ) ; 
437-                     self . in_possible_lhs_union_assign  = false ; 
452+                     self . assignment_info  = Some ( ( lhs. ty ,  expr. span ) ) ; 
453+                     visit:: walk_expr ( self ,  lhs) ; 
454+                     self . assignment_info  = None ; 
438455                    visit:: walk_expr ( self ,  & self . thir ( ) [ rhs] ) ; 
439456                    return ;  // we have already visited everything by now 
440457                } 
@@ -506,12 +523,9 @@ enum UnsafeOpKind {
506523    UseOfMutableStatic , 
507524    UseOfExternStatic , 
508525    DerefOfRawPointer , 
509-     #[ allow( dead_code) ]   // FIXME 
510526    AssignToDroppingUnionField , 
511527    AccessToUnionField , 
512-     #[ allow( dead_code) ]   // FIXME 
513528    MutationOfLayoutConstrainedField , 
514-     #[ allow( dead_code) ]   // FIXME 
515529    BorrowOfLayoutConstrainedField , 
516530    CallToFunctionWith , 
517531} 
@@ -619,7 +633,7 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
619633        hir_context :  hir_id, 
620634        body_unsafety, 
621635        body_target_features, 
622-         in_possible_lhs_union_assign :   false , 
636+         assignment_info :   None , 
623637        in_union_destructure :  false , 
624638        param_env :  tcx. param_env ( def. did ) , 
625639        inside_adt :  false , 
0 commit comments