@@ -2,61 +2,57 @@ use rustc_hir::*;
2
2
use rustc_lint:: { LateContext , LateLintPass } ;
3
3
use rustc_session:: declare_lint_pass;
4
4
use 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 ;
6
8
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 {
14
10
let asm_in_expr = match asm_op {
11
+ InlineAsmOperand :: SymStatic { .. }
12
+ | InlineAsmOperand :: Out { .. }
13
+ | InlineAsmOperand :: Const { .. }
14
+ | InlineAsmOperand :: SymFn { .. }
15
+ | InlineAsmOperand :: Label { .. } => return false ,
15
16
InlineAsmOperand :: In { expr, .. } => expr,
16
17
InlineAsmOperand :: InOut { expr, .. } => expr,
17
18
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 ,
23
19
} ;
24
20
25
21
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 ,
29
25
} ;
30
26
}
31
27
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 ) )
34
30
}
35
31
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) ;
45
35
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
+ }
51
48
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 > > ( ) ;
58
53
59
- yeet_lint ( cx, * asm_op_span, msg) ;
54
+ if !spans. is_empty ( ) {
55
+ yeet_lint ( cx, asm, asm_span, spans) ;
60
56
}
61
57
}
62
58
@@ -84,7 +80,7 @@ declare_lint_pass!(PointerInNomemAsmBlock => [POINTER_IN_NOMEM_ASM_BLOCK]);
84
80
impl < ' tcx > LateLintPass < ' tcx > for PointerInNomemAsmBlock {
85
81
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) {
86
82
if let ExprKind :: InlineAsm ( asm) = & expr. kind {
87
- check_asm ( cx, asm) ;
83
+ check_asm ( cx, asm, expr . span ) ;
88
84
}
89
85
}
90
86
}
0 commit comments