@@ -7,7 +7,7 @@ use either::Either;
77use hir_def:: {
88 AdtId , DefWithBodyId , FieldId , FunctionId , VariantId ,
99 expr_store:: { Body , path:: Path } ,
10- hir:: { Expr , ExprId , ExprOrPatId , Pat , PatId , Statement , UnaryOp } ,
10+ hir:: { AsmOperand , Expr , ExprId , ExprOrPatId , Pat , PatId , Statement , UnaryOp } ,
1111 resolver:: { HasResolver , ResolveValueResult , Resolver , ValueNs } ,
1212 signatures:: StaticFlags ,
1313 type_ref:: Rawness ,
@@ -199,6 +199,17 @@ impl<'db> UnsafeVisitor<'db> {
199199 }
200200 }
201201
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+
202213 fn walk_pats_top ( & mut self , pats : impl Iterator < Item = PatId > , parent_expr : ExprId ) {
203214 let guard = self . resolver . update_to_inner_scope ( self . db , self . def , parent_expr) ;
204215 pats. for_each ( |pat| self . walk_pat ( pat) ) ;
@@ -303,7 +314,29 @@ impl<'db> UnsafeVisitor<'db> {
303314 self . walk_pats_top ( std:: iter:: once ( target) , current) ;
304315 self . inside_assignment = old_inside_assignment;
305316 }
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+ }
307340 // rustc allows union assignment to propagate through field accesses and casts.
308341 Expr :: Cast { .. } => self . inside_assignment = inside_assignment,
309342 Expr :: Field { .. } => {
@@ -317,17 +350,16 @@ impl<'db> UnsafeVisitor<'db> {
317350 }
318351 }
319352 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+ } ) ;
331363 return ;
332364 }
333365 Expr :: Block { statements, .. } | Expr :: Async { statements, .. } => {
0 commit comments