Skip to content

Commit

Permalink
Make lifetimes in constants live at the point of use
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewjasper committed Oct 2, 2019
1 parent 08a60ac commit 2180c24
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 27 deletions.
64 changes: 41 additions & 23 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,17 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {

fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
self.super_constant(constant, location);
self.sanitize_type(constant, constant.literal.ty);
let ty = self.sanitize_type(constant, constant.literal.ty);

self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| {
let live_region_vid =
self.cx.borrowck_context.universal_regions.to_region_vid(live_region);
self.cx
.borrowck_context
.constraints
.liveness_constraints
.add_element(live_region_vid, location);
});

if let Some(annotation_index) = constant.user_ty {
if let Err(terr) = self.cx.relate_type_and_user_type(
Expand Down Expand Up @@ -528,56 +538,64 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {

let parent_body = mem::replace(&mut self.body, promoted_body);

// Use new sets of constraints and closure bounds so that we can
// modify their locations.
let all_facts = &mut None;
let mut constraints = Default::default();
let mut closure_bounds = Default::default();
let mut liveness_constraints = LivenessValues::new(
Rc::new(RegionValueElements::new(promoted_body)),
);
// Don't try to add borrow_region facts for the promoted MIR
mem::swap(self.cx.borrowck_context.all_facts, all_facts);

// Use a new sets of constraints and closure bounds so that we can
// modify their locations.
mem::swap(
&mut self.cx.borrowck_context.constraints.outlives_constraints,
&mut constraints
);
mem::swap(
&mut self.cx.borrowck_context.constraints.closure_bounds_mapping,
&mut closure_bounds
);
let mut swap_constraints = |this: &mut Self| {
mem::swap(this.cx.borrowck_context.all_facts, all_facts);
mem::swap(
&mut this.cx.borrowck_context.constraints.outlives_constraints,
&mut constraints
);
mem::swap(
&mut this.cx.borrowck_context.constraints.closure_bounds_mapping,
&mut closure_bounds
);
mem::swap(
&mut this.cx.borrowck_context.constraints.liveness_constraints,
&mut liveness_constraints
);
};

swap_constraints(self);

self.visit_body(promoted_body);


if !self.errors_reported {
// if verifier failed, don't do further checks to avoid ICEs
self.cx.typeck_mir(promoted_body);
}

self.body = parent_body;
// Merge the outlives constraints back in, at the given location.
mem::swap(self.cx.borrowck_context.all_facts, all_facts);
mem::swap(
&mut self.cx.borrowck_context.constraints.outlives_constraints,
&mut constraints
);
mem::swap(
&mut self.cx.borrowck_context.constraints.closure_bounds_mapping,
&mut closure_bounds
);
swap_constraints(self);

let locations = location.to_locations();
for constraint in constraints.outlives().iter() {
let mut constraint = *constraint;
constraint.locations = locations;
if let ConstraintCategory::Return
| ConstraintCategory::UseAsConst
| ConstraintCategory::UseAsStatic = constraint.category
| ConstraintCategory::UseAsConst
| ConstraintCategory::UseAsStatic = constraint.category
{
// "Returning" from a promoted is an assigment to a
// temporary from the user's point of view.
constraint.category = ConstraintCategory::Boring;
}
self.cx.borrowck_context.constraints.outlives_constraints.push(constraint)
}
for live_region in liveness_constraints.rows() {
self.cx.borrowck_context.constraints.liveness_constraints
.add_element(live_region, location);
}

if !closure_bounds.is_empty() {
let combined_bounds_mapping = closure_bounds
Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/hrtb/due-to-where-clause.nll.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: higher-ranked subtype error
--> $DIR/due-to-where-clause.rs:2:5
|
LL | test::<FooS>(&mut 42);
| ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

3 changes: 0 additions & 3 deletions src/test/ui/hrtb/due-to-where-clause.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// ignore-compare-mode-nll
// ^ This code works in nll mode.

fn main() {
test::<FooS>(&mut 42); //~ ERROR implementation of `Foo` is not general enough
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/hrtb/due-to-where-clause.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: implementation of `Foo` is not general enough
--> $DIR/due-to-where-clause.rs:5:5
--> $DIR/due-to-where-clause.rs:2:5
|
LL | test::<FooS>(&mut 42);
| ^^^^^^^^^^^^ implementation of `Foo` is not general enough
Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/nll/promoted-liveness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Test that promoted that have larger mir bodies than their containing function
// don't cause an ICE.

// check-pass

fn main() {
&["0", "1", "2", "3", "4", "5", "6", "7"];
}

0 comments on commit 2180c24

Please sign in to comment.