Skip to content

Commit ddee9fb

Browse files
committed
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 | ^^^^^^^^^^^^^^^ ```
1 parent 14039a4 commit ddee9fb

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

782816
let labeled_user_string = match bound_kind {
783817
GenericKind::Param(ref p) =>
@@ -799,6 +833,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
799833
return;
800834
}
801835

836+
fn binding_suggestion<'tcx, S: fmt::Display>(err: &mut DiagnosticBuilder<'tcx>,
837+
type_param_span: Option<(Span, bool)>,
838+
bound_kind: GenericKind<'tcx>,
839+
sub: S) {
840+
let consider = &format!("consider adding an explicit lifetime bound `{}: {}`...",
841+
bound_kind,
842+
sub);
843+
if let Some((sp, has_lifetimes)) = type_param_span {
844+
let tail = if has_lifetimes {
845+
" + "
846+
} else {
847+
""
848+
};
849+
let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
850+
err.span_suggestion_short(sp, consider, suggestion);
851+
} else {
852+
err.help(consider);
853+
}
854+
}
855+
802856
let mut err = match *sub {
803857
ty::ReEarlyBound(_) |
804858
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
@@ -808,9 +862,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
808862
E0309,
809863
"{} may not live long enough",
810864
labeled_user_string);
811-
err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...",
812-
bound_kind,
813-
sub));
865+
binding_suggestion(&mut err, type_param_span, bound_kind, sub);
814866
err
815867
}
816868

@@ -821,9 +873,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
821873
E0310,
822874
"{} may not live long enough",
823875
labeled_user_string);
824-
err.help(&format!("consider adding an explicit lifetime \
825-
bound `{}: 'static`...",
826-
bound_kind));
876+
binding_suggestion(&mut err, type_param_span, bound_kind, "'static");
827877
err
828878
}
829879

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
@@ -201,7 +201,7 @@ impl Scope {
201201
}
202202

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

src/librustc/ty/context.rs

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

317-
#[derive(RustcEncodable, RustcDecodable)]
317+
#[derive(RustcEncodable, RustcDecodable, Debug)]
318318
pub struct TypeckTables<'tcx> {
319319
/// The HirId::owner all ItemLocalIds in this table are relative to.
320320
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)