Skip to content

Commit fdcd225

Browse files
committed
trace span info for constraints and report errors
1 parent 53e4bd4 commit fdcd225

File tree

5 files changed

+155
-31
lines changed

5 files changed

+155
-31
lines changed

src/librustc_mir/transform/nll/constraint_generation.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,14 +191,16 @@ impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
191191
_borrowed_lv: &Lvalue<'tcx>,
192192
) {
193193
let tcx = self.infcx.tcx;
194+
let span = self.mir.source_info(location).span;
194195
let destination_ty = destination_lv.ty(self.mir, tcx).to_ty(tcx);
195196

196197
let destination_region = match destination_ty.sty {
197198
ty::TyRef(r, _) => r,
198199
_ => bug!()
199200
};
200201

201-
self.regioncx.add_outlives(borrow_region.to_region_index(),
202+
self.regioncx.add_outlives(span,
203+
borrow_region.to_region_index(),
202204
destination_region.to_region_index(),
203205
location.successor_within_block());
204206
}
@@ -226,7 +228,9 @@ impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
226228
},
227229
}
228230

229-
self.regioncx.add_outlives(base_region.to_region_index(),
231+
let span = self.mir.source_info(location).span;
232+
self.regioncx.add_outlives(span,
233+
base_region.to_region_index(),
230234
borrow_region.to_region_index(),
231235
location.successor_within_block());
232236
}
@@ -259,8 +263,9 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cx, 'gcx, 'tcx> {
259263
let destination_ty = destination_lv.ty(self.mir, tcx).to_ty(tcx);
260264
let rv_ty = rv.ty(self.mir, tcx);
261265

266+
let span = self.mir.source_info(location).span;
262267
for (a, b) in subtype::outlives_pairs(tcx, rv_ty, destination_ty) {
263-
self.regioncx.add_outlives(a, b, location.successor_within_block());
268+
self.regioncx.add_outlives(span, a, b, location.successor_within_block());
264269
}
265270
}
266271

src/librustc_mir/transform/nll/region_infer.rs

Lines changed: 96 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
1717
use rustc_data_structures::fx::FxHashSet;
1818
use std::collections::BTreeSet;
1919
use std::fmt;
20+
use syntax_pos::Span;
2021

2122
pub struct RegionInferenceContext<'tcx> {
2223
/// Contains the definition for every region variable. Region
@@ -70,10 +71,11 @@ struct Region {
7071

7172
impl fmt::Debug for Region {
7273
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
73-
formatter.debug_set()
74-
.entries(&self.points)
75-
.entries(&self.free_regions)
76-
.finish()
74+
formatter
75+
.debug_set()
76+
.entries(&self.points)
77+
.entries(&self.free_regions)
78+
.finish()
7779
}
7880
}
7981

@@ -93,8 +95,16 @@ impl Region {
9395

9496
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
9597
pub struct Constraint {
96-
sub: RegionIndex,
98+
/// Where did this constraint arise?
99+
span: Span,
100+
101+
/// The region SUP must outlive SUB...
97102
sup: RegionIndex,
103+
104+
/// Region that must be outlived.
105+
sub: RegionIndex,
106+
107+
/// At this location.
98108
point: Location,
99109
}
100110

@@ -210,56 +220,116 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
210220
pub(super) fn add_live_point(&mut self, v: RegionIndex, point: Location) {
211221
debug!("add_live_point({:?}, {:?})", v, point);
212222
let definition = &mut self.definitions[v];
213-
definition.value.add_point(point);
223+
if !definition.constant {
224+
definition.value.add_point(point);
225+
} else {
226+
// Constants are used for free regions, which already
227+
// contain all the points in the control-flow graph.
228+
assert!(definition.value.contains_point(point));
229+
}
214230
}
215231

216232
/// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
217-
pub(super) fn add_outlives(&mut self, sup: RegionIndex, sub: RegionIndex, point: Location) {
233+
pub(super) fn add_outlives(
234+
&mut self,
235+
span: Span,
236+
sup: RegionIndex,
237+
sub: RegionIndex,
238+
point: Location,
239+
) {
218240
debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
219-
self.constraints.push(Constraint { sup, sub, point });
241+
self.constraints.push(Constraint {
242+
span,
243+
sup,
244+
sub,
245+
point,
246+
});
220247
}
221248

222249
/// Perform region inference.
223250
pub(super) fn solve(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>) {
224-
self.propagate_constraints(infcx, mir);
251+
let errors = self.propagate_constraints(mir);
252+
253+
// worst error msg ever
254+
for (fr1, span, fr2) in errors {
255+
infcx.tcx.sess.span_err(
256+
span,
257+
&format!(
258+
"free region `{}` does not outlive `{}`",
259+
self.definitions[fr1].name.unwrap(),
260+
self.definitions[fr2].name.unwrap()
261+
),
262+
);
263+
}
225264
}
226265

227266
/// Propagate the region constraints: this will grow the values
228267
/// for each region variable until all the constraints are
229268
/// satisfied. Note that some values may grow **too** large to be
230269
/// feasible, but we check this later.
231-
fn propagate_constraints(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>) {
270+
fn propagate_constraints(
271+
&mut self,
272+
mir: &Mir<'tcx>,
273+
) -> Vec<(RegionIndex, Span, RegionIndex)> {
232274
let mut changed = true;
233-
let mut dfs = Dfs::new(infcx, mir);
275+
let mut dfs = Dfs::new(mir);
276+
let mut error_regions = FxHashSet();
277+
let mut errors = vec![];
234278
while changed {
235279
changed = false;
236280
for constraint in &self.constraints {
281+
debug!("constraint: {:?}", constraint);
237282
let sub = &self.definitions[constraint.sub].value.clone();
238283
let sup_def = &mut self.definitions[constraint.sup];
239-
debug!("constraint: {:?}", constraint);
284+
240285
debug!(" sub (before): {:?}", sub);
241286
debug!(" sup (before): {:?}", sup_def.value);
242287

243-
if dfs.copy(sub, &mut sup_def.value, constraint.point) {
244-
changed = true;
288+
if !sup_def.constant {
289+
// If this is not a constant, then grow the value as needed to
290+
// accommodate the outlives constraint.
291+
292+
if dfs.copy(sub, &mut sup_def.value, constraint.point) {
293+
changed = true;
294+
}
295+
296+
debug!(" sup (after) : {:?}", sup_def.value);
297+
debug!(" changed : {:?}", changed);
298+
} else {
299+
// If this is a constant, check whether it *would
300+
// have* to grow in order for the constraint to be
301+
// satisfied. If so, create an error.
302+
303+
let mut sup_value = sup_def.value.clone();
304+
if dfs.copy(sub, &mut sup_value, constraint.point) {
305+
// Constant values start out with the entire
306+
// CFG, so it must be some new free region
307+
// that was added. Find one.
308+
let &new_region = sup_value
309+
.free_regions
310+
.difference(&sup_def.value.free_regions)
311+
.next()
312+
.unwrap();
313+
debug!(" new_region : {:?}", new_region);
314+
if error_regions.insert(constraint.sup) {
315+
errors.push((constraint.sup, constraint.span, new_region));
316+
}
317+
}
245318
}
246-
247-
debug!(" sup (after) : {:?}", sup_def.value);
248-
debug!(" changed : {:?}", changed);
249319
}
250320
debug!("\n");
251321
}
322+
errors
252323
}
253324
}
254325

255-
struct Dfs<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> {
256-
#[allow(dead_code)] infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
326+
struct Dfs<'a, 'tcx: 'a> {
257327
mir: &'a Mir<'tcx>,
258328
}
259329

260-
impl<'a, 'gcx: 'tcx, 'tcx: 'a> Dfs<'a, 'gcx, 'tcx> {
261-
fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
262-
Self { infcx, mir }
330+
impl<'a, 'tcx> Dfs<'a, 'tcx> {
331+
fn new(mir: &'a Mir<'tcx>) -> Self {
332+
Self { mir }
263333
}
264334

265335
fn copy(
@@ -316,7 +386,10 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> Dfs<'a, 'gcx, 'tcx> {
316386
// over any skolemized end points in the `from_region`
317387
// and make sure they are included in the `to_region`.
318388

319-
to_region.free_regions.extend(&from_region.free_regions);
389+
debug!(" dfs: free_regions={:?}", from_region.free_regions);
390+
for &fr in &from_region.free_regions {
391+
changed |= to_region.free_regions.insert(fr);
392+
}
320393
} else {
321394
stack.extend(successor_points);
322395
}

src/test/compile-fail/nll/region-error.rs

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/test/ui/nll/named-region-basic.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2016 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+
// Basic test for free regions in the NLL code. This test ought to
12+
// report an error due to a reborrowing constraint. Right now, we get
13+
// a variety of errors from the older, AST-based machinery (notably
14+
// borrowck), and then we get the NLL error at the end.
15+
16+
// compile-flags:-Znll
17+
18+
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 {
19+
&*x
20+
}
21+
22+
fn main() { }
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
warning: not reporting region error due to -Znll: SubSupConflict(AddrOfRegion($DIR/named-region-basic.rs:19:5: 19:8), Reborrow($DIR/named-region-basic.rs:19:5: 19:8), ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:3) => named_region_basic[317d]::foo[0] }, BrNamed(CrateNum(0):DefIndex(1:10), 'b(88))), Reborrow($DIR/named-region-basic.rs:19:5: 19:8), ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:3) => named_region_basic[317d]::foo[0] }, BrNamed(CrateNum(0):DefIndex(1:9), 'a(86))))
2+
--> $DIR/named-region-basic.rs:19:5
3+
|
4+
19 | &*x
5+
| ^^^
6+
7+
error[E0597]: `*x` does not live long enough
8+
--> $DIR/named-region-basic.rs:19:6
9+
|
10+
19 | &*x
11+
| ^^ does not live long enough
12+
|
13+
= note: borrowed value must be valid for the static lifetime...
14+
note: ...but borrowed value is only valid for the lifetime 'a as defined on the function body at 18:1
15+
--> $DIR/named-region-basic.rs:18:1
16+
|
17+
18 | / fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 {
18+
19 | | &*x
19+
20 | | }
20+
| |_^
21+
22+
error: free region `'a` does not outlive `'b`
23+
--> $DIR/named-region-basic.rs:19:5
24+
|
25+
19 | &*x
26+
| ^^^
27+
28+
error: aborting due to 2 previous errors
29+

0 commit comments

Comments
 (0)