Skip to content

Commit ebf0c83

Browse files
committed
Merge pull request #26829 from nikomatsakis/better-object-defaults-warn-beta
Better object defaults warn beta
2 parents 18adf62 + b229195 commit ebf0c83

30 files changed

+481
-90
lines changed

src/librustc/diagnostics.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,42 @@ static mut FOO: Option<Box<usize>> = None;
995995
// error: mutable statics are not allowed to have destructors
996996
static mut BAR: Option<Vec<i32>> = None;
997997
```
998+
"##,
999+
1000+
E0398: r##"
1001+
In Rust 1.3, the default object lifetime bounds are expected to
1002+
change, as described in RFC #1156 [1]. You are getting a warning
1003+
because the compiler thinks it is possible that this change will cause
1004+
a compilation error in your code. It is possible, though unlikely,
1005+
that this is a false alarm.
1006+
1007+
The heart of the change is that where `&'a Box<SomeTrait>` used to
1008+
default to `&'a Box<SomeTrait+'a>`, it now defaults to `&'a
1009+
Box<SomeTrait+'static>` (here, `SomeTrait` is the name of some trait
1010+
type). Note that the only types which are affected are references to
1011+
boxes, like `&Box<SomeTrait>` or `&[Box<SomeTrait>]`. More common
1012+
types like `&SomeTrait` or `Box<SomeTrait>` are unaffected.
1013+
1014+
To silence this warning, edit your code to use an explicit bound.
1015+
Most of the time, this means that you will want to change the
1016+
signature of a function that you are calling. For example, if
1017+
the error is reported on a call like `foo(x)`, and `foo` is
1018+
defined as follows:
1019+
1020+
```
1021+
fn foo(arg: &Box<SomeTrait>) { ... }
1022+
```
1023+
1024+
you might change it to:
1025+
1026+
```
1027+
fn foo<'a>(arg: &Box<SomeTrait+'a>) { ... }
1028+
```
1029+
1030+
This explicitly states that you expect the trait object `SomeTrait` to
1031+
contain references (with a maximum lifetime of `'a`).
1032+
1033+
[1]: https://github.com/rust-lang/rfcs/pull/1156
9981034
"##
9991035

10001036
}

src/librustc/metadata/tydecode.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -843,15 +843,15 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
843843

844844
fn parse_object_lifetime_default<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
845845
conv: &mut F)
846-
-> Option<ty::ObjectLifetimeDefault>
846+
-> ty::ObjectLifetimeDefault
847847
where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
848848
{
849849
match next(st) {
850-
'n' => None,
851-
'a' => Some(ty::ObjectLifetimeDefault::Ambiguous),
850+
'a' => ty::ObjectLifetimeDefault::Ambiguous,
851+
'b' => ty::ObjectLifetimeDefault::BaseDefault,
852852
's' => {
853853
let region = parse_region_(st, conv);
854-
Some(ty::ObjectLifetimeDefault::Specific(region))
854+
ty::ObjectLifetimeDefault::Specific(region)
855855
}
856856
_ => panic!("parse_object_lifetime_default: bad input")
857857
}
@@ -887,9 +887,16 @@ fn parse_existential_bounds_<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
887887
}
888888
}
889889

890+
let region_bound_will_change = match next(st) {
891+
'y' => true,
892+
'n' => false,
893+
c => panic!("parse_ty: expected y/n not '{}'", c)
894+
};
895+
890896
return ty::ExistentialBounds { region_bound: region_bound,
891897
builtin_bounds: builtin_bounds,
892-
projection_bounds: projection_bounds };
898+
projection_bounds: projection_bounds,
899+
region_bound_will_change: region_bound_will_change };
893900
}
894901

895902
fn parse_builtin_bounds<F>(st: &mut PState, mut _conv: F) -> ty::BuiltinBounds where

src/librustc/metadata/tyencode.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ pub fn enc_existential_bounds<'a,'tcx>(w: &mut Encoder,
390390
}
391391

392392
mywrite!(w, ".");
393+
394+
mywrite!(w, "{}", if bs.region_bound_will_change {'y'} else {'n'});
393395
}
394396

395397
pub fn enc_region_bounds<'a, 'tcx>(w: &mut Encoder,
@@ -414,12 +416,12 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
414416

415417
fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Encoder,
416418
cx: &ctxt<'a, 'tcx>,
417-
default: Option<ty::ObjectLifetimeDefault>)
419+
default: ty::ObjectLifetimeDefault)
418420
{
419421
match default {
420-
None => mywrite!(w, "n"),
421-
Some(ty::ObjectLifetimeDefault::Ambiguous) => mywrite!(w, "a"),
422-
Some(ty::ObjectLifetimeDefault::Specific(r)) => {
422+
ty::ObjectLifetimeDefault::Ambiguous => mywrite!(w, "a"),
423+
ty::ObjectLifetimeDefault::BaseDefault => mywrite!(w, "b"),
424+
ty::ObjectLifetimeDefault::Specific(r) => {
423425
mywrite!(w, "s");
424426
enc_region(w, cx, r);
425427
}

src/librustc/middle/infer/bivariate.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> {
4949

5050
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
5151

52+
fn will_change(&mut self, _: bool, _: bool) -> bool {
53+
// since we are not comparing regions, we don't care
54+
false
55+
}
56+
5257
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
5358
variance: ty::Variance,
5459
a: &T,

src/librustc/middle/infer/combine.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ pub struct CombineFields<'a, 'tcx: 'a> {
5656
pub infcx: &'a InferCtxt<'a, 'tcx>,
5757
pub a_is_expected: bool,
5858
pub trace: TypeTrace<'tcx>,
59+
pub cause: Option<ty_relate::Cause>,
5960
}
6061

6162
pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,

src/librustc/middle/infer/equate.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> {
3434

3535
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
3636

37+
fn will_change(&mut self, a: bool, b: bool) -> bool {
38+
// if either side changed from what it was, that could cause equality to fail
39+
a || b
40+
}
41+
3742
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
3843
_: ty::Variance,
3944
a: &T,

src/librustc/middle/infer/error_reporting.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
592592
sub: Region,
593593
sup: Region) {
594594
match origin {
595-
infer::Subtype(trace) => {
595+
infer::Subtype(trace) |
596+
infer::DefaultExistentialBound(trace) => {
596597
let terr = ty::terr_regions_does_not_outlive(sup, sub);
597598
self.report_and_explain_type_error(trace, &terr);
598599
}
@@ -1604,7 +1605,8 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
16041605

16051606
fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) {
16061607
match *origin {
1607-
infer::Subtype(ref trace) => {
1608+
infer::Subtype(ref trace) |
1609+
infer::DefaultExistentialBound(ref trace) => {
16081610
let desc = match trace.origin {
16091611
infer::Misc(_) => {
16101612
"types are compatible"

src/librustc/middle/infer/glb.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> {
3535

3636
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
3737

38+
fn will_change(&mut self, a: bool, b: bool) -> bool {
39+
// Hmm, so the result of GLB will still be a LB if one or both
40+
// sides change to 'static, but it may no longer be the GLB.
41+
// I'm going to go with `a || b` here to be conservative,
42+
// since the result of this operation may be affected, though
43+
// I think it would mostly be more accepting than before (since the result
44+
// would be a bigger region).
45+
a || b
46+
}
47+
3848
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
3949
variance: ty::Variance,
4050
a: &T,

src/librustc/middle/infer/lub.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> {
3535

3636
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
3737

38+
fn will_change(&mut self, a: bool, b: bool) -> bool {
39+
// result will be 'static if a || b
40+
a || b
41+
}
42+
3843
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
3944
variance: ty::Variance,
4045
a: &T,

src/librustc/middle/infer/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ pub enum SubregionOrigin<'tcx> {
173173
// Arose from a subtyping relation
174174
Subtype(TypeTrace<'tcx>),
175175

176+
// Arose from a subtyping relation
177+
DefaultExistentialBound(TypeTrace<'tcx>),
178+
176179
// Stack-allocated closures cannot outlive innermost loop
177180
// or function so as to ensure we only require finite stack
178181
InfStackClosure(Span),
@@ -472,7 +475,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
472475
-> CombineFields<'a, 'tcx> {
473476
CombineFields {infcx: self,
474477
a_is_expected: a_is_expected,
475-
trace: trace}
478+
trace: trace,
479+
cause: None}
476480
}
477481

478482
// public so that it can be used from the rustc_driver unit tests
@@ -1125,6 +1129,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
11251129
pub fn span(&self) -> Span {
11261130
match *self {
11271131
Subtype(ref a) => a.span(),
1132+
DefaultExistentialBound(ref a) => a.span(),
11281133
InfStackClosure(a) => a,
11291134
InvokeClosure(a) => a,
11301135
DerefPointer(a) => a,

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

Lines changed: 47 additions & 0 deletions
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

src/librustc/middle/infer/sub.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,17 @@
1010

1111
use super::combine::{self, CombineFields};
1212
use super::higher_ranked::HigherRankedRelations;
13-
use super::Subtype;
13+
use super::SubregionOrigin;
1414
use super::type_variable::{SubtypeOf, SupertypeOf};
1515

1616
use middle::ty::{self, Ty};
1717
use middle::ty::TyVar;
18-
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
18+
use middle::ty_relate::{Cause, Relate, RelateResult, TypeRelation};
19+
use std::mem;
1920

2021
/// "Greatest lower bound" (common subtype)
2122
pub struct Sub<'a, 'tcx: 'a> {
22-
fields: CombineFields<'a, 'tcx>
23+
fields: CombineFields<'a, 'tcx>,
2324
}
2425

2526
impl<'a, 'tcx> Sub<'a, 'tcx> {
@@ -33,6 +34,25 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
3334
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.infcx.tcx }
3435
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
3536

37+
fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R
38+
where F: FnOnce(&mut Self) -> R
39+
{
40+
debug!("sub with_cause={:?}", cause);
41+
let old_cause = mem::replace(&mut self.fields.cause, Some(cause));
42+
let r = f(self);
43+
debug!("sub old_cause={:?}", old_cause);
44+
self.fields.cause = old_cause;
45+
r
46+
}
47+
48+
fn will_change(&mut self, a: bool, b: bool) -> bool {
49+
// if we have (Foo+'a) <: (Foo+'b), this requires that 'a:'b.
50+
// So if 'a becomes 'static, no additional errors can occur.
51+
// OTOH, if 'a stays the same, but 'b becomes 'static, we
52+
// could have a problem.
53+
!a && b
54+
}
55+
3656
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
3757
variance: ty::Variance,
3858
a: &T,
@@ -84,11 +104,14 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
84104
}
85105

86106
fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
87-
debug!("{}.regions({:?}, {:?})",
88-
self.tag(),
89-
a,
90-
b);
91-
let origin = Subtype(self.fields.trace.clone());
107+
debug!("{}.regions({:?}, {:?}) self.cause={:?}",
108+
self.tag(), a, b, self.fields.cause);
109+
let origin = match self.fields.cause {
110+
Some(Cause::ExistentialRegionBound(true)) =>
111+
SubregionOrigin::DefaultExistentialBound(self.fields.trace.clone()),
112+
_ =>
113+
SubregionOrigin::Subtype(self.fields.trace.clone()),
114+
};
92115
self.fields.infcx.region_vars.make_subregion(origin, a, b);
93116
Ok(a)
94117
}

src/librustc/middle/traits/select.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,6 +2449,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
24492449
region_bound: data_b.bounds.region_bound,
24502450
builtin_bounds: data_b.bounds.builtin_bounds,
24512451
projection_bounds: data_a.bounds.projection_bounds.clone(),
2452+
region_bound_will_change: data_b.bounds.region_bound_will_change,
24522453
};
24532454

24542455
let new_trait = ty::mk_trait(tcx, data_a.principal.clone(), bounds);

src/librustc/middle/ty.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,11 @@ pub struct ExistentialBounds<'tcx> {
18541854
pub region_bound: ty::Region,
18551855
pub builtin_bounds: BuiltinBounds,
18561856
pub projection_bounds: Vec<PolyProjectionPredicate<'tcx>>,
1857+
1858+
// If true, this TyTrait used a "default bound" in the surface
1859+
// syntax. This makes no difference to the type system but is
1860+
// handy for error reporting.
1861+
pub region_bound_will_change: bool,
18571862
}
18581863

18591864
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
@@ -1911,7 +1916,8 @@ pub enum BuiltinBound {
19111916
pub fn region_existential_bound<'tcx>(r: ty::Region) -> ExistentialBounds<'tcx> {
19121917
ty::ExistentialBounds { region_bound: r,
19131918
builtin_bounds: BuiltinBounds::empty(),
1914-
projection_bounds: Vec::new() }
1919+
projection_bounds: Vec::new(),
1920+
region_bound_will_change: false, }
19151921
}
19161922

19171923
impl CLike for BuiltinBound {
@@ -2051,6 +2057,9 @@ pub enum ObjectLifetimeDefault {
20512057
/// `T:'a` constraints are found.
20522058
Ambiguous,
20532059

2060+
/// Use the base default, typically 'static, but in a fn body it is a fresh variable
2061+
BaseDefault,
2062+
20542063
/// Use the given region as the default.
20552064
Specific(Region),
20562065
}
@@ -2062,7 +2071,7 @@ pub struct TypeParameterDef<'tcx> {
20622071
pub space: subst::ParamSpace,
20632072
pub index: u32,
20642073
pub default: Option<Ty<'tcx>>,
2065-
pub object_lifetime_default: Option<ObjectLifetimeDefault>,
2074+
pub object_lifetime_default: ObjectLifetimeDefault,
20662075
}
20672076

20682077
#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
@@ -7764,6 +7773,7 @@ impl<'tcx> fmt::Debug for ObjectLifetimeDefault {
77647773
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77657774
match *self {
77667775
ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
7776+
ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
77677777
ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
77687778
}
77697779
}

0 commit comments

Comments
 (0)