"detects use of deprecated items"
}
+declare_lint! {
+ pub UNUSED_UNSAFE,
+ Warn,
+ "unnecessary use of an `unsafe` block"
+}
+
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
MISSING_FRAGMENT_SPECIFIER,
PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
LATE_BOUND_LIFETIME_ARGUMENTS,
- DEPRECATED
+ DEPRECATED,
+ UNUSED_UNSAFE
)
}
}
use ty::{self, TyCtxt};
use lint;
+use lint::builtin::UNUSED_UNSAFE;
-use syntax::ast;
-use syntax_pos::Span;
-use hir::{self, PatKind};
use hir::def::Def;
use hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap};
+use hir::{self, PatKind};
+use syntax::ast;
+use syntax_pos::Span;
+use util::nodemap::FxHashSet;
#[derive(Copy, Clone)]
struct UnsafeContext {
/// Whether we're in an unsafe context.
unsafe_context: UnsafeContext,
+ used_unsafe: FxHashSet<ast::NodeId>,
}
impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> {
UnsafeBlock(block_id) => {
// OK, but record this.
debug!("effect: recording unsafe block as used: {}", block_id);
- self.tcx.used_unsafe.borrow_mut().insert(block_id);
+ self.used_unsafe.insert(block_id);
}
UnsafeFn => {}
}
intravisit::walk_block(self, block);
- self.unsafe_context = old_unsafe_context
+ self.unsafe_context = old_unsafe_context;
+
+ // Don't warn about generated blocks, that'll just pollute the output.
+ match block.rules {
+ hir::UnsafeBlock(hir::UserProvided) => {}
+ _ => return,
+ }
+ if self.used_unsafe.contains(&block.id) {
+ return
+ }
+
+ /// Return the NodeId for an enclosing scope that is also `unsafe`
+ fn is_enclosed(tcx: TyCtxt,
+ used_unsafe: &FxHashSet<ast::NodeId>,
+ id: ast::NodeId) -> Option<(String, ast::NodeId)> {
+ let parent_id = tcx.hir.get_parent_node(id);
+ if parent_id != id {
+ if used_unsafe.contains(&parent_id) {
+ Some(("block".to_string(), parent_id))
+ } else if let Some(hir::map::NodeItem(&hir::Item {
+ node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _),
+ ..
+ })) = tcx.hir.find(parent_id) {
+ Some(("fn".to_string(), parent_id))
+ } else {
+ is_enclosed(tcx, used_unsafe, parent_id)
+ }
+ } else {
+ None
+ }
+ }
+
+ let mut db = self.tcx.struct_span_lint_node(UNUSED_UNSAFE,
+ block.id,
+ block.span,
+ "unnecessary `unsafe` block");
+ db.span_label(block.span, "unnecessary `unsafe` block");
+ if let Some((kind, id)) = is_enclosed(self.tcx, &self.used_unsafe, block.id) {
+ db.span_note(self.tcx.hir.span(id),
+ &format!("because it's nested under this `unsafe` {}", kind));
+ }
+ db.emit();
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
tables: &ty::TypeckTables::empty(None),
body_id: hir::BodyId { node_id: ast::CRATE_NODE_ID },
unsafe_context: UnsafeContext::new(SafeContext),
+ used_unsafe: FxHashSet(),
};
tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
pub lang_items: middle::lang_items::LanguageItems,
- /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
- /// present in this set can be warned about.
- pub used_unsafe: RefCell<NodeSet>,
-
/// Set of nodes which mark locals as mutable which end up getting used at
/// some point. Local variable definitions not in this set can be warned
/// about.
normalized_cache: RefCell::new(FxHashMap()),
inhabitedness_cache: RefCell::new(FxHashMap()),
lang_items,
- used_unsafe: RefCell::new(NodeSet()),
used_mut_nodes: RefCell::new(NodeSet()),
stability: RefCell::new(stability),
selection_cache: traits::SelectionCache::new(),
NonSnakeCase,
NonUpperCaseGlobals,
NonShorthandFieldPatterns,
- UnusedUnsafe,
UnsafeCode,
UnusedMut,
UnusedAllocation,
}
}
-declare_lint! {
- pub UNUSED_UNSAFE,
- Warn,
- "unnecessary use of an `unsafe` block"
-}
-
-#[derive(Copy, Clone)]
-pub struct UnusedUnsafe;
-
-impl LintPass for UnusedUnsafe {
- fn get_lints(&self) -> LintArray {
- lint_array!(UNUSED_UNSAFE)
- }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedUnsafe {
- fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
- /// Return the NodeId for an enclosing scope that is also `unsafe`
- fn is_enclosed(cx: &LateContext, id: ast::NodeId) -> Option<(String, ast::NodeId)> {
- let parent_id = cx.tcx.hir.get_parent_node(id);
- if parent_id != id {
- if cx.tcx.used_unsafe.borrow().contains(&parent_id) {
- Some(("block".to_string(), parent_id))
- } else if let Some(hir::map::NodeItem(&hir::Item {
- node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _),
- ..
- })) = cx.tcx.hir.find(parent_id) {
- Some(("fn".to_string(), parent_id))
- } else {
- is_enclosed(cx, parent_id)
- }
- } else {
- None
- }
- }
- if let hir::ExprBlock(ref blk) = e.node {
- // Don't warn about generated blocks, that'll just pollute the output.
- if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
- !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
-
- let mut db = cx.struct_span_lint(UNUSED_UNSAFE, blk.span,
- "unnecessary `unsafe` block");
-
- db.span_label(blk.span, "unnecessary `unsafe` block");
- if let Some((kind, id)) = is_enclosed(cx, blk.id) {
- db.span_note(cx.tcx.hir.span(id),
- &format!("because it's nested under this `unsafe` {}", kind));
- }
- db.emit();
- }
- }
- }
-}
-
declare_lint! {
pub PATH_STATEMENTS,
Warn,
| |_____^
error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:39:5
+ --> $DIR/lint-unused-unsafe.rs:40:9
|
-39 | / unsafe { //~ ERROR: unnecessary `unsafe` block
-40 | | unsafe { //~ ERROR: unnecessary `unsafe` block
+40 | / unsafe { //~ ERROR: unnecessary `unsafe` block
41 | | unsf()
42 | | }
-43 | | }
- | |_____^ unnecessary `unsafe` block
+ | |_________^ unnecessary `unsafe` block
|
note: because it's nested under this `unsafe` fn
--> $DIR/lint-unused-unsafe.rs:38:1
| |_^
error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:40:9
+ --> $DIR/lint-unused-unsafe.rs:39:5
|
-40 | / unsafe { //~ ERROR: unnecessary `unsafe` block
+39 | / unsafe { //~ ERROR: unnecessary `unsafe` block
+40 | | unsafe { //~ ERROR: unnecessary `unsafe` block
41 | | unsf()
42 | | }
- | |_________^ unnecessary `unsafe` block
+43 | | }
+ | |_____^ unnecessary `unsafe` block
|
note: because it's nested under this `unsafe` fn
--> $DIR/lint-unused-unsafe.rs:38:1