Skip to content

Commit 2ae157b

Browse files
authored
Unrolled build for rust-lang#117835
Rollup merge of rust-lang#117835 - Nilstrieb:note-object-lifetime-defaults, r=compiler-errors Note about object lifetime defaults in does not live long enough error This is a aspect of Rust that frequently trips up people who are not aware of it yet. This diagnostic attempts to explain what's happening and why the lifetime constraint, that was never mentioned in the source, arose. The implementation feels a bit questionable, I'm not sure whether there are better ways to do this. There probably are. fixes rust-lang#117835 r? types
2 parents 8534923 + e5c330a commit 2ae157b

File tree

8 files changed

+132
-11
lines changed

8 files changed

+132
-11
lines changed

compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs

+59-1
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use rustc_hir as hir;
55
use rustc_hir::intravisit::Visitor;
66
use rustc_index::IndexSlice;
77
use rustc_infer::infer::NllRegionVariableOrigin;
8+
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
89
use rustc_middle::mir::{
910
Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location,
1011
Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind,
1112
};
1213
use rustc_middle::ty::adjustment::PointerCoercion;
13-
use rustc_middle::ty::{self, RegionVid, TyCtxt};
14+
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
1415
use rustc_span::symbol::{kw, Symbol};
1516
use rustc_span::{sym, DesugaringKind, Span};
1617
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
@@ -290,12 +291,69 @@ impl<'tcx> BorrowExplanation<'tcx> {
290291
}
291292
}
292293

294+
if let ConstraintCategory::Cast { unsize_to: Some(unsize_ty) } = category {
295+
self.add_object_lifetime_default_note(tcx, err, unsize_ty);
296+
}
293297
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
294298
}
295299
_ => {}
296300
}
297301
}
298302

303+
fn add_object_lifetime_default_note(
304+
&self,
305+
tcx: TyCtxt<'tcx>,
306+
err: &mut Diagnostic,
307+
unsize_ty: Ty<'tcx>,
308+
) {
309+
if let ty::Adt(def, args) = unsize_ty.kind() {
310+
// We try to elaborate the object lifetime defaults and present those to the user. This should
311+
// make it clear where the region constraint is coming from.
312+
let generics = tcx.generics_of(def.did());
313+
314+
let mut has_dyn = false;
315+
let mut failed = false;
316+
317+
let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
318+
if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) {
319+
let default = tcx.object_lifetime_default(param.def_id);
320+
321+
let re_static = tcx.lifetimes.re_static;
322+
323+
let implied_region = match default {
324+
// This is not entirely precise.
325+
ObjectLifetimeDefault::Empty => re_static,
326+
ObjectLifetimeDefault::Ambiguous => {
327+
failed = true;
328+
re_static
329+
}
330+
ObjectLifetimeDefault::Param(param_def_id) => {
331+
let index = generics.param_def_id_to_index[&param_def_id] as usize;
332+
args.get(index).and_then(|arg| arg.as_region()).unwrap_or_else(|| {
333+
failed = true;
334+
re_static
335+
})
336+
}
337+
ObjectLifetimeDefault::Static => re_static,
338+
};
339+
340+
has_dyn = true;
341+
342+
Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into()
343+
} else {
344+
arg
345+
}
346+
});
347+
let elaborated_ty = Ty::new_adt(tcx, *def, tcx.mk_args_from_iter(elaborated_args));
348+
349+
if has_dyn && !failed {
350+
err.note(format!(
351+
"due to object lifetime defaults, `{unsize_ty}` actually means `{elaborated_ty}`"
352+
));
353+
}
354+
}
355+
}
356+
299357
fn add_lifetime_bound_suggestion_to_diagnostic(
300358
&self,
301359
err: &mut Diagnostic,

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
5353
ConstraintCategory::Yield => "yielding this value ",
5454
ConstraintCategory::UseAsConst => "using this value as a constant ",
5555
ConstraintCategory::UseAsStatic => "using this value as a static ",
56-
ConstraintCategory::Cast => "cast ",
56+
ConstraintCategory::Cast { .. } => "cast ",
5757
ConstraintCategory::CallArgument(_) => "argument ",
5858
ConstraintCategory::TypeAnnotation => "type annotation ",
5959
ConstraintCategory::ClosureBounds => "closure body ",

compiler/rustc_borrowck/src/type_check/mod.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -1934,7 +1934,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
19341934
*ty,
19351935
ty_fn_ptr_from,
19361936
location.to_locations(),
1937-
ConstraintCategory::Cast,
1937+
ConstraintCategory::Cast { unsize_to: None },
19381938
) {
19391939
span_mirbug!(
19401940
self,
@@ -1959,7 +1959,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
19591959
*ty,
19601960
ty_fn_ptr_from,
19611961
location.to_locations(),
1962-
ConstraintCategory::Cast,
1962+
ConstraintCategory::Cast { unsize_to: None },
19631963
) {
19641964
span_mirbug!(
19651965
self,
@@ -1988,7 +1988,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
19881988
*ty,
19891989
ty_fn_ptr_from,
19901990
location.to_locations(),
1991-
ConstraintCategory::Cast,
1991+
ConstraintCategory::Cast { unsize_to: None },
19921992
) {
19931993
span_mirbug!(
19941994
self,
@@ -2013,7 +2013,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
20132013
self.prove_trait_ref(
20142014
trait_ref,
20152015
location.to_locations(),
2016-
ConstraintCategory::Cast,
2016+
ConstraintCategory::Cast {
2017+
unsize_to: Some(tcx.fold_regions(ty, |r, _| {
2018+
if let ty::ReVar(_) = r.kind() {
2019+
tcx.lifetimes.re_erased
2020+
} else {
2021+
r
2022+
}
2023+
})),
2024+
},
20172025
);
20182026
}
20192027

@@ -2033,7 +2041,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
20332041
.iter()
20342042
.map(|predicate| predicate.with_self_ty(tcx, self_ty)),
20352043
location.to_locations(),
2036-
ConstraintCategory::Cast,
2044+
ConstraintCategory::Cast { unsize_to: None },
20372045
);
20382046

20392047
let outlives_predicate = tcx.mk_predicate(Binder::dummy(
@@ -2044,7 +2052,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
20442052
self.prove_predicate(
20452053
outlives_predicate,
20462054
location.to_locations(),
2047-
ConstraintCategory::Cast,
2055+
ConstraintCategory::Cast { unsize_to: None },
20482056
);
20492057
}
20502058

@@ -2065,7 +2073,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
20652073
*ty_from,
20662074
*ty_to,
20672075
location.to_locations(),
2068-
ConstraintCategory::Cast,
2076+
ConstraintCategory::Cast { unsize_to: None },
20692077
) {
20702078
span_mirbug!(
20712079
self,
@@ -2131,7 +2139,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
21312139
*ty_elem,
21322140
*ty_to,
21332141
location.to_locations(),
2134-
ConstraintCategory::Cast,
2142+
ConstraintCategory::Cast { unsize_to: None },
21352143
) {
21362144
span_mirbug!(
21372145
self,

compiler/rustc_middle/src/mir/query.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,11 @@ pub enum ConstraintCategory<'tcx> {
341341
UseAsConst,
342342
UseAsStatic,
343343
TypeAnnotation,
344-
Cast,
344+
Cast {
345+
/// Whether this is an unsizing cast and if yes, this contains the target type.
346+
/// Region variables are erased to ReErased.
347+
unsize_to: Option<Ty<'tcx>>,
348+
},
345349

346350
/// A constraint that came from checking the body of a closure.
347351
///

tests/ui/borrowck/two-phase-surprise-no-conflict.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ LL | reg.register_univ(Box::new(CapturePass::new(&reg.sess_mut)));
7777
| | | immutable borrow occurs here
7878
| | cast requires that `reg.sess_mut` is borrowed for `'a`
7979
| mutable borrow occurs here
80+
|
81+
= note: due to object lifetime defaults, `Box<dyn for<'b> LateLintPass<'b>>` actually means `Box<(dyn for<'b> LateLintPass<'b> + 'static)>`
8082

8183
error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable
8284
--> $DIR/two-phase-surprise-no-conflict.rs:144:5
@@ -119,6 +121,8 @@ LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
119121
| | | first mutable borrow occurs here
120122
| | cast requires that `reg.sess_mut` is borrowed for `'a`
121123
| second mutable borrow occurs here
124+
|
125+
= note: due to object lifetime defaults, `Box<dyn for<'b> LateLintPass<'b>>` actually means `Box<(dyn for<'b> LateLintPass<'b> + 'static)>`
122126

123127
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
124128
--> $DIR/two-phase-surprise-no-conflict.rs:158:53

tests/ui/dropck/dropck_trait_cycle_checked.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ LL | o1.set0(&o2);
88
...
99
LL | }
1010
| - `o2` dropped here while still borrowed
11+
|
12+
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
1113

1214
error[E0597]: `o3` does not live long enough
1315
--> $DIR/dropck_trait_cycle_checked.rs:112:13
@@ -20,6 +22,8 @@ LL | o1.set1(&o3);
2022
...
2123
LL | }
2224
| - `o3` dropped here while still borrowed
25+
|
26+
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
2327

2428
error[E0597]: `o2` does not live long enough
2529
--> $DIR/dropck_trait_cycle_checked.rs:113:13
@@ -32,6 +36,8 @@ LL | o2.set0(&o2);
3236
...
3337
LL | }
3438
| - `o2` dropped here while still borrowed
39+
|
40+
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
3541

3642
error[E0597]: `o3` does not live long enough
3743
--> $DIR/dropck_trait_cycle_checked.rs:114:13
@@ -44,6 +50,8 @@ LL | o2.set1(&o3);
4450
...
4551
LL | }
4652
| - `o3` dropped here while still borrowed
53+
|
54+
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
4755

4856
error[E0597]: `o1` does not live long enough
4957
--> $DIR/dropck_trait_cycle_checked.rs:115:13
@@ -56,6 +64,8 @@ LL | o3.set0(&o1);
5664
LL | o3.set1(&o2);
5765
LL | }
5866
| - `o1` dropped here while still borrowed
67+
|
68+
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
5969

6070
error[E0597]: `o2` does not live long enough
6171
--> $DIR/dropck_trait_cycle_checked.rs:116:13
@@ -67,6 +77,8 @@ LL | o3.set1(&o2);
6777
| ^^^ borrowed value does not live long enough
6878
LL | }
6979
| - `o2` dropped here while still borrowed
80+
|
81+
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
7082

7183
error: aborting due to 6 previous errors
7284

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
trait A {}
2+
3+
impl<T> A for T {}
4+
5+
fn main() {
6+
let local = 0; //~ NOTE binding `local` declared here
7+
let r = &local; //~ ERROR `local` does not live long enough
8+
//~| NOTE borrowed value does not live long enough
9+
//~| NOTE due to object lifetime defaults, `Box<dyn A>` actually means `Box<(dyn A + 'static)>`
10+
require_box(Box::new(r));
11+
//~^ NOTE cast requires that `local` is borrowed for `'static`
12+
13+
let _ = 0;
14+
} //~ NOTE `local` dropped here while still borrowed
15+
16+
fn require_box(_a: Box<dyn A>) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0597]: `local` does not live long enough
2+
--> $DIR/trait-object-lifetime-default-note.rs:7:13
3+
|
4+
LL | let local = 0;
5+
| ----- binding `local` declared here
6+
LL | let r = &local;
7+
| ^^^^^^ borrowed value does not live long enough
8+
...
9+
LL | require_box(Box::new(r));
10+
| ----------- cast requires that `local` is borrowed for `'static`
11+
...
12+
LL | }
13+
| - `local` dropped here while still borrowed
14+
|
15+
= note: due to object lifetime defaults, `Box<dyn A>` actually means `Box<(dyn A + 'static)>`
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0597`.

0 commit comments

Comments
 (0)