@@ -2,61 +2,57 @@ use rustc_hir::*;
22use rustc_lint:: { LateContext , LateLintPass } ;
33use rustc_session:: declare_lint_pass;
44use rustc_ast:: InlineAsmOptions ;
5- use clippy_utils:: diagnostics:: span_lint;
5+ use clippy_utils:: diagnostics:: span_lint_and_then;
6+ use rustc_span:: { BytePos , Span } ;
7+ use rustc_errors:: Applicability ;
68
7- #[ derive( Clone , Copy , PartialEq , Eq ) ]
8- enum AsmMemoryOptions {
9- NoMem ,
10- Readonly ,
11- }
12-
13- fn has_in_operand_pointer ( cx : & LateContext < ' _ > , asm_op : & InlineAsmOperand < ' _ > ) -> Option < Mutability > {
9+ fn has_in_operand_pointer ( cx : & LateContext < ' _ > , asm_op : & InlineAsmOperand < ' _ > ) -> bool {
1410 let asm_in_expr = match asm_op {
11+ InlineAsmOperand :: SymStatic { .. }
12+ | InlineAsmOperand :: Out { .. }
13+ | InlineAsmOperand :: Const { .. }
14+ | InlineAsmOperand :: SymFn { .. }
15+ | InlineAsmOperand :: Label { .. } => return false ,
1516 InlineAsmOperand :: In { expr, .. } => expr,
1617 InlineAsmOperand :: InOut { expr, .. } => expr,
1718 InlineAsmOperand :: SplitInOut { in_expr, ..} => in_expr,
18- InlineAsmOperand :: SymStatic { .. } => return Some ( Mutability :: Not ) ,
19- InlineAsmOperand :: Out { .. } => return None ,
20- InlineAsmOperand :: Const { .. } => return None ,
21- InlineAsmOperand :: SymFn { .. } => return None ,
22- InlineAsmOperand :: Label { .. } => return None ,
2319 } ;
2420
2521 return match cx. typeck_results ( ) . expr_ty ( asm_in_expr) . kind ( ) {
26- rustc_middle:: ty:: TyKind :: RawPtr ( _ , mutbl ) => Some ( * mutbl ) ,
27- rustc_middle:: ty:: TyKind :: Ref ( _ , _ , mutbl ) => Some ( * mutbl ) ,
28- _ => None ,
22+ rustc_middle:: ty:: TyKind :: RawPtr ( .. ) => true ,
23+ rustc_middle:: ty:: TyKind :: Ref ( .. ) => true ,
24+ _ => false ,
2925 } ;
3026}
3127
32- fn yeet_lint ( cx : & LateContext < ' _ > , span : rustc_span :: Span , msg : & ' static str ) {
33- span_lint ( cx , POINTER_IN_NOMEM_ASM_BLOCK , span , msg ) ;
28+ fn shift_span_by_two_bytes ( s : Span ) -> Span {
29+ s . with_lo ( s . lo ( ) + BytePos ( 2 ) )
3430}
3531
36- fn check_asm ( cx : & LateContext < ' _ > , asm : & InlineAsm < ' _ > ) {
37- let nomem = asm. options . contains ( InlineAsmOptions :: NOMEM ) ;
38- let rdonly = asm. options . contains ( InlineAsmOptions :: READONLY ) ;
39- let memopt = match ( nomem, rdonly) {
40- ( false , false ) => return , // nothing to check
41- ( false , true ) => AsmMemoryOptions :: Readonly ,
42- ( true , false ) => AsmMemoryOptions :: NoMem ,
43- ( true , true ) => return , // just return, rustc should fail anyway
44- } ;
32+ fn yeet_lint ( cx : & LateContext < ' _ > , asm : & InlineAsm < ' _ > , asm_span : Span , op_spans : Vec < Span > ) {
33+ let last_op_span = asm. operands . last ( ) . unwrap ( ) . 1 ;
34+ let probably_asm_options_span = asm_span. trim_start ( last_op_span) . map ( shift_span_by_two_bytes) ;
4535
46- for ( asm_op, asm_op_span) in asm. operands {
47- let p = match has_in_operand_pointer ( cx, asm_op) {
48- Some ( p) => p,
49- None => continue ,
50- } ;
36+ span_lint_and_then ( cx, POINTER_IN_NOMEM_ASM_BLOCK , op_spans, "passing pointer to nomem asm block" , |diag| {
37+ if let Some ( probably_asm_options_span) = probably_asm_options_span {
38+ diag. span_suggestion ( probably_asm_options_span, "heeelppp" , "suggg" , Applicability :: MaybeIncorrect ) ;
39+ }
40+ // note_span.inspect(|s| { diag.span_note(*s, "declared here"); });
41+ } ) ;
42+ }
43+
44+ fn check_asm ( cx : & LateContext < ' _ > , asm : & InlineAsm < ' _ > , asm_span : Span ) {
45+ if !asm. options . contains ( InlineAsmOptions :: NOMEM ) || asm. operands . is_empty ( ) {
46+ return ;
47+ }
5148
52- let msg = match ( p, memopt) {
53- ( Mutability :: Not , AsmMemoryOptions :: Readonly ) => continue ,
54- ( Mutability :: Not , AsmMemoryOptions :: NoMem ) => "const pointer in nomem" ,
55- ( Mutability :: Mut , AsmMemoryOptions :: Readonly ) => "mut pointer in readonly" ,
56- ( Mutability :: Mut , AsmMemoryOptions :: NoMem ) => "mut pointer in nomem" ,
57- } ;
49+ let spans = asm. operands . iter ( )
50+ . filter ( |( op, _span) | has_in_operand_pointer ( cx, op) )
51+ . map ( |( _op, span) | * span)
52+ . collect :: < Vec < Span > > ( ) ;
5853
59- yeet_lint ( cx, * asm_op_span, msg) ;
54+ if !spans. is_empty ( ) {
55+ yeet_lint ( cx, asm, asm_span, spans) ;
6056 }
6157}
6258
@@ -84,7 +80,7 @@ declare_lint_pass!(PointerInNomemAsmBlock => [POINTER_IN_NOMEM_ASM_BLOCK]);
8480impl < ' tcx > LateLintPass < ' tcx > for PointerInNomemAsmBlock {
8581 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) {
8682 if let ExprKind :: InlineAsm ( asm) = & expr. kind {
87- check_asm ( cx, asm) ;
83+ check_asm ( cx, asm, expr . span ) ;
8884 }
8985 }
9086}
0 commit comments