1- use clippy_utils :: desugar_await ;
1+ use clippy_config :: Conf ;
22use clippy_utils:: diagnostics:: span_lint_and_then;
3+ use clippy_utils:: msrvs:: Msrv ;
34use clippy_utils:: visitors:: { Descend , Visitable , for_each_expr} ;
5+ use clippy_utils:: { desugar_await, msrvs} ;
46use core:: ops:: ControlFlow :: Continue ;
57use hir:: def:: { DefKind , Res } ;
68use hir:: { BlockCheckMode , ExprKind , QPath , UnOp } ;
@@ -9,7 +11,7 @@ use rustc_data_structures::fx::FxHashSet;
911use rustc_hir as hir;
1012use rustc_lint:: { LateContext , LateLintPass } ;
1113use rustc_middle:: ty;
12- use rustc_session:: declare_lint_pass ;
14+ use rustc_session:: impl_lint_pass ;
1315use rustc_span:: { DesugaringKind , Span } ;
1416
1517declare_clippy_lint ! {
@@ -61,7 +63,18 @@ declare_clippy_lint! {
6163 restriction,
6264 "more than one unsafe operation per `unsafe` block"
6365}
64- declare_lint_pass ! ( MultipleUnsafeOpsPerBlock => [ MULTIPLE_UNSAFE_OPS_PER_BLOCK ] ) ;
66+
67+ pub struct MultipleUnsafeOpsPerBlock {
68+ msrv : Msrv ,
69+ }
70+
71+ impl_lint_pass ! ( MultipleUnsafeOpsPerBlock => [ MULTIPLE_UNSAFE_OPS_PER_BLOCK ] ) ;
72+
73+ impl MultipleUnsafeOpsPerBlock {
74+ pub fn new ( conf : & Conf ) -> Self {
75+ Self { msrv : conf. msrv }
76+ }
77+ }
6578
6679impl < ' tcx > LateLintPass < ' tcx > for MultipleUnsafeOpsPerBlock {
6780 fn check_block ( & mut self , cx : & LateContext < ' tcx > , block : & ' tcx hir:: Block < ' _ > ) {
@@ -72,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
7285 return ;
7386 }
7487 let mut unsafe_ops = vec ! [ ] ;
75- collect_unsafe_exprs ( cx, block, & mut unsafe_ops) ;
88+ collect_unsafe_exprs ( cx, block, & mut unsafe_ops, self . msrv ) ;
7689 if unsafe_ops. len ( ) > 1 {
7790 span_lint_and_then (
7891 cx,
@@ -96,14 +109,15 @@ fn collect_unsafe_exprs<'tcx>(
96109 cx : & LateContext < ' tcx > ,
97110 node : impl Visitable < ' tcx > ,
98111 unsafe_ops : & mut Vec < ( & ' static str , Span ) > ,
112+ msrv : Msrv ,
99113) {
100114 let mut ignored_field = FxHashSet :: default ( ) ;
101115 for_each_expr ( cx, node, |expr| {
102116 match expr. kind {
103117 // The `await` itself will desugar to two unsafe calls, but we should ignore those.
104118 // Instead, check the expression that is `await`ed
105119 _ if let Some ( e) = desugar_await ( expr) => {
106- collect_unsafe_exprs ( cx, e, unsafe_ops) ;
120+ collect_unsafe_exprs ( cx, e, unsafe_ops, msrv ) ;
107121 return Continue ( Descend :: No ) ;
108122 } ,
109123
@@ -113,7 +127,15 @@ fn collect_unsafe_exprs<'tcx>(
113127 // still be checked, it should not trigger if the place is a union field. The prefix of the field
114128 // access should still be checked, so it is necessary to descend.
115129 ExprKind :: AddrOf ( BorrowKind :: Raw , _, mut inner_expr) => {
130+ // Checking current MSRV might be expensive, do it only if necessary
131+ let mut msrv_checked = false ;
116132 while let ExprKind :: Field ( e, _) = inner_expr. kind {
133+ if !msrv_checked {
134+ if !msrv. meets ( cx, msrvs:: SAFE_RAW_PTR_TO_UNION_FIELD ) {
135+ break ;
136+ }
137+ msrv_checked = true ;
138+ }
117139 ignored_field. insert ( inner_expr. hir_id ) ;
118140 inner_expr = e;
119141 }
@@ -186,7 +208,7 @@ fn collect_unsafe_exprs<'tcx>(
186208 ) )
187209 ) {
188210 unsafe_ops. push ( ( "modification of a mutable static occurs here" , expr. span ) ) ;
189- collect_unsafe_exprs ( cx, rhs, unsafe_ops) ;
211+ collect_unsafe_exprs ( cx, rhs, unsafe_ops, msrv ) ;
190212 return Continue ( Descend :: No ) ;
191213 }
192214 } ,
0 commit comments