]> git.lizzy.rs Git - rust.git/blobdiff - src/escape.rs
Rustup to 1.9.0-nightly (5ab11d72c 2016-04-02)
[rust.git] / src / escape.rs
index 4b6a8258dbe58ab930d21e33e49da65031fedd2e..98500bf62f016ba78178409d95c69eeada040c18 100644 (file)
@@ -1,20 +1,21 @@
+use rustc::front::map::Node::{NodeExpr, NodeStmt};
 use rustc::lint::*;
-use rustc_front::hir::*;
-use rustc_front::intravisit as visit;
-use rustc::front::map::Node;
-use rustc::middle::ty;
-use rustc::middle::ty::adjustment::AutoAdjustment;
 use rustc::middle::expr_use_visitor::*;
-use rustc::middle::infer;
+use rustc::infer;
 use rustc::middle::mem_categorization::{cmt, Categorization};
+use rustc::traits::ProjectionMode;
+use rustc::ty::adjustment::AutoAdjustment;
+use rustc::ty;
 use rustc::util::nodemap::NodeSet;
+use rustc_front::hir::*;
+use rustc_front::intravisit as visit;
 use syntax::ast::NodeId;
 use syntax::codemap::Span;
 use utils::span_lint;
 
 pub struct EscapePass;
 
-/// **What it does:** This lint checks for usage of `Box<T>` where an unboxed `T` would work fine. It is `Warn` by default.
+/// **What it does:** This lint checks for usage of `Box<T>` where an unboxed `T` would work fine.
 ///
 /// **Why is this bad?** This is an unnecessary allocation, and bad for performance. It is only necessary to allocate if you wish to move the box into something.
 ///
 ///     println!("{}", *x);
 /// }
 /// ```
-declare_lint!(pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary");
+declare_lint! {
+    pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary"
+}
+
+fn is_non_trait_box(ty: ty::Ty) -> bool {
+    match ty.sty {
+        ty::TyBox(ref inner) => !inner.is_trait(),
+        _ => false,
+    }
+}
 
 struct EscapeDelegate<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>,
@@ -43,15 +53,9 @@ fn get_lints(&self) -> LintArray {
 }
 
 impl LateLintPass for EscapePass {
-    fn check_fn(&mut self,
-                cx: &LateContext,
-                _: visit::FnKind,
-                decl: &FnDecl,
-                body: &Block,
-                _: Span,
-                id: NodeId) {
+    fn check_fn(&mut self, cx: &LateContext, _: visit::FnKind, decl: &FnDecl, body: &Block, _: Span, id: NodeId) {
         let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id);
-        let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(param_env), false);
+        let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(param_env), ProjectionMode::Any);
         let mut v = EscapeDelegate {
             cx: cx,
             set: NodeSet(),
@@ -70,11 +74,7 @@ fn check_fn(&mut self,
 }
 
 impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
-    fn consume(&mut self,
-               _: NodeId,
-               _: Span,
-               cmt: cmt<'tcx>,
-               mode: ConsumeMode) {
+    fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) {
 
         if let Categorization::Local(lid) = cmt.cat {
             if self.set.contains(&lid) {
@@ -87,16 +87,24 @@ fn consume(&mut self,
     }
     fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {}
     fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, _: ConsumeMode) {
+        let map = &self.cx.tcx.map;
+        if map.is_argument(consume_pat.id) {
+            // Skip closure arguments
+            if let Some(NodeExpr(..)) = map.find(map.get_parent_node(consume_pat.id)) {
+                return;
+            }
+            if is_non_trait_box(cmt.ty) {
+                self.set.insert(consume_pat.id);
+            }
+            return;
+        }
         if let Categorization::Rvalue(..) = cmt.cat {
-            if let Some(Node::NodeStmt(st)) = self.cx
-                                                  .tcx
-                                                  .map
-                                                  .find(self.cx.tcx.map.get_parent_node(cmt.id)) {
+            if let Some(NodeStmt(st)) = map.find(map.get_parent_node(cmt.id)) {
                 if let StmtDecl(ref decl, _) = st.node {
                     if let DeclLocal(ref loc) = decl.node {
                         if let Some(ref ex) = loc.init {
                             if let ExprBox(..) = ex.node {
-                                if let ty::TyBox(..) = cmt.ty.sty {
+                                if is_non_trait_box(cmt.ty) {
                                     // let x = box (...)
                                     self.set.insert(consume_pat.id);
                                 }
@@ -119,12 +127,7 @@ fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, _: ConsumeMode) {
         }
 
     }
-    fn borrow(&mut self,
-              borrow_id: NodeId,
-              _: Span,
-              cmt: cmt<'tcx>,
-              _: ty::Region,
-              _: ty::BorrowKind,
+    fn borrow(&mut self, borrow_id: NodeId, _: Span, cmt: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind,
               loan_cause: LoanCause) {
 
         if let Categorization::Local(lid) = cmt.cat {
@@ -137,17 +140,23 @@ fn borrow(&mut self,
                                                                         .get(&borrow_id) {
                     if LoanCause::AutoRef == loan_cause {
                         // x.foo()
-                        if adj.autoderefs <= 0 {
+                        if adj.autoderefs == 0 {
                             self.set.remove(&lid); // Used without autodereffing (i.e. x.clone())
                         }
                     } else {
-                        self.cx.sess().span_bug(cmt.span, "Unknown adjusted AutoRef");
+                        span_bug!(cmt.span, "Unknown adjusted AutoRef");
                     }
                 } else if LoanCause::AddrOf == loan_cause {
                     // &x
-                    if let Some(&AutoAdjustment::AdjustDerefRef(adj)) =
-                           self.cx.tcx.tables.borrow().adjustments
-                               .get(&self.cx.tcx.map.get_parent_node(borrow_id)) {
+                    if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.cx
+                                                                            .tcx
+                                                                            .tables
+                                                                            .borrow()
+                                                                            .adjustments
+                                                                            .get(&self.cx
+                                                                                      .tcx
+                                                                                      .map
+                                                                                      .get_parent_node(borrow_id)) {
                         if adj.autoderefs <= 1 {
                             // foo(&x) where no extra autoreffing is happening
                             self.set.remove(&lid);
@@ -162,10 +171,5 @@ fn borrow(&mut self,
         }
     }
     fn decl_without_init(&mut self, _: NodeId, _: Span) {}
-    fn mutate(&mut self,
-              _: NodeId,
-              _: Span,
-              _: cmt<'tcx>,
-              _: MutateMode) {
-    }
+    fn mutate(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: MutateMode) {}
 }