Skip to content

Commit cd9f5ff

Browse files
committed
Check Copy lifetimes bounds when copying from a projection
1 parent d538b80 commit cd9f5ff

File tree

3 files changed

+51
-27
lines changed

3 files changed

+51
-27
lines changed

src/librustc_mir/borrow_check/type_check/mod.rs

+25-27
Original file line numberDiff line numberDiff line change
@@ -466,33 +466,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
466466

467467
let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
468468

469-
if place.projection.is_empty() {
470-
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
471-
let tcx = self.tcx();
472-
let trait_ref = ty::TraitRef {
473-
def_id: tcx.lang_items().copy_trait().unwrap(),
474-
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
475-
};
476-
477-
// To have a `Copy` operand, the type `T` of the
478-
// value must be `Copy`. Note that we prove that `T: Copy`,
479-
// rather than using the `is_copy_modulo_regions`
480-
// test. This is important because
481-
// `is_copy_modulo_regions` ignores the resulting region
482-
// obligations and assumes they pass. This can result in
483-
// bounds from `Copy` impls being unsoundly ignored (e.g.,
484-
// #29149). Note that we decide to use `Copy` before knowing
485-
// whether the bounds fully apply: in effect, the rule is
486-
// that if a value of some type could implement `Copy`, then
487-
// it must.
488-
self.cx.prove_trait_ref(
489-
trait_ref,
490-
location.to_locations(),
491-
ConstraintCategory::CopyBound,
492-
);
493-
}
494-
}
495-
496469
for elem in place.projection.iter() {
497470
if place_ty.variant_index.is_none() {
498471
if place_ty.ty.references_error() {
@@ -503,6 +476,31 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
503476
place_ty = self.sanitize_projection(place_ty, elem, place, location)
504477
}
505478

479+
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
480+
let tcx = self.tcx();
481+
let trait_ref = ty::TraitRef {
482+
def_id: tcx.lang_items().copy_trait().unwrap(),
483+
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
484+
};
485+
486+
// To have a `Copy` operand, the type `T` of the
487+
// value must be `Copy`. Note that we prove that `T: Copy`,
488+
// rather than using the `is_copy_modulo_regions`
489+
// test. This is important because
490+
// `is_copy_modulo_regions` ignores the resulting region
491+
// obligations and assumes they pass. This can result in
492+
// bounds from `Copy` impls being unsoundly ignored (e.g.,
493+
// #29149). Note that we decide to use `Copy` before knowing
494+
// whether the bounds fully apply: in effect, the rule is
495+
// that if a value of some type could implement `Copy`, then
496+
// it must.
497+
self.cx.prove_trait_ref(
498+
trait_ref,
499+
location.to_locations(),
500+
ConstraintCategory::CopyBound,
501+
);
502+
}
503+
506504
place_ty
507505
}
508506

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Test that the 'static bound from the Copy impl is respected. Regression test for #29149.
2+
3+
#[derive(Clone)]
4+
struct Foo<'a>(&'a u32);
5+
impl Copy for Foo<'static> {}
6+
7+
fn main() {
8+
let s = 2;
9+
let a = (Foo(&s),); //~ ERROR `s` does not live long enough [E0597]
10+
drop(a.0);
11+
drop(a.0);
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0597]: `s` does not live long enough
2+
--> $DIR/do-not-ignore-lifetime-bounds-in-copy-proj.rs:9:18
3+
|
4+
LL | let a = (Foo(&s),);
5+
| ^^ borrowed value does not live long enough
6+
LL | drop(a.0);
7+
| --- copying this value requires that `s` is borrowed for `'static`
8+
LL | drop(a.0);
9+
LL | }
10+
| - `s` dropped here while still borrowed
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0597`.

0 commit comments

Comments
 (0)