Skip to content

Commit 44d5090

Browse files
committed
Auto merge of #44782 - estebank:issue-36700, r=GuillaumeGomez
Point at parameter type on E0301 On "the parameter type `T` may not live long enough" error, point to the parameter type suggesting lifetime bindings: ``` error[E0310]: the parameter type `T` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:28:5 | 27 | struct Foo<T> { | - help: consider adding an explicit lifetime bound `T: 'static`... 28 | foo: &'static T | ^^^^^^^^^^^^^^^ | note: ...so that the reference type `&'static T` does not outlive the data it points at --> $DIR/lifetime-doesnt-live-long-enough.rs:28:5 | 28 | foo: &'static T | ^^^^^^^^^^^^^^^ ``` Fix #36700.
2 parents 0e6f4cf + ddee9fb commit 44d5090

File tree

8 files changed

+102
-20
lines changed

8 files changed

+102
-20
lines changed

src/librustc/infer/error_reporting/mod.rs

+60-10
Original file line numberDiff line numberDiff line change
@@ -785,10 +785,44 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
785785
bound_kind: GenericKind<'tcx>,
786786
sub: Region<'tcx>)
787787
{
788-
// FIXME: it would be better to report the first error message
789-
// with the span of the parameter itself, rather than the span
790-
// where the error was detected. But that span is not readily
791-
// accessible.
788+
// Attempt to obtain the span of the parameter so we can
789+
// suggest adding an explicit lifetime bound to it.
790+
let type_param_span = match (self.in_progress_tables, bound_kind) {
791+
(Some(ref table), GenericKind::Param(ref param)) => {
792+
let table = table.borrow();
793+
table.local_id_root.and_then(|did| {
794+
let generics = self.tcx.generics_of(did);
795+
// Account for the case where `did` corresponds to `Self`, which doesn't have
796+
// the expected type argument.
797+
if generics.types.len() > 0 {
798+
let type_param = generics.type_param(param);
799+
let hir = &self.tcx.hir;
800+
hir.as_local_node_id(type_param.def_id).map(|id| {
801+
// Get the `hir::TyParam` to verify wether it already has any bounds.
802+
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
803+
// instead we suggest `T: 'a + 'b` in that case.
804+
let has_lifetimes = if let hir_map::NodeTyParam(ref p) = hir.get(id) {
805+
p.bounds.len() > 0
806+
} else {
807+
false
808+
};
809+
let sp = hir.span(id);
810+
// `sp` only covers `T`, change it so that it covers
811+
// `T:` when appropriate
812+
let sp = if has_lifetimes {
813+
sp.to(sp.next_point().next_point())
814+
} else {
815+
sp
816+
};
817+
(sp, has_lifetimes)
818+
})
819+
} else {
820+
None
821+
}
822+
})
823+
}
824+
_ => None,
825+
};
792826

793827
let labeled_user_string = match bound_kind {
794828
GenericKind::Param(ref p) =>
@@ -810,6 +844,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
810844
return;
811845
}
812846

847+
fn binding_suggestion<'tcx, S: fmt::Display>(err: &mut DiagnosticBuilder<'tcx>,
848+
type_param_span: Option<(Span, bool)>,
849+
bound_kind: GenericKind<'tcx>,
850+
sub: S) {
851+
let consider = &format!("consider adding an explicit lifetime bound `{}: {}`...",
852+
bound_kind,
853+
sub);
854+
if let Some((sp, has_lifetimes)) = type_param_span {
855+
let tail = if has_lifetimes {
856+
" + "
857+
} else {
858+
""
859+
};
860+
let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
861+
err.span_suggestion_short(sp, consider, suggestion);
862+
} else {
863+
err.help(consider);
864+
}
865+
}
866+
813867
let mut err = match *sub {
814868
ty::ReEarlyBound(_) |
815869
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
@@ -819,9 +873,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
819873
E0309,
820874
"{} may not live long enough",
821875
labeled_user_string);
822-
err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...",
823-
bound_kind,
824-
sub));
876+
binding_suggestion(&mut err, type_param_span, bound_kind, sub);
825877
err
826878
}
827879

@@ -832,9 +884,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
832884
E0310,
833885
"{} may not live long enough",
834886
labeled_user_string);
835-
err.help(&format!("consider adding an explicit lifetime \
836-
bound `{}: 'static`...",
837-
bound_kind));
887+
binding_suggestion(&mut err, type_param_span, bound_kind, "'static");
838888
err
839889
}
840890

src/librustc/middle/free_region.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
117117
}
118118
}
119119

120-
#[derive(Clone, RustcEncodable, RustcDecodable)]
120+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
121121
pub struct FreeRegionMap<'tcx> {
122122
// Stores the relation `a < b`, where `a` and `b` are regions.
123123
//

src/librustc/middle/region.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ impl Scope {
293293
}
294294

295295
/// The region scope tree encodes information about region relationships.
296-
#[derive(Default)]
296+
#[derive(Default, Debug)]
297297
pub struct ScopeTree {
298298
/// If not empty, this body is the root of this region hierarchy.
299299
root_body: Option<hir::HirId>,

src/librustc/ty/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ impl<'a, V> LocalTableInContextMut<'a, V> {
315315
}
316316
}
317317

318-
#[derive(RustcEncodable, RustcDecodable)]
318+
#[derive(RustcEncodable, RustcDecodable, Debug)]
319319
pub struct TypeckTables<'tcx> {
320320
/// The HirId::owner all ItemLocalIds in this table are relative to.
321321
pub local_id_root: Option<DefId>,

src/librustc_data_structures/bitvec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl FromIterator<bool> for BitVector {
138138
/// A "bit matrix" is basically a matrix of booleans represented as
139139
/// one gigantic bitvector. In other words, it is as if you have
140140
/// `rows` bitvectors, each of length `columns`.
141-
#[derive(Clone)]
141+
#[derive(Clone, Debug)]
142142
pub struct BitMatrix {
143143
columns: usize,
144144
vector: Vec<u64>,

src/librustc_data_structures/transitive_relation.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::hash::Hash;
1818
use std::mem;
1919

2020

21-
#[derive(Clone)]
21+
#[derive(Clone, Debug)]
2222
pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash + Clone> {
2323
// List of elements. This is used to map from a T to a usize.
2424
elements: Vec<T>,
@@ -42,10 +42,10 @@ pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash + Clone> {
4242
closure: RefCell<Option<BitMatrix>>,
4343
}
4444

45-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
45+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
4646
struct Index(usize);
4747

48-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
48+
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
4949
struct Edge {
5050
source: Index,
5151
target: Index,

src/test/compile-fail/issue-16747.rs renamed to src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@ trait Collection { fn len(&self) -> usize; }
1616

1717
struct List<'a, T: ListItem<'a>> {
1818
slice: &'a [T]
19-
//~^ ERROR the parameter type `T` may not live long enough
20-
//~| HELP consider adding an explicit lifetime bound
21-
//~| NOTE ...so that the reference type `&'a [T]` does not outlive the data it points at
2219
}
20+
2321
impl<'a, T: ListItem<'a>> Collection for List<'a, T> {
2422
fn len(&self) -> usize {
2523
0
2624
}
2725
}
2826

27+
struct Foo<T> {
28+
foo: &'static T
29+
}
30+
2931
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error[E0309]: the parameter type `T` may not live long enough
2+
--> $DIR/lifetime-doesnt-live-long-enough.rs:18:5
3+
|
4+
17 | struct List<'a, T: ListItem<'a>> {
5+
| -- help: consider adding an explicit lifetime bound `T: 'a`...
6+
18 | slice: &'a [T]
7+
| ^^^^^^^^^^^^^^
8+
|
9+
note: ...so that the reference type `&'a [T]` does not outlive the data it points at
10+
--> $DIR/lifetime-doesnt-live-long-enough.rs:18:5
11+
|
12+
18 | slice: &'a [T]
13+
| ^^^^^^^^^^^^^^
14+
15+
error[E0310]: the parameter type `T` may not live long enough
16+
--> $DIR/lifetime-doesnt-live-long-enough.rs:28:5
17+
|
18+
27 | struct Foo<T> {
19+
| - help: consider adding an explicit lifetime bound `T: 'static`...
20+
28 | foo: &'static T
21+
| ^^^^^^^^^^^^^^^
22+
|
23+
note: ...so that the reference type `&'static T` does not outlive the data it points at
24+
--> $DIR/lifetime-doesnt-live-long-enough.rs:28:5
25+
|
26+
28 | foo: &'static T
27+
| ^^^^^^^^^^^^^^^
28+
29+
error: aborting due to 2 previous errors
30+

0 commit comments

Comments
 (0)