@@ -35,6 +35,10 @@ struct UnsafetyVisitor<'a, 'tcx> {
3535 param_env : ParamEnv < ' tcx > ,
3636 inside_adt : bool ,
3737 warnings : & ' a mut Vec < UnusedUnsafeWarning > ,
38+
39+ /// Flag to ensure that we only suggest wrapping the entire function body in
40+ /// an unsafe block once.
41+ suggest_unsafe_block : bool ,
3842}
3943
4044impl < ' tcx > UnsafetyVisitor < ' _ , ' tcx > {
@@ -95,7 +99,13 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
9599 SafetyContext :: UnsafeFn if unsafe_op_in_unsafe_fn_allowed => { }
96100 SafetyContext :: UnsafeFn => {
97101 // unsafe_op_in_unsafe_fn is disallowed
98- kind. emit_unsafe_op_in_unsafe_fn_lint ( self . tcx , self . hir_context , span) ;
102+ kind. emit_unsafe_op_in_unsafe_fn_lint (
103+ self . tcx ,
104+ self . hir_context ,
105+ span,
106+ self . suggest_unsafe_block ,
107+ ) ;
108+ self . suggest_unsafe_block = false ;
99109 }
100110 SafetyContext :: Safe => {
101111 kind. emit_requires_unsafe_err (
@@ -297,6 +307,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
297307 }
298308 PatKind :: InlineConstant { def, .. } => {
299309 self . visit_inner_body ( * def) ;
310+ visit:: walk_pat ( self , pat) ;
300311 }
301312 _ => {
302313 visit:: walk_pat ( self , pat) ;
@@ -394,7 +405,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
394405 }
395406 }
396407 ExprKind :: Deref { arg } => {
397- if let ExprKind :: StaticRef { def_id, .. } = self . thir [ arg] . kind {
408+ if let ExprKind :: StaticRef { def_id, .. } | ExprKind :: ThreadLocalRef ( def_id) =
409+ self . thir [ arg] . kind
410+ {
398411 if self . tcx . is_mutable_static ( def_id) {
399412 self . requires_unsafe ( expr. span , UseOfMutableStatic ) ;
400413 } else if self . tcx . is_foreign_item ( def_id) {
@@ -482,14 +495,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
482495 }
483496 }
484497 }
485- ExprKind :: Let { expr : expr_id, .. } => {
486- let let_expr = & self . thir [ expr_id] ;
487- if let ty:: Adt ( adt_def, _) = let_expr. ty . kind ( )
488- && adt_def. is_union ( )
489- {
490- self . requires_unsafe ( expr. span , AccessToUnionField ) ;
491- }
492- }
493498 _ => { }
494499 }
495500 visit:: walk_expr ( self , expr) ;
@@ -543,7 +548,22 @@ impl UnsafeOpKind {
543548 tcx : TyCtxt < ' _ > ,
544549 hir_id : hir:: HirId ,
545550 span : Span ,
551+ suggest_unsafe_block : bool ,
546552 ) {
553+ let parent_id = tcx. hir ( ) . get_parent_item ( hir_id) ;
554+ let parent_owner = tcx. hir ( ) . owner ( parent_id) ;
555+ let should_suggest = parent_owner. fn_sig ( ) . map_or ( false , |sig| sig. header . is_unsafe ( ) ) ;
556+ let unsafe_not_inherited_note = if should_suggest {
557+ suggest_unsafe_block. then ( || {
558+ let body_span = tcx. hir ( ) . body ( parent_owner. body_id ( ) . unwrap ( ) ) . value . span ;
559+ UnsafeNotInheritedLintNote {
560+ signature_span : tcx. def_span ( parent_id. def_id ) ,
561+ body_span,
562+ }
563+ } )
564+ } else {
565+ None
566+ } ;
547567 // FIXME: ideally we would want to trim the def paths, but this is not
548568 // feasible with the current lint emission API (see issue #106126).
549569 match self {
@@ -554,61 +574,89 @@ impl UnsafeOpKind {
554574 UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
555575 span,
556576 function : & with_no_trimmed_paths ! ( tcx. def_path_str( * did) ) ,
577+ unsafe_not_inherited_note,
557578 } ,
558579 ) ,
559580 CallToUnsafeFunction ( None ) => tcx. emit_spanned_lint (
560581 UNSAFE_OP_IN_UNSAFE_FN ,
561582 hir_id,
562583 span,
563- UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { span } ,
584+ UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
585+ span,
586+ unsafe_not_inherited_note,
587+ } ,
564588 ) ,
565589 UseOfInlineAssembly => tcx. emit_spanned_lint (
566590 UNSAFE_OP_IN_UNSAFE_FN ,
567591 hir_id,
568592 span,
569- UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { span } ,
593+ UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
594+ span,
595+ unsafe_not_inherited_note,
596+ } ,
570597 ) ,
571598 InitializingTypeWith => tcx. emit_spanned_lint (
572599 UNSAFE_OP_IN_UNSAFE_FN ,
573600 hir_id,
574601 span,
575- UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { span } ,
602+ UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
603+ span,
604+ unsafe_not_inherited_note,
605+ } ,
576606 ) ,
577607 UseOfMutableStatic => tcx. emit_spanned_lint (
578608 UNSAFE_OP_IN_UNSAFE_FN ,
579609 hir_id,
580610 span,
581- UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { span } ,
611+ UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
612+ span,
613+ unsafe_not_inherited_note,
614+ } ,
582615 ) ,
583616 UseOfExternStatic => tcx. emit_spanned_lint (
584617 UNSAFE_OP_IN_UNSAFE_FN ,
585618 hir_id,
586619 span,
587- UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { span } ,
620+ UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
621+ span,
622+ unsafe_not_inherited_note,
623+ } ,
588624 ) ,
589625 DerefOfRawPointer => tcx. emit_spanned_lint (
590626 UNSAFE_OP_IN_UNSAFE_FN ,
591627 hir_id,
592628 span,
593- UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { span } ,
629+ UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
630+ span,
631+ unsafe_not_inherited_note,
632+ } ,
594633 ) ,
595634 AccessToUnionField => tcx. emit_spanned_lint (
596635 UNSAFE_OP_IN_UNSAFE_FN ,
597636 hir_id,
598637 span,
599- UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { span } ,
638+ UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
639+ span,
640+ unsafe_not_inherited_note,
641+ } ,
600642 ) ,
601643 MutationOfLayoutConstrainedField => tcx. emit_spanned_lint (
602644 UNSAFE_OP_IN_UNSAFE_FN ,
603645 hir_id,
604646 span,
605- UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { span } ,
647+ UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
648+ span,
649+ unsafe_not_inherited_note,
650+ } ,
606651 ) ,
607652 BorrowOfLayoutConstrainedField => tcx. emit_spanned_lint (
608653 UNSAFE_OP_IN_UNSAFE_FN ,
609654 hir_id,
610655 span,
611- UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { span } ,
656+ UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
657+ span,
658+ unsafe_not_inherited_note,
659+ } ,
612660 ) ,
613661 CallToFunctionWith ( did) => tcx. emit_spanned_lint (
614662 UNSAFE_OP_IN_UNSAFE_FN ,
@@ -617,6 +665,7 @@ impl UnsafeOpKind {
617665 UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
618666 span,
619667 function : & with_no_trimmed_paths ! ( tcx. def_path_str( * did) ) ,
668+ unsafe_not_inherited_note,
620669 } ,
621670 ) ,
622671 }
@@ -831,6 +880,7 @@ pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
831880 param_env : tcx. param_env ( def) ,
832881 inside_adt : false ,
833882 warnings : & mut warnings,
883+ suggest_unsafe_block : true ,
834884 } ;
835885 visitor. visit_expr ( & thir[ expr] ) ;
836886
0 commit comments