replace constant regions with a post-inference check
Rather than declaring some region variables to be constant, and reporting errors when they would have to change, we instead populate each free region X with a minimal set of points (the CFG plus end(X)), and then we let inference do its thing. This may add other `end(Y)` points into X; we can then check after the fact that indeed `X: Y` holds. This requires a bit of "blame" detection to find where the bad constraint came from: we are currently using a pretty dumb algorithm. Good place for later expansion.
This commit is contained in:
parent
932452ecc7
commit
a96b0cf86d
3 changed files with 163 additions and 100 deletions
|
@ -63,28 +63,28 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
|
||||||
-> bool {
|
-> bool {
|
||||||
let result = sub_region == super_region || {
|
let result = sub_region == super_region || {
|
||||||
match (sub_region, super_region) {
|
match (sub_region, super_region) {
|
||||||
(&ty::ReEmpty, _) |
|
(ty::ReEmpty, _) |
|
||||||
(_, &ty::ReStatic) =>
|
(_, ty::ReStatic) =>
|
||||||
true,
|
true,
|
||||||
|
|
||||||
(&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) =>
|
(ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
|
||||||
self.region_scope_tree.is_subscope_of(sub_scope, super_scope),
|
self.region_scope_tree.is_subscope_of(*sub_scope, *super_scope),
|
||||||
|
|
||||||
(&ty::ReScope(sub_scope), &ty::ReEarlyBound(ref br)) => {
|
(ty::ReScope(sub_scope), ty::ReEarlyBound(ref br)) => {
|
||||||
let fr_scope = self.region_scope_tree.early_free_scope(self.tcx, br);
|
let fr_scope = self.region_scope_tree.early_free_scope(self.tcx, br);
|
||||||
self.region_scope_tree.is_subscope_of(sub_scope, fr_scope)
|
self.region_scope_tree.is_subscope_of(*sub_scope, fr_scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
(&ty::ReScope(sub_scope), &ty::ReFree(ref fr)) => {
|
(ty::ReScope(sub_scope), ty::ReFree(fr)) => {
|
||||||
let fr_scope = self.region_scope_tree.free_scope(self.tcx, fr);
|
let fr_scope = self.region_scope_tree.free_scope(self.tcx, fr);
|
||||||
self.region_scope_tree.is_subscope_of(sub_scope, fr_scope)
|
self.region_scope_tree.is_subscope_of(*sub_scope, fr_scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
(&ty::ReEarlyBound(_), &ty::ReEarlyBound(_)) |
|
(ty::ReEarlyBound(_), ty::ReEarlyBound(_)) |
|
||||||
(&ty::ReFree(_), &ty::ReEarlyBound(_)) |
|
(ty::ReFree(_), ty::ReEarlyBound(_)) |
|
||||||
(&ty::ReEarlyBound(_), &ty::ReFree(_)) |
|
(ty::ReEarlyBound(_), ty::ReFree(_)) |
|
||||||
(&ty::ReFree(_), &ty::ReFree(_)) =>
|
(ty::ReFree(_), ty::ReFree(_)) =>
|
||||||
self.free_regions.sub_free_regions(&sub_region, &super_region),
|
self.free_regions.sub_free_regions(sub_region, super_region),
|
||||||
|
|
||||||
_ =>
|
_ =>
|
||||||
false,
|
false,
|
||||||
|
@ -162,23 +162,23 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
||||||
/// (with the exception that `'static: 'x` is not notable)
|
/// (with the exception that `'static: 'x` is not notable)
|
||||||
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
|
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
|
||||||
debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
|
debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
|
||||||
if (is_free(sub) || *sub == ty::ReStatic) && is_free(sup) {
|
if is_free_or_static(sub) && is_free(sup) {
|
||||||
self.relation.add(sub, sup)
|
self.relation.add(sub, sup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True if `r_a <= r_b` is known to hold. Both `r_a` and `r_b`
|
/// Tests whether `r_a <= sup`. Both must be free regions or
|
||||||
/// must be free regions from the function header.
|
/// `'static`.
|
||||||
pub fn sub_free_regions<'a, 'gcx>(&self,
|
pub fn sub_free_regions<'a, 'gcx>(&self,
|
||||||
r_a: Region<'tcx>,
|
r_a: Region<'tcx>,
|
||||||
r_b: Region<'tcx>)
|
r_b: Region<'tcx>)
|
||||||
-> bool {
|
-> bool {
|
||||||
debug!("sub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
|
assert!(is_free_or_static(r_a) && is_free_or_static(r_b));
|
||||||
assert!(is_free(r_a));
|
if let ty::ReStatic = r_b {
|
||||||
assert!(is_free(r_b));
|
true // `'a <= 'static` is just always true, and not stored in the relation explicitly
|
||||||
let result = r_a == r_b || self.relation.contains(&r_a, &r_b);
|
} else {
|
||||||
debug!("sub_free_regions: result={}", result);
|
r_a == r_b || self.relation.contains(&r_a, &r_b)
|
||||||
result
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the least-upper-bound of two free regions. In some
|
/// Compute the least-upper-bound of two free regions. In some
|
||||||
|
@ -224,6 +224,13 @@ fn is_free(r: Region) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_free_or_static(r: Region) -> bool {
|
||||||
|
match *r {
|
||||||
|
ty::ReStatic => true,
|
||||||
|
_ => is_free(r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_stable_hash_for!(struct FreeRegionMap<'tcx> {
|
impl_stable_hash_for!(struct FreeRegionMap<'tcx> {
|
||||||
relation
|
relation
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,6 +13,7 @@ use rustc::infer::InferCtxt;
|
||||||
use rustc::infer::RegionVariableOrigin;
|
use rustc::infer::RegionVariableOrigin;
|
||||||
use rustc::infer::NLLRegionVariableOrigin;
|
use rustc::infer::NLLRegionVariableOrigin;
|
||||||
use rustc::infer::region_constraints::VarOrigins;
|
use rustc::infer::region_constraints::VarOrigins;
|
||||||
|
use rustc::middle::free_region::FreeRegionMap;
|
||||||
use rustc::mir::{Location, Mir};
|
use rustc::mir::{Location, Mir};
|
||||||
use rustc::ty::{self, RegionVid};
|
use rustc::ty::{self, RegionVid};
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
|
@ -40,6 +41,8 @@ pub struct RegionInferenceContext<'tcx> {
|
||||||
|
|
||||||
/// The constraints we have accumulated and used during solving.
|
/// The constraints we have accumulated and used during solving.
|
||||||
constraints: Vec<Constraint>,
|
constraints: Vec<Constraint>,
|
||||||
|
|
||||||
|
free_region_map: &'tcx FreeRegionMap<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RegionDefinition<'tcx> {
|
struct RegionDefinition<'tcx> {
|
||||||
|
@ -52,10 +55,6 @@ struct RegionDefinition<'tcx> {
|
||||||
/// If this is a free-region, then this is `Some(X)` where `X` is
|
/// If this is a free-region, then this is `Some(X)` where `X` is
|
||||||
/// the name of the region.
|
/// the name of the region.
|
||||||
name: Option<ty::Region<'tcx>>,
|
name: Option<ty::Region<'tcx>>,
|
||||||
|
|
||||||
/// If true, this is a constant region which cannot grow larger.
|
|
||||||
/// This is used for named regions as well as `'static`.
|
|
||||||
constant: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The value of an individual region variable. Region variables
|
/// The value of an individual region variable. Region variables
|
||||||
|
@ -100,7 +99,6 @@ pub struct Constraint {
|
||||||
// it is for convenience. Before we dump the constraints in the
|
// it is for convenience. Before we dump the constraints in the
|
||||||
// debugging logs, we sort them, and we'd like the "super region"
|
// debugging logs, we sort them, and we'd like the "super region"
|
||||||
// to be first, etc. (In particular, span should remain last.)
|
// to be first, etc. (In particular, span should remain last.)
|
||||||
|
|
||||||
/// The region SUP must outlive SUB...
|
/// The region SUP must outlive SUB...
|
||||||
sup: RegionVid,
|
sup: RegionVid,
|
||||||
|
|
||||||
|
@ -114,7 +112,7 @@ pub struct Constraint {
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
/// Creates a new region inference context with a total of
|
/// Creates a new region inference context with a total of
|
||||||
/// `num_region_variables` valid inference variables; the first N
|
/// `num_region_variables` valid inference variables; the first N
|
||||||
/// of those will be constant regions representing the free
|
/// of those will be constant regions representing the free
|
||||||
|
@ -133,6 +131,7 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
||||||
liveness_constraints: IndexVec::from_elem_n(Region::default(), num_region_variables),
|
liveness_constraints: IndexVec::from_elem_n(Region::default(), num_region_variables),
|
||||||
inferred_values: None,
|
inferred_values: None,
|
||||||
constraints: Vec::new(),
|
constraints: Vec::new(),
|
||||||
|
free_region_map: free_regions.free_region_map,
|
||||||
};
|
};
|
||||||
|
|
||||||
result.init_free_regions(free_regions, mir);
|
result.init_free_regions(free_regions, mir);
|
||||||
|
@ -162,7 +161,7 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
||||||
fn init_free_regions(&mut self, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx>) {
|
fn init_free_regions(&mut self, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx>) {
|
||||||
let FreeRegions {
|
let FreeRegions {
|
||||||
indices,
|
indices,
|
||||||
free_region_map,
|
free_region_map: _,
|
||||||
} = free_regions;
|
} = free_regions;
|
||||||
|
|
||||||
// For each free region X:
|
// For each free region X:
|
||||||
|
@ -175,7 +174,6 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
||||||
|
|
||||||
// Initialize the name and a few other details.
|
// Initialize the name and a few other details.
|
||||||
self.definitions[variable].name = Some(free_region);
|
self.definitions[variable].name = Some(free_region);
|
||||||
self.definitions[variable].constant = true;
|
|
||||||
|
|
||||||
// Add all nodes in the CFG to `definition.value`.
|
// Add all nodes in the CFG to `definition.value`.
|
||||||
for (block, block_data) in mir.basic_blocks().iter_enumerated() {
|
for (block, block_data) in mir.basic_blocks().iter_enumerated() {
|
||||||
|
@ -192,21 +190,6 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
||||||
// Add `end(X)` into the set for X.
|
// Add `end(X)` into the set for X.
|
||||||
self.liveness_constraints[variable].add_free_region(variable);
|
self.liveness_constraints[variable].add_free_region(variable);
|
||||||
|
|
||||||
// `'static` outlives all other free regions as well.
|
|
||||||
if let ty::ReStatic = free_region {
|
|
||||||
for &other_variable in indices.values() {
|
|
||||||
self.liveness_constraints[variable]
|
|
||||||
.add_free_region(other_variable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through each region Y that outlives X (i.e., where
|
|
||||||
// Y: X is true). Add `end(X)` into the set for `Y`.
|
|
||||||
for superregion in free_region_map.regions_that_outlive(&free_region) {
|
|
||||||
let superregion_index = indices[superregion];
|
|
||||||
self.liveness_constraints[superregion_index].add_free_region(variable);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"init_free_regions: region variable for `{:?}` is `{:?}` with value `{:?}`",
|
"init_free_regions: region variable for `{:?}` is `{:?}` with value `{:?}`",
|
||||||
free_region,
|
free_region,
|
||||||
|
@ -265,20 +248,72 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform region inference.
|
/// Perform region inference.
|
||||||
pub(super) fn solve(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>) {
|
pub(super) fn solve(&mut self, infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) {
|
||||||
assert!(self.inferred_values.is_none(), "values already inferred");
|
assert!(self.inferred_values.is_none(), "values already inferred");
|
||||||
let errors = self.propagate_constraints(mir);
|
|
||||||
|
|
||||||
// worst error msg ever
|
// Find the minimal regions that can solve the constraints. This is infallible.
|
||||||
for (fr1, span, fr2) in errors {
|
self.propagate_constraints(mir);
|
||||||
infcx.tcx.sess.span_err(
|
|
||||||
span,
|
// Now, see whether any of the constraints were too strong. In particular,
|
||||||
&format!(
|
// we want to check for a case where a free region exceeded its bounds.
|
||||||
"free region `{}` does not outlive `{}`",
|
// Consider:
|
||||||
self.definitions[fr1].name.unwrap(),
|
//
|
||||||
self.definitions[fr2].name.unwrap()
|
// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
|
||||||
),
|
//
|
||||||
);
|
// In this case, returning `x` requires `&'a u32 <: &'b u32`
|
||||||
|
// and hence we establish (transitively) a constraint that
|
||||||
|
// `'a: 'b`. The `propagate_constraints` code above will
|
||||||
|
// therefore add `end('a)` into the region for `'b` -- but we
|
||||||
|
// have no evidence that `'b` outlives `'a`, so we want to report
|
||||||
|
// an error.
|
||||||
|
|
||||||
|
// The free regions are always found in a prefix of the full list.
|
||||||
|
let free_region_definitions = self.definitions
|
||||||
|
.iter_enumerated()
|
||||||
|
.take_while(|(_, fr_definition)| fr_definition.name.is_some());
|
||||||
|
|
||||||
|
for (fr, fr_definition) in free_region_definitions {
|
||||||
|
self.check_free_region(infcx, fr, fr_definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_free_region(
|
||||||
|
&self,
|
||||||
|
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||||
|
fr: RegionVid,
|
||||||
|
fr_definition: &RegionDefinition<'tcx>,
|
||||||
|
) {
|
||||||
|
let inferred_values = self.inferred_values.as_ref().unwrap();
|
||||||
|
let fr_name = fr_definition.name.unwrap();
|
||||||
|
let fr_value = &inferred_values[fr];
|
||||||
|
|
||||||
|
// Find every region `o` such that `fr: o`
|
||||||
|
// (because `fr` includes `end(o)`).
|
||||||
|
for &outlived_fr in &fr_value.free_regions {
|
||||||
|
// `fr` includes `end(fr)`, that's not especially
|
||||||
|
// interesting.
|
||||||
|
if fr == outlived_fr {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let outlived_fr_definition = &self.definitions[outlived_fr];
|
||||||
|
let outlived_fr_name = outlived_fr_definition.name.unwrap();
|
||||||
|
|
||||||
|
// Check that `o <= fr`. If not, report an error.
|
||||||
|
if !self.free_region_map
|
||||||
|
.sub_free_regions(outlived_fr_name, fr_name)
|
||||||
|
{
|
||||||
|
// worst error msg ever
|
||||||
|
let blame_span = self.blame_span(fr, outlived_fr);
|
||||||
|
infcx.tcx.sess.span_err(
|
||||||
|
blame_span,
|
||||||
|
&format!(
|
||||||
|
"free region `{}` does not outlive `{}`",
|
||||||
|
fr_name,
|
||||||
|
outlived_fr_name
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,11 +321,9 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
||||||
/// for each region variable until all the constraints are
|
/// for each region variable until all the constraints are
|
||||||
/// satisfied. Note that some values may grow **too** large to be
|
/// satisfied. Note that some values may grow **too** large to be
|
||||||
/// feasible, but we check this later.
|
/// feasible, but we check this later.
|
||||||
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) -> Vec<(RegionVid, Span, RegionVid)> {
|
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
|
||||||
let mut changed = true;
|
let mut changed = true;
|
||||||
let mut dfs = Dfs::new(mir);
|
let mut dfs = Dfs::new(mir);
|
||||||
let mut error_regions = FxHashSet();
|
|
||||||
let mut errors = vec![];
|
|
||||||
|
|
||||||
debug!("propagate_constraints()");
|
debug!("propagate_constraints()");
|
||||||
debug!("propagate_constraints: constraints={:#?}", {
|
debug!("propagate_constraints: constraints={:#?}", {
|
||||||
|
@ -305,51 +338,78 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
||||||
|
|
||||||
while changed {
|
while changed {
|
||||||
changed = false;
|
changed = false;
|
||||||
|
debug!("propagate_constraints: --------------------");
|
||||||
for constraint in &self.constraints {
|
for constraint in &self.constraints {
|
||||||
debug!("propagate_constraints: constraint={:?}", constraint);
|
debug!("propagate_constraints: constraint={:?}", constraint);
|
||||||
|
|
||||||
let sub = &inferred_values[constraint.sub].clone();
|
let sub = &inferred_values[constraint.sub].clone();
|
||||||
let sup_value = &mut inferred_values[constraint.sup];
|
let sup_value = &mut inferred_values[constraint.sup];
|
||||||
|
|
||||||
debug!("propagate_constraints: sub (before): {:?}", sub);
|
// Grow the value as needed to accommodate the
|
||||||
debug!("propagate_constraints: sup (before): {:?}", sup_value);
|
// outlives constraint.
|
||||||
|
|
||||||
if !self.definitions[constraint.sup].constant {
|
if dfs.copy(sub, sup_value, constraint.point) {
|
||||||
// If this is not a constant, then grow the value as needed to
|
debug!("propagate_constraints: sub={:?}", sub);
|
||||||
// accommodate the outlives constraint.
|
debug!("propagate_constraints: sup={:?}", sup_value);
|
||||||
|
changed = true;
|
||||||
if dfs.copy(sub, sup_value, constraint.point) {
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("propagate_constraints: sup (after) : {:?}", sup_value);
|
|
||||||
debug!("propagate_constraints: changed : {:?}", changed);
|
|
||||||
} else {
|
|
||||||
// If this is a constant, check whether it *would
|
|
||||||
// have* to grow in order for the constraint to be
|
|
||||||
// satisfied. If so, create an error.
|
|
||||||
|
|
||||||
let sup_value = &mut sup_value.clone();
|
|
||||||
if dfs.copy(sub, sup_value, constraint.point) {
|
|
||||||
// Constant values start out with the entire
|
|
||||||
// CFG, so it must be some new free region
|
|
||||||
// that was added. Find one.
|
|
||||||
let &new_region = sup_value
|
|
||||||
.free_regions
|
|
||||||
.difference(&sup_value.free_regions)
|
|
||||||
.next()
|
|
||||||
.unwrap();
|
|
||||||
debug!("propagate_constraints: new_region : {:?}", new_region);
|
|
||||||
if error_regions.insert(constraint.sup) {
|
|
||||||
errors.push((constraint.sup, constraint.span, new_region));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("\n");
|
debug!("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inferred_values = Some(inferred_values);
|
self.inferred_values = Some(inferred_values);
|
||||||
errors
|
}
|
||||||
|
|
||||||
|
/// Tries to finds a good span to blame for the fact that `fr1`
|
||||||
|
/// contains `fr2`.
|
||||||
|
fn blame_span(&self, fr1: RegionVid, fr2: RegionVid) -> Span {
|
||||||
|
// Find everything that influenced final value of `fr`.
|
||||||
|
let influenced_fr1 = self.dependencies(fr1);
|
||||||
|
|
||||||
|
// Try to find some outlives constraint `'X: fr2` where `'X`
|
||||||
|
// influenced `fr1`. Blame that.
|
||||||
|
//
|
||||||
|
// NB, this is a pretty bad choice most of the time. In
|
||||||
|
// particular, the connection between `'X` and `fr1` may not
|
||||||
|
// be obvious to the user -- not to mention the naive notion
|
||||||
|
// of dependencies, which doesn't account for the locations of
|
||||||
|
// contraints at all. But it will do for now.
|
||||||
|
for constraint in &self.constraints {
|
||||||
|
if constraint.sub == fr2 && influenced_fr1[constraint.sup] {
|
||||||
|
return constraint.span;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bug!(
|
||||||
|
"could not find any constraint to blame for {:?}: {:?}",
|
||||||
|
fr1,
|
||||||
|
fr2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds all regions whose values `'a` may depend on in some way.
|
||||||
|
/// Basically if there exists a constraint `'a: 'b @ P`, then `'b`
|
||||||
|
/// and `dependencies('b)` will be in the final set.
|
||||||
|
///
|
||||||
|
/// Used during error reporting, extremely naive and inefficient.
|
||||||
|
fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, bool> {
|
||||||
|
let mut result_set = IndexVec::from_elem(false, &self.definitions);
|
||||||
|
let mut changed = true;
|
||||||
|
result_set[r0] = true;
|
||||||
|
|
||||||
|
while changed {
|
||||||
|
changed = false;
|
||||||
|
for constraint in &self.constraints {
|
||||||
|
if result_set[constraint.sup] {
|
||||||
|
if !result_set[constraint.sub] {
|
||||||
|
result_set[constraint.sub] = true;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result_set
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,11 +494,7 @@ impl<'tcx> RegionDefinition<'tcx> {
|
||||||
// Create a new region definition. Note that, for free
|
// Create a new region definition. Note that, for free
|
||||||
// regions, these fields get updated later in
|
// regions, these fields get updated later in
|
||||||
// `init_free_regions`.
|
// `init_free_regions`.
|
||||||
Self {
|
Self { origin, name: None }
|
||||||
origin,
|
|
||||||
name: None,
|
|
||||||
constant: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,9 @@ fn main() {
|
||||||
|
|
||||||
// END RUST SOURCE
|
// END RUST SOURCE
|
||||||
// START rustc.use_x.nll.0.mir
|
// START rustc.use_x.nll.0.mir
|
||||||
// | '_#0r: {bb0[0], bb0[1], '_#0r, '_#1r, '_#2r, '_#3r}
|
// | '_#0r: {bb0[0], bb0[1], '_#0r}
|
||||||
// | '_#1r: {bb0[0], bb0[1], '_#1r}
|
// | '_#1r: {bb0[0], bb0[1], '_#1r}
|
||||||
// | '_#2r: {bb0[0], bb0[1], '_#1r, '_#2r}
|
// | '_#2r: {bb0[0], bb0[1], '_#2r}
|
||||||
// | '_#3r: {bb0[0], bb0[1], '_#3r}
|
// | '_#3r: {bb0[0], bb0[1], '_#3r}
|
||||||
// fn use_x(_1: &'_#1r mut i32, _2: &'_#2r u32, _3: &'_#1r u32, _4: &'_#3r u32) -> bool {
|
// fn use_x(_1: &'_#1r mut i32, _2: &'_#2r u32, _3: &'_#1r u32, _4: &'_#3r u32) -> bool {
|
||||||
// END rustc.use_x.nll.0.mir
|
// END rustc.use_x.nll.0.mir
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue