|
1 | 1 | use crate::utils::span_lint;
|
2 | 2 | use rustc::hir::intravisit as visit;
|
| 3 | +use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; |
3 | 4 | use rustc::hir::*;
|
4 | 5 | use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
5 | 6 | use rustc::middle::expr_use_visitor::*;
|
6 | 7 | use rustc::middle::mem_categorization::{cmt_, Categorization};
|
7 | 8 | use rustc::ty::layout::LayoutOf;
|
8 |
| -use rustc::ty::{self, Ty}; |
| 9 | +use rustc::ty::{self, Ty, UpvarCapture}; |
9 | 10 | use rustc::util::nodemap::NodeSet;
|
10 | 11 | use rustc::{declare_tool_lint, lint_array};
|
11 | 12 | use syntax::ast::NodeId;
|
@@ -88,11 +89,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
88 | 89 | let region_scope_tree = &cx.tcx.region_scope_tree(fn_def_id);
|
89 | 90 | ExprUseVisitor::new(&mut v, cx.tcx, cx.param_env, region_scope_tree, cx.tables, None).consume_body(body);
|
90 | 91 |
|
91 |
| - for node in v.set { |
| 92 | + let mut capture_visitor = CaptureVisitor { |
| 93 | + cx, |
| 94 | + moved: NodeSet::default(), |
| 95 | + }; |
| 96 | + capture_visitor.visit_body(body); |
| 97 | + |
| 98 | + for node in v.set.difference(&capture_visitor.moved) { |
92 | 99 | span_lint(
|
93 | 100 | cx,
|
94 | 101 | BOXED_LOCAL,
|
95 |
| - cx.tcx.hir().span(node), |
| 102 | + cx.tcx.hir().span(*node), |
96 | 103 | "local variable doesn't need to be boxed here",
|
97 | 104 | );
|
98 | 105 | }
|
@@ -192,3 +199,32 @@ impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
|
192 | 199 | }
|
193 | 200 | }
|
194 | 201 | }
|
| 202 | + |
| 203 | +struct CaptureVisitor<'a, 'tcx: 'a> { |
| 204 | + cx: &'a LateContext<'a, 'tcx>, |
| 205 | + moved: NodeSet, |
| 206 | +} |
| 207 | + |
| 208 | +impl<'a, 'tcx> Visitor<'tcx> for CaptureVisitor<'a, 'tcx> { |
| 209 | + fn visit_expr(&mut self, expr: &'tcx Expr) { |
| 210 | + if let ExprKind::Closure(..) = expr.node { |
| 211 | + if let ty::Closure(def_id, _) = &self.cx.tables.expr_ty(expr).sty { |
| 212 | + if let Some(upvar_list) = &self.cx.tables.upvar_list.get(&def_id) { |
| 213 | + for upvar_id in upvar_list.iter() { |
| 214 | + if let UpvarCapture::ByValue = self.cx.tables.upvar_capture(*upvar_id) { |
| 215 | + let hir_id = upvar_id.var_path.hir_id; |
| 216 | + let id = &self.cx.tcx.hir().hir_to_node_id(hir_id); |
| 217 | + self.moved.insert(*id); |
| 218 | + } |
| 219 | + } |
| 220 | + } |
| 221 | + } |
| 222 | + } else { |
| 223 | + walk_expr(self, expr); |
| 224 | + } |
| 225 | + } |
| 226 | + |
| 227 | + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { |
| 228 | + NestedVisitorMap::None |
| 229 | + } |
| 230 | +} |
0 commit comments