about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/mem_categorization.rs65
-rw-r--r--src/librustc_typeck/check/upvar.rs6
-rw-r--r--src/test/run-pass/unboxed-closures-move-from-projection-issue-30046.rs35
-rw-r--r--src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.rs26
-rw-r--r--src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.stderr16
5 files changed, 87 insertions, 61 deletions
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index fc10406c8ce..4071f81ea51 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -88,7 +88,7 @@ use std::fmt;
 use std::rc::Rc;
 use util::nodemap::ItemLocalSet;
 
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum Categorization<'tcx> {
     Rvalue(ty::Region<'tcx>),              // temporary val, argument is its scope
     StaticItem,
@@ -109,7 +109,7 @@ pub struct Upvar {
 }
 
 // different kinds of pointers:
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub enum PointerKind<'tcx> {
     /// `Box<T>`
     Unique,
@@ -177,7 +177,7 @@ pub enum Note {
 // dereference, but its type is the type *before* the dereference
 // (`@T`). So use `cmt.ty` to find the type of the value in a consistent
 // fashion. For more details, see the method `cat_pattern`
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct cmt_<'tcx> {
     pub id: ast::NodeId,           // id of expr/pat producing this value
     pub span: Span,                // span of same expr/pat
@@ -750,12 +750,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         let kind = match self.node_ty(fn_hir_id)?.sty {
             ty::TyGenerator(..) => ty::ClosureKind::FnOnce,
-            _ => {
+            ty::TyClosure(..) => {
                 match self.tables.closure_kinds().get(fn_hir_id) {
                     Some(&(kind, _)) => kind,
                     None => span_bug!(span, "missing closure kind"),
                 }
             }
+            ref t => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", t),
         };
 
         let closure_expr_def_index = self.tcx.hir.local_def_id(fn_node_id).index;
@@ -1499,41 +1500,6 @@ impl<'tcx> cmt_<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for cmt_<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{{{:?} id:{} m:{:?} ty:{:?}}}",
-               self.cat,
-               self.id,
-               self.mutbl,
-               self.ty)
-    }
-}
-
-impl<'tcx> fmt::Debug for Categorization<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Categorization::StaticItem => write!(f, "static"),
-            Categorization::Rvalue(r) => { write!(f, "rvalue({:?})", r) }
-            Categorization::Local(id) => {
-               let name = ty::tls::with(|tcx| tcx.hir.name(id));
-               write!(f, "local({})", name)
-            }
-            Categorization::Upvar(upvar) => {
-                write!(f, "upvar({:?})", upvar)
-            }
-            Categorization::Deref(ref cmt, ptr) => {
-                write!(f, "{:?}-{:?}->", cmt.cat, ptr)
-            }
-            Categorization::Interior(ref cmt, interior) => {
-                write!(f, "{:?}.{:?}", cmt.cat, interior)
-            }
-            Categorization::Downcast(ref cmt, _) => {
-                write!(f, "{:?}->(enum)", cmt.cat)
-            }
-        }
-    }
-}
-
 pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
     match ptr {
         Unique => "Box",
@@ -1547,27 +1513,6 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
     }
 }
 
-impl<'tcx> fmt::Debug for PointerKind<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Unique => write!(f, "Box"),
-            BorrowedPtr(ty::ImmBorrow, ref r) |
-            Implicit(ty::ImmBorrow, ref r) => {
-                write!(f, "&{:?}", r)
-            }
-            BorrowedPtr(ty::MutBorrow, ref r) |
-            Implicit(ty::MutBorrow, ref r) => {
-                write!(f, "&{:?} mut", r)
-            }
-            BorrowedPtr(ty::UniqueImmBorrow, ref r) |
-            Implicit(ty::UniqueImmBorrow, ref r) => {
-                write!(f, "&{:?} uniq", r)
-            }
-            UnsafePtr(_) => write!(f, "*")
-        }
-    }
-}
-
 impl fmt::Debug for InteriorKind {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index d179b390a29..a6a81485b23 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -289,10 +289,14 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
         let guarantor = cmt.guarantor();
         debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
                guarantor);
+        debug!("adjust_upvar_borrow_kind_for_consume: guarantor.cat={:?}",
+               guarantor.cat);
         match guarantor.cat {
             Categorization::Deref(_, mc::BorrowedPtr(..)) |
             Categorization::Deref(_, mc::Implicit(..)) => {
-                match cmt.note {
+                debug!("adjust_upvar_borrow_kind_for_consume: found deref with note {:?}",
+                       cmt.note);
+                match guarantor.note {
                     mc::NoteUpvarRef(upvar_id) => {
                         debug!("adjust_upvar_borrow_kind_for_consume: \
                                 setting upvar_id={:?} to by value",
diff --git a/src/test/run-pass/unboxed-closures-move-from-projection-issue-30046.rs b/src/test/run-pass/unboxed-closures-move-from-projection-issue-30046.rs
new file mode 100644
index 00000000000..d902ebc9dc9
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-move-from-projection-issue-30046.rs
@@ -0,0 +1,35 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused)]
+
+fn foo<F>(f: F)
+    where F: FnOnce()
+{
+}
+
+fn main() {
+    // Test that this closure is inferred to `FnOnce`
+    // because it moves from `y.as<Option::Some>.0`:
+    let x = Some(vec![1, 2, 3]);
+    foo(|| {
+        match x {
+            Some(y) => { }
+            None => { }
+        }
+    });
+
+    // Test that this closure is inferred to `FnOnce`
+    // because it moves from `y.0`:
+    let y = (vec![1, 2, 3], 0);
+    foo(|| {
+        let x = y.0;
+    });
+}
diff --git a/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.rs b/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.rs
new file mode 100644
index 00000000000..14ef3b5f178
--- /dev/null
+++ b/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused)]
+
+fn foo<F>(f: F)
+    where F: Fn()
+{
+}
+
+fn main() {
+    // Test that this closure is inferred to `FnOnce` because it moves
+    // from `y.0`. This affects the error output (the error is that
+    // the closure implements `FnOnce`, not that it moves from inside
+    // a `Fn` closure.)
+    let y = (vec![1, 2, 3], 0);
+    let c = || drop(y.0);
+    foo(c);
+}
diff --git a/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.stderr b/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.stderr
new file mode 100644
index 00000000000..d968c409396
--- /dev/null
+++ b/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.stderr
@@ -0,0 +1,16 @@
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:24:13
+   |
+24 |     let c = || drop(y.0);
+   |             ^^^^^^^^^^^^
+25 |     foo(c);
+   |     --- the requirement to implement `Fn` derives from here
+   |
+note: closure is `FnOnce` because it moves the variable `y` out of its environment
+  --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:24:21
+   |
+24 |     let c = || drop(y.0);
+   |                     ^
+
+error: aborting due to previous error
+