Skip to content

Commit 6195b60

Browse files
matthewjasperMark-Simulacrum
authored andcommitted
Check Copy lifetimes bounds when copying from a projection
1 parent c5b841c commit 6195b60

File tree

3 files changed

+64
-40
lines changed

3 files changed

+64
-40
lines changed

src/librustc_mir/borrow_check/type_check/mod.rs

+38-40
Original file line numberDiff line numberDiff line change
@@ -497,46 +497,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
497497
}
498498
};
499499

500-
if place.projection.is_empty() {
501-
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
502-
let is_promoted = match place.as_ref() {
503-
PlaceRef {
504-
base: &PlaceBase::Static(box Static {
505-
kind: StaticKind::Promoted(..),
506-
..
507-
}),
508-
projection: &[],
509-
} => true,
510-
_ => false,
511-
};
512-
513-
if !is_promoted {
514-
let tcx = self.tcx();
515-
let trait_ref = ty::TraitRef {
516-
def_id: tcx.lang_items().copy_trait().unwrap(),
517-
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
518-
};
519-
520-
// To have a `Copy` operand, the type `T` of the
521-
// value must be `Copy`. Note that we prove that `T: Copy`,
522-
// rather than using the `is_copy_modulo_regions`
523-
// test. This is important because
524-
// `is_copy_modulo_regions` ignores the resulting region
525-
// obligations and assumes they pass. This can result in
526-
// bounds from `Copy` impls being unsoundly ignored (e.g.,
527-
// #29149). Note that we decide to use `Copy` before knowing
528-
// whether the bounds fully apply: in effect, the rule is
529-
// that if a value of some type could implement `Copy`, then
530-
// it must.
531-
self.cx.prove_trait_ref(
532-
trait_ref,
533-
location.to_locations(),
534-
ConstraintCategory::CopyBound,
535-
);
536-
}
537-
}
538-
}
539-
540500
for elem in place.projection.iter() {
541501
if place_ty.variant_index.is_none() {
542502
if place_ty.ty.references_error() {
@@ -547,6 +507,44 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
547507
place_ty = self.sanitize_projection(place_ty, elem, place, location)
548508
}
549509

510+
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
511+
let is_promoted = match place.as_ref() {
512+
PlaceRef {
513+
base: &PlaceBase::Static(box Static {
514+
kind: StaticKind::Promoted(..),
515+
..
516+
}),
517+
projection: &[],
518+
} => true,
519+
_ => false,
520+
};
521+
522+
if !is_promoted {
523+
let tcx = self.tcx();
524+
let trait_ref = ty::TraitRef {
525+
def_id: tcx.lang_items().copy_trait().unwrap(),
526+
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
527+
};
528+
529+
// To have a `Copy` operand, the type `T` of the
530+
// value must be `Copy`. Note that we prove that `T: Copy`,
531+
// rather than using the `is_copy_modulo_regions`
532+
// test. This is important because
533+
// `is_copy_modulo_regions` ignores the resulting region
534+
// obligations and assumes they pass. This can result in
535+
// bounds from `Copy` impls being unsoundly ignored (e.g.,
536+
// #29149). Note that we decide to use `Copy` before knowing
537+
// whether the bounds fully apply: in effect, the rule is
538+
// that if a value of some type could implement `Copy`, then
539+
// it must.
540+
self.cx.prove_trait_ref(
541+
trait_ref,
542+
location.to_locations(),
543+
ConstraintCategory::CopyBound,
544+
);
545+
}
546+
}
547+
550548
place_ty
551549
}
552550

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)