Skip to content

Commit 12aedc8

Browse files
committed
collect unused unsafe code
FIXME: de-uglify
1 parent cd279a5 commit 12aedc8

File tree

10 files changed

+221
-74
lines changed

10 files changed

+221
-74
lines changed

src/librustc/dep_graph/dep_node.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ define_dep_nodes!( <'tcx>
482482
[] BorrowCheckKrate,
483483
[] BorrowCheck(DefId),
484484
[] MirBorrowCheck(DefId),
485-
[] UnsafetyViolations(DefId),
485+
[] UnsafetyCheckResult(DefId),
486486

487487
[] Reachability,
488488
[] MirKeys,

src/librustc/ich/impls_mir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
3434
impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref });
3535
impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup });
3636
impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, lint_node_id });
37+
impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks });
3738

3839
impl<'gcx> HashStable<StableHashingContext<'gcx>>
3940
for mir::Terminator<'gcx> {

src/librustc/mir/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use std::cell::Ref;
3333
use std::fmt::{self, Debug, Formatter, Write};
3434
use std::{iter, u32};
3535
use std::ops::{Index, IndexMut};
36+
use std::rc::Rc;
3637
use std::vec::IntoIter;
3738
use syntax::ast::{self, Name};
3839
use syntax_pos::Span;
@@ -1683,6 +1684,15 @@ pub struct UnsafetyViolation {
16831684
pub lint_node_id: Option<ast::NodeId>,
16841685
}
16851686

1687+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1688+
pub struct UnsafetyCheckResult {
1689+
/// Violations that are propagated *upwards* from this function
1690+
pub violations: Rc<[UnsafetyViolation]>,
1691+
/// unsafe blocks in this function, along with whether they are used. This is
1692+
/// used for the "unused_unsafe" lint.
1693+
pub unsafe_blocks: Rc<[(ast::NodeId, bool)]>,
1694+
}
1695+
16861696
/// The layout of generator state
16871697
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
16881698
pub struct GeneratorLayout<'tcx> {

src/librustc/ty/maps/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,8 @@ define_maps! { <'tcx>
171171
/// expression defining the closure.
172172
[] fn closure_kind: ClosureKind(DefId) -> ty::ClosureKind,
173173

174-
/// Unsafety violations for this def ID.
175-
[] fn unsafety_violations: UnsafetyViolations(DefId)
176-
-> Rc<[mir::UnsafetyViolation]>,
174+
/// The result of unsafety-checking this def-id.
175+
[] fn unsafety_check_result: UnsafetyCheckResult(DefId) -> mir::UnsafetyCheckResult,
177176

178177
/// The signature of functions and closures.
179178
[] fn fn_sig: FnSignature(DefId) -> ty::PolyFnSig<'tcx>,

src/librustc/ty/maps/plumbing.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
720720

721721
DepKind::BorrowCheck => { force!(borrowck, def_id!()); }
722722
DepKind::MirBorrowCheck => { force!(mir_borrowck, def_id!()); }
723-
DepKind::UnsafetyViolations => { force!(unsafety_violations, def_id!()); }
723+
DepKind::UnsafetyCheckResult => { force!(unsafety_check_result, def_id!()); }
724724
DepKind::Reachability => { force!(reachable_set, LOCAL_CRATE); }
725725
DepKind::MirKeys => { force!(mir_keys, LOCAL_CRATE); }
726726
DepKind::CrateVariances => { force!(crate_variances, LOCAL_CRATE); }

src/librustc_mir/transform/check_unsafety.rs

+91-60
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> {
3434
tcx: TyCtxt<'a, 'tcx, 'tcx>,
3535
param_env: ty::ParamEnv<'tcx>,
3636
used_unsafe: FxHashSet<ast::NodeId>,
37+
inherited_blocks: Vec<(ast::NodeId, bool)>,
3738
}
3839

3940
impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> {
@@ -52,6 +53,7 @@ impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> {
5253
tcx,
5354
param_env,
5455
used_unsafe: FxHashSet(),
56+
inherited_blocks: vec![],
5557
}
5658
}
5759
}
@@ -124,8 +126,11 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
124126
&AggregateKind::Adt(..) => {}
125127
&AggregateKind::Closure(def_id, _) |
126128
&AggregateKind::Generator(def_id, _, _) => {
127-
let unsafety_violations = self.tcx.unsafety_violations(def_id);
128-
self.register_violations(&unsafety_violations);
129+
let UnsafetyCheckResult {
130+
violations, unsafe_blocks
131+
} = self.tcx.unsafety_check_result(def_id);
132+
self.inherited_blocks.extend(unsafe_blocks.iter().cloned());
133+
self.register_violations(&violations, &unsafe_blocks);
129134
}
130135
}
131136
}
@@ -194,7 +199,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
194199
source_info,
195200
description: "use of extern static",
196201
lint_node_id: Some(lint_root)
197-
}]);
202+
}], &[]);
198203
}
199204
}
200205
}
@@ -227,41 +232,49 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
227232
let source_info = self.source_info;
228233
self.register_violations(&[UnsafetyViolation {
229234
source_info, description, lint_node_id: None
230-
}]);
235+
}], &[]);
231236
}
232237

233-
fn register_violations(&mut self, violations: &[UnsafetyViolation]) {
234-
match self.visibility_scope_info[self.source_info.scope].safety {
238+
fn register_violations(&mut self,
239+
violations: &[UnsafetyViolation],
240+
unsafe_blocks: &[(ast::NodeId, bool)]) {
241+
let within_unsafe = match self.visibility_scope_info[self.source_info.scope].safety {
235242
Safety::Safe => {
236243
for violation in violations {
237244
if !self.violations.contains(violation) {
238245
self.violations.push(violation.clone())
239246
}
240247
}
248+
249+
false
241250
}
242-
Safety::BuiltinUnsafe | Safety::FnUnsafe => {}
251+
Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
243252
Safety::ExplicitUnsafe(node_id) => {
244253
if !violations.is_empty() {
245254
self.used_unsafe.insert(node_id);
246255
}
256+
true
247257
}
248-
}
258+
};
259+
self.inherited_blocks.extend(unsafe_blocks.iter().map(|&(node_id, is_used)| {
260+
(node_id, is_used && !within_unsafe)
261+
}));
249262
}
250263
}
251264

252265
pub(crate) fn provide(providers: &mut Providers) {
253266
*providers = Providers {
254-
unsafety_violations,
267+
unsafety_check_result,
255268
..*providers
256269
};
257270
}
258271

259-
struct UnusedUnsafeVisitor<'a, 'tcx: 'a> {
260-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
261-
used_unsafe: FxHashSet<ast::NodeId>
272+
struct UnusedUnsafeVisitor<'a> {
273+
used_unsafe: &'a FxHashSet<ast::NodeId>,
274+
unsafe_blocks: &'a mut Vec<(ast::NodeId, bool)>,
262275
}
263276

264-
impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'a, 'tcx> {
277+
impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'a> {
265278
fn nested_visit_map<'this>(&'this mut self) ->
266279
hir::intravisit::NestedVisitorMap<'this, 'tcx>
267280
{
@@ -272,50 +285,15 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'a, 'tcx>
272285
hir::intravisit::walk_block(self, block);
273286

274287
if let hir::UnsafeBlock(hir::UserProvided) = block.rules {
275-
if !self.used_unsafe.contains(&block.id) {
276-
self.report_unused_unsafe(block);
277-
}
278-
}
279-
}
280-
}
281-
282-
impl<'a, 'tcx> UnusedUnsafeVisitor<'a, 'tcx> {
283-
/// Return the NodeId for an enclosing scope that is also `unsafe`
284-
fn is_enclosed(&self, id: ast::NodeId) -> Option<(String, ast::NodeId)> {
285-
let parent_id = self.tcx.hir.get_parent_node(id);
286-
if parent_id != id {
287-
if self.used_unsafe.contains(&parent_id) {
288-
Some(("block".to_string(), parent_id))
289-
} else if let Some(hir::map::NodeItem(&hir::Item {
290-
node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _),
291-
..
292-
})) = self.tcx.hir.find(parent_id) {
293-
Some(("fn".to_string(), parent_id))
294-
} else {
295-
self.is_enclosed(parent_id)
296-
}
297-
} else {
298-
None
288+
self.unsafe_blocks.push((block.id, self.used_unsafe.contains(&block.id)));
299289
}
300290
}
301-
302-
fn report_unused_unsafe(&self, block: &'tcx hir::Block) {
303-
let mut db = self.tcx.struct_span_lint_node(UNUSED_UNSAFE,
304-
block.id,
305-
block.span,
306-
"unnecessary `unsafe` block");
307-
db.span_label(block.span, "unnecessary `unsafe` block");
308-
if let Some((kind, id)) = self.is_enclosed(block.id) {
309-
db.span_note(self.tcx.hir.span(id),
310-
&format!("because it's nested under this `unsafe` {}", kind));
311-
}
312-
db.emit();
313-
}
314291
}
315292

316293
fn check_unused_unsafe<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
317294
def_id: DefId,
318-
used_unsafe: FxHashSet<ast::NodeId>)
295+
used_unsafe: &FxHashSet<ast::NodeId>,
296+
unsafe_blocks: &'a mut Vec<(ast::NodeId, bool)>)
319297
{
320298
let body_id =
321299
tcx.hir.as_local_node_id(def_id).and_then(|node_id| {
@@ -333,13 +311,12 @@ fn check_unused_unsafe<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
333311
debug!("check_unused_unsafe({:?}, body={:?}, used_unsafe={:?})",
334312
def_id, body, used_unsafe);
335313

336-
hir::intravisit::Visitor::visit_body(
337-
&mut UnusedUnsafeVisitor { tcx, used_unsafe },
338-
body);
314+
let mut visitor = UnusedUnsafeVisitor { used_unsafe, unsafe_blocks };
315+
hir::intravisit::Visitor::visit_body(&mut visitor, body);
339316
}
340317

341-
fn unsafety_violations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) ->
342-
Rc<[UnsafetyViolation]>
318+
fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
319+
-> UnsafetyCheckResult
343320
{
344321
debug!("unsafety_violations({:?})", def_id);
345322

@@ -351,7 +328,10 @@ fn unsafety_violations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) ->
351328
ClearOnDecode::Set(ref data) => data,
352329
ClearOnDecode::Clear => {
353330
debug!("unsafety_violations: {:?} - remote, skipping", def_id);
354-
return Rc::new([])
331+
return UnsafetyCheckResult {
332+
violations: Rc::new([]),
333+
unsafe_blocks: Rc::new([])
334+
}
355335
}
356336
};
357337

@@ -360,8 +340,43 @@ fn unsafety_violations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) ->
360340
mir, visibility_scope_info, tcx, param_env);
361341
checker.visit_mir(mir);
362342

363-
check_unused_unsafe(tcx, def_id, checker.used_unsafe);
364-
checker.violations.into()
343+
check_unused_unsafe(tcx, def_id, &checker.used_unsafe, &mut checker.inherited_blocks);
344+
UnsafetyCheckResult {
345+
violations: checker.violations.into(),
346+
unsafe_blocks: checker.inherited_blocks.into()
347+
}
348+
}
349+
350+
/// Return the NodeId for an enclosing scope that is also `unsafe`
351+
fn is_enclosed(tcx: TyCtxt,
352+
used_unsafe: &FxHashSet<ast::NodeId>,
353+
id: ast::NodeId) -> Option<(String, ast::NodeId)> {
354+
let parent_id = tcx.hir.get_parent_node(id);
355+
if parent_id != id {
356+
if used_unsafe.contains(&parent_id) {
357+
Some(("block".to_string(), parent_id))
358+
} else if let Some(hir::map::NodeItem(&hir::Item {
359+
node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _),
360+
..
361+
})) = tcx.hir.find(parent_id) {
362+
Some(("fn".to_string(), parent_id))
363+
} else {
364+
is_enclosed(tcx, used_unsafe, parent_id)
365+
}
366+
} else {
367+
None
368+
}
369+
}
370+
371+
fn report_unused_unsafe(tcx: TyCtxt, used_unsafe: &FxHashSet<ast::NodeId>, id: ast::NodeId) {
372+
let span = tcx.hir.span(id);
373+
let mut db = tcx.struct_span_lint_node(UNUSED_UNSAFE, id, span, "unnecessary `unsafe` block");
374+
db.span_label(span, "unnecessary `unsafe` block");
375+
if let Some((kind, id)) = is_enclosed(tcx, used_unsafe, id) {
376+
db.span_note(tcx.hir.span(id),
377+
&format!("because it's nested under this `unsafe` {}", kind));
378+
}
379+
db.emit();
365380
}
366381

367382
pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
@@ -372,9 +387,14 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
372387
_ => {}
373388
};
374389

390+
let UnsafetyCheckResult {
391+
violations,
392+
unsafe_blocks
393+
} = tcx.unsafety_check_result(def_id);
394+
375395
for &UnsafetyViolation {
376396
source_info, description, lint_node_id
377-
} in &*tcx.unsafety_violations(def_id) {
397+
} in violations.iter() {
378398
// Report an error.
379399
if let Some(lint_node_id) = lint_node_id {
380400
tcx.lint_node(SAFE_EXTERN_STATICS,
@@ -390,4 +410,15 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
390410
.emit();
391411
}
392412
}
413+
414+
let mut unsafe_blocks: Vec<_> = unsafe_blocks.into_iter().collect();
415+
unsafe_blocks.sort();
416+
let used_unsafe: FxHashSet<_> = unsafe_blocks.iter()
417+
.flat_map(|&&(id, used)| if used { Some(id) } else { None })
418+
.collect();
419+
for &(block_id, is_used) in unsafe_blocks {
420+
if !is_used {
421+
report_unused_unsafe(tcx, &used_unsafe, block_id);
422+
}
423+
}
393424
}

src/librustc_mir/transform/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ fn mir_built<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Stea
111111

112112
fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
113113
// Unsafety check uses the raw mir, so make sure it is run
114-
let _ = tcx.unsafety_violations(def_id);
114+
let _ = tcx.unsafety_check_result(def_id);
115115

116116
let source = MirSource::from_local_def_id(tcx, def_id);
117117
let mut mir = tcx.mir_built(def_id).steal();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[deny(unused_unsafe)]
12+
fn main() {
13+
let mut v = Vec::<i32>::with_capacity(24);
14+
15+
unsafe {
16+
let f = |v: &mut Vec<_>| {
17+
unsafe {
18+
v.set_len(24);
19+
|w: &mut Vec<u32>| { unsafe {
20+
w.set_len(32);
21+
} };
22+
}
23+
|x: &mut Vec<u32>| { unsafe {
24+
x.set_len(40);
25+
} };
26+
};
27+
28+
v.set_len(0);
29+
f(&mut v);
30+
}
31+
32+
|y: &mut Vec<u32>| { unsafe {
33+
y.set_len(48);
34+
} };
35+
}

0 commit comments

Comments
 (0)