Skip to content

Commit 1e7a6b8

Browse files
committed
After inferring regions, scan for any bounds that are due to a lifetime
bound that is likely to change. In that case, it will change to 'static, so then scan down the graph to see whether there are any hard constraints that would prevent 'static from being a valid value here. Report a warning.
1 parent 9099577 commit 1e7a6b8

File tree

4 files changed

+168
-0
lines changed

4 files changed

+168
-0
lines changed

src/librustc/diagnostics.rs

+36
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,42 @@ static mut FOO: Option<Box<usize>> = None;
11601160
// error: mutable statics are not allowed to have destructors
11611161
static mut BAR: Option<Vec<i32>> = None;
11621162
```
1163+
"##,
1164+
1165+
E0398: r##"
1166+
In Rust 1.3, the default object lifetime bounds are expected to
1167+
change, as described in RFC #1156 [1]. You are getting a warning
1168+
because the compiler thinks it is possible that this change will cause
1169+
a compilation error in your code. It is possible, though unlikely,
1170+
that this is a false alarm.
1171+
1172+
The heart of the change is that where `&'a Box<SomeTrait>` used to
1173+
default to `&'a Box<SomeTrait+'a>`, it now defaults to `&'a
1174+
Box<SomeTrait+'static>` (here, `SomeTrait` is the name of some trait
1175+
type). Note that the only types which are affected are references to
1176+
boxes, like `&Box<SomeTrait>` or `&[Box<SomeTrait>]`. More common
1177+
types like `&SomeTrait` or `Box<SomeTrait>` are unaffected.
1178+
1179+
To silence this warning, edit your code to use an explicit bound.
1180+
Most of the time, this means that you will want to change the
1181+
signature of a function that you are calling. For example, if
1182+
the error is reported on a call like `foo(x)`, and `foo` is
1183+
defined as follows:
1184+
1185+
```
1186+
fn foo(arg: &Box<SomeTrait>) { ... }
1187+
```
1188+
1189+
you might change it to:
1190+
1191+
```
1192+
fn foo<'a>(arg: &Box<SomeTrait+'a>) { ... }
1193+
```
1194+
1195+
This explicitly states that you expect the trait object `SomeTrait` to
1196+
contain references (with a maximum lifetime of `'a`).
1197+
1198+
[1]: https://github.com/rust-lang/rfcs/pull/1156
11631199
"##
11641200

11651201
}

src/librustc/middle/infer/region_inference/mod.rs

+47
Original file line numberDiff line numberDiff line change
@@ -1358,9 +1358,56 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
13581358
}
13591359
}
13601360

1361+
// Check for future hostile edges tied to a bad default
1362+
self.report_future_hostility(&graph);
1363+
13611364
(0..self.num_vars() as usize).map(|idx| var_data[idx].value).collect()
13621365
}
13631366

1367+
fn report_future_hostility(&self, graph: &RegionGraph) {
1368+
let constraints = self.constraints.borrow();
1369+
for edge in graph.all_edges() {
1370+
match constraints[&edge.data] {
1371+
SubregionOrigin::DefaultExistentialBound(_) => {
1372+
// this will become 'static in the future
1373+
}
1374+
_ => { continue; }
1375+
}
1376+
1377+
// this constraint will become a 'static constraint in the
1378+
// future, so walk outward and see if we have any hard
1379+
// bounds that could not be inferred to 'static
1380+
for nid in graph.depth_traverse(edge.target()) {
1381+
for (_, succ) in graph.outgoing_edges(nid) {
1382+
match succ.data {
1383+
ConstrainVarSubReg(_, r) => {
1384+
match r {
1385+
ty::ReStatic | ty::ReInfer(_) => {
1386+
/* OK */
1387+
}
1388+
ty::ReFree(_) | ty::ReScope(_) | ty::ReEmpty => {
1389+
span_warn!(
1390+
self.tcx.sess,
1391+
constraints[&edge.data].span(),
1392+
E0398,
1393+
"this code may fail to compile in Rust 1.3 due to \
1394+
the proposed change in object lifetime bound defaults");
1395+
return; // only issue the warning once per fn
1396+
}
1397+
ty::ReEarlyBound(..) | ty::ReLateBound(..) => {
1398+
self.tcx.sess.span_bug(
1399+
constraints[&succ.data].span(),
1400+
"relation to bound region");
1401+
}
1402+
}
1403+
}
1404+
_ => { }
1405+
}
1406+
}
1407+
}
1408+
}
1409+
}
1410+
13641411
fn construct_graph(&self) -> RegionGraph {
13651412
let num_vars = self.num_vars();
13661413

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type = "rlib"]
12+
13+
// Helper for testing that we get suitable warnings when lifetime
14+
// bound change will cause breakage.
15+
16+
pub fn just_ref(x: &Fn()) {
17+
}
18+
19+
pub fn ref_obj(x: &Box<Fn()>) {
20+
// this will change to &Box<Fn()+'static>...
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:lifetime_bound_will_change_warning_lib.rs
12+
13+
// Test that we get suitable warnings when lifetime bound change will
14+
// cause breakage.
15+
16+
#![allow(dead_code)]
17+
#![allow(unused_variables)]
18+
#![feature(rustc_attrs)]
19+
20+
extern crate lifetime_bound_will_change_warning_lib as lib;
21+
22+
fn just_ref(x: &Fn()) {
23+
}
24+
25+
fn ref_obj(x: &Box<Fn()>) {
26+
// this will change to &Box<Fn()+'static>...
27+
28+
// Note: no warning is issued here, because the type of `x` will change to 'static
29+
if false { ref_obj(x); }
30+
}
31+
32+
fn test1<'a>(x: &'a Box<Fn()+'a>) {
33+
// just_ref will stay the same.
34+
just_ref(&**x)
35+
}
36+
37+
fn test1cc<'a>(x: &'a Box<Fn()+'a>) {
38+
// same as test1, but cross-crate
39+
lib::just_ref(&**x)
40+
}
41+
42+
fn test2<'a>(x: &'a Box<Fn()+'a>) {
43+
// but ref_obj will not, so warn.
44+
ref_obj(x) //~ WARNING this code may fail to compile in Rust 1.3
45+
}
46+
47+
fn test2cc<'a>(x: &'a Box<Fn()+'a>) {
48+
// same as test2, but cross crate
49+
lib::ref_obj(x) //~ WARNING this code may fail to compile in Rust 1.3
50+
}
51+
52+
fn test3<'a>(x: &'a Box<Fn()+'static>) {
53+
// here, we have a 'static bound, so even when ref_obj changes, no error results
54+
ref_obj(x)
55+
}
56+
57+
fn test3cc<'a>(x: &'a Box<Fn()+'static>) {
58+
// same as test3, but cross crate
59+
lib::ref_obj(x)
60+
}
61+
62+
#[rustc_error]
63+
fn main() { //~ ERROR compilation successful
64+
}

0 commit comments

Comments
 (0)