Skip to content

Commit bfb9604

Browse files
committed
Auto merge of #69145 - matthewjasper:mir-typeck-static-ty, r=nikomatsakis
Fix MIR typeck soundness holes * Check types of static items * Always check lifetime bounds of `Copy` impls r? @nikomatsakis closes #69114
2 parents 93711d0 + ddc2545 commit bfb9604

7 files changed

+148
-29
lines changed

src/librustc_mir/borrow_check/type_check/mod.rs

+41-29
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
313313
);
314314
}
315315
} else {
316+
let tcx = self.tcx();
316317
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val {
317318
if let Some(promoted) = promoted {
318319
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
@@ -362,10 +363,23 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
362363
);
363364
}
364365
}
366+
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
367+
let unnormalized_ty = tcx.type_of(static_def_id);
368+
let locations = location.to_locations();
369+
let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
370+
let literal_ty = constant.literal.ty.builtin_deref(true).unwrap().ty;
371+
372+
if let Err(terr) = self.cx.eq_types(
373+
normalized_ty,
374+
literal_ty,
375+
locations,
376+
ConstraintCategory::Boring,
377+
) {
378+
span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr);
379+
}
365380
}
366-
if let ty::FnDef(def_id, substs) = constant.literal.ty.kind {
367-
let tcx = self.tcx();
368381

382+
if let ty::FnDef(def_id, substs) = constant.literal.ty.kind {
369383
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
370384
self.cx.normalize_and_prove_instantiated_predicates(
371385
instantiated_predicates,
@@ -470,33 +484,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
470484

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

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

497+
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
498+
let tcx = self.tcx();
499+
let trait_ref = ty::TraitRef {
500+
def_id: tcx.lang_items().copy_trait().unwrap(),
501+
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
502+
};
503+
504+
// To have a `Copy` operand, the type `T` of the
505+
// value must be `Copy`. Note that we prove that `T: Copy`,
506+
// rather than using the `is_copy_modulo_regions`
507+
// test. This is important because
508+
// `is_copy_modulo_regions` ignores the resulting region
509+
// obligations and assumes they pass. This can result in
510+
// bounds from `Copy` impls being unsoundly ignored (e.g.,
511+
// #29149). Note that we decide to use `Copy` before knowing
512+
// whether the bounds fully apply: in effect, the rule is
513+
// that if a value of some type could implement `Copy`, then
514+
// it must.
515+
self.cx.prove_trait_ref(
516+
trait_ref,
517+
location.to_locations(),
518+
ConstraintCategory::CopyBound,
519+
);
520+
}
521+
510522
place_ty
511523
}
512524

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`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Check that borrowck ensures that `static mut` items have the expected type.
2+
3+
static FOO: u8 = 42;
4+
static mut BAR: &'static u8 = &FOO;
5+
static mut BAR_ELIDED: &u8 = &FOO;
6+
7+
fn main() {
8+
unsafe {
9+
println!("{} {}", BAR, BAR_ELIDED);
10+
set_bar();
11+
set_bar_elided();
12+
println!("{} {}", BAR, BAR_ELIDED);
13+
}
14+
}
15+
16+
fn set_bar() {
17+
let n = 42;
18+
unsafe {
19+
BAR = &n;
20+
//~^ ERROR does not live long enough
21+
}
22+
}
23+
24+
fn set_bar_elided() {
25+
let n = 42;
26+
unsafe {
27+
BAR_ELIDED = &n;
28+
//~^ ERROR does not live long enough
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0597]: `n` does not live long enough
2+
--> $DIR/issue-69114-static-mut-ty.rs:19:15
3+
|
4+
LL | BAR = &n;
5+
| ------^^
6+
| | |
7+
| | borrowed value does not live long enough
8+
| assignment requires that `n` is borrowed for `'static`
9+
...
10+
LL | }
11+
| - `n` dropped here while still borrowed
12+
13+
error[E0597]: `n` does not live long enough
14+
--> $DIR/issue-69114-static-mut-ty.rs:27:22
15+
|
16+
LL | BAR_ELIDED = &n;
17+
| -------------^^
18+
| | |
19+
| | borrowed value does not live long enough
20+
| assignment requires that `n` is borrowed for `'static`
21+
...
22+
LL | }
23+
| - `n` dropped here while still borrowed
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0597`.
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Check that borrowck ensures that `static` items have the expected type.
2+
3+
static FOO: &'static (dyn Fn(&'static u8) + Send + Sync) = &drop;
4+
5+
fn main() {
6+
let n = 42;
7+
FOO(&n);
8+
//~^ ERROR does not live long enough
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0597]: `n` does not live long enough
2+
--> $DIR/issue-69114-static-ty.rs:7:9
3+
|
4+
LL | FOO(&n);
5+
| ----^^-
6+
| | |
7+
| | borrowed value does not live long enough
8+
| argument requires that `n` is borrowed for `'static`
9+
LL |
10+
LL | }
11+
| - `n` dropped here while still borrowed
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0597`.

0 commit comments

Comments
 (0)