about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2018-01-30 11:20:57 -0300
committerSantiago Pastorino <spastorino@gmail.com>2018-01-30 14:00:27 -0300
commitb9f756416a02fe3fd1c145fc081494b68f494f76 (patch)
tree3b7b010931eb642b083bccefc499a8cfde3bbf9d
parentfe7e1a45f37f4265434cead827f587e75412f85c (diff)
downloadrust-b9f756416a02fe3fd1c145fc081494b68f494f76.tar.gz
rust-b9f756416a02fe3fd1c145fc081494b68f494f76.zip
Do not ignore lifetime bounds in Copy impls
Closes #29149
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs21
-rw-r--r--src/test/compile-fail/nll/do-not-ignore-lifetime-bounds-in-copy.rs23
2 files changed, 37 insertions, 7 deletions
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 015eb8a3b66..cebdd4d2826 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -374,13 +374,20 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             }
         };
         if let PlaceContext::Copy = context {
-            let ty = place_ty.to_ty(self.tcx());
-            if self.cx
-                .infcx
-                .type_moves_by_default(self.cx.param_env, ty, DUMMY_SP)
-            {
-                span_mirbug!(self, place, "attempted copy of non-Copy type ({:?})", ty);
-            }
+            let tcx = self.tcx();
+            let trait_ref = ty::TraitRef {
+                def_id: tcx.lang_items().copy_trait().unwrap(),
+                substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]),
+            };
+
+            // In order to have a Copy operand, the type T of the value must be Copy. Note that we
+            // prove that T: Copy, rather than using the type_moves_by_default test. This is
+            // important because type_moves_by_default ignores the resulting region obligations and
+            // assumes they pass. This can result in bounds from Copy impls being unsoundly ignored
+            // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds
+            // fully apply: in effect, the rule is that if a value of some type could implement
+            // Copy, then it must.
+            self.cx.prove_trait_ref(trait_ref, location);
         }
         place_ty
     }
diff --git a/src/test/compile-fail/nll/do-not-ignore-lifetime-bounds-in-copy.rs b/src/test/compile-fail/nll/do-not-ignore-lifetime-bounds-in-copy.rs
new file mode 100644
index 00000000000..2a4295fd90a
--- /dev/null
+++ b/src/test/compile-fail/nll/do-not-ignore-lifetime-bounds-in-copy.rs
@@ -0,0 +1,23 @@
+// Copyright 2012 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.
+
+// Test that the 'static bound from the Copy impl is respected. Regression test for #29149.
+
+#![feature(nll)]
+
+#[derive(Clone)] struct Foo<'a>(&'a u32);
+impl Copy for Foo<'static> {}
+
+fn main() {
+    let s = 2;
+    let a = Foo(&s); //~ ERROR `s` does not live long enough [E0597]
+    drop(a);
+    drop(a);
+}