@@ -2,14 +2,16 @@ use rustc_data_structures::fx::FxHashSet;
22use  rustc_errors:: struct_span_err; 
33use  rustc_hir as  hir; 
44use  rustc_hir:: def_id:: { DefId ,  LocalDefId } ; 
5+ use  rustc_hir:: hir_id:: HirId ; 
56use  rustc_hir:: intravisit; 
67use  rustc_hir:: Node ; 
78use  rustc_middle:: mir:: visit:: { MutatingUseContext ,  PlaceContext ,  Visitor } ; 
89use  rustc_middle:: mir:: * ; 
910use  rustc_middle:: ty:: cast:: CastTy ; 
1011use  rustc_middle:: ty:: query:: Providers ; 
1112use  rustc_middle:: ty:: { self ,  TyCtxt } ; 
12- use  rustc_session:: lint:: builtin:: { SAFE_PACKED_BORROWS ,  UNUSED_UNSAFE } ; 
13+ use  rustc_session:: lint:: builtin:: { SAFE_PACKED_BORROWS ,  UNSAFE_OP_IN_UNSAFE_FN ,  UNUSED_UNSAFE } ; 
14+ use  rustc_session:: lint:: Level ; 
1315use  rustc_span:: symbol:: { sym,  Symbol } ; 
1416
1517use  std:: ops:: Bound ; 
@@ -202,25 +204,30 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
202204
203205        if  context. is_borrow ( )  { 
204206            if  util:: is_disaligned ( self . tcx ,  self . body ,  self . param_env ,  * place)  { 
205-                 let  source_info = self . source_info ; 
206-                 let  lint_root = self . body . source_scopes [ source_info. scope ] 
207-                     . local_data 
208-                     . as_ref ( ) 
209-                     . assert_crate_local ( ) 
210-                     . lint_root ; 
211207                self . require_unsafe ( 
212208                    "borrow of packed field" , 
213209                    "fields of packed structs might be misaligned: dereferencing a \  
214210                     misaligned pointer or even just creating a misaligned reference \ 
215211                     is undefined behavior", 
216-                     UnsafetyViolationKind :: BorrowPacked ( lint_root ) , 
212+                     UnsafetyViolationKind :: BorrowPacked , 
217213                ) ; 
218214            } 
219215        } 
220216
221217        for  ( i,  elem)  in  place. projection . iter ( ) . enumerate ( )  { 
222218            let  proj_base = & place. projection [ ..i] ; 
223-             let  old_source_info = self . source_info ; 
219+             if  context. is_borrow ( )  { 
220+                 if  util:: is_disaligned ( self . tcx ,  self . body ,  self . param_env ,  * place)  { 
221+                     self . require_unsafe ( 
222+                         "borrow of packed field" , 
223+                         "fields of packed structs might be misaligned: dereferencing a \  
224+                          misaligned pointer or even just creating a misaligned reference \ 
225+                          is undefined behavior", 
226+                         UnsafetyViolationKind :: BorrowPacked , 
227+                     ) ; 
228+                 } 
229+             } 
230+             let  source_info = self . source_info ; 
224231            if  let  [ ]  = proj_base { 
225232                let  decl = & self . body . local_decls [ place. local ] ; 
226233                if  decl. internal  { 
@@ -301,7 +308,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
301308                } 
302309                _ => { } 
303310            } 
304-             self . source_info  = old_source_info ; 
311+             self . source_info  = source_info ; 
305312        } 
306313    } 
307314} 
@@ -314,9 +321,15 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
314321        kind :  UnsafetyViolationKind , 
315322    )  { 
316323        let  source_info = self . source_info ; 
324+         let  lint_root = self . body . source_scopes [ self . source_info . scope ] 
325+             . local_data 
326+             . as_ref ( ) 
327+             . assert_crate_local ( ) 
328+             . lint_root ; 
317329        self . register_violations ( 
318330            & [ UnsafetyViolation  { 
319331                source_info, 
332+                 lint_root, 
320333                description :  Symbol :: intern ( description) , 
321334                details :  Symbol :: intern ( details) , 
322335                kind, 
@@ -343,22 +356,42 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
343356                    match  violation. kind  { 
344357                        UnsafetyViolationKind :: GeneralAndConstFn 
345358                        | UnsafetyViolationKind :: General  => { } 
346-                         UnsafetyViolationKind :: BorrowPacked ( _ )  => { 
359+                         UnsafetyViolationKind :: BorrowPacked  => { 
347360                            if  self . min_const_fn  { 
348361                                // const fns don't need to be backwards compatible and can 
349362                                // emit these violations as a hard error instead of a backwards 
350363                                // compat lint 
351364                                violation. kind  = UnsafetyViolationKind :: General ; 
352365                            } 
353366                        } 
367+                         UnsafetyViolationKind :: UnsafeFn 
368+                         | UnsafetyViolationKind :: UnsafeFnBorrowPacked  => { 
369+                             bug ! ( "`UnsafetyViolationKind::UnsafeFn` in an `Safe` context" ) 
370+                         } 
371+                     } 
372+                     if  !self . violations . contains ( & violation)  { 
373+                         self . violations . push ( violation) 
374+                     } 
375+                 } 
376+                 false 
377+             } 
378+             // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s 
379+             Safety :: FnUnsafe  if  self . tcx . features ( ) . unsafe_block_in_unsafe_fn  => { 
380+                 for  violation in  violations { 
381+                     let  mut  violation = * violation; 
382+ 
383+                     if  violation. kind  == UnsafetyViolationKind :: BorrowPacked  { 
384+                         violation. kind  = UnsafetyViolationKind :: UnsafeFnBorrowPacked ; 
385+                     }  else  { 
386+                         violation. kind  = UnsafetyViolationKind :: UnsafeFn ; 
354387                    } 
355388                    if  !self . violations . contains ( & violation)  { 
356389                        self . violations . push ( violation) 
357390                    } 
358391                } 
359392                false 
360393            } 
361-             // `unsafe` function bodies allow unsafe without additional unsafe blocks 
394+             // `unsafe` function bodies allow unsafe without additional unsafe blocks (before RFC 2585)  
362395            Safety :: BuiltinUnsafe  | Safety :: FnUnsafe  => true , 
363396            Safety :: ExplicitUnsafe ( hir_id)  => { 
364397                // mark unsafe block as used if there are any unsafe operations inside 
@@ -373,7 +406,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
373406                            UnsafetyViolationKind :: GeneralAndConstFn  => { } 
374407                            // these things are forbidden in const fns 
375408                            UnsafetyViolationKind :: General 
376-                             | UnsafetyViolationKind :: BorrowPacked ( _ )  => { 
409+                             | UnsafetyViolationKind :: BorrowPacked  => { 
377410                                let  mut  violation = * violation; 
378411                                // const fns don't need to be backwards compatible and can 
379412                                // emit these violations as a hard error instead of a backwards 
@@ -383,6 +416,10 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
383416                                    self . violations . push ( violation) 
384417                                } 
385418                            } 
419+                             UnsafetyViolationKind :: UnsafeFn 
420+                             | UnsafetyViolationKind :: UnsafeFnBorrowPacked  => bug ! ( 
421+                                 "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context" 
422+                             ) , 
386423                        } 
387424                    } 
388425                } 
@@ -575,9 +612,12 @@ fn is_enclosed(
575612            kind :  hir:: ItemKind :: Fn ( ref  sig,  _,  _) ,  ..
576613        } ) )  = tcx. hir ( ) . find ( parent_id) 
577614        { 
578-             match  sig. header . unsafety  { 
579-                 hir:: Unsafety :: Unsafe  => Some ( ( "fn" . to_string ( ) ,  parent_id) ) , 
580-                 hir:: Unsafety :: Normal  => None , 
615+             if  sig. header . unsafety  == hir:: Unsafety :: Unsafe 
616+                 && !tcx. features ( ) . unsafe_block_in_unsafe_fn 
617+             { 
618+                 Some ( ( "fn" . to_string ( ) ,  parent_id) ) 
619+             }  else  { 
620+                 None 
581621            } 
582622        }  else  { 
583623            is_enclosed ( tcx,  used_unsafe,  parent_id) 
@@ -630,40 +670,90 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
630670    let  UnsafetyCheckResult  {  violations,  unsafe_blocks }  =
631671        tcx. unsafety_check_result ( def_id. expect_local ( ) ) ; 
632672
633-     for  & UnsafetyViolation  {  source_info,  description,  details,  kind }  in  violations. iter ( )  { 
673+     for  & UnsafetyViolation  {  source_info,  lint_root,  description,  details,  kind }  in 
674+         violations. iter ( ) 
675+     { 
634676        // Report an error. 
677+         let  unsafe_fn_msg =
678+             if  unsafe_op_in_unsafe_fn_allowed ( tcx,  lint_root)  {  " function or"  }  else  {  ""  } ; 
679+ 
635680        match  kind { 
636681            UnsafetyViolationKind :: GeneralAndConstFn  | UnsafetyViolationKind :: General  => { 
682+                 // once 
637683                struct_span_err ! ( 
638684                    tcx. sess, 
639685                    source_info. span, 
640686                    E0133 , 
641-                     "{} is unsafe and requires unsafe function or block" , 
642-                     description
687+                     "{} is unsafe and requires unsafe{} block" , 
688+                     description, 
689+                     unsafe_fn_msg, 
643690                ) 
644691                . span_label ( source_info. span ,  & * description. as_str ( ) ) 
645692                . note ( & details. as_str ( ) ) 
646693                . emit ( ) ; 
647694            } 
648-             UnsafetyViolationKind :: BorrowPacked ( lint_hir_id )  => { 
695+             UnsafetyViolationKind :: BorrowPacked  => { 
649696                if  let  Some ( impl_def_id)  = builtin_derive_def_id ( tcx,  def_id)  { 
650697                    tcx. ensure ( ) . unsafe_derive_on_repr_packed ( impl_def_id) ; 
651698                }  else  { 
652699                    tcx. struct_span_lint_hir ( 
653700                        SAFE_PACKED_BORROWS , 
654-                         lint_hir_id , 
701+                         lint_root , 
655702                        source_info. span , 
656703                        |lint| { 
657704                            lint. build ( & format ! ( 
658-                                 "{} is unsafe and requires unsafe function or  block (error E0133)" , 
659-                                 description
705+                                 "{} is unsafe and requires unsafe{}  block (error E0133)" , 
706+                                 description,  unsafe_fn_msg , 
660707                            ) ) 
661708                            . note ( & details. as_str ( ) ) 
662709                            . emit ( ) 
663710                        } , 
664711                    ) 
665712                } 
666713            } 
714+             UnsafetyViolationKind :: UnsafeFn  => tcx. struct_span_lint_hir ( 
715+                 UNSAFE_OP_IN_UNSAFE_FN , 
716+                 lint_root, 
717+                 source_info. span , 
718+                 |lint| { 
719+                     lint. build ( & format ! ( 
720+                         "{} is unsafe and requires unsafe block (error E0133)" , 
721+                         description, 
722+                     ) ) 
723+                     . span_label ( source_info. span ,  & * description. as_str ( ) ) 
724+                     . note ( & details. as_str ( ) ) 
725+                     . emit ( ) ; 
726+                 } , 
727+             ) , 
728+             UnsafetyViolationKind :: UnsafeFnBorrowPacked  => { 
729+                 // When `unsafe_op_in_unsafe_fn` is disallowed, the behavior of safe and unsafe functions 
730+                 // should be the same in terms of warnings and errors. Therefore, with `#[warn(safe_packed_borrows)]`, 
731+                 // a safe packed borrow should emit a warning *but not an error* in an unsafe function, 
732+                 // just like in a safe function, even if `unsafe_op_in_unsafe_fn` is `deny`. 
733+                 // 
734+                 // Also, `#[warn(unsafe_op_in_unsafe_fn)]` can't cause any new errors. Therefore, with 
735+                 // `#[deny(safe_packed_borrows)]` and `#[warn(unsafe_op_in_unsafe_fn)]`, a packed borrow 
736+                 // should only issue a warning for the sake of backwards compatibility. 
737+                 // 
738+                 // The solution those 2 expectations is to always take the minimum of both lints. 
739+                 // This prevent any new errors (unless both lints are explicitely set to `deny`). 
740+                 let  lint = if  tcx. lint_level_at_node ( SAFE_PACKED_BORROWS ,  lint_root) . 0 
741+                     <= tcx. lint_level_at_node ( UNSAFE_OP_IN_UNSAFE_FN ,  lint_root) . 0 
742+                 { 
743+                     SAFE_PACKED_BORROWS 
744+                 }  else  { 
745+                     UNSAFE_OP_IN_UNSAFE_FN 
746+                 } ; 
747+                 tcx. struct_span_lint_hir ( & lint,  lint_root,  source_info. span ,  |lint| { 
748+                     lint. build ( & format ! ( 
749+                         "{} is unsafe and requires unsafe block (error E0133)" , 
750+                         description, 
751+                     ) ) 
752+                     . span_label ( source_info. span ,  & * description. as_str ( ) ) 
753+                     . note ( & details. as_str ( ) ) 
754+                     . emit ( ) ; 
755+                 } ) 
756+             } 
667757        } 
668758    } 
669759
@@ -683,3 +773,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
683773        report_unused_unsafe ( tcx,  & unsafe_used,  block_id) ; 
684774    } 
685775} 
776+ 
777+ fn  unsafe_op_in_unsafe_fn_allowed ( tcx :  TyCtxt < ' _ > ,  id :  HirId )  -> bool  { 
778+     tcx. lint_level_at_node ( UNSAFE_OP_IN_UNSAFE_FN ,  id) . 0  == Level :: Allow 
779+ } 
0 commit comments