Skip to content

Commit 2b4a2b9

Browse files
Check normalized call signature for WF in mir typeck
1 parent bc1b9e0 commit 2b4a2b9

File tree

3 files changed

+94
-4
lines changed

3 files changed

+94
-4
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -1432,7 +1432,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
14321432
return;
14331433
}
14341434
};
1435-
let (sig, map) = tcx.instantiate_bound_regions(sig, |br| {
1435+
let (unnormalized_sig, map) = tcx.instantiate_bound_regions(sig, |br| {
14361436
use crate::renumber::RegionCtxt;
14371437

14381438
let region_ctxt_fn = || {
@@ -1454,7 +1454,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
14541454
region_ctxt_fn,
14551455
)
14561456
});
1457-
debug!(?sig);
1457+
debug!(?unnormalized_sig);
14581458
// IMPORTANT: We have to prove well formed for the function signature before
14591459
// we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc`
14601460
// get normalized away, causing us to ignore the `'b: 'a` bound used by the function.
@@ -1464,15 +1464,31 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
14641464
//
14651465
// See #91068 for an example.
14661466
self.prove_predicates(
1467-
sig.inputs_and_output.iter().map(|ty| {
1467+
unnormalized_sig.inputs_and_output.iter().map(|ty| {
14681468
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
14691469
ty.into(),
14701470
)))
14711471
}),
14721472
term_location.to_locations(),
14731473
ConstraintCategory::Boring,
14741474
);
1475-
let sig = self.normalize(sig, term_location);
1475+
1476+
let sig = self.normalize(unnormalized_sig, term_location);
1477+
// HACK(#114936): `WF(sig)` does not imply `WF(normalized(sig))`
1478+
// with built-in `Fn` implementations, since the impl may not be
1479+
// well-formed itself.
1480+
if sig != unnormalized_sig {
1481+
self.prove_predicates(
1482+
sig.inputs_and_output.iter().map(|ty| {
1483+
ty::Binder::dummy(ty::PredicateKind::Clause(
1484+
ty::ClauseKind::WellFormed(ty.into()),
1485+
))
1486+
}),
1487+
term_location.to_locations(),
1488+
ConstraintCategory::Boring,
1489+
);
1490+
}
1491+
14761492
self.check_call_dest(body, term, &sig, *destination, *target, term_location);
14771493

14781494
// The ordinary liveness rules will ensure that all
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// <https://github.com/rust-lang/rust/issues/114936>
2+
fn whoops(
3+
s: String,
4+
f: impl for<'s> FnOnce(&'s str) -> (&'static str, [&'static &'s (); 0]),
5+
) -> &'static str
6+
{
7+
f(&s).0
8+
//~^ ERROR `s` does not live long enough
9+
}
10+
11+
// <https://github.com/rust-lang/rust/issues/118876>
12+
fn extend<T>(input: &T) -> &'static T {
13+
struct Bounded<'a, 'b: 'static, T>(&'a T, [&'b (); 0]);
14+
let n: Box<dyn FnOnce(&T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, []));
15+
n(input).0
16+
//~^ ERROR borrowed data escapes outside of function
17+
}
18+
19+
// <https://github.com/rust-lang/rust/issues/118876>
20+
fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
21+
struct Bounded<'a, 'b: 'static, T>(&'a mut T, [&'b (); 0]);
22+
let mut n: Box<dyn FnMut(&mut T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, []));
23+
n(input).0
24+
//~^ ERROR borrowed data escapes outside of function
25+
}
26+
27+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error[E0597]: `s` does not live long enough
2+
--> $DIR/check-normalized-sig-for-wf.rs:7:7
3+
|
4+
LL | s: String,
5+
| - binding `s` declared here
6+
...
7+
LL | f(&s).0
8+
| --^^-
9+
| | |
10+
| | borrowed value does not live long enough
11+
| argument requires that `s` is borrowed for `'static`
12+
LL |
13+
LL | }
14+
| - `s` dropped here while still borrowed
15+
16+
error[E0521]: borrowed data escapes outside of function
17+
--> $DIR/check-normalized-sig-for-wf.rs:15:5
18+
|
19+
LL | fn extend<T>(input: &T) -> &'static T {
20+
| ----- - let's call the lifetime of this reference `'1`
21+
| |
22+
| `input` is a reference that is only valid in the function body
23+
...
24+
LL | n(input).0
25+
| ^^^^^^^^
26+
| |
27+
| `input` escapes the function body here
28+
| argument requires that `'1` must outlive `'static`
29+
30+
error[E0521]: borrowed data escapes outside of function
31+
--> $DIR/check-normalized-sig-for-wf.rs:23:5
32+
|
33+
LL | fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
34+
| -- ----- `input` is a reference that is only valid in the function body
35+
| |
36+
| lifetime `'a` defined here
37+
...
38+
LL | n(input).0
39+
| ^^^^^^^^
40+
| |
41+
| `input` escapes the function body here
42+
| argument requires that `'a` must outlive `'static`
43+
44+
error: aborting due to 3 previous errors
45+
46+
Some errors have detailed explanations: E0521, E0597.
47+
For more information about an error, try `rustc --explain E0521`.

0 commit comments

Comments
 (0)