@@ -14,12 +14,14 @@ use self::RootUnsafeContext::*;
14
14
15
15
use ty:: { self , TyCtxt } ;
16
16
use lint;
17
+ use lint:: builtin:: UNUSED_UNSAFE ;
17
18
18
- use syntax:: ast;
19
- use syntax_pos:: Span ;
20
- use hir:: { self , PatKind } ;
21
19
use hir:: def:: Def ;
22
20
use hir:: intravisit:: { self , FnKind , Visitor , NestedVisitorMap } ;
21
+ use hir:: { self , PatKind } ;
22
+ use syntax:: ast;
23
+ use syntax_pos:: Span ;
24
+ use util:: nodemap:: FxHashSet ;
23
25
24
26
#[ derive( Copy , Clone ) ]
25
27
struct UnsafeContext {
@@ -47,6 +49,7 @@ struct EffectCheckVisitor<'a, 'tcx: 'a> {
47
49
48
50
/// Whether we're in an unsafe context.
49
51
unsafe_context : UnsafeContext ,
52
+ used_unsafe : FxHashSet < ast:: NodeId > ,
50
53
}
51
54
52
55
impl < ' a , ' tcx > EffectCheckVisitor < ' a , ' tcx > {
@@ -73,7 +76,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> {
73
76
UnsafeBlock ( block_id) => {
74
77
// OK, but record this.
75
78
debug ! ( "effect: recording unsafe block as used: {}" , block_id) ;
76
- self . tcx . used_unsafe . borrow_mut ( ) . insert ( block_id) ;
79
+ self . used_unsafe . insert ( block_id) ;
77
80
}
78
81
UnsafeFn => { }
79
82
}
@@ -159,7 +162,48 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
159
162
160
163
intravisit:: walk_block ( self , block) ;
161
164
162
- self . unsafe_context = old_unsafe_context
165
+ self . unsafe_context = old_unsafe_context;
166
+
167
+ // Don't warn about generated blocks, that'll just pollute the output.
168
+ match block. rules {
169
+ hir:: UnsafeBlock ( hir:: UserProvided ) => { }
170
+ _ => return ,
171
+ }
172
+ if self . used_unsafe . contains ( & block. id ) {
173
+ return
174
+ }
175
+
176
+ /// Return the NodeId for an enclosing scope that is also `unsafe`
177
+ fn is_enclosed ( tcx : TyCtxt ,
178
+ used_unsafe : & FxHashSet < ast:: NodeId > ,
179
+ id : ast:: NodeId ) -> Option < ( String , ast:: NodeId ) > {
180
+ let parent_id = tcx. hir . get_parent_node ( id) ;
181
+ if parent_id != id {
182
+ if used_unsafe. contains ( & parent_id) {
183
+ Some ( ( "block" . to_string ( ) , parent_id) )
184
+ } else if let Some ( hir:: map:: NodeItem ( & hir:: Item {
185
+ node : hir:: ItemFn ( _, hir:: Unsafety :: Unsafe , _, _, _, _) ,
186
+ ..
187
+ } ) ) = tcx. hir . find ( parent_id) {
188
+ Some ( ( "fn" . to_string ( ) , parent_id) )
189
+ } else {
190
+ is_enclosed ( tcx, used_unsafe, parent_id)
191
+ }
192
+ } else {
193
+ None
194
+ }
195
+ }
196
+
197
+ let mut db = self . tcx . struct_span_lint_node ( UNUSED_UNSAFE ,
198
+ block. id ,
199
+ block. span ,
200
+ "unnecessary `unsafe` block" ) ;
201
+ db. span_label ( block. span , "unnecessary `unsafe` block" ) ;
202
+ if let Some ( ( kind, id) ) = is_enclosed ( self . tcx , & self . used_unsafe , block. id ) {
203
+ db. span_note ( self . tcx . hir . span ( id) ,
204
+ & format ! ( "because it's nested under this `unsafe` {}" , kind) ) ;
205
+ }
206
+ db. emit ( ) ;
163
207
}
164
208
165
209
fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr ) {
@@ -265,6 +309,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
265
309
tables : & ty:: TypeckTables :: empty ( None ) ,
266
310
body_id : hir:: BodyId { node_id : ast:: CRATE_NODE_ID } ,
267
311
unsafe_context : UnsafeContext :: new ( SafeContext ) ,
312
+ used_unsafe : FxHashSet ( ) ,
268
313
} ;
269
314
270
315
tcx. hir . krate ( ) . visit_all_item_likes ( & mut visitor. as_deep_visitor ( ) ) ;
0 commit comments