@@ -7,7 +7,7 @@ use either::Either;
7
7
use hir_def:: {
8
8
AdtId , DefWithBodyId , FieldId , FunctionId , VariantId ,
9
9
expr_store:: { Body , path:: Path } ,
10
- hir:: { Expr , ExprId , ExprOrPatId , Pat , PatId , Statement , UnaryOp } ,
10
+ hir:: { AsmOperand , Expr , ExprId , ExprOrPatId , Pat , PatId , Statement , UnaryOp } ,
11
11
resolver:: { HasResolver , ResolveValueResult , Resolver , ValueNs } ,
12
12
signatures:: StaticFlags ,
13
13
type_ref:: Rawness ,
@@ -199,6 +199,17 @@ impl<'db> UnsafeVisitor<'db> {
199
199
}
200
200
}
201
201
202
+ fn with_inside_unsafe_block < R > (
203
+ & mut self ,
204
+ inside_unsafe_block : InsideUnsafeBlock ,
205
+ f : impl FnOnce ( & mut Self ) -> R ,
206
+ ) -> R {
207
+ let old = mem:: replace ( & mut self . inside_unsafe_block , inside_unsafe_block) ;
208
+ let result = f ( self ) ;
209
+ self . inside_unsafe_block = old;
210
+ result
211
+ }
212
+
202
213
fn walk_pats_top ( & mut self , pats : impl Iterator < Item = PatId > , parent_expr : ExprId ) {
203
214
let guard = self . resolver . update_to_inner_scope ( self . db , self . def , parent_expr) ;
204
215
pats. for_each ( |pat| self . walk_pat ( pat) ) ;
@@ -303,7 +314,29 @@ impl<'db> UnsafeVisitor<'db> {
303
314
self . walk_pats_top ( std:: iter:: once ( target) , current) ;
304
315
self . inside_assignment = old_inside_assignment;
305
316
}
306
- Expr :: InlineAsm ( _) => self . on_unsafe_op ( current. into ( ) , UnsafetyReason :: InlineAsm ) ,
317
+ Expr :: InlineAsm ( asm) => {
318
+ self . on_unsafe_op ( current. into ( ) , UnsafetyReason :: InlineAsm ) ;
319
+ asm. operands . iter ( ) . for_each ( |( _, op) | match op {
320
+ AsmOperand :: In { expr, .. }
321
+ | AsmOperand :: Out { expr : Some ( expr) , .. }
322
+ | AsmOperand :: InOut { expr, .. }
323
+ | AsmOperand :: Const ( expr) => self . walk_expr ( * expr) ,
324
+ AsmOperand :: SplitInOut { in_expr, out_expr, .. } => {
325
+ self . walk_expr ( * in_expr) ;
326
+ if let Some ( out_expr) = out_expr {
327
+ self . walk_expr ( * out_expr) ;
328
+ }
329
+ }
330
+ AsmOperand :: Out { expr : None , .. } | AsmOperand :: Sym ( _) => ( ) ,
331
+ AsmOperand :: Label ( expr) => {
332
+ // Inline asm labels are considered safe even when inside unsafe blocks.
333
+ self . with_inside_unsafe_block ( InsideUnsafeBlock :: No , |this| {
334
+ this. walk_expr ( * expr)
335
+ } ) ;
336
+ }
337
+ } ) ;
338
+ return ;
339
+ }
307
340
// rustc allows union assignment to propagate through field accesses and casts.
308
341
Expr :: Cast { .. } => self . inside_assignment = inside_assignment,
309
342
Expr :: Field { .. } => {
@@ -317,17 +350,16 @@ impl<'db> UnsafeVisitor<'db> {
317
350
}
318
351
}
319
352
Expr :: Unsafe { statements, .. } => {
320
- let old_inside_unsafe_block =
321
- mem:: replace ( & mut self . inside_unsafe_block , InsideUnsafeBlock :: Yes ) ;
322
- self . walk_pats_top (
323
- statements. iter ( ) . filter_map ( |statement| match statement {
324
- & Statement :: Let { pat, .. } => Some ( pat) ,
325
- _ => None ,
326
- } ) ,
327
- current,
328
- ) ;
329
- self . body . walk_child_exprs_without_pats ( current, |child| self . walk_expr ( child) ) ;
330
- self . inside_unsafe_block = old_inside_unsafe_block;
353
+ self . with_inside_unsafe_block ( InsideUnsafeBlock :: Yes , |this| {
354
+ this. walk_pats_top (
355
+ statements. iter ( ) . filter_map ( |statement| match statement {
356
+ & Statement :: Let { pat, .. } => Some ( pat) ,
357
+ _ => None ,
358
+ } ) ,
359
+ current,
360
+ ) ;
361
+ this. body . walk_child_exprs_without_pats ( current, |child| this. walk_expr ( child) ) ;
362
+ } ) ;
331
363
return ;
332
364
}
333
365
Expr :: Block { statements, .. } | Expr :: Async { statements, .. } => {
0 commit comments