Skip to content

Commit e169d69

Browse files
matthewjasperMark-Simulacrum
authored andcommitted
Check Copy lifetimes bounds when copying from a projection
1 parent ee392df commit e169d69

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

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -467,33 +467,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
467467

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

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

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

Lines changed: 12 additions & 0 deletions
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+
}
Lines changed: 14 additions & 0 deletions
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)