Auto merge of #46733 - nikomatsakis:nll-master-to-rust-master-5, r=arielb1

nll part 5

Next round of changes from the nll-master branch.

Extensions:

- we now propagate ty-region-outlives constraints out of closures and into their creator when necessary
- we fix a few ICEs that can occur by doing liveness analysis (and the resulting normalization) during type-checking
- we handle the implicit region bound that assumes that each type `T` outlives the fn body
- we handle normalization of inputs/outputs in fn signatures

Not included in this PR (will come next):

- handling `impl Trait`
- tracking causal information
- extended errors

r? @arielb1
This commit is contained in:
bors 2017-12-20 03:58:15 +00:00
commit 588f7db8ef
78 changed files with 4056 additions and 645 deletions

View file

@ -536,14 +536,29 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Literal<'gcx> {
impl_stable_hash_for!(struct mir::Location { block, statement_index });
impl_stable_hash_for!(struct mir::ClosureRegionRequirements {
impl_stable_hash_for!(struct mir::ClosureRegionRequirements<'tcx> {
num_external_vids,
outlives_requirements
});
impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement {
free_region,
impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
subject,
outlived_free_region,
blame_span
});
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::ClosureOutlivesSubject<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
mir::ClosureOutlivesSubject::Ty(ref ty) => {
ty.hash_stable(hcx, hasher);
}
mir::ClosureOutlivesSubject::Region(ref region) => {
region.hash_stable(hcx, hasher);
}
}
}
}

View file

@ -75,6 +75,9 @@ for ty::RegionKind {
ty::ReFree(ref free_region) => {
free_region.hash_stable(hcx, hasher);
}
ty::ReClosureBound(vid) => {
vid.hash_stable(hcx, hasher);
}
ty::ReLateBound(..) |
ty::ReVar(..) |
ty::ReSkolemized(..) => {

View file

@ -475,6 +475,14 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
ty::Bivariant | ty::Covariant | ty::Contravariant => (),
}
}
ty::ReClosureBound(..) => {
span_bug!(
self.span,
"encountered unexpected ReClosureBound: {:?}",
r,
);
}
}
// FIXME: This is non-ideal because we don't give a

View file

@ -240,6 +240,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ty::ReErased => {
(format!("lifetime {:?}", region), None)
}
// We shouldn't encounter an error message with ReClosureBound.
ty::ReClosureBound(..) => {
bug!(
"encountered unexpected ReClosureBound: {:?}",
region,
);
}
};
let message = format!("{}{}{}", prefix, description, suffix);
if let Some(span) = span {

View file

@ -113,6 +113,13 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
// replace all free regions with 'erased
self.tcx().types.re_erased
}
ty::ReClosureBound(..) => {
bug!(
"encountered unexpected ReClosureBound: {:?}",
r,
);
}
}
}

View file

@ -258,7 +258,12 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
let tcx = self.region_rels.tcx;
match (a, b) {
(&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => {
(&ty::ReClosureBound(..), _) |
(_, &ty::ReClosureBound(..)) |
(&ReLateBound(..), _) |
(_, &ReLateBound(..)) |
(&ReErased, _) |
(_, &ReErased) => {
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
}

View file

@ -1832,8 +1832,17 @@ pub struct GeneratorLayout<'tcx> {
/// instance of the closure is created, the corresponding free regions
/// can be extracted from its type and constrained to have the given
/// outlives relationship.
///
/// In some cases, we have to record outlives requirements between
/// types and regions as well. In that case, if those types include
/// any regions, those regions are recorded as `ReClosureBound`
/// instances assigned one of these same indices. Those regions will
/// be substituted away by the creator. We use `ReClosureBound` in
/// that case because the regions must be allocated in the global
/// TyCtxt, and hence we cannot use `ReVar` (which is what we use
/// internally within the rest of the NLL code).
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ClosureRegionRequirements {
pub struct ClosureRegionRequirements<'gcx> {
/// The number of external regions defined on the closure. In our
/// example above, it would be 3 -- one for `'static`, then `'1`
/// and `'2`. This is just used for a sanity check later on, to
@ -1843,15 +1852,15 @@ pub struct ClosureRegionRequirements {
/// Requirements between the various free regions defined in
/// indices.
pub outlives_requirements: Vec<ClosureOutlivesRequirement>,
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'gcx>>,
}
/// Indicates an outlives constraint between two free-regions declared
/// on the closure.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct ClosureOutlivesRequirement {
// This region ...
pub free_region: ty::RegionVid,
/// Indicates an outlives constraint between a type or between two
/// free-regions declared on the closure.
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ClosureOutlivesRequirement<'tcx> {
// This region or type ...
pub subject: ClosureOutlivesSubject<'tcx>,
// .. must outlive this one.
pub outlived_free_region: ty::RegionVid,
@ -1860,6 +1869,23 @@ pub struct ClosureOutlivesRequirement {
pub blame_span: Span,
}
/// The subject of a ClosureOutlivesRequirement -- that is, the thing
/// that must outlive some region.
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum ClosureOutlivesSubject<'tcx> {
/// Subject is a type, typically a type parameter, but could also
/// be a projection. Indicates a requirement like `T: 'a` being
/// passed to the caller, where the type here is `T`.
///
/// The type here is guaranteed not to contain any free regions at
/// present.
Ty(Ty<'tcx>),
/// Subject is a free region from the closure. Indicates a requirement
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
Region(ty::RegionVid),
}
/*
* TypeFoldable implementations for MIR types
*/

View file

@ -97,14 +97,19 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
fn has_closure_types(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_CLOSURE)
}
fn has_erasable_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND |
TypeFlags::HAS_RE_INFER |
TypeFlags::HAS_FREE_REGIONS)
/// "Free" regions in this context means that it has any region
/// that is not (a) erased or (b) late-bound.
fn has_free_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
}
/// True if there any any un-erased free regions.
fn has_erasable_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
}
fn is_normalized_for_trans(&self) -> bool {
!self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND |
TypeFlags::HAS_RE_INFER |
!self.has_type_flags(TypeFlags::HAS_RE_INFER |
TypeFlags::HAS_FREE_REGIONS |
TypeFlags::HAS_TY_INFER |
TypeFlags::HAS_PARAMS |

View file

@ -193,7 +193,7 @@ define_maps! { <'tcx>
/// Borrow checks the function body. If this is a closure, returns
/// additional requirements that the closure's creator must verify.
[] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements>,
[] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements<'tcx>>,
/// Gets a complete map from all types to their inherent impls.
/// Not meant to be used directly outside of coherence.

View file

@ -421,8 +421,18 @@ bitflags! {
const HAS_TY_INFER = 1 << 2;
const HAS_RE_INFER = 1 << 3;
const HAS_RE_SKOL = 1 << 4;
/// Does this have any `ReEarlyBound` regions? Used to
/// determine whether substitition is required, since those
/// represent regions that are bound in a `ty::Generics` and
/// hence may be substituted.
const HAS_RE_EARLY_BOUND = 1 << 5;
/// Does this have any region that "appears free" in the type?
/// Basically anything but `ReLateBound` and `ReErased`.
const HAS_FREE_REGIONS = 1 << 6;
/// Is an error type reachable?
const HAS_TY_ERR = 1 << 7;
const HAS_PROJECTION = 1 << 8;

View file

@ -1036,6 +1036,12 @@ pub enum RegionKind {
/// Erased region, used by trait selection, in MIR and during trans.
ReErased,
/// These are regions bound in the "defining type" for a
/// closure. They are used ONLY as part of the
/// `ClosureRegionRequirements` that are produced by MIR borrowck.
/// See `ClosureRegionRequirements` for more details.
ReClosureBound(RegionVid),
}
impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {}
@ -1184,18 +1190,32 @@ impl RegionKind {
match *self {
ty::ReVar(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_RE_INFER;
flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX;
}
ty::ReSkolemized(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_RE_INFER;
flags = flags | TypeFlags::HAS_RE_SKOL;
flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX;
}
ty::ReLateBound(..) => { }
ty::ReEarlyBound(..) => { flags = flags | TypeFlags::HAS_RE_EARLY_BOUND; }
ty::ReStatic | ty::ReErased => { }
_ => { flags = flags | TypeFlags::HAS_FREE_REGIONS; }
ty::ReEarlyBound(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_RE_EARLY_BOUND;
}
ty::ReEmpty |
ty::ReStatic |
ty::ReFree { .. } |
ty::ReScope { .. } => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
}
ty::ReErased => {
}
ty::ReClosureBound(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
}
}
match *self {

View file

@ -822,6 +822,8 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => {
self.def_id(def_id);
}
ty::ReClosureBound(..) |
ty::ReLateBound(..) |
ty::ReFree(..) |
ty::ReScope(..) |

View file

@ -733,6 +733,9 @@ define_print! {
ty::ReErased => Ok(()),
ty::ReStatic => write!(f, "'static"),
ty::ReEmpty => write!(f, "'<empty>"),
// The user should never encounter these in unsubstituted form.
ty::ReClosureBound(vid) => write!(f, "{:?}", vid),
}
}
debug {
@ -743,6 +746,11 @@ define_print! {
data.name)
}
ty::ReClosureBound(ref vid) => {
write!(f, "ReClosureBound({:?})",
vid)
}
ty::ReLateBound(binder_id, ref bound_region) => {
write!(f, "ReLateBound({:?}, {:?})",
binder_id,

View file

@ -367,6 +367,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
ty::ReStatic => self.item_ub,
ty::ReEmpty |
ty::ReClosureBound(..) |
ty::ReLateBound(..) |
ty::ReVar(..) |
ty::ReSkolemized(..) |

View file

@ -381,6 +381,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
},
(RegionKind::ReLateBound(_, _), _) |
(RegionKind::ReSkolemized(_, _), _) |
(RegionKind::ReClosureBound(_), _) |
(RegionKind::ReErased, _) => {
span_bug!(drop_span, "region does not make sense in this context");
},

View file

@ -22,16 +22,16 @@ use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
use rustc::mir::ClosureRegionRequirements;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_set::{IdxSetBuf};
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::Idx;
use syntax::ast;
use syntax_pos::Span;
use dataflow::{do_dataflow, DebugFormatted};
use dataflow::FlowAtLocation;
use dataflow::MoveDataParamEnv;
use dataflow::{DataflowAnalysis, DataflowResultsConsumer};
use dataflow::{FlowAtLocation, FlowsAtLocation};
use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use dataflow::{EverInitializedLvals, MovingOutStatements};
use dataflow::{Borrows, BorrowData, ReserveOrActivateIndex};
@ -65,7 +65,7 @@ pub fn provide(providers: &mut Providers) {
fn mir_borrowck<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> Option<ClosureRegionRequirements> {
) -> Option<ClosureRegionRequirements<'tcx>> {
let input_mir = tcx.mir_validated(def_id);
debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
@ -89,7 +89,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
input_mir: &Mir<'gcx>,
def_id: DefId,
) -> Option<ClosureRegionRequirements> {
) -> Option<ClosureRegionRequirements<'gcx>> {
let tcx = infcx.tcx;
let attributes = tcx.get_attrs(def_id);
let param_env = tcx.param_env(def_id);

View file

@ -12,21 +12,13 @@ use rustc::hir;
use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue};
use rustc::mir::visit::Visitor;
use rustc::mir::Place::Projection;
use rustc::mir::{Local, PlaceProjection, ProjectionElem};
use rustc::mir::{PlaceProjection, ProjectionElem};
use rustc::mir::visit::TyContext;
use rustc::infer::InferCtxt;
use rustc::traits::{self, ObligationCause};
use rustc::ty::{self, ClosureSubsts, Ty};
use rustc::ty::{self, ClosureSubsts};
use rustc::ty::subst::Substs;
use rustc::ty::fold::TypeFoldable;
use rustc::util::common::ErrorReported;
use rustc_data_structures::fx::FxHashSet;
use syntax::codemap::DUMMY_SP;
use borrow_check::{FlowAtLocation, FlowsAtLocation};
use dataflow::MaybeInitializedLvals;
use dataflow::move_paths::{HasMoveData, MoveData};
use super::LivenessResults;
use super::ToRegionVid;
use super::region_infer::RegionInferenceContext;
@ -34,19 +26,11 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
regioncx: &mut RegionInferenceContext<'tcx>,
mir: &Mir<'tcx>,
param_env: ty::ParamEnv<'tcx>,
liveness: &LivenessResults,
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) {
let mut cg = ConstraintGeneration {
infcx,
regioncx,
mir,
liveness,
param_env,
flow_inits,
move_data,
};
for (bb, data) in mir.basic_blocks().iter_enumerated() {
@ -59,16 +43,10 @@ struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> {
infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
regioncx: &'cg mut RegionInferenceContext<'tcx>,
mir: &'cg Mir<'tcx>,
liveness: &'cg LivenessResults,
param_env: ty::ParamEnv<'tcx>,
flow_inits: &'cg mut FlowAtLocation<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
move_data: &'cg MoveData<'tcx>,
}
impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
self.add_liveness_constraints(bb);
self.super_basic_block_data(bb, data);
}
@ -130,84 +108,6 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
}
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
/// Liveness constraints:
///
/// > If a variable V is live at point P, then all regions R in the type of V
/// > must include the point P.
fn add_liveness_constraints(&mut self, bb: BasicBlock) {
debug!("add_liveness_constraints(bb={:?})", bb);
self.liveness
.regular
.simulate_block(self.mir, bb, |location, live_locals| {
for live_local in live_locals.iter() {
let live_local_ty = self.mir.local_decls[live_local].ty;
self.add_regular_live_constraint(live_local_ty, location);
}
});
let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
self.liveness
.drop
.simulate_block(self.mir, bb, |location, live_locals| {
all_live_locals.push((location, live_locals.iter().collect()));
});
debug!(
"add_liveness_constraints: all_live_locals={:#?}",
all_live_locals
);
let terminator_index = self.mir.basic_blocks()[bb].statements.len();
self.flow_inits.reset_to_entry_of(bb);
while let Some((location, live_locals)) = all_live_locals.pop() {
for live_local in live_locals {
debug!(
"add_liveness_constraints: location={:?} live_local={:?}",
location,
live_local
);
self.flow_inits.each_state_bit(|mpi_init| {
debug!(
"add_liveness_constraints: location={:?} initialized={:?}",
location,
&self.flow_inits
.operator()
.move_data()
.move_paths[mpi_init]
);
});
let mpi = self.move_data.rev_lookup.find_local(live_local);
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
debug!(
"add_liveness_constraints: mpi={:?} has initialized child {:?}",
self.move_data.move_paths[mpi],
self.move_data.move_paths[initialized_child]
);
let live_local_ty = self.mir.local_decls[live_local].ty;
self.add_drop_live_constraint(live_local_ty, location);
}
}
if location.statement_index == terminator_index {
debug!(
"add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
location
);
self.flow_inits.reconstruct_terminator_effect(location);
} else {
debug!(
"add_liveness_constraints: reconstruct_statement_effect from {:#?}",
location
);
self.flow_inits.reconstruct_statement_effect(location);
}
self.flow_inits.apply_local_effect(location);
}
}
/// Some variable with type `live_ty` is "regular live" at
/// `location` -- i.e., it may be used later. This means that all
/// regions appearing in the type `live_ty` must be live at
@ -230,75 +130,6 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
});
}
/// Some variable with type `live_ty` is "drop live" at `location`
/// -- i.e., it may be dropped later. This means that *some* of
/// the regions in its type must be live at `location`. The
/// precise set will depend on the dropck constraints, and in
/// particular this takes `#[may_dangle]` into account.
fn add_drop_live_constraint(&mut self, dropped_ty: Ty<'tcx>, location: Location) {
debug!(
"add_drop_live_constraint(dropped_ty={:?}, location={:?})",
dropped_ty,
location
);
let tcx = self.infcx.tcx;
let mut types = vec![(dropped_ty, 0)];
let mut known = FxHashSet();
while let Some((ty, depth)) = types.pop() {
let span = DUMMY_SP; // FIXME
let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
Ok(result) => result,
Err(ErrorReported) => {
continue;
}
};
let ty::DtorckConstraint {
outlives,
dtorck_types,
} = result;
// All things in the `outlives` array may be touched by
// the destructor and must be live at this point.
for outlive in outlives {
self.add_regular_live_constraint(outlive, location);
}
// However, there may also be some types that
// `dtorck_constraint_for_ty` could not resolve (e.g.,
// associated types and parameters). We need to normalize
// associated types here and possibly recursively process.
for ty in dtorck_types {
let cause = ObligationCause::dummy();
// We know that our original `dropped_ty` is well-formed,
// so region obligations resulting from this normalization
// should always hold.
//
// Therefore we ignore them instead of trying to match
// them up with a location.
let fulfillcx = traits::FulfillmentContext::new_ignoring_regions();
match traits::fully_normalize_with_fulfillcx(
self.infcx, fulfillcx, cause, self.param_env, &ty
) {
Ok(ty) => match ty.sty {
ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
self.add_regular_live_constraint(ty, location);
}
_ => if known.insert(ty) {
types.push((ty, depth + 1));
},
},
Err(errors) => {
self.infcx.report_fulfillment_errors(&errors, None);
}
}
}
}
}
fn add_reborrow_constraint(
&mut self,
location: Location,

View file

@ -9,16 +9,16 @@
// except according to those terms.
use rustc::hir::def_id::DefId;
use rustc::mir::{ClosureRegionRequirements, Mir};
use rustc::mir::{ClosureRegionRequirements, ClosureOutlivesSubject, Mir};
use rustc::infer::InferCtxt;
use rustc::ty::{self, RegionKind, RegionVid};
use rustc::util::nodemap::FxHashMap;
use std::collections::BTreeSet;
use std::fmt::Debug;
use std::io;
use transform::MirSource;
use transform::type_check;
use util::liveness::{self, LivenessMode, LivenessResult, LocalSet};
use borrow_check::FlowAtLocation;
use util::liveness::{LivenessResults, LocalSet};
use dataflow::FlowAtLocation;
use dataflow::MaybeInitializedLvals;
use dataflow::move_paths::MoveData;
@ -27,14 +27,15 @@ use util::pretty::{self, ALIGN};
use self::mir_util::PassWhere;
mod constraint_generation;
pub(crate) mod region_infer;
mod renumber;
mod subtype_constraint_generation;
pub(crate) mod type_check;
mod universal_regions;
use self::region_infer::RegionInferenceContext;
use self::universal_regions::UniversalRegions;
pub(crate) mod region_infer;
use self::region_infer::RegionInferenceContext;
mod renumber;
/// Rewrites the regions in the MIR to use NLL variables, also
/// scraping out the set of universal regions (e.g., region parameters)
@ -52,7 +53,7 @@ pub(in borrow_check) fn replace_regions_in_mir<'cx, 'gcx, 'tcx>(
let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
// Replace all remaining regions with fresh inference variables.
renumber::renumber_mir(infcx, &universal_regions, mir);
renumber::renumber_mir(infcx, mir);
let source = MirSource::item(def_id);
mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, mir, |_, _| Ok(()));
@ -73,11 +74,24 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
move_data: &MoveData<'tcx>,
) -> (
RegionInferenceContext<'tcx>,
Option<ClosureRegionRequirements>,
Option<ClosureRegionRequirements<'gcx>>,
) {
// Run the MIR type-checker.
let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
let constraint_sets = &type_check::type_check(infcx, mir_node_id, param_env, mir);
let liveness = &LivenessResults::compute(mir);
let fr_fn_body = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
let constraint_sets = &type_check::type_check(
infcx,
mir_node_id,
param_env,
mir,
fr_fn_body,
universal_regions.input_tys,
universal_regions.output_ty,
&liveness,
flow_inits,
move_data,
);
// Create the region inference context, taking ownership of the region inference
// data that was contained in `infcx`.
@ -85,35 +99,9 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir);
subtype_constraint_generation::generate(&mut regioncx, mir, constraint_sets);
// Compute what is live where.
let liveness = &LivenessResults {
regular: liveness::liveness_of_locals(
&mir,
LivenessMode {
include_regular_use: true,
include_drops: false,
},
),
drop: liveness::liveness_of_locals(
&mir,
LivenessMode {
include_regular_use: false,
include_drops: true,
},
),
};
// Generate non-subtyping constraints.
constraint_generation::generate_constraints(
infcx,
&mut regioncx,
&mir,
param_env,
liveness,
flow_inits,
move_data,
);
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir);
// Solve the region constraints.
let closure_region_requirements = regioncx.solve(infcx, &mir, def_id);
@ -136,11 +124,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
(regioncx, closure_region_requirements)
}
struct LivenessResults {
regular: LivenessResult,
drop: LivenessResult,
}
fn dump_mir_results<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
liveness: &LivenessResults,
@ -283,9 +266,13 @@ fn for_each_region_constraint(
with_msg: &mut FnMut(&str) -> io::Result<()>,
) -> io::Result<()> {
for req in &closure_region_requirements.outlives_requirements {
let subject: &Debug = match &req.subject {
ClosureOutlivesSubject::Region(subject) => subject,
ClosureOutlivesSubject::Ty(ty) => ty,
};
with_msg(&format!(
"where {:?}: {:?}",
req.free_region,
subject,
req.outlived_free_region,
))?;
}

View file

@ -0,0 +1,234 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Module defining the `dfs` method on `RegionInferenceContext`, along with
//! its associated helper traits.
use borrow_check::nll::universal_regions::UniversalRegions;
use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::region_infer::values::{RegionElementIndex, RegionValueElements,
RegionValues};
use rustc::mir::{Location, Mir};
use rustc::ty::RegionVid;
use rustc_data_structures::fx::FxHashSet;
impl<'tcx> RegionInferenceContext<'tcx> {
/// Function used to satisfy or test a `R1: R2 @ P`
/// constraint. The core idea is that it performs a DFS starting
/// from `P`. The precise actions *during* that DFS depend on the
/// `op` supplied, so see (e.g.) `CopyFromSourceToTarget` for more
/// details.
///
/// Returns:
///
/// - `Ok(true)` if the walk was completed and something changed
/// along the way;
/// - `Ok(false)` if the walk was completed with no changes;
/// - `Err(early)` if the walk was existed early by `op`. `earlyelem` is the
/// value that `op` returned.
pub(super) fn dfs<C>(&self, mir: &Mir<'tcx>, mut op: C) -> Result<bool, C::Early>
where
C: DfsOp,
{
let mut changed = false;
let mut stack = vec![];
let mut visited = FxHashSet();
stack.push(op.start_point());
while let Some(p) = stack.pop() {
let point_index = self.elements.index(p);
if !op.source_region_contains(point_index) {
debug!(" not in from-region");
continue;
}
if !visited.insert(p) {
debug!(" already visited");
continue;
}
let new = op.add_to_target_region(point_index)?;
changed |= new;
let block_data = &mir[p.block];
let start_stack_len = stack.len();
if p.statement_index < block_data.statements.len() {
stack.push(Location {
statement_index: p.statement_index + 1,
..p
});
} else {
stack.extend(block_data.terminator().successors().iter().map(
|&basic_block| {
Location {
statement_index: 0,
block: basic_block,
}
},
));
}
if stack.len() == start_stack_len {
// If we reach the END point in the graph, then copy
// over any skolemized end points in the `from_region`
// and make sure they are included in the `to_region`.
changed |= op.add_universal_regions_outlived_by_source_to_target()?;
}
}
Ok(changed)
}
}
/// Customizes the operation of the `dfs` function. This function is
/// used during inference to satisfy a `R1: R2 @ P` constraint.
pub(super) trait DfsOp {
/// If this op stops the walk early, what type does it propagate?
type Early;
/// Returns the point from which to start the DFS.
fn start_point(&self) -> Location;
/// Returns true if the source region contains the given point.
fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool;
/// Adds the given point to the target region, returning true if
/// something has changed. Returns `Err` if we should abort the
/// walk early.
fn add_to_target_region(
&mut self,
point_index: RegionElementIndex,
) -> Result<bool, Self::Early>;
/// Adds all universal regions in the source region to the target region, returning
/// true if something has changed.
fn add_universal_regions_outlived_by_source_to_target(&mut self) -> Result<bool, Self::Early>;
}
/// Used during inference to enforce a `R1: R2 @ P` constraint. For
/// each point Q we reach along the DFS, we check if Q is in R2 (the
/// "source region"). If not, we stop the walk. Otherwise, we add Q to
/// R1 (the "target region") and continue to Q's successors. If we
/// reach the end of the graph, then we add any universal regions from
/// R2 into R1.
pub(super) struct CopyFromSourceToTarget<'v> {
pub source_region: RegionVid,
pub target_region: RegionVid,
pub inferred_values: &'v mut RegionValues,
pub constraint_point: Location,
}
impl<'v> DfsOp for CopyFromSourceToTarget<'v> {
/// We never stop the walk early.
type Early = !;
fn start_point(&self) -> Location {
self.constraint_point
}
fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool {
self.inferred_values
.contains(self.source_region, point_index)
}
fn add_to_target_region(&mut self, point_index: RegionElementIndex) -> Result<bool, !> {
Ok(self.inferred_values.add(self.target_region, point_index))
}
fn add_universal_regions_outlived_by_source_to_target(&mut self) -> Result<bool, !> {
Ok(
self.inferred_values
.add_universal_regions_outlived_by(self.source_region, self.target_region),
)
}
}
/// Used after inference to *test* a `R1: R2 @ P` constraint. For
/// each point Q we reach along the DFS, we check if Q in R2 is also
/// contained in R1. If not, we abort the walk early with an `Err`
/// condition. Similarly, if we reach the end of the graph and find
/// that R1 contains some universal region that R2 does not contain,
/// we abort the walk early.
pub(super) struct TestTargetOutlivesSource<'v, 'tcx: 'v> {
pub source_region: RegionVid,
pub target_region: RegionVid,
pub elements: &'v RegionValueElements,
pub universal_regions: &'v UniversalRegions<'tcx>,
pub inferred_values: &'v RegionValues,
pub constraint_point: Location,
}
impl<'v, 'tcx> DfsOp for TestTargetOutlivesSource<'v, 'tcx> {
/// The element that was not found within R2.
type Early = RegionElementIndex;
fn start_point(&self) -> Location {
self.constraint_point
}
fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool {
self.inferred_values
.contains(self.source_region, point_index)
}
fn add_to_target_region(
&mut self,
point_index: RegionElementIndex,
) -> Result<bool, RegionElementIndex> {
if !self.inferred_values
.contains(self.target_region, point_index)
{
return Err(point_index);
}
Ok(false)
}
fn add_universal_regions_outlived_by_source_to_target(
&mut self,
) -> Result<bool, RegionElementIndex> {
// For all `ur_in_source` in `source_region`.
for ur_in_source in self.inferred_values
.universal_regions_outlived_by(self.source_region)
{
// Check that `target_region` outlives `ur_in_source`.
// If `ur_in_source` is a member of `target_region`, OK.
//
// (This is implied by the loop below, actually, just an
// irresistible micro-opt. Mm. Premature optimization. So
// tasty.)
if self.inferred_values
.contains(self.target_region, ur_in_source)
{
continue;
}
// If there is some other element X such that `target_region: X` and
// `X: ur_in_source`, OK.
if self.inferred_values
.universal_regions_outlived_by(self.target_region)
.any(|ur_in_target| {
self.universal_regions.outlives(ur_in_target, ur_in_source)
}) {
continue;
}
// Otherwise, not known to be true.
return Err(self.elements.index(ur_in_source));
}
Ok(false)
}
}

View file

@ -12,18 +12,23 @@ use super::universal_regions::UniversalRegions;
use rustc::hir::def_id::DefId;
use rustc::infer::InferCtxt;
use rustc::infer::NLLRegionVariableOrigin;
use rustc::infer::RegionObligation;
use rustc::infer::RegionVariableOrigin;
use rustc::infer::SubregionOrigin;
use rustc::infer::region_constraints::VarOrigins;
use rustc::mir::{ClosureOutlivesRequirement, ClosureRegionRequirements, Location, Mir};
use rustc::ty::{self, RegionVid};
use rustc::infer::region_constraints::{GenericKind, VarOrigins};
use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
Location, Mir};
use rustc::traits::ObligationCause;
use rustc::ty::{self, RegionVid, Ty, TypeFoldable};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashSet;
use std::fmt;
use std::rc::Rc;
use syntax::ast;
use syntax_pos::Span;
mod annotation;
mod dfs;
use self::dfs::{CopyFromSourceToTarget, TestTargetOutlivesSource};
mod dump_mir;
mod graphviz;
mod values;
@ -52,6 +57,9 @@ pub struct RegionInferenceContext<'tcx> {
/// The constraints we have accumulated and used during solving.
constraints: Vec<Constraint>,
/// Type constraints that we check after solving.
type_tests: Vec<TypeTest<'tcx>>,
/// Information about the universally quantified regions in scope
/// on this function and their (known) relations to one another.
universal_regions: UniversalRegions<'tcx>,
@ -94,6 +102,92 @@ pub struct Constraint {
span: Span,
}
/// A "type test" corresponds to an outlives constraint between a type
/// and a lifetime, like `T: 'x` or `<T as Foo>::Bar: 'x`. They are
/// translated from the `Verify` region constraints in the ordinary
/// inference context.
///
/// These sorts of constraints are handled differently than ordinary
/// constraints, at least at present. During type checking, the
/// `InferCtxt::process_registered_region_obligations` method will
/// attempt to convert a type test like `T: 'x` into an ordinary
/// outlives constraint when possible (for example, `&'a T: 'b` will
/// be converted into `'a: 'b` and registered as a `Constraint`).
///
/// In some cases, however, there are outlives relationships that are
/// not converted into a region constraint, but rather into one of
/// these "type tests". The distinction is that a type test does not
/// influence the inference result, but instead just examines the
/// values that we ultimately inferred for each region variable and
/// checks that they meet certain extra criteria. If not, an error
/// can be issued.
///
/// One reason for this is that these type tests typically boil down
/// to a check like `'a: 'x` where `'a` is a universally quantified
/// region -- and therefore not one whose value is really meant to be
/// *inferred*, precisely (this is not always the case: one can have a
/// type test like `<Foo as Trait<'?0>>::Bar: 'x`, where `'?0` is an
/// inference variable). Another reason is that these type tests can
/// involve *disjunction* -- that is, they can be satisfied in more
/// than one way.
///
/// For more information about this translation, see
/// `InferCtxt::process_registered_region_obligations` and
/// `InferCtxt::type_must_outlive` in `rustc::infer::outlives`.
#[derive(Clone, Debug)]
pub struct TypeTest<'tcx> {
/// The type `T` that must outlive the region.
pub generic_kind: GenericKind<'tcx>,
/// The region `'x` that the type must outlive.
pub lower_bound: RegionVid,
/// The point where the outlives relation must hold.
pub point: Location,
/// Where did this constraint arise?
pub span: Span,
/// A test which, if met by the region `'x`, proves that this type
/// constraint is satisfied.
pub test: RegionTest,
}
/// A "test" that can be applied to some "subject region" `'x`. These are used to
/// describe type constraints. Tests do not presently affect the
/// region values that get inferred for each variable; they only
/// examine the results *after* inference. This means they can
/// conveniently include disjuction ("a or b must be true").
#[derive(Clone, Debug)]
pub enum RegionTest {
/// The subject region `'x` must by outlived by *some* region in
/// the given set of regions.
///
/// This test comes from e.g. a where clause like `T: 'a + 'b`,
/// which implies that we know that `T: 'a` and that `T:
/// 'b`. Therefore, if we are trying to prove that `T: 'x`, we can
/// do so by showing that `'a: 'x` *or* `'b: 'x`.
IsOutlivedByAnyRegionIn(Vec<RegionVid>),
/// The subject region `'x` must by outlived by *all* regions in
/// the given set of regions.
///
/// This test comes from e.g. a projection type like `T = <u32 as
/// Trait<'a, 'b>>::Foo`, which must outlive `'a` or `'b`, and
/// maybe both. Therefore we can prove that `T: 'x` if we know
/// that `'a: 'x` *and* `'b: 'x`.
IsOutlivedByAllRegionsIn(Vec<RegionVid>),
/// Any of the given tests are true.
///
/// This arises from projections, for which there are multiple
/// ways to prove an outlives relationship.
Any(Vec<RegionTest>),
/// All of the given tests are true.
All(Vec<RegionTest>),
}
impl<'tcx> RegionInferenceContext<'tcx> {
/// Creates a new region inference context with a total of
/// `num_region_variables` valid inference variables; the first N
@ -121,6 +215,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
liveness_constraints: RegionValues::new(elements, num_region_variables),
inferred_values: None,
constraints: Vec::new(),
type_tests: Vec::new(),
universal_regions,
};
@ -242,32 +337,414 @@ impl<'tcx> RegionInferenceContext<'tcx> {
});
}
/// Perform region inference.
pub(super) fn solve(
/// Add a "type test" that must be satisfied.
pub(super) fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
self.type_tests.push(type_test);
}
/// Perform region inference and report errors if we see any
/// unsatisfiable constraints. If this is a closure, returns the
/// region requirements to propagate to our creator, if any.
pub(super) fn solve<'gcx>(
&mut self,
infcx: &InferCtxt<'_, '_, 'tcx>,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
mir_def_id: DefId,
) -> Option<ClosureRegionRequirements> {
) -> Option<ClosureRegionRequirements<'gcx>> {
assert!(self.inferred_values.is_none(), "values already inferred");
let tcx = infcx.tcx;
// Find the minimal regions that can solve the constraints. This is infallible.
self.propagate_constraints(mir);
// Now, see whether any of the constraints were too strong. In
// particular, we want to check for a case where a universally
// quantified region exceeded its bounds. Consider:
//
// 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 `'a` outlives `'b`, so we want to report
// an error.
// If this is a closure, we can propagate unsatisfied
// `outlives_requirements` to our creator, so create a vector
// to store those. Otherwise, we'll pass in `None` to the
// functions below, which will trigger them to report errors
// eagerly.
let mut outlives_requirements = if infcx.tcx.is_closure(mir_def_id) {
Some(vec![])
} else {
None
};
self.check_type_tests(infcx, mir, outlives_requirements.as_mut());
self.check_universal_regions(infcx, outlives_requirements.as_mut());
let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
if outlives_requirements.is_empty() {
None
} else {
let num_external_vids = self.universal_regions.num_global_and_external_regions();
Some(ClosureRegionRequirements {
num_external_vids,
outlives_requirements,
})
}
}
/// Propagate the region constraints: this will grow the values
/// for each region variable until all the constraints are
/// satisfied. Note that some values may grow **too** large to be
/// feasible, but we check this later.
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
let mut changed = true;
debug!("propagate_constraints()");
debug!("propagate_constraints: constraints={:#?}", {
let mut constraints: Vec<_> = self.constraints.iter().collect();
constraints.sort();
constraints
});
// The initial values for each region are derived from the liveness
// constraints we have accumulated.
let mut inferred_values = self.liveness_constraints.clone();
while changed {
changed = false;
debug!("propagate_constraints: --------------------");
for constraint in &self.constraints {
debug!("propagate_constraints: constraint={:?}", constraint);
// Grow the value as needed to accommodate the
// outlives constraint.
let Ok(made_changes) = self.dfs(
mir,
CopyFromSourceToTarget {
source_region: constraint.sub,
target_region: constraint.sup,
inferred_values: &mut inferred_values,
constraint_point: constraint.point,
},
);
if made_changes {
debug!("propagate_constraints: sub={:?}", constraint.sub);
debug!("propagate_constraints: sup={:?}", constraint.sup);
changed = true;
}
}
debug!("\n");
}
self.inferred_values = Some(inferred_values);
}
/// Once regions have been propagated, this method is used to see
/// whether the "type tests" produced by typeck were satisfied;
/// type tests encode type-outlives relationships like `T:
/// 'a`. See `TypeTest` for more details.
fn check_type_tests<'gcx>(
&self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
) {
let tcx = infcx.tcx;
for type_test in &self.type_tests {
debug!("check_type_test: {:?}", type_test);
if self.eval_region_test(mir, type_test.point, type_test.lower_bound, &type_test.test) {
continue;
}
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) {
continue;
}
}
// Oh the humanity. Obviously we will do better than this error eventually.
tcx.sess.span_err(
type_test.span,
&format!(
"`{}` does not outlive `{:?}`",
type_test.generic_kind,
type_test.lower_bound,
),
);
}
}
fn try_promote_type_test<'gcx>(
&self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
type_test: &TypeTest<'tcx>,
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>,
) -> bool {
let tcx = infcx.tcx;
let TypeTest {
generic_kind,
lower_bound,
point: _,
span,
test: _,
} = type_test;
let generic_ty = generic_kind.to_ty(tcx);
let subject = match self.try_promote_type_test_subject(infcx, generic_ty) {
Some(s) => s,
None => return false,
};
// Find some bounding subject-region R+ that is a super-region
// of the existing subject-region R. This should be a non-local, universal
// region, which ensures it can be encoded in a `ClosureOutlivesRequirement`.
let lower_bound_plus = self.non_local_universal_upper_bound(*lower_bound);
assert!(self.universal_regions.is_universal_region(lower_bound_plus));
assert!(!self.universal_regions
.is_local_free_region(lower_bound_plus));
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject,
outlived_free_region: lower_bound_plus,
blame_span: *span,
});
true
}
/// When we promote a type test `T: 'r`, we have to convert the
/// type `T` into something we can store in a query result (so
/// something allocated for `'gcx`). This is problematic if `ty`
/// contains regions. During the course of NLL region checking, we
/// will have replaced all of those regions with fresh inference
/// variables. To create a test subject, we want to replace those
/// inference variables with some region from the closure
/// signature -- this is not always possible, so this is a
/// fallible process. Presuming we do find a suitable region, we
/// will represent it with a `ReClosureBound`, which is a
/// `RegionKind` variant that can be allocated in the gcx.
fn try_promote_type_test_subject<'gcx>(
&self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
ty: Ty<'tcx>,
) -> Option<ClosureOutlivesSubject<'gcx>> {
let tcx = infcx.tcx;
let gcx = tcx.global_tcx();
let inferred_values = self.inferred_values
.as_ref()
.expect("region values not yet inferred");
debug!("try_promote_type_test_subject(ty = {:?})", ty);
let ty = tcx.fold_regions(&ty, &mut false, |r, _depth| {
let region_vid = self.to_region_vid(r);
// The challenge if this. We have some region variable `r`
// whose value is a set of CFG points and universal
// regions. We want to find if that set is *equivalent* to
// any of the named regions found in the closure.
//
// To do so, we compute the
// `non_local_universal_upper_bound`. This will be a
// non-local, universal region that is greater than `r`.
// However, it might not be *contained* within `r`, so
// then we further check whether this bound is contained
// in `r`. If so, we can say that `r` is equivalent to the
// bound.
//
// Let's work through a few examples. For these, imagine
// that we have 3 non-local regions (I'll denote them as
// `'static`, `'a`, and `'b`, though of course in the code
// they would be represented with indices) where:
//
// - `'static: 'a`
// - `'static: 'b`
//
// First, let's assume that `r` is some existential
// variable with an inferred value `{'a, 'static}` (plus
// some CFG nodes). In this case, the non-local upper
// bound is `'static`, since that outlives `'a`. `'static`
// is also a member of `r` and hence we consider `r`
// equivalent to `'static` (and replace it with
// `'static`).
//
// Now let's consider the inferred value `{'a, 'b}`. This
// means `r` is effectively `'a | 'b`. I'm not sure if
// this can come about, actually, but assuming it did, we
// would get a non-local upper bound of `'static`. Since
// `'static` is not contained in `r`, we would fail to
// find an equivalent.
let upper_bound = self.non_local_universal_upper_bound(region_vid);
if inferred_values.contains(region_vid, upper_bound) {
tcx.mk_region(ty::ReClosureBound(upper_bound))
} else {
// In the case of a failure, use a `ReVar`
// result. This will cause the `lift` later on to
// fail.
r
}
});
debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
// `lift` will only fail if we failed to promote some region.
let ty = gcx.lift(&ty)?;
Some(ClosureOutlivesSubject::Ty(ty))
}
/// Given some universal or existential region `r`, finds a
/// non-local, universal region `r+` that outlives `r` at entry to (and
/// exit from) the closure. In the worst case, this will be
/// `'static`.
///
/// This is used for two purposes. First, if we are propagated
/// some requirement `T: r`, we can use this method to enlarge `r`
/// to something we can encode for our creator (which only knows
/// about non-local, universal regions). It is also used when
/// encoding `T` as part of `try_promote_type_test_subject` (see
/// that fn for details).
///
/// Since `r` is (potentially) an existential region, it has some
/// value which may include (a) any number of points in the CFG
/// and (b) any number of `end('x)` elements of universally
/// quantified regions. To convert this into a single universal
/// region we do as follows:
///
/// - Ignore the CFG points in `'r`. All universally quantified regions
/// include the CFG anyhow.
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
/// a result `'y`.
/// - Finally, we take the non-local upper bound of `'y`.
/// - This uses `UniversalRegions::non_local_upper_bound`, which
/// is similar to this method but only works on universal
/// regions).
fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
let inferred_values = self.inferred_values.as_ref().unwrap();
debug!(
"non_local_universal_upper_bound(r={:?}={})",
r,
inferred_values.region_value_str(r)
);
// Find the smallest universal region that contains all other
// universal regions within `region`.
let mut lub = self.universal_regions.fr_fn_body;
for ur in inferred_values.universal_regions_outlived_by(r) {
lub = self.universal_regions.postdom_upper_bound(lub, ur);
}
debug!("non_local_universal_upper_bound: lub={:?}", lub);
// Grow further to get smallest universal region known to
// creator.
let non_local_lub = self.universal_regions.non_local_upper_bound(lub);
debug!(
"non_local_universal_upper_bound: non_local_lub={:?}",
non_local_lub
);
non_local_lub
}
/// Test if `test` is true when applied to `lower_bound` at
/// `point`, and returns true or false.
fn eval_region_test(
&self,
mir: &Mir<'tcx>,
point: Location,
lower_bound: RegionVid,
test: &RegionTest,
) -> bool {
debug!(
"eval_region_test(point={:?}, lower_bound={:?}, test={:?})",
point,
lower_bound,
test
);
match test {
RegionTest::IsOutlivedByAllRegionsIn(regions) => regions
.iter()
.all(|&r| self.eval_outlives(mir, r, lower_bound, point)),
RegionTest::IsOutlivedByAnyRegionIn(regions) => regions
.iter()
.any(|&r| self.eval_outlives(mir, r, lower_bound, point)),
RegionTest::Any(tests) => tests
.iter()
.any(|test| self.eval_region_test(mir, point, lower_bound, test)),
RegionTest::All(tests) => tests
.iter()
.all(|test| self.eval_region_test(mir, point, lower_bound, test)),
}
}
// Evaluate whether `sup_region: sub_region @ point`.
fn eval_outlives(
&self,
mir: &Mir<'tcx>,
sup_region: RegionVid,
sub_region: RegionVid,
point: Location,
) -> bool {
debug!(
"eval_outlives({:?}: {:?} @ {:?})",
sup_region,
sub_region,
point
);
// Roughly speaking, do a DFS of all region elements reachable
// from `point` contained in `sub_region`. If any of those are
// *not* present in `sup_region`, the DFS will abort early and
// yield an `Err` result.
match self.dfs(
mir,
TestTargetOutlivesSource {
source_region: sub_region,
target_region: sup_region,
constraint_point: point,
elements: &self.elements,
universal_regions: &self.universal_regions,
inferred_values: self.inferred_values.as_ref().unwrap(),
},
) {
Ok(_) => {
debug!("eval_outlives: true");
true
}
Err(elem) => {
debug!(
"eval_outlives: false because `{:?}` is not present in `{:?}`",
self.elements.to_element(elem),
sup_region
);
false
}
}
}
/// Once regions have been propagated, this method is used to see
/// whether any of the constraints were too strong. In particular,
/// we want to check for a case where a universally quantified
/// region exceeded its bounds. Consider:
///
/// 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.
///
/// If `propagated_outlives_requirements` is `Some`, then we will
/// push unsatisfied obligations into there. Otherwise, we'll
/// report them as errors.
fn check_universal_regions<'gcx>(
&self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
) {
// The universal regions are always found in a prefix of the
// full list.
let universal_definitions = self.definitions
@ -277,32 +754,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Go through each of the universal regions `fr` and check that
// they did not grow too large, accumulating any requirements
// for our caller into the `outlives_requirements` vector.
let mut outlives_requirements = vec![];
for (fr, _) in universal_definitions {
self.check_universal_region(infcx, fr, &mut outlives_requirements);
self.check_universal_region(infcx, fr, &mut propagated_outlives_requirements);
}
// If this is not a closure, then there is no caller to which we can
// "pass the buck". So if there are any outlives-requirements that were
// not satisfied, we just have to report a hard error here.
if !tcx.is_closure(mir_def_id) {
for outlives_requirement in outlives_requirements {
self.report_error(
infcx,
outlives_requirement.free_region,
outlives_requirement.outlived_free_region,
outlives_requirement.blame_span,
);
}
return None;
}
let num_external_vids = self.universal_regions.num_global_and_external_regions();
Some(ClosureRegionRequirements {
num_external_vids,
outlives_requirements,
})
}
/// Check the final value for the free region `fr` to see if it
@ -313,11 +767,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
///
/// Things that are to be propagated are accumulated into the
/// `outlives_requirements` vector.
fn check_universal_region(
fn check_universal_region<'gcx>(
&self,
infcx: &InferCtxt<'_, '_, 'tcx>,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
longer_fr: RegionVid,
outlives_requirements: &mut Vec<ClosureOutlivesRequirement>,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
) {
let inferred_values = self.inferred_values.as_ref().unwrap();
@ -339,33 +793,39 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let blame_span = self.blame_span(longer_fr, shorter_fr);
// Shrink `fr` until we find a non-local region (if we do).
// We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) {
debug!("check_universal_region: fr_minus={:?}", fr_minus);
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
// Shrink `fr` until we find a non-local region (if we do).
// We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) {
debug!("check_universal_region: fr_minus={:?}", fr_minus);
// Grow `shorter_fr` until we find a non-local
// regon. (We always will.) We'll call that
// `shorter_fr+` -- it's ever so slightly larger than
// `fr`.
let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr);
debug!(
"check_universal_region: shorter_fr_plus={:?}",
shorter_fr_plus
);
// Grow `shorter_fr` until we find a non-local
// regon. (We always will.) We'll call that
// `shorter_fr+` -- it's ever so slightly larger than
// `fr`.
let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr);
debug!(
"check_universal_region: shorter_fr_plus={:?}",
shorter_fr_plus
);
// Push the constraint `fr-: shorter_fr+`
outlives_requirements.push(ClosureOutlivesRequirement {
free_region: fr_minus,
outlived_free_region: shorter_fr_plus,
blame_span: blame_span,
});
return;
// Push the constraint `fr-: shorter_fr+`
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject: ClosureOutlivesSubject::Region(fr_minus),
outlived_free_region: shorter_fr_plus,
blame_span: blame_span,
});
return;
}
}
// If we could not shrink `fr` to something smaller that
// the external users care about, then we can't pass the
// buck; just report an error.
// If we are not in a context where we can propagate
// errors, or we could not shrink `fr` to something
// smaller, then just report an error.
//
// Note: in this case, we use the unapproximated regions
// to report the error. This gives better error messages
// in some cases.
self.report_error(infcx, longer_fr, shorter_fr, blame_span);
}
}
@ -395,117 +855,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
);
}
/// Propagate the region constraints: this will grow the values
/// for each region variable until all the constraints are
/// satisfied. Note that some values may grow **too** large to be
/// feasible, but we check this later.
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
let mut changed = true;
debug!("propagate_constraints()");
debug!("propagate_constraints: constraints={:#?}", {
let mut constraints: Vec<_> = self.constraints.iter().collect();
constraints.sort();
constraints
});
// The initial values for each region are derived from the liveness
// constraints we have accumulated.
let mut inferred_values = self.liveness_constraints.clone();
while changed {
changed = false;
debug!("propagate_constraints: --------------------");
for constraint in &self.constraints {
debug!("propagate_constraints: constraint={:?}", constraint);
// Grow the value as needed to accommodate the
// outlives constraint.
if self.copy(
&mut inferred_values,
mir,
constraint.sub,
constraint.sup,
constraint.point,
) {
debug!("propagate_constraints: sub={:?}", constraint.sub);
debug!("propagate_constraints: sup={:?}", constraint.sup);
changed = true;
}
}
debug!("\n");
}
self.inferred_values = Some(inferred_values);
}
fn copy(
&self,
inferred_values: &mut RegionValues,
mir: &Mir<'tcx>,
from_region: RegionVid,
to_region: RegionVid,
constraint_point: Location,
) -> bool {
let mut changed = false;
let mut stack = vec![];
let mut visited = FxHashSet();
stack.push(constraint_point);
while let Some(p) = stack.pop() {
let point_index = self.elements.index(p);
if !inferred_values.contains(from_region, point_index) {
debug!(" not in from-region");
continue;
}
if !visited.insert(p) {
debug!(" already visited");
continue;
}
let new = inferred_values.add(to_region, point_index);
changed |= new;
let block_data = &mir[p.block];
let successor_points = if p.statement_index < block_data.statements.len() {
vec![
Location {
statement_index: p.statement_index + 1,
..p
},
]
} else {
block_data
.terminator()
.successors()
.iter()
.map(|&basic_block| {
Location {
statement_index: 0,
block: basic_block,
}
})
.collect::<Vec<_>>()
};
if successor_points.is_empty() {
// If we reach the END point in the graph, then copy
// over any skolemized end points in the `from_region`
// and make sure they are included in the `to_region`.
changed |=
inferred_values.add_universal_regions_outlived_by(from_region, to_region);
} else {
stack.extend(successor_points);
}
}
changed
}
/// Tries to finds a good span to blame for the fact that `fr1`
/// contains `fr2`.
fn blame_span(&self, fr1: RegionVid, fr2: RegionVid) -> Span {
@ -520,35 +869,50 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// 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;
}
}
let relevant_constraint = self.constraints
.iter()
.filter_map(|constraint| {
if constraint.sub != fr2 {
None
} else {
influenced_fr1[constraint.sup]
.map(|distance| (distance, constraint.span))
}
})
.min() // constraining fr1 with fewer hops *ought* to be more obvious
.map(|(_dist, span)| span);
bug!(
"could not find any constraint to blame for {:?}: {:?}",
fr1,
fr2
);
relevant_constraint.unwrap_or_else(|| {
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.
/// For each region, returns either `None` (does not influence
/// `'a`) or `Some(d)` which indicates that it influences `'a`
/// with distinct `d` (minimum number of edges that must be
/// traversed).
///
/// 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);
fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
let mut result_set = IndexVec::from_elem(None, &self.definitions);
let mut changed = true;
result_set[r0] = true;
result_set[r0] = Some(0); // distance 0 from `r0`
while changed {
changed = false;
for constraint in &self.constraints {
if result_set[constraint.sup] {
if !result_set[constraint.sub] {
result_set[constraint.sub] = true;
if let Some(n) = result_set[constraint.sup] {
let m = n + 1;
if result_set[constraint.sub]
.map(|distance| m < distance)
.unwrap_or(true)
{
result_set[constraint.sub] = Some(m);
changed = true;
}
}
@ -585,17 +949,27 @@ impl fmt::Debug for Constraint {
}
}
pub trait ClosureRegionRequirementsExt {
fn apply_requirements<'tcx>(
pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> {
fn apply_requirements(
&self,
infcx: &InferCtxt<'_, '_, 'tcx>,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
body_id: ast::NodeId,
location: Location,
closure_def_id: DefId,
closure_substs: ty::ClosureSubsts<'tcx>,
);
fn subst_closure_mapping<T>(
&self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
value: &T,
) -> T
where
T: TypeFoldable<'tcx>;
}
impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequirements<'gcx> {
/// Given an instance T of the closure type, this method
/// instantiates the "extra" requirements that we computed for the
/// closure into the inference context. This has the effect of
@ -608,9 +982,10 @@ impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
/// a vector. Then we can just index into that vector to extract
/// out the corresponding region from T and apply the
/// requirements.
fn apply_requirements<'tcx>(
fn apply_requirements(
&self,
infcx: &InferCtxt<'_, '_, 'tcx>,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
body_id: ast::NodeId,
location: Location,
closure_def_id: DefId,
closure_substs: ty::ClosureSubsts<'tcx>,
@ -632,22 +1007,71 @@ impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
// into a vector. These are the regions that we will be
// relating to one another.
let closure_mapping =
UniversalRegions::closure_mapping(infcx, user_closure_ty, self.num_external_vids);
&UniversalRegions::closure_mapping(infcx, user_closure_ty, self.num_external_vids);
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
// Create the predicates.
for outlives_requirement in &self.outlives_requirements {
let region = closure_mapping[outlives_requirement.free_region];
let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
debug!(
"apply_requirements: region={:?} outlived_region={:?} outlives_requirements={:?}",
region,
outlived_region,
outlives_requirement
);
// FIXME, this origin is not entirely suitable.
let origin = SubregionOrigin::CallRcvr(outlives_requirement.blame_span);
infcx.sub_regions(origin, outlived_region, region);
match outlives_requirement.subject {
ClosureOutlivesSubject::Region(region) => {
let region = closure_mapping[region];
debug!(
"apply_requirements: region={:?} \
outlived_region={:?} \
outlives_requirement={:?}",
region,
outlived_region,
outlives_requirement,
);
infcx.sub_regions(origin, outlived_region, region);
}
ClosureOutlivesSubject::Ty(ty) => {
let ty = self.subst_closure_mapping(infcx, closure_mapping, &ty);
debug!(
"apply_requirements: ty={:?} \
outlived_region={:?} \
outlives_requirement={:?}",
ty,
outlived_region,
outlives_requirement,
);
infcx.register_region_obligation(
body_id,
RegionObligation {
sup_type: ty,
sub_region: outlived_region,
cause: ObligationCause::misc(outlives_requirement.blame_span, body_id),
},
);
}
}
}
}
fn subst_closure_mapping<T>(
&self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
value: &T,
) -> T
where
T: TypeFoldable<'tcx>,
{
infcx.tcx.fold_regions(value, &mut false, |r, _depth| {
if let ty::ReClosureBound(vid) = r {
closure_mapping[*vid]
} else {
bug!(
"subst_closure_mapping: encountered non-closure bound free region {:?}",
r
)
}
})
}
}

View file

@ -215,8 +215,11 @@ impl RegionValues {
// FIXME. We could optimize this by improving
// `BitMatrix::merge` so it does not always merge an entire
// row.
debug!("add_universal_regions_outlived_by(from_region={:?}, to_region={:?})",
from_region, to_region);
debug!(
"add_universal_regions_outlived_by(from_region={:?}, to_region={:?})",
from_region,
to_region
);
let mut changed = false;
for elem in self.elements.all_universal_region_indices() {
if self.contains(from_region, elem) {
@ -269,24 +272,70 @@ impl RegionValues {
let mut result = String::new();
result.push_str("{");
for (index, element) in self.elements_contained_in(r).enumerate() {
if index > 0 {
result.push_str(", ");
}
// Set to Some(l1, l2) when we have observed all the locations
// from l1..=l2 (inclusive) but not yet printed them. This
// gets extended if we then see l3 where l3 is the successor
// to l2.
let mut open_location: Option<(Location, Location)> = None;
let mut sep = "";
let mut push_sep = |s: &mut String| {
s.push_str(sep);
sep = ", ";
};
for element in self.elements_contained_in(r) {
match element {
RegionElement::Location(l) => {
result.push_str(&format!("{:?}", l));
if let Some((location1, location2)) = open_location {
if location2.block == l.block
&& location2.statement_index == l.statement_index - 1
{
open_location = Some((location1, l));
continue;
}
push_sep(&mut result);
Self::push_location_range(&mut result, location1, location2);
}
open_location = Some((l, l));
}
RegionElement::UniversalRegion(fr) => {
if let Some((location1, location2)) = open_location {
push_sep(&mut result);
Self::push_location_range(&mut result, location1, location2);
open_location = None;
}
push_sep(&mut result);
result.push_str(&format!("{:?}", fr));
}
}
}
if let Some((location1, location2)) = open_location {
push_sep(&mut result);
Self::push_location_range(&mut result, location1, location2);
}
result.push_str("}");
result
}
fn push_location_range(str: &mut String, location1: Location, location2: Location) {
if location1 == location2 {
str.push_str(&format!("{:?}", location1));
} else {
assert_eq!(location1.block, location2.block);
str.push_str(&format!(
"{:?}[{}..={}]",
location1.block,
location1.statement_index,
location2.statement_index
));
}
}
}

View file

@ -8,50 +8,24 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc_data_structures::indexed_vec::Idx;
use rustc::ty::subst::Substs;
use rustc::ty::{self, ClosureSubsts, Ty, TypeFoldable};
use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind};
use rustc::mir::RETURN_PLACE;
use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use super::ToRegionVid;
use super::universal_regions::UniversalRegions;
/// Replaces all free regions appearing in the MIR with fresh
/// inference variables, returning the number of variables created.
pub fn renumber_mir<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
universal_regions: &UniversalRegions<'tcx>,
mir: &mut Mir<'tcx>,
) {
pub fn renumber_mir<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &mut Mir<'tcx>) {
debug!("renumber_mir()");
debug!("renumber_mir: mir.arg_count={:?}", mir.arg_count);
// Update the return type and types of the arguments based on the
// `universal_regions` computation.
debug!("renumber_mir: output_ty={:?}", universal_regions.output_ty);
mir.local_decls[RETURN_PLACE].ty = universal_regions.output_ty;
for (&input_ty, local) in universal_regions
.input_tys
.iter()
.zip((1..).map(Local::new))
{
debug!("renumber_mir: input_ty={:?} local={:?}", input_ty, local);
mir.local_decls[local].ty = input_ty;
}
let mut visitor = NLLVisitor {
infcx,
arg_count: mir.arg_count,
};
let mut visitor = NLLVisitor { infcx };
visitor.visit_mir(mir);
}
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
arg_count: usize,
}
impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
@ -71,45 +45,13 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
self.infcx.next_nll_region_var(origin)
})
}
/// Checks that all the regions appearing in `value` have already
/// been renumbered. `FreeRegions` code should have done this.
fn assert_free_regions_are_renumbered<T>(&self, value: &T)
where
T: TypeFoldable<'tcx>,
{
debug!("assert_free_regions_are_renumbered(value={:?})", value);
self.infcx.tcx.for_each_free_region(value, |region| {
region.to_region_vid(); // will panic if `region` is not renumbered
});
}
fn is_argument_or_return_slot(&self, local: Local) -> bool {
// The first argument is return slot, next N are arguments.
local.index() <= self.arg_count
}
}
impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
let is_arg = match ty_context {
TyContext::LocalDecl { local, .. } => self.is_argument_or_return_slot(local),
TyContext::ReturnTy(..) => true,
TyContext::Location(..) => false,
};
debug!(
"visit_ty(ty={:?}, is_arg={:?}, ty_context={:?})",
ty,
is_arg,
ty_context
);
debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context);
if is_arg {
self.assert_free_regions_are_renumbered(ty);
} else {
*ty = self.renumber_regions(ty_context, ty);
}
*ty = self.renumber_regions(ty_context, ty);
debug!("visit_ty: ty={:?}", ty);
}

View file

@ -11,11 +11,14 @@
use rustc::mir::Mir;
use rustc::infer::region_constraints::Constraint;
use rustc::infer::region_constraints::RegionConstraintData;
use rustc::infer::region_constraints::{Verify, VerifyBound};
use rustc::ty;
use transform::type_check::MirTypeckRegionConstraints;
use transform::type_check::OutlivesSet;
use syntax::codemap::Span;
use super::region_infer::RegionInferenceContext;
use super::region_infer::{TypeTest, RegionInferenceContext, RegionTest};
use super::type_check::Locations;
use super::type_check::MirTypeckRegionConstraints;
use super::type_check::OutlivesSet;
/// When the MIR type-checker executes, it validates all the types in
/// the MIR, and in the process generates a set of constraints that
@ -27,10 +30,7 @@ pub(super) fn generate<'tcx>(
mir: &Mir<'tcx>,
constraints: &MirTypeckRegionConstraints<'tcx>,
) {
SubtypeConstraintGenerator {
regioncx,
mir,
}.generate(constraints);
SubtypeConstraintGenerator { regioncx, mir }.generate(constraints);
}
struct SubtypeConstraintGenerator<'cx, 'tcx: 'cx> {
@ -65,6 +65,8 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
givens,
} = data;
let span = self.mir.source_info(locations.from_location).span;
for constraint in constraints.keys() {
debug!("generate: constraint: {:?}", constraint);
let (a_vid, b_vid) = match constraint {
@ -81,12 +83,15 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
// reverse direction, because `regioncx` talks about
// "outlives" (`>=`) whereas the region constraints
// talk about `<=`.
let span = self.mir.source_info(locations.from_location).span;
self.regioncx
.add_outlives(span, b_vid, a_vid, locations.at_location);
}
assert!(verifys.is_empty(), "verifys not yet implemented");
for verify in verifys {
let type_test = self.verify_to_type_test(verify, span, locations);
self.regioncx.add_type_test(type_test);
}
assert!(
givens.is_empty(),
"MIR type-checker does not use givens (thank goodness)"
@ -94,6 +99,55 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
}
}
fn verify_to_type_test(
&self,
verify: &Verify<'tcx>,
span: Span,
locations: &Locations,
) -> TypeTest<'tcx> {
let generic_kind = verify.kind;
let lower_bound = self.to_region_vid(verify.region);
let point = locations.at_location;
let test = self.verify_bound_to_region_test(&verify.bound);
TypeTest {
generic_kind,
lower_bound,
point,
span,
test,
}
}
fn verify_bound_to_region_test(&self, verify_bound: &VerifyBound<'tcx>) -> RegionTest {
match verify_bound {
VerifyBound::AnyRegion(regions) => RegionTest::IsOutlivedByAnyRegionIn(
regions.iter().map(|r| self.to_region_vid(r)).collect(),
),
VerifyBound::AllRegions(regions) => RegionTest::IsOutlivedByAllRegionsIn(
regions.iter().map(|r| self.to_region_vid(r)).collect(),
),
VerifyBound::AnyBound(bounds) => RegionTest::Any(
bounds
.iter()
.map(|b| self.verify_bound_to_region_test(b))
.collect(),
),
VerifyBound::AllBounds(bounds) => RegionTest::All(
bounds
.iter()
.map(|b| self.verify_bound_to_region_test(b))
.collect(),
),
}
}
fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid {
// Every region that we see in the constraints came from the
// MIR or from the parameter environment. If the former, it

View file

@ -0,0 +1,220 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use dataflow::{FlowAtLocation, FlowsAtLocation};
use dataflow::MaybeInitializedLvals;
use dataflow::move_paths::{HasMoveData, MoveData};
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::mir::Local;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::util::common::ErrorReported;
use rustc_data_structures::fx::FxHashSet;
use syntax::codemap::DUMMY_SP;
use util::liveness::LivenessResults;
use super::TypeChecker;
/// Combines liveness analysis with initialization analysis to
/// determine which variables are live at which points, both due to
/// ordinary uses and drops. Returns a set of (ty, location) pairs
/// that indicate which types must be live at which point in the CFG.
/// This vector is consumed by `constraint_generation`.
///
/// NB. This computation requires normalization; therefore, it must be
/// performed before
pub(super) fn generate<'gcx, 'tcx>(
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
liveness: &LivenessResults,
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) {
let tcx = cx.tcx();
let mut generator = TypeLivenessGenerator {
cx,
tcx,
mir,
liveness,
flow_inits,
move_data,
};
for bb in mir.basic_blocks().indices() {
generator.add_liveness_constraints(bb);
}
}
struct TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx>
where
'typeck: 'gen,
'flow: 'gen,
'tcx: 'typeck + 'flow,
'gcx: 'tcx,
{
cx: &'gen mut TypeChecker<'typeck, 'gcx, 'tcx>,
tcx: TyCtxt<'typeck, 'gcx, 'tcx>,
mir: &'gen Mir<'tcx>,
liveness: &'gen LivenessResults,
flow_inits: &'gen mut FlowAtLocation<MaybeInitializedLvals<'flow, 'gcx, 'tcx>>,
move_data: &'gen MoveData<'tcx>,
}
impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> {
/// Liveness constraints:
///
/// > If a variable V is live at point P, then all regions R in the type of V
/// > must include the point P.
fn add_liveness_constraints(&mut self, bb: BasicBlock) {
debug!("add_liveness_constraints(bb={:?})", bb);
self.liveness
.regular
.simulate_block(self.mir, bb, |location, live_locals| {
for live_local in live_locals.iter() {
let live_local_ty = self.mir.local_decls[live_local].ty;
self.push_type_live_constraint(live_local_ty, location);
}
});
let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
self.liveness
.drop
.simulate_block(self.mir, bb, |location, live_locals| {
all_live_locals.push((location, live_locals.iter().collect()));
});
debug!(
"add_liveness_constraints: all_live_locals={:#?}",
all_live_locals
);
let terminator_index = self.mir.basic_blocks()[bb].statements.len();
self.flow_inits.reset_to_entry_of(bb);
while let Some((location, live_locals)) = all_live_locals.pop() {
for live_local in live_locals {
debug!(
"add_liveness_constraints: location={:?} live_local={:?}",
location,
live_local
);
self.flow_inits.each_state_bit(|mpi_init| {
debug!(
"add_liveness_constraints: location={:?} initialized={:?}",
location,
&self.flow_inits.operator().move_data().move_paths[mpi_init]
);
});
let mpi = self.move_data.rev_lookup.find_local(live_local);
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
debug!(
"add_liveness_constraints: mpi={:?} has initialized child {:?}",
self.move_data.move_paths[mpi],
self.move_data.move_paths[initialized_child]
);
let live_local_ty = self.mir.local_decls[live_local].ty;
self.add_drop_live_constraint(live_local_ty, location);
}
}
if location.statement_index == terminator_index {
debug!(
"add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
location
);
self.flow_inits.reconstruct_terminator_effect(location);
} else {
debug!(
"add_liveness_constraints: reconstruct_statement_effect from {:#?}",
location
);
self.flow_inits.reconstruct_statement_effect(location);
}
self.flow_inits.apply_local_effect(location);
}
}
/// Some variable with type `live_ty` is "regular live" at
/// `location` -- i.e., it may be used later. This means that all
/// regions appearing in the type `live_ty` must be live at
/// `location`.
fn push_type_live_constraint<T>(&mut self, value: T, location: Location)
where
T: TypeFoldable<'tcx>,
{
debug!(
"push_type_live_constraint(live_ty={:?}, location={:?})",
value,
location
);
self.tcx.for_each_free_region(&value, |live_region| {
self.cx
.constraints
.liveness_set
.push((live_region, location));
});
}
/// Some variable with type `live_ty` is "drop live" at `location`
/// -- i.e., it may be dropped later. This means that *some* of
/// the regions in its type must be live at `location`. The
/// precise set will depend on the dropck constraints, and in
/// particular this takes `#[may_dangle]` into account.
fn add_drop_live_constraint(&mut self, dropped_ty: Ty<'tcx>, location: Location) {
debug!(
"add_drop_live_constraint(dropped_ty={:?}, location={:?})",
dropped_ty,
location
);
let tcx = self.cx.infcx.tcx;
let mut types = vec![(dropped_ty, 0)];
let mut known = FxHashSet();
while let Some((ty, depth)) = types.pop() {
let span = DUMMY_SP; // FIXME
let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
Ok(result) => result,
Err(ErrorReported) => {
continue;
}
};
let ty::DtorckConstraint {
outlives,
dtorck_types,
} = result;
// All things in the `outlives` array may be touched by
// the destructor and must be live at this point.
for outlive in outlives {
self.push_type_live_constraint(outlive, location);
}
// However, there may also be some types that
// `dtorck_constraint_for_ty` could not resolve (e.g.,
// associated types and parameters). We need to normalize
// associated types here and possibly recursively process.
for ty in dtorck_types {
let ty = self.cx.normalize(&ty, location);
match ty.sty {
ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
self.push_type_live_constraint(ty, location);
}
_ => if known.insert(ty) {
types.push((ty, depth + 1));
},
}
}
}
}
}

View file

@ -12,6 +12,9 @@
#![allow(unreachable_code)]
use borrow_check::nll::region_infer::ClosureRegionRequirementsExt;
use dataflow::FlowAtLocation;
use dataflow::MaybeInitializedLvals;
use dataflow::move_paths::MoveData;
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
use rustc::infer::region_constraints::RegionConstraintData;
use rustc::traits::{self, FulfillmentContext};
@ -26,24 +29,80 @@ use std::fmt;
use syntax::ast;
use syntax_pos::{Span, DUMMY_SP};
use transform::{MirPass, MirSource};
use util::liveness::LivenessResults;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::Idx;
mod liveness;
/// Type checks the given `mir` in the context of the inference
/// context `infcx`. Returns any region constraints that have yet to
/// be proven.
/// be proven. This result is includes liveness constraints that
/// ensure that regions appearing in the types of all local variables
/// are live at all points where that local variable may later be
/// used.
///
/// This phase of type-check ought to be infallible -- this is because
/// the original, HIR-based type-check succeeded. So if any errors
/// occur here, we will get a `bug!` reported.
pub fn type_check<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
///
/// # Parameters
///
/// - `infcx` -- inference context to use
/// - `body_id` -- body-id of the MIR being checked
/// - `param_env` -- parameter environment to use for trait solving
/// - `mir` -- MIR to type-check
/// - `implicit_region_bound` -- a region which all generic parameters are assumed
/// to outlive; should represent the fn body
/// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments;
/// the types of the input parameters found in the MIR itself will be equated with these
/// - `output_ty` -- fully liberaetd, but **not** normalized, expected return type;
/// the type for the RETURN_PLACE will be equated with this
/// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
/// constraints for the regions in the types of variables
/// - `flow_inits` -- results of a maybe-init dataflow analysis
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
pub(crate) fn type_check<'gcx, 'tcx>(
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
body_id: ast::NodeId,
param_env: ty::ParamEnv<'gcx>,
mir: &Mir<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
input_tys: &[Ty<'tcx>],
output_ty: Ty<'tcx>,
liveness: &LivenessResults,
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) -> MirTypeckRegionConstraints<'tcx> {
let mut checker = TypeChecker::new(infcx, body_id, param_env);
type_check_internal(
infcx,
body_id,
param_env,
mir,
Some(implicit_region_bound),
&mut |cx| {
liveness::generate(cx, mir, liveness, flow_inits, move_data);
// Equate the input and output tys given by the user with
// the ones found in the MIR.
cx.equate_input_or_output(output_ty, mir.local_decls[RETURN_PLACE].ty);
for (&input_ty, local) in input_tys.iter().zip((1..).map(Local::new)) {
cx.equate_input_or_output(input_ty, mir.local_decls[local].ty);
}
},
)
}
fn type_check_internal<'gcx, 'tcx>(
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
body_id: ast::NodeId,
param_env: ty::ParamEnv<'gcx>,
mir: &Mir<'tcx>,
implicit_region_bound: Option<ty::Region<'tcx>>,
extra: &mut FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>),
) -> MirTypeckRegionConstraints<'tcx> {
let mut checker = TypeChecker::new(infcx, body_id, param_env, implicit_region_bound);
let errors_reported = {
let mut verifier = TypeVerifier::new(&mut checker, mir);
verifier.visit_mir(mir);
@ -55,9 +114,12 @@ pub fn type_check<'a, 'gcx, 'tcx>(
checker.typeck_mir(mir);
}
extra(&mut checker);
checker.constraints
}
fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
// We sometimes see MIR failures (notably predicate failures) due to
// the fact that we check rvalue sized predicates here. So use `delay_span_bug`
@ -503,11 +565,12 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
/// constraints needed for it to be valid and well-typed. Along the
/// way, it accrues region constraints -- these can later be used by
/// NLL region checking.
pub struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'gcx>,
last_span: Span,
body_id: ast::NodeId,
implicit_region_bound: Option<ty::Region<'tcx>>,
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
constraints: MirTypeckRegionConstraints<'tcx>,
}
@ -561,12 +624,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
body_id: ast::NodeId,
param_env: ty::ParamEnv<'gcx>,
implicit_region_bound: Option<ty::Region<'tcx>>,
) -> Self {
TypeChecker {
infcx,
last_span: DUMMY_SP,
body_id,
param_env,
implicit_region_bound,
reported_errors: FxHashSet(),
constraints: MirTypeckRegionConstraints::default(),
}
@ -591,8 +656,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
span_mirbug!(self, "", "errors selecting obligation: {:?}", e);
}
self.infcx
.process_registered_region_obligations(&[], None, self.param_env, self.body_id);
self.infcx.process_registered_region_obligations(
&[],
self.implicit_region_bound,
self.param_env,
self.body_id,
);
let data = self.infcx.take_and_reset_region_constraints();
if !data.is_empty() {
@ -625,6 +694,25 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
})
}
fn equate_input_or_output(&mut self, unnormalized_a: Ty<'tcx>, b: Ty<'tcx>) {
let start_position = Location {
block: START_BLOCK,
statement_index: 0,
};
let a = self.normalize(&unnormalized_a, start_position);
if let Err(terr) = self.eq_types(a, b, start_position.at_self()) {
span_mirbug!(
self,
start_position,
"bad input or output {:?} normalized to {:?} should equal {:?} but got error {:?}",
unnormalized_a,
a,
b,
terr
);
}
}
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
self.infcx.tcx
}
@ -1368,6 +1456,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
if let Some(closure_region_requirements) = tcx.mir_borrowck(*def_id) {
closure_region_requirements.apply_requirements(
self.infcx,
self.body_id,
location,
*def_id,
*substs,
@ -1474,7 +1563,7 @@ impl MirPass for TypeckMir {
}
let param_env = tcx.param_env(def_id);
tcx.infer_ctxt().enter(|infcx| {
let _region_constraint_sets = type_check(&infcx, id, param_env, mir);
let _ = type_check_internal(&infcx, id, param_env, mir, None, &mut |_| ());
// For verification purposes, we just ignore the resulting
// region constraint sets. Not our problem. =)

View file

@ -45,6 +45,11 @@ pub struct UniversalRegions<'tcx> {
/// The vid assigned to `'static`
pub fr_static: RegionVid,
/// A special region vid created to represent the current MIR fn
/// body. It will outlive the entire CFG but it will not outlive
/// any other universal regions.
pub fr_fn_body: RegionVid,
/// We create region variables such that they are ordered by their
/// `RegionClassification`. The first block are globals, then
/// externals, then locals. So things from:
@ -64,12 +69,16 @@ pub struct UniversalRegions<'tcx> {
/// closure type, but for a top-level function it's the `TyFnDef`.
pub defining_ty: Ty<'tcx>,
/// The return type of this function, with all regions replaced
/// by their universal `RegionVid` equivalents.
/// The return type of this function, with all regions replaced by
/// their universal `RegionVid` equivalents. This type is **NOT
/// NORMALIZED** (i.e., it contains unnormalized associated type
/// projections).
pub output_ty: Ty<'tcx>,
/// The fully liberated input types of this function, with all
/// regions replaced by their universal `RegionVid` equivalents.
/// This type is **NOT NORMALIZED** (i.e., it contains
/// unnormalized associated type projections).
pub input_tys: &'tcx [Ty<'tcx>],
/// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to
@ -242,17 +251,7 @@ impl<'tcx> UniversalRegions<'tcx> {
(FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::new)
}
/// True if `r` is classied as a global region.
pub fn is_global_free_region(&self, r: RegionVid) -> bool {
self.region_classification(r) == Some(RegionClassification::Global)
}
/// True if `r` is classied as an external region.
pub fn is_extern_free_region(&self, r: RegionVid) -> bool {
self.region_classification(r) == Some(RegionClassification::External)
}
/// True if `r` is classied as an local region.
/// True if `r` is classified as an local region.
pub fn is_local_free_region(&self, r: RegionVid) -> bool {
self.region_classification(r) == Some(RegionClassification::Local)
}
@ -262,6 +261,20 @@ impl<'tcx> UniversalRegions<'tcx> {
self.num_universals
}
/// Given two universal regions, returns the postdominating
/// upper-bound (effectively the least upper bound).
///
/// (See `TransitiveRelation::postdom_upper_bound` for details on
/// the postdominating upper bound in general.)
pub fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
assert!(self.is_universal_region(fr1));
assert!(self.is_universal_region(fr2));
*self.relations
.inverse_outlives
.postdom_upper_bound(&fr1, &fr2)
.unwrap_or(&self.fr_static)
}
/// Finds an "upper bound" for `fr` that is not local. In other
/// words, returns the smallest (*) known region `fr1` that (a)
/// outlives `fr` and (b) is not local. This cannot fail, because
@ -305,6 +318,10 @@ impl<'tcx> UniversalRegions<'tcx> {
relation: &TransitiveRelation<RegionVid>,
fr0: RegionVid,
) -> Option<RegionVid> {
// This method assumes that `fr0` is one of the universally
// quantified region variables.
assert!(self.is_universal_region(fr0));
let mut external_parents = vec![];
let mut queue = vec![&fr0];
@ -408,6 +425,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
let first_local_index = self.infcx.num_region_vars();
let inputs_and_output = self.infcx
.replace_bound_regions_with_nll_infer_vars(FR, &bound_inputs_and_output);
let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid();
let num_universals = self.infcx.num_region_vars();
// Insert the facts we know from the predicates. Why? Why not.
@ -419,12 +437,19 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
self.add_implied_bounds(&indices, ty);
}
// Finally, outlives is reflexive, and static outlives every
// other free region.
// Finally:
// - outlives is reflexive, so `'r: 'r` for every region `'r`
// - `'static: 'r` for every region `'r`
// - `'r: 'fn_body` for every (other) universally quantified
// region `'r`, all of which are provided by our caller
for fr in (FIRST_GLOBAL_INDEX..num_universals).map(RegionVid::new) {
debug!("build: relating free region {:?} to itself and to 'static", fr);
debug!(
"build: relating free region {:?} to itself and to 'static",
fr
);
self.relations.relate_universal_regions(fr, fr);
self.relations.relate_universal_regions(fr_static, fr);
self.relations.relate_universal_regions(fr, fr_fn_body);
}
let (output_ty, input_tys) = inputs_and_output.split_last().unwrap();
@ -432,19 +457,26 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
// we should not have created any more variables
assert_eq!(self.infcx.num_region_vars(), num_universals);
debug!("build: global regions = {}..{}",
FIRST_GLOBAL_INDEX,
first_extern_index);
debug!("build: extern regions = {}..{}",
first_extern_index,
first_local_index);
debug!("build: local regions = {}..{}",
first_local_index,
num_universals);
debug!(
"build: global regions = {}..{}",
FIRST_GLOBAL_INDEX,
first_extern_index
);
debug!(
"build: extern regions = {}..{}",
first_extern_index,
first_local_index
);
debug!(
"build: local regions = {}..{}",
first_local_index,
num_universals
);
UniversalRegions {
indices,
fr_static,
fr_fn_body,
first_extern_index,
first_local_index,
num_universals,

View file

@ -25,26 +25,43 @@ use std::iter;
/// There's probably a way to auto-impl this, but I think
/// it is cleaner to have manual visitor impls.
pub trait FlowsAtLocation {
// reset the state bitvector to represent the entry to block `bb`.
/// Reset the state bitvector to represent the entry to block `bb`.
fn reset_to_entry_of(&mut self, bb: BasicBlock);
// build gen + kill sets for statement at `loc`.
/// Build gen + kill sets for statement at `loc`.
///
/// Note that invoking this method alone does not change the
/// `curr_state` -- you must invoke `apply_local_effect`
/// afterwards.
fn reconstruct_statement_effect(&mut self, loc: Location);
// build gen + kill sets for terminator for `loc`.
/// Build gen + kill sets for terminator for `loc`.
///
/// Note that invoking this method alone does not change the
/// `curr_state` -- you must invoke `apply_local_effect`
/// afterwards.
fn reconstruct_terminator_effect(&mut self, loc: Location);
// apply current gen + kill sets to `flow_state`.
//
// (`bb` and `stmt_idx` parameters can be ignored if desired by
// client. For the terminator, the `stmt_idx` will be the number
// of statements in the block.)
/// Apply current gen + kill sets to `flow_state`.
///
/// (`loc` parameters can be ignored if desired by
/// client. For the terminator, the `stmt_idx` will be the number
/// of statements in the block.)
fn apply_local_effect(&mut self, loc: Location);
}
/// Represents the state of dataflow at a particular
/// CFG location, both before and after it is
/// executed.
///
/// Data flow results are typically computed only as basic block
/// boundaries. A `FlowInProgress` allows you to reconstruct the
/// effects at any point in the control-flow graph by starting with
/// the state at the start of the basic block (`reset_to_entry_of`)
/// and then replaying the effects of statements and terminators
/// (e.g. via `reconstruct_statement_effect` and
/// `reconstruct_terminator_effect`; don't forget to call
/// `apply_local_effect`).
pub struct FlowAtLocation<BD>
where
BD: BitDenotation,
@ -59,6 +76,7 @@ impl<BD> FlowAtLocation<BD>
where
BD: BitDenotation,
{
/// Iterate over each bit set in the current state.
pub fn each_state_bit<F>(&self, f: F)
where
F: FnMut(BD::Idx),
@ -67,6 +85,9 @@ where
.each_bit(self.base_results.operator().bits_per_block(), f)
}
/// Iterate over each `gen` bit in the current effect (invoke
/// `reconstruct_statement_effect` or
/// `reconstruct_terminator_effect` first).
pub fn each_gen_bit<F>(&self, f: F)
where
F: FnMut(BD::Idx),
@ -88,6 +109,7 @@ where
}
}
/// Access the underlying operator.
pub fn operator(&self) -> &BD {
self.base_results.operator()
}
@ -96,11 +118,15 @@ where
self.curr_state.contains(x)
}
/// Returns an iterator over the elements present in the current state.
pub fn elems_incoming(&self) -> iter::Peekable<indexed_set::Elems<BD::Idx>> {
let univ = self.base_results.sets().bits_per_block();
self.curr_state.elems(univ).peekable()
}
/// Creates a clone of the current state and applies the local
/// effects to the clone (leaving the state of self intact).
/// Invokes `f` with an iterator over the resulting state.
pub fn with_elems_outgoing<F>(&self, f: F)
where
F: FnOnce(indexed_set::Elems<BD::Idx>),

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use borrow_check::nll::type_check;
use build;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::mir::{Mir, Promoted};
@ -30,7 +31,6 @@ pub mod simplify_branches;
pub mod simplify;
pub mod erase_regions;
pub mod no_landing_pads;
pub mod type_check;
pub mod rustc_peek;
pub mod elaborate_drops;
pub mod add_call_guards;

View file

@ -80,6 +80,39 @@ pub struct LivenessMode {
pub include_drops: bool,
}
/// A combination of liveness results, used in NLL.
pub struct LivenessResults {
/// Liveness results where a regular use makes a variable X live,
/// but not a drop.
pub regular: LivenessResult,
/// Liveness results where a drop makes a variable X live,
/// but not a regular use.
pub drop: LivenessResult,
}
impl LivenessResults {
pub fn compute<'tcx>(mir: &Mir<'tcx>) -> LivenessResults {
LivenessResults {
regular: liveness_of_locals(
&mir,
LivenessMode {
include_regular_use: true,
include_drops: false,
},
),
drop: liveness_of_locals(
&mir,
LivenessMode {
include_regular_use: false,
include_drops: true,
},
),
}
}
}
/// Compute which local variables are live within the given function
/// `mir`. The liveness mode `mode` determines what sorts of uses are
/// considered to make a variable live (e.g., do drops count?).

View file

@ -465,6 +465,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
}
ty::ReFree(..) |
ty::ReClosureBound(..) |
ty::ReScope(..) |
ty::ReVar(..) |
ty::ReSkolemized(..) |

View file

@ -1055,6 +1055,7 @@ impl Clean<Option<Lifetime>> for ty::RegionKind {
ty::ReVar(..) |
ty::ReSkolemized(..) |
ty::ReEmpty |
ty::ReClosureBound(_) |
ty::ReErased => None
}
}

View file

@ -14,9 +14,9 @@
fn bar<'a, 'b>() -> fn(&'a u32, &'b u32) -> &'a u32 {
let g: fn(_, _) -> _ = |_x, y| y;
//~^ ERROR free region `'b` does not outlive free region `'a`
g
//~^ WARNING not reporting region error due to -Znll
//~| ERROR free region `'b` does not outlive free region `'a`
}
fn main() {}

View file

@ -45,8 +45,8 @@ fn bar<'a>(x: &'a u32) -> &'static u32 {
// as part of checking the `ReifyFnPointer`.
let f: fn(_) -> _ = foo;
//~^ WARNING not reporting region error due to -Znll
//~| ERROR free region `'_#1r` does not outlive free region `'static`
f(x)
//~^ ERROR free region `'_#1r` does not outlive free region `'static`
}
fn main() {}

View file

@ -17,8 +17,8 @@ fn bar<'a>(input: &'a u32, f: fn(&'a u32) -> &'a u32) -> &'static u32 {
// in `g`. These are related via the `UnsafeFnPointer` cast.
let g: unsafe fn(_) -> _ = f;
//~^ WARNING not reporting region error due to -Znll
//~| ERROR free region `'_#1r` does not outlive free region `'static`
unsafe { g(input) }
//~^ ERROR free region `'_#1r` does not outlive free region `'static`
}
fn main() {}

View file

@ -27,17 +27,23 @@ fn main() {
// END RUST SOURCE
// START rustc.use_x.nll.0.mir
// | Free Region Mapping
// | '_#0r | Global | ['_#2r, '_#1r, '_#0r, '_#3r]
// | '_#1r | External | ['_#1r]
// | '_#2r | External | ['_#2r, '_#1r]
// | '_#3r | Local | ['_#3r]
// | '_#0r | Global | ['_#2r, '_#1r, '_#0r, '_#4r, '_#3r]
// | '_#1r | External | ['_#1r, '_#4r]
// | '_#2r | External | ['_#2r, '_#1r, '_#4r]
// | '_#3r | Local | ['_#4r, '_#3r]
// | '_#4r | Local | ['_#4r]
// |
// | Inferred Region Values
// | '_#0r | {'_#0r, bb0[0], bb0[1]}
// | '_#1r | {'_#1r, bb0[0], bb0[1]}
// | '_#2r | {'_#2r, bb0[0], bb0[1]}
// | '_#3r | {'_#3r, bb0[0], bb0[1]}
// | '_#0r | {'_#0r, bb0[0..=1]}
// | '_#1r | {'_#1r, bb0[0..=1]}
// | '_#2r | {'_#2r, bb0[0..=1]}
// | '_#3r | {'_#3r, bb0[0..=1]}
// | '_#4r | {'_#4r, bb0[0..=1]}
// | '_#5r | {'_#1r, bb0[0..=1]}
// | '_#6r | {'_#2r, bb0[0..=1]}
// | '_#7r | {'_#1r, bb0[0..=1]}
// | '_#8r | {'_#3r, bb0[0..=1]}
// |
// ...
// fn use_x(_1: &'_#1r mut i32, _2: &'_#2r u32, _3: &'_#1r u32, _4: &'_#3r u32) -> bool {
// fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool {
// END rustc.use_x.nll.0.mir

View file

@ -28,11 +28,11 @@ fn main() {
// END RUST SOURCE
// START rustc.main.nll.0.mir
// | '_#6r | {bb0[6], bb0[7], bb0[8], bb0[9], bb0[10], bb0[11], bb0[12], bb0[13], bb0[14]}
// | '_#7r | {bb0[6..=14]}
// ...
// | '_#8r | {bb0[11], bb0[12], bb0[13], bb0[14]}
// | '_#9r | {bb0[11..=14]}
// ...
// let _2: &'_#6r mut i32;
// let _2: &'_#7r mut i32;
// ...
// let _4: &'_#8r mut i32;
// let _4: &'_#9r mut i32;
// END rustc.main.nll.0.mir

View file

@ -31,15 +31,15 @@ fn main() {
// END RUST SOURCE
// START rustc.main.nll.0.mir
// | '_#1r | {bb2[0], bb2[1], bb3[0], bb3[1]}
// | '_#2r | {bb2[1], bb3[0], bb3[1]}
// | '_#2r | {bb2[0..=1], bb3[0..=1]}
// | '_#3r | {bb2[1], bb3[0..=1]}
// ...
// let _2: &'_#2r usize;
// let _2: &'_#3r usize;
// END rustc.main.nll.0.mir
// START rustc.main.nll.0.mir
// bb2: {
// | Live variables on entry to bb2[0]: [_1, _3]
// _2 = &'_#1r _1[_3];
// _2 = &'_#2r _1[_3];
// | Live variables on entry to bb2[1]: [_2]
// switchInt(const true) -> [0u8: bb4, otherwise: bb3];
// }

View file

@ -44,5 +44,7 @@ unsafe impl<#[may_dangle] T> Drop for Wrap<T> {
// END RUST SOURCE
// START rustc.main.nll.0.mir
// | '_#5r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1]}
// | '_#6r | {bb2[3..=5], bb3[0..=1]}
// ...
// let _2: Wrap<&'_#6r usize>;
// END rustc.main.nll.0.mir

View file

@ -46,5 +46,7 @@ impl<T> Drop for Wrap<T> {
// END RUST SOURCE
// START rustc.main.nll.0.mir
// | '_#5r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1], bb3[2], bb4[0], bb5[0], bb5[1], bb5[2], bb6[0], bb7[0], bb7[1], bb8[0]}
// | '_#6r | {bb2[3..=5], bb3[0..=2], bb4[0], bb5[0..=2], bb6[0], bb7[0..=1], bb8[0]}
// ...
// let _2: Wrap<&'_#6r usize>;
// END rustc.main.nll.0.mir

View file

@ -36,14 +36,14 @@ fn main() {
// END RUST SOURCE
// START rustc.main.nll.0.mir
// | '_#1r | {bb2[0], bb2[1], bb3[0], bb3[1]}
// | '_#2r | {bb2[0..=1], bb3[0..=1]}
// ...
// | '_#3r | {bb8[1], bb8[2], bb8[3], bb8[4]}
// | '_#4r | {bb2[1], bb3[0], bb3[1], bb8[2], bb8[3], bb8[4]}
// | '_#4r | {bb8[1..=4]}
// | '_#5r | {bb2[1], bb3[0..=1], bb8[2..=4]}
// ...
// let mut _2: &'_#4r usize;
// let mut _2: &'_#5r usize;
// ...
// _2 = &'_#1r _1[_3];
// _2 = &'_#2r _1[_3];
// ...
// _2 = &'_#3r (*_10);
// _2 = &'_#4r (*_10);
// END rustc.main.nll.0.mir

View file

@ -32,16 +32,16 @@ fn main() {
// END RUST SOURCE
// START rustc.main.nll.0.mir
// | '_#1r | {bb2[0], bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]}
// | '_#2r | {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]}
// | '_#3r | {bb2[5], bb2[6], bb3[0], bb3[1]}
// | '_#2r | {bb2[0..=6], bb3[0..=1]}
// | '_#3r | {bb2[1..=6], bb3[0..=1]}
// | '_#4r | {bb2[5..=6], bb3[0..=1]}
// END rustc.main.nll.0.mir
// START rustc.main.nll.0.mir
// let _2: &'_#2r usize;
// let _2: &'_#3r usize;
// ...
// let _6: &'_#3r usize;
// let _6: &'_#4r usize;
// ...
// _2 = &'_#1r _1[_3];
// _2 = &'_#2r _1[_3];
// ...
// _7 = _2;
// ...

View file

@ -7,7 +7,7 @@ error[E0597]: `y` does not live long enough
37 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for lifetime '_#4r...
= note: borrowed value must be valid for lifetime '_#5r...
error: aborting due to previous error

View file

@ -10,7 +10,7 @@ error: free region `'_#4r` does not outlive free region `'_#3r`
36 | let mut closure = expect_sig(|p, y| *p = y);
| ^^^^^^
note: External requirements
note: No external requirements
--> $DIR/escape-argument-callee.rs:36:38
|
36 | let mut closure = expect_sig(|p, y| *p = y);
@ -20,7 +20,6 @@ note: External requirements
i16,
for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) i32))
]
= note: number of external vids: 1
note: No external requirements
--> $DIR/escape-argument-callee.rs:30:1

View file

@ -1,4 +1,4 @@
note: External requirements
note: No external requirements
--> $DIR/escape-argument.rs:36:38
|
36 | let mut closure = expect_sig(|p, y| *p = y);
@ -8,7 +8,6 @@ note: External requirements
i16,
for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32))
]
= note: number of external vids: 1
note: No external requirements
--> $DIR/escape-argument.rs:30:1
@ -33,7 +32,7 @@ error[E0597]: `y` does not live long enough
39 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for lifetime '_#5r...
= note: borrowed value must be valid for lifetime '_#6r...
error: aborting due to previous error

View file

@ -59,7 +59,7 @@ error[E0597]: `y` does not live long enough
36 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for lifetime '_#3r...
= note: borrowed value must be valid for lifetime '_#4r...
error: aborting due to previous error

View file

@ -36,7 +36,7 @@ error[E0597]: `y` does not live long enough
36 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for lifetime '_#3r...
= note: borrowed value must be valid for lifetime '_#4r...
error: aborting due to previous error

View file

@ -54,8 +54,8 @@ fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell
// Only works if 'x: 'y:
let p = x.get();
//~^ WARN not reporting region error due to -Znll
//~| ERROR free region `'_#5r` does not outlive free region `'_#6r`
demand_y(x, y, p)
//~^ ERROR free region `'_#5r` does not outlive free region `'_#6r`
},
);
}

View file

@ -5,20 +5,20 @@ warning: not reporting region error due to -Znll
| ^^^^^^^
error: free region `'_#5r` does not outlive free region `'_#6r`
--> $DIR/propagate-approximated-fail-no-postdom.rs:57:25
--> $DIR/propagate-approximated-fail-no-postdom.rs:55:17
|
57 | demand_y(x, y, p)
| ^
55 | let p = x.get();
| ^
note: External requirements
note: No external requirements
--> $DIR/propagate-approximated-fail-no-postdom.rs:53:9
|
53 | / |_outlives1, _outlives2, _outlives3, x, y| {
54 | | // Only works if 'x: 'y:
55 | | let p = x.get();
56 | | //~^ WARN not reporting region error due to -Znll
57 | | demand_y(x, y, p)
58 | | //~^ ERROR free region `'_#5r` does not outlive free region `'_#6r`
57 | | //~| ERROR free region `'_#5r` does not outlive free region `'_#6r`
58 | | demand_y(x, y, p)
59 | | },
| |_________^
|
@ -26,7 +26,6 @@ note: External requirements
i16,
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
= note: number of external vids: 4
note: No external requirements
--> $DIR/propagate-approximated-fail-no-postdom.rs:48:1

View file

@ -24,10 +24,10 @@ note: External requirements
= note: where '_#1r: '_#2r
error: free region `'_#1r` does not outlive free region `'_#2r`
--> $DIR/propagate-approximated-ref.rs:53:38
--> $DIR/propagate-approximated-ref.rs:53:29
|
53 | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
| ^^^^^^^
| ^^^^^^^
note: No external requirements
--> $DIR/propagate-approximated-ref.rs:52:1

View file

@ -10,7 +10,7 @@ error: free region `'_#2r` does not outlive free region `'_#1r`
33 | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
| ^^^^^^
note: External requirements
note: No external requirements
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15
|
31 | foo(cell, |cell_a, cell_x| {
@ -25,7 +25,6 @@ note: External requirements
i32,
for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>))
]
= note: number of external vids: 2
note: No external requirements
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:28:1
@ -80,7 +79,7 @@ error[E0597]: `a` does not live long enough
49 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for lifetime '_#1r...
= note: borrowed value must be valid for lifetime '_#2r...
error: aborting due to 2 previous errors

View file

@ -0,0 +1,45 @@
warning: not reporting region error due to -Znll
--> $DIR/propagate-approximated-to-empty.rs:41:9
|
41 | demand_y(x, y, x.get())
| ^^^^^^^^^^^^^^^^^^^^^^^
error: free region `'_#6r` does not outlive free region `'_#4r`
--> $DIR/propagate-approximated-to-empty.rs:41:18
|
41 | demand_y(x, y, x.get())
| ^
note: No external requirements
--> $DIR/propagate-approximated-to-empty.rs:39:47
|
39 | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
| _______________________________________________^
40 | | // Only works if 'x: 'y:
41 | | demand_y(x, y, x.get())
42 | | //~^ WARN not reporting region error due to -Znll
43 | | //~| ERROR free region `'_#6r` does not outlive free region `'_#4r`
44 | | });
| |_____^
|
= note: defining type: DefId(0/1:18 ~ propagate_approximated_to_empty[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
note: No external requirements
--> $DIR/propagate-approximated-to-empty.rs:38:1
|
38 | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
39 | | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
40 | | // Only works if 'x: 'y:
41 | | demand_y(x, y, x.get())
... |
44 | | });
45 | | }
| |_^
|
= note: defining type: DefId(0/0:6 ~ propagate_approximated_to_empty[317d]::supply[0]) with substs []
error: aborting due to previous error

View file

@ -24,10 +24,10 @@ note: External requirements
= note: where '_#1r: '_#2r
error: free region `'_#1r` does not outlive free region `'_#2r`
--> $DIR/propagate-approximated-val.rs:46:37
--> $DIR/propagate-approximated-val.rs:46:29
|
46 | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
| ^^^^^^
| ^^^^^^
note: No external requirements
--> $DIR/propagate-approximated-val.rs:45:1

View file

@ -5,12 +5,12 @@ warning: not reporting region error due to -Znll
| ^^^^^^^^^^^^^^^^^^^^^^^
error: free region `'_#6r` does not outlive free region `'_#4r`
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:21
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:18
|
47 | demand_y(x, y, x.get())
| ^
| ^
note: External requirements
note: No external requirements
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47
|
45 | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
@ -26,7 +26,6 @@ note: External requirements
i16,
for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
= note: number of external vids: 2
note: No external requirements
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:44:1

View file

@ -5,12 +5,12 @@ warning: not reporting region error due to -Znll
| ^^^^^^^^^^^^^^^^^^^^^^^
error: free region `'_#5r` does not outlive free region `'_#7r`
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:21
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:18
|
51 | demand_y(x, y, x.get())
| ^
| ^
note: External requirements
note: No external requirements
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:49:47
|
49 | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
@ -26,7 +26,6 @@ note: External requirements
i16,
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
]
= note: number of external vids: 3
note: No external requirements
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:48:1

View file

@ -0,0 +1,60 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that regions which appear only in the closure's generics (in
// this case, `'a`) are properly mapped to the creator's generics. In
// this case, the closure constrains its type parameter `T` to outlive
// the same `'a` for which it implements `Trait`, which can only be the `'a`
// from the function definition.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
#![allow(dead_code)]
trait Trait<'a> {}
fn establish_relationships<T, F>(value: T, closure: F)
where
F: FnOnce(T),
{
closure(value)
}
fn require<'a, T>(t: T)
where
T: Trait<'a> + 'a,
{
}
#[rustc_regions]
fn supply<'a, T>(value: T)
where
T: Trait<'a>,
{
establish_relationships(value, |value| {
//~^ ERROR `T` does not outlive
// This function call requires that
//
// (a) T: Trait<'a>
//
// and
//
// (b) T: 'a
//
// The latter does not hold.
require(value);
//~^ WARNING not reporting region error due to -Znll
});
}
fn main() {}

View file

@ -0,0 +1,60 @@
warning: not reporting region error due to -Znll
--> $DIR/propagate-from-trait-match.rs:55:9
|
55 | require(value);
| ^^^^^^^
note: External requirements
--> $DIR/propagate-from-trait-match.rs:42:36
|
42 | establish_relationships(value, |value| {
| ____________________________________^
43 | | //~^ ERROR `T` does not outlive
44 | |
45 | | // This function call requires that
... |
56 | | //~^ WARNING not reporting region error due to -Znll
57 | | });
| |_____^
|
= note: defining type: DefId(0/1:16 ~ propagate_from_trait_match[317d]::supply[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((T,))
]
= note: number of external vids: 2
= note: where T: '_#1r
error: `T` does not outlive `'_#3r`
--> $DIR/propagate-from-trait-match.rs:42:36
|
42 | establish_relationships(value, |value| {
| ____________________________________^
43 | | //~^ ERROR `T` does not outlive
44 | |
45 | | // This function call requires that
... |
56 | | //~^ WARNING not reporting region error due to -Znll
57 | | });
| |_____^
note: No external requirements
--> $DIR/propagate-from-trait-match.rs:38:1
|
38 | / fn supply<'a, T>(value: T)
39 | | where
40 | | T: Trait<'a>,
41 | | {
... |
57 | | });
58 | | }
| |_^
|
= note: defining type: DefId(0/0:6 ~ propagate_from_trait_match[317d]::supply[0]) with substs [
'_#1r,
T
]
error: aborting due to previous error

View file

@ -10,7 +10,7 @@ error: free region `'_#3r` does not outlive free region `'_#2r`
21 | expect_sig(|a, b| b); // ought to return `a`
| ^
note: External requirements
note: No external requirements
--> $DIR/return-wrong-bound-region.rs:21:16
|
21 | expect_sig(|a, b| b); // ought to return `a`
@ -20,7 +20,6 @@ note: External requirements
i16,
for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32)) -> &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) i32
]
= note: number of external vids: 1
note: No external requirements
--> $DIR/return-wrong-bound-region.rs:20:1

View file

@ -0,0 +1,29 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Znll -Zborrowck=mir
// must-compile-successfully
#![feature(rustc_attrs)]
trait Foo {
type Bar;
}
impl Foo for () {
type Bar = u32;
}
fn foo() -> <() as Foo>::Bar {
22
}
fn main() { }

View file

@ -0,0 +1,68 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
// Tests closures that propagate an outlives relationship to their
// creator where the subject is a projection with no regions (`<T as
// Iterator>::Item`, to be exact).
#![allow(warnings)]
#![feature(dyn_trait)]
#![feature(rustc_attrs)]
trait Anything { }
impl<T> Anything for T { }
fn with_signature<'a, T, F>(x: Box<T>, op: F) -> Box<dyn Anything + 'a>
where F: FnOnce(Box<T>) -> Box<dyn Anything + 'a>
{
op(x)
}
#[rustc_regions]
fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
where
T: Iterator,
{
with_signature(x, |mut y| Box::new(y.next()))
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
}
#[rustc_regions]
fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
where
T: 'a + Iterator,
{
with_signature(x, |mut y| Box::new(y.next()))
}
#[rustc_regions]
fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
where
T: 'b + Iterator,
{
with_signature(x, |mut y| Box::new(y.next()))
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
}
#[rustc_regions]
fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
where
T: 'b + Iterator,
'b: 'a,
{
with_signature(x, |mut y| Box::new(y.next()))
}
fn main() {}

View file

@ -0,0 +1,157 @@
warning: not reporting region error due to -Znll
--> $DIR/projection-no-regions-closure.rs:36:31
|
36 | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^
warning: not reporting region error due to -Znll
--> $DIR/projection-no-regions-closure.rs:54:31
|
54 | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^
note: External requirements
--> $DIR/projection-no-regions-closure.rs:36:23
|
36 | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:15 ~ projection_no_regions_closure[317d]::no_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#2r>
]
= note: number of external vids: 3
= note: where <T as std::iter::Iterator>::Item: '_#2r
note: External requirements
--> $DIR/projection-no-regions-closure.rs:46:23
|
46 | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#2r>
]
= note: number of external vids: 3
= note: where <T as std::iter::Iterator>::Item: '_#2r
note: External requirements
--> $DIR/projection-no-regions-closure.rs:54:23
|
54 | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#3r>
]
= note: number of external vids: 4
= note: where <T as std::iter::Iterator>::Item: '_#3r
note: External requirements
--> $DIR/projection-no-regions-closure.rs:65:23
|
65 | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#3r>
]
= note: number of external vids: 4
= note: where <T as std::iter::Iterator>::Item: '_#3r
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#4r`
--> $DIR/projection-no-regions-closure.rs:36:23
|
36 | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: No external requirements
--> $DIR/projection-no-regions-closure.rs:32:1
|
32 | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
33 | | where
34 | | T: Iterator,
35 | | {
... |
38 | | //~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
39 | | }
| |_^
|
= note: defining type: DefId(0/0:6 ~ projection_no_regions_closure[317d]::no_region[0]) with substs [
'_#1r,
T
]
note: No external requirements
--> $DIR/projection-no-regions-closure.rs:42:1
|
42 | / fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
43 | | where
44 | | T: 'a + Iterator,
45 | | {
46 | | with_signature(x, |mut y| Box::new(y.next()))
47 | | }
| |_^
|
= note: defining type: DefId(0/0:7 ~ projection_no_regions_closure[317d]::correct_region[0]) with substs [
'_#1r,
T
]
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#6r`
--> $DIR/projection-no-regions-closure.rs:54:23
|
54 | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: No external requirements
--> $DIR/projection-no-regions-closure.rs:50:1
|
50 | / fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
51 | | where
52 | | T: 'b + Iterator,
53 | | {
... |
56 | | //~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
57 | | }
| |_^
|
= note: defining type: DefId(0/0:8 ~ projection_no_regions_closure[317d]::wrong_region[0]) with substs [
'_#1r,
'_#2r,
T
]
note: No external requirements
--> $DIR/projection-no-regions-closure.rs:60:1
|
60 | / fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
61 | | where
62 | | T: 'b + Iterator,
63 | | 'b: 'a,
64 | | {
65 | | with_signature(x, |mut y| Box::new(y.next()))
66 | | }
| |_^
|
= note: defining type: DefId(0/0:9 ~ projection_no_regions_closure[317d]::outlives_region[0]) with substs [
'_#1r,
'_#2r,
T
]
error: aborting due to 2 previous errors

View file

@ -0,0 +1,53 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
trait Anything { }
impl<T> Anything for T { }
fn no_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
where
T: Iterator,
{
Box::new(x.next())
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
}
fn correct_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
where
T: 'a + Iterator,
{
Box::new(x.next())
}
fn wrong_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
where
T: 'b + Iterator,
{
Box::new(x.next())
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
}
fn outlives_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
where
T: 'b + Iterator,
'b: 'a,
{
Box::new(x.next())
}
fn main() {}

View file

@ -0,0 +1,26 @@
warning: not reporting region error due to -Znll
--> $DIR/projection-no-regions-fn.rs:24:5
|
24 | Box::new(x.next())
| ^^^^^^^^^^^^^^^^^^
warning: not reporting region error due to -Znll
--> $DIR/projection-no-regions-fn.rs:40:5
|
40 | Box::new(x.next())
| ^^^^^^^^^^^^^^^^^^
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#4r`
--> $DIR/projection-no-regions-fn.rs:24:5
|
24 | Box::new(x.next())
| ^^^^^^^^^^^^^^^^^^
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#5r`
--> $DIR/projection-no-regions-fn.rs:40:5
|
40 | Box::new(x.next())
| ^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View file

@ -0,0 +1,106 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
// outlive `'a` and there are no bounds in the trait definition of
// `Anything`. This means that the constraint can only be satisfied in two
// ways:
//
// - by ensuring that `T: 'a` and `'b: 'a`, or
// - by something in the where clauses.
//
// As of this writing, the where clause option does not work because
// of limitations in our region inferencing system (this is true both
// with and without NLL). See `projection_outlives`.
//
// Ensuring that both `T: 'a` and `'b: 'a` holds does work (`elements_outlive`).
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
#![feature(rustc_attrs)]
use std::cell::Cell;
trait Anything<'a> {
type AssocType;
}
fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
where
F: FnOnce(Cell<&'a ()>, T),
{
op(cell, t)
}
fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
where
T: Anything<'b>,
T::AssocType: 'a,
{
}
#[rustc_regions]
fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
{
with_signature(cell, t, |cell, t| require(cell, t));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `T` does not outlive
//~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
}
#[rustc_regions]
fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
'a: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `T` does not outlive
//~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
}
#[rustc_regions]
fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
T::AssocType: 'a,
{
// This error is unfortunate. This code ought to type-check: we
// are projecting `<T as Anything<'b>>::AssocType`, and we know
// that this outlives `'a` because of the where-clause. However,
// the way the region checker works, we don't register this
// outlives obligation, and hence we get an error: this is because
// what we see is a projection like `<T as
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
// equal `'b` or not, so we ignore the where-clause. Obviously we
// can do better here with a more involved verification step.
with_signature(cell, t, |cell, t| require(cell, t));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `T` does not outlive
//~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
}
#[rustc_regions]
fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
T: 'a,
'b: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
}
fn main() {}

View file

@ -0,0 +1,194 @@
warning: not reporting region error due to -Znll
--> $DIR/projection-one-region-closure.rs:56:39
|
56 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
warning: not reporting region error due to -Znll
--> $DIR/projection-one-region-closure.rs:68:39
|
68 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
warning: not reporting region error due to -Znll
--> $DIR/projection-one-region-closure.rs:90:39
|
90 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
note: External requirements
--> $DIR/projection-one-region-closure.rs:56:29
|
56 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:19 ~ projection_one_region_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
]
= note: number of external vids: 3
= note: where T: '_#2r
= note: where '_#1r: '_#2r
note: External requirements
--> $DIR/projection-one-region-closure.rs:68:29
|
68 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: where T: '_#3r
= note: where '_#2r: '_#3r
note: External requirements
--> $DIR/projection-one-region-closure.rs:90:29
|
90 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: where T: '_#3r
= note: where '_#2r: '_#3r
note: External requirements
--> $DIR/projection-one-region-closure.rs:103:29
|
103 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: where T: '_#3r
= note: where '_#2r: '_#3r
error: `T` does not outlive `'_#5r`
--> $DIR/projection-one-region-closure.rs:56:29
|
56 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
--> $DIR/projection-one-region-closure.rs:56:20
|
56 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^
note: No external requirements
--> $DIR/projection-one-region-closure.rs:52:1
|
52 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
53 | | where
54 | | T: Anything<'b>,
55 | | {
... |
59 | | //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
60 | | }
| |_^
|
= note: defining type: DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]) with substs [
'_#1r,
T
]
error: `T` does not outlive `'_#6r`
--> $DIR/projection-one-region-closure.rs:68:29
|
68 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
--> $DIR/projection-one-region-closure.rs:68:20
|
68 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^
note: No external requirements
--> $DIR/projection-one-region-closure.rs:63:1
|
63 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
64 | | where
65 | | T: Anything<'b>,
66 | | 'a: 'a,
... |
71 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
72 | | }
| |_^
|
= note: defining type: DefId(0/0:9 ~ projection_one_region_closure[317d]::no_relationships_early[0]) with substs [
'_#1r,
'_#2r,
T
]
error: `T` does not outlive `'_#6r`
--> $DIR/projection-one-region-closure.rs:90:29
|
90 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
--> $DIR/projection-one-region-closure.rs:90:20
|
90 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^
note: No external requirements
--> $DIR/projection-one-region-closure.rs:75:1
|
75 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
76 | | where
77 | | T: Anything<'b>,
78 | | T::AssocType: 'a,
... |
93 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
94 | | }
| |_^
|
= note: defining type: DefId(0/0:10 ~ projection_one_region_closure[317d]::projection_outlives[0]) with substs [
'_#1r,
'_#2r,
T
]
note: No external requirements
--> $DIR/projection-one-region-closure.rs:97:1
|
97 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
98 | | where
99 | | T: Anything<'b>,
100 | | T: 'a,
... |
103 | | with_signature(cell, t, |cell, t| require(cell, t));
104 | | }
| |_^
|
= note: defining type: DefId(0/0:11 ~ projection_one_region_closure[317d]::elements_outlive[0]) with substs [
'_#1r,
'_#2r,
T
]
error: aborting due to 6 previous errors

View file

@ -0,0 +1,106 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
// outlive `'a` and there is a unique bound in the trait definition of
// `Anything` -- i.e., we know that `AssocType` outlives `'b`. In this
// case, the best way to satisfy the trait bound is to show that `'b:
// 'a`, which can be done in various ways.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
#![feature(rustc_attrs)]
use std::cell::Cell;
trait Anything<'a> {
type AssocType: 'a;
}
fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
where
F: FnOnce(Cell<&'a ()>, T),
{
op(cell, t)
}
fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
where
T: Anything<'b>,
T::AssocType: 'a,
{
}
#[rustc_regions]
fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
{
with_signature(cell, t, |cell, t| require(cell, t));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
}
#[rustc_regions]
fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
'a: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
}
#[rustc_regions]
fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
T::AssocType: 'a,
{
// This error is unfortunate. This code ought to type-check: we
// are projecting `<T as Anything<'b>>::AssocType`, and we know
// that this outlives `'a` because of the where-clause. However,
// the way the region checker works, we don't register this
// outlives obligation, and hence we get an error: this is because
// what we see is a projection like `<T as
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
// equal `'b` or not, so we ignore the where-clause. Obviously we
// can do better here with a more involved verification step.
with_signature(cell, t, |cell, t| require(cell, t));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
}
#[rustc_regions]
fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
'b: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
}
#[rustc_regions]
fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'a>,
{
// Note that in this case the closure still propagates an external
// requirement between two variables in its signature, but the
// creator maps both those two region variables to `'a` on its
// side.
with_signature(cell, t, |cell, t| require(cell, t));
}
fn main() {}

View file

@ -0,0 +1,204 @@
warning: not reporting region error due to -Znll
--> $DIR/projection-one-region-trait-bound-closure.rs:48:39
|
48 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
warning: not reporting region error due to -Znll
--> $DIR/projection-one-region-trait-bound-closure.rs:59:39
|
59 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
warning: not reporting region error due to -Znll
--> $DIR/projection-one-region-trait-bound-closure.rs:80:39
|
80 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:48:29
|
48 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
]
= note: number of external vids: 3
= note: where '_#1r: '_#2r
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:59:29
|
59 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: where '_#2r: '_#3r
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:80:29
|
80 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: where '_#2r: '_#3r
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:91:29
|
91 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: where '_#2r: '_#3r
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:103:29
|
103 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
]
= note: number of external vids: 3
= note: where '_#1r: '_#2r
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
--> $DIR/projection-one-region-trait-bound-closure.rs:48:20
|
48 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^
note: No external requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:44:1
|
44 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
45 | | where
46 | | T: Anything<'b>,
47 | | {
... |
50 | | //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
51 | | }
| |_^
|
= note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [
'_#1r,
T
]
error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
--> $DIR/projection-one-region-trait-bound-closure.rs:59:20
|
59 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^
note: No external requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:54:1
|
54 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
55 | | where
56 | | T: Anything<'b>,
57 | | 'a: 'a,
... |
61 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
62 | | }
| |_^
|
= note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [
'_#1r,
'_#2r,
T
]
error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
--> $DIR/projection-one-region-trait-bound-closure.rs:80:20
|
80 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^
note: No external requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:65:1
|
65 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
66 | | where
67 | | T: Anything<'b>,
68 | | T::AssocType: 'a,
... |
82 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
83 | | }
| |_^
|
= note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [
'_#1r,
'_#2r,
T
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:86:1
|
86 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
87 | | where
88 | | T: Anything<'b>,
89 | | 'b: 'a,
90 | | {
91 | | with_signature(cell, t, |cell, t| require(cell, t));
92 | | }
| |_^
|
= note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]) with substs [
'_#1r,
'_#2r,
T
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:95:1
|
95 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
96 | | where
97 | | T: Anything<'a>,
98 | | {
... |
103 | | with_signature(cell, t, |cell, t| require(cell, t));
104 | | }
| |_^
|
= note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]) with substs [
'_#1r,
T
]
error: aborting due to 3 previous errors

View file

@ -0,0 +1,99 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
// outlive `'static`. In this case, we don't get any errors, and in fact
// we don't even propagate constraints from the closures to the callers.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
// must-compile-successfully
#![allow(warnings)]
#![feature(dyn_trait)]
#![feature(rustc_attrs)]
use std::cell::Cell;
trait Anything<'a> {
type AssocType: 'static;
}
fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
where
F: FnOnce(Cell<&'a ()>, T),
{
op(cell, t)
}
fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
where
T: Anything<'b>,
T::AssocType: 'a,
{
}
#[rustc_regions]
fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
{
with_signature(cell, t, |cell, t| require(cell, t));
}
#[rustc_regions]
fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
'a: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
}
#[rustc_regions]
fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
T::AssocType: 'a,
{
// This error is unfortunate. This code ought to type-check: we
// are projecting `<T as Anything<'b>>::AssocType`, and we know
// that this outlives `'a` because of the where-clause. However,
// the way the region checker works, we don't register this
// outlives obligation, and hence we get an error: this is because
// what we see is a projection like `<T as
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
// equal `'b` or not, so we ignore the where-clause. Obviously we
// can do better here with a more involved verification step.
with_signature(cell, t, |cell, t| require(cell, t));
}
#[rustc_regions]
fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b>,
'b: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
}
#[rustc_regions]
fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'a>,
{
// Note that in this case the closure still propagates an external
// requirement between two variables in its signature, but the
// creator maps both those two region variables to `'a` on its
// side.
with_signature(cell, t, |cell, t| require(cell, t));
}
fn main() {}

View file

@ -0,0 +1,155 @@
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:47:29
|
47 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29
|
56 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29
|
75 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29
|
84 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29
|
96 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1
|
43 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
44 | | where
45 | | T: Anything<'b>,
46 | | {
47 | | with_signature(cell, t, |cell, t| require(cell, t));
48 | | }
| |_^
|
= note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [
'_#1r,
T
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:51:1
|
51 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
52 | | where
53 | | T: Anything<'b>,
54 | | 'a: 'a,
55 | | {
56 | | with_signature(cell, t, |cell, t| require(cell, t));
57 | | }
| |_^
|
= note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]) with substs [
'_#1r,
'_#2r,
T
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:60:1
|
60 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
61 | | where
62 | | T: Anything<'b>,
63 | | T::AssocType: 'a,
... |
75 | | with_signature(cell, t, |cell, t| require(cell, t));
76 | | }
| |_^
|
= note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]) with substs [
'_#1r,
'_#2r,
T
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:79:1
|
79 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
80 | | where
81 | | T: Anything<'b>,
82 | | 'b: 'a,
83 | | {
84 | | with_signature(cell, t, |cell, t| require(cell, t));
85 | | }
| |_^
|
= note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]) with substs [
'_#1r,
'_#2r,
T
]
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:88:1
|
88 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
89 | | where
90 | | T: Anything<'a>,
91 | | {
... |
96 | | with_signature(cell, t, |cell, t| require(cell, t));
97 | | }
| |_^
|
= note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]) with substs [
'_#1r,
T
]

View file

@ -0,0 +1,135 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test cases where we constrain `<T as Anything<'a, 'b>>::AssocType`
// to outlive `'a` and there are two bounds in the trait definition of
// `Anything` -- i.e., we know that `AssocType` outlives `'a` and
// `'b`. In this case, it's not clear what is the best way to satisfy
// the trait bound, and hence we propagate it to the caller as a type
// test.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
#![feature(rustc_attrs)]
use std::cell::Cell;
trait Anything<'a, 'b> {
type AssocType: 'a + 'b;
}
fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
where
F: FnOnce(Cell<&'a ()>, T),
{
op(cell, t)
}
fn require<'a, 'b, 'c, T>(_cell: Cell<&'a ()>, _t: T)
where
T: Anything<'b, 'c>,
T::AssocType: 'a,
{
}
#[rustc_regions]
fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b, 'c>,
{
with_signature(cell, t, |cell, t| require(cell, t));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `<T as Anything<'_#5r, '_#6r>>::AssocType` does not outlive `'_#7r`
}
#[rustc_regions]
fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b, 'c>,
'a: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
}
#[rustc_regions]
fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b, 'c>,
T::AssocType: 'a,
{
// This error is unfortunate. This code ought to type-check: we
// are projecting `<T as Anything<'b>>::AssocType`, and we know
// that this outlives `'a` because of the where-clause. However,
// the way the region checker works, we don't register this
// outlives obligation, and hence we get an error: this is because
// what we see is a projection like `<T as
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
// equal `'b` or not, so we ignore the where-clause. Obviously we
// can do better here with a more involved verification step.
with_signature(cell, t, |cell, t| require(cell, t));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
}
#[rustc_regions]
fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b, 'c>,
'b: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
}
#[rustc_regions]
fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b, 'c>,
'c: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
}
#[rustc_regions]
fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b, 'b>,
{
with_signature(cell, t, |cell, t| require(cell, t));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
}
#[rustc_regions]
fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'b, 'b>,
'b: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
}
#[rustc_regions]
fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
where
T: Anything<'a, 'a>,
{
// Note that in this case the closure still propagates an external
// requirement between two variables in its signature, but the
// creator maps both those two region variables to `'a` on its
// side.
with_signature(cell, t, |cell, t| require(cell, t));
}
fn main() {}

View file

@ -0,0 +1,326 @@
warning: not reporting region error due to -Znll
--> $DIR/projection-two-region-trait-bound-closure.rs:49:39
|
49 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
warning: not reporting region error due to -Znll
--> $DIR/projection-two-region-trait-bound-closure.rs:60:39
|
60 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
warning: not reporting region error due to -Znll
--> $DIR/projection-two-region-trait-bound-closure.rs:81:39
|
81 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
warning: not reporting region error due to -Znll
--> $DIR/projection-two-region-trait-bound-closure.rs:109:39
|
109 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:49:29
|
49 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:22 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#2r)>>::AssocType: '_#3r
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:60:29
|
60 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
'_#3r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
]
= note: number of external vids: 5
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:81:29
|
81 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
'_#3r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
]
= note: number of external vids: 5
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:92:29
|
92 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
'_#3r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
]
= note: number of external vids: 5
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:101:29
|
101 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
'_#3r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
]
= note: number of external vids: 5
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:109:29
|
109 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
]
= note: number of external vids: 3
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:120:29
|
120 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:132:29
|
132 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
]
= note: number of external vids: 3
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
error: `<T as Anything<'_#5r, '_#6r>>::AssocType` does not outlive `'_#7r`
--> $DIR/projection-two-region-trait-bound-closure.rs:49:29
|
49 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:45:1
|
45 | / fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
46 | | where
47 | | T: Anything<'b, 'c>,
48 | | {
... |
51 | | //~| ERROR `<T as Anything<'_#5r, '_#6r>>::AssocType` does not outlive `'_#7r`
52 | | }
| |_^
|
= note: defining type: DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [
'_#1r,
'_#2r,
T
]
error: `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
--> $DIR/projection-two-region-trait-bound-closure.rs:60:29
|
60 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:55:1
|
55 | / fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
56 | | where
57 | | T: Anything<'b, 'c>,
58 | | 'a: 'a,
... |
62 | | //~| ERROR `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
63 | | }
| |_^
|
= note: defining type: DefId(0/0:9 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [
'_#1r,
'_#2r,
'_#3r,
T
]
error: `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
--> $DIR/projection-two-region-trait-bound-closure.rs:81:29
|
81 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:66:1
|
66 | / fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
67 | | where
68 | | T: Anything<'b, 'c>,
69 | | T::AssocType: 'a,
... |
83 | | //~| ERROR `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
84 | | }
| |_^
|
= note: defining type: DefId(0/0:10 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [
'_#1r,
'_#2r,
'_#3r,
T
]
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:87:1
|
87 | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
88 | | where
89 | | T: Anything<'b, 'c>,
90 | | 'b: 'a,
91 | | {
92 | | with_signature(cell, t, |cell, t| require(cell, t));
93 | | }
| |_^
|
= note: defining type: DefId(0/0:11 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]) with substs [
'_#1r,
'_#2r,
'_#3r,
T
]
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:96:1
|
96 | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
97 | | where
98 | | T: Anything<'b, 'c>,
99 | | 'c: 'a,
100 | | {
101 | | with_signature(cell, t, |cell, t| require(cell, t));
102 | | }
| |_^
|
= note: defining type: DefId(0/0:12 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]) with substs [
'_#1r,
'_#2r,
'_#3r,
T
]
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
--> $DIR/projection-two-region-trait-bound-closure.rs:109:20
|
109 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:105:1
|
105 | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
106 | | where
107 | | T: Anything<'b, 'b>,
108 | | {
... |
111 | | //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
112 | | }
| |_^
|
= note: defining type: DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]) with substs [
'_#1r,
T
]
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:115:1
|
115 | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
116 | | where
117 | | T: Anything<'b, 'b>,
118 | | 'b: 'a,
119 | | {
120 | | with_signature(cell, t, |cell, t| require(cell, t));
121 | | }
| |_^
|
= note: defining type: DefId(0/0:14 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]) with substs [
'_#1r,
'_#2r,
T
]
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:124:1
|
124 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
125 | | where
126 | | T: Anything<'a, 'a>,
127 | | {
... |
132 | | with_signature(cell, t, |cell, t| require(cell, t));
133 | | }
| |_^
|
= note: defining type: DefId(0/0:15 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]) with substs [
'_#1r,
T
]
error: aborting due to 4 previous errors

View file

@ -0,0 +1,66 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
#![feature(rustc_attrs)]
use std::fmt::Debug;
fn with_signature<'a, T, F>(x: Box<T>, op: F) -> Box<dyn Debug + 'a>
where F: FnOnce(Box<T>) -> Box<dyn Debug + 'a>
{
op(x)
}
#[rustc_regions]
fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
where
T: Debug,
{
// Here, the closure winds up being required to prove that `T:
// 'a`. In principle, it could know that, except that it is
// type-checked in a fully generic way, and hence it winds up with
// a propagated requirement that `T: '_#2`, where `'_#2` appears
// in the return type. The caller makes the mapping from `'_#2` to
// `'a` (and subsequently reports an error).
with_signature(x, |y| y)
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `T` does not outlive
}
fn correct_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
where
T: 'a + Debug,
{
x
}
fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
where
T: 'b + Debug,
{
x
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `T` does not outlive
}
fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
where
T: 'b + Debug,
'b: 'a,
{
x
}
fn main() {}

View file

@ -0,0 +1,58 @@
warning: not reporting region error due to -Znll
--> $DIR/ty-param-closure-outlives-from-return-type.rs:37:27
|
37 | with_signature(x, |y| y)
| ^
warning: not reporting region error due to -Znll
--> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5
|
53 | x
| ^
note: External requirements
--> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23
|
37 | with_signature(x, |y| y)
| ^^^^^
|
= note: defining type: DefId(0/1:14 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<std::fmt::Debug + '_#2r>
]
= note: number of external vids: 3
= note: where T: '_#2r
error: `T` does not outlive `'_#4r`
--> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23
|
37 | with_signature(x, |y| y)
| ^^^^^
note: No external requirements
--> $DIR/ty-param-closure-outlives-from-return-type.rs:26:1
|
26 | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
27 | | where
28 | | T: Debug,
29 | | {
... |
39 | | //~| ERROR `T` does not outlive
40 | | }
| |_^
|
= note: defining type: DefId(0/0:5 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]) with substs [
'_#1r,
T
]
error: `T` does not outlive `'_#4r`
--> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5
|
53 | x
| ^
error: aborting due to 2 previous errors

View file

@ -0,0 +1,96 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that we can propagate `T: 'a` obligations to our caller. See
// `correct_region` for an explanation of how this test is setup; it's
// somewhat intricate.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
#![feature(rustc_attrs)]
use std::cell::Cell;
fn with_signature<'a, T, F>(a: Cell<&'a ()>, b: T, op: F)
where
F: FnOnce(Cell<&'a ()>, T),
{
op(a, b)
}
fn require<'a, T>(_a: &Cell<&'a ()>, _b: &T)
where
T: 'a,
{
}
#[rustc_regions]
fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
with_signature(a, b, |x, y| {
//~^ ERROR `T` does not outlive
//
// See `correct_region`, which explains the point of this
// test. The only difference is that, in the case of this
// function, there is no where clause *anywhere*, and hence we
// get an error (but reported by the closure creator).
require(&x, &y)
//~^ WARNING not reporting region error due to -Znll
})
}
#[rustc_regions]
fn correct_region<'a, T>(a: Cell<&'a ()>, b: T)
where
T: 'a,
{
with_signature(a, b, |x, y| {
// Key point of this test:
//
// The *closure* is being type-checked with all of its free
// regions "universalized". In particular, it does not know
// that `x` has the type `Cell<&'a ()>`, but rather treats it
// as if the type of `x` is `Cell<&'A ()>`, where `'A` is some
// fresh, independent region distinct from the `'a` which
// appears in the environment. The call to `require` here
// forces us then to prove that `T: 'A`, but the closure
// cannot do it on its own. It has to surface this requirement
// to its creator (which knows that `'a == 'A`).
require(&x, &y)
})
}
#[rustc_regions]
fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
where
T: 'b,
{
with_signature(a, b, |x, y| {
//~^ ERROR `T` does not outlive
// See `correct_region`
require(&x, &y)
//~^ WARNING not reporting region error due to -Znll
})
}
#[rustc_regions]
fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
where
T: 'b,
'b: 'a,
{
with_signature(a, b, |x, y| {
// See `correct_region`
require(&x, &y)
})
}
fn main() {}

View file

@ -0,0 +1,191 @@
warning: not reporting region error due to -Znll
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:45:9
|
45 | require(&x, &y)
| ^^^^^^^
warning: not reporting region error due to -Znll
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:79:9
|
79 | require(&x, &y)
| ^^^^^^^
note: External requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26
|
38 | with_signature(a, b, |x, y| {
| __________________________^
39 | | //~^ ERROR `T` does not outlive
40 | | //
41 | | // See `correct_region`, which explains the point of this
... |
46 | | //~^ WARNING not reporting region error due to -Znll
47 | | })
| |_____^
|
= note: defining type: DefId(0/1:16 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]::{{closure}}[0]) with closure substs [
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T))
]
= note: number of external vids: 2
= note: where T: '_#1r
note: External requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26
|
55 | with_signature(a, b, |x, y| {
| __________________________^
56 | | // Key point of this test:
57 | | //
58 | | // The *closure* is being type-checked with all of its free
... |
67 | | require(&x, &y)
68 | | })
| |_____^
|
= note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
]
= note: number of external vids: 3
= note: where T: '_#2r
note: External requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26
|
76 | with_signature(a, b, |x, y| {
| __________________________^
77 | | //~^ ERROR `T` does not outlive
78 | | // See `correct_region`
79 | | require(&x, &y)
80 | | //~^ WARNING not reporting region error due to -Znll
81 | | })
| |_____^
|
= note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
]
= note: number of external vids: 3
= note: where T: '_#2r
note: External requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26
|
90 | with_signature(a, b, |x, y| {
| __________________________^
91 | | // See `correct_region`
92 | | require(&x, &y)
93 | | })
| |_____^
|
= note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: where T: '_#3r
error: `T` does not outlive `'_#3r`
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26
|
38 | with_signature(a, b, |x, y| {
| __________________________^
39 | | //~^ ERROR `T` does not outlive
40 | | //
41 | | // See `correct_region`, which explains the point of this
... |
46 | | //~^ WARNING not reporting region error due to -Znll
47 | | })
| |_____^
note: No external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:1
|
37 | / fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
38 | | with_signature(a, b, |x, y| {
39 | | //~^ ERROR `T` does not outlive
40 | | //
... |
47 | | })
48 | | }
| |_^
|
= note: defining type: DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]) with substs [
T
]
note: No external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:51:1
|
51 | / fn correct_region<'a, T>(a: Cell<&'a ()>, b: T)
52 | | where
53 | | T: 'a,
54 | | {
... |
68 | | })
69 | | }
| |_^
|
= note: defining type: DefId(0/0:7 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]) with substs [
'_#1r,
T
]
error: `T` does not outlive `'_#5r`
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26
|
76 | with_signature(a, b, |x, y| {
| __________________________^
77 | | //~^ ERROR `T` does not outlive
78 | | // See `correct_region`
79 | | require(&x, &y)
80 | | //~^ WARNING not reporting region error due to -Znll
81 | | })
| |_____^
note: No external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:72:1
|
72 | / fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
73 | | where
74 | | T: 'b,
75 | | {
... |
81 | | })
82 | | }
| |_^
|
= note: defining type: DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]) with substs [
'_#1r,
T
]
note: No external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:85:1
|
85 | / fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
86 | | where
87 | | T: 'b,
88 | | 'b: 'a,
... |
93 | | })
94 | | }
| |_^
|
= note: defining type: DefId(0/0:9 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]) with substs [
'_#1r,
'_#2r,
T
]
error: aborting due to 2 previous errors

View file

@ -0,0 +1,41 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Znll -Zborrowck=mir
// Test that we assume that universal types like `T` outlive the
// function body.
#![allow(warnings)]
#![feature(dyn_trait)]
use std::cell::Cell;
// No errors here, because `'a` is local to the body.
fn region_within_body<T>(t: T) {
let some_int = 22;
let cell = Cell::new(&some_int);
outlives(cell, t)
}
// Error here, because T: 'a is not satisfied.
fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
outlives(cell, t)
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `T` does not outlive
}
fn outlives<'a, T>(x: Cell<&'a usize>, y: T)
where
T: 'a,
{
}
fn main() {}

View file

@ -0,0 +1,14 @@
warning: not reporting region error due to -Znll
--> $DIR/ty-param-fn-body.rs:30:5
|
30 | outlives(cell, t)
| ^^^^^^^^
error: `T` does not outlive `'_#4r`
--> $DIR/ty-param-fn-body.rs:30:5
|
30 | outlives(cell, t)
| ^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -0,0 +1,51 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Znll -Zborrowck=mir
#![allow(warnings)]
#![feature(dyn_trait)]
use std::fmt::Debug;
fn no_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
where
T: Debug,
{
x
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `T` does not outlive
}
fn correct_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
where
T: 'a + Debug,
{
x
}
fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
where
T: 'b + Debug,
{
x
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `T` does not outlive
}
fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
where
T: 'b + Debug,
'b: 'a,
{
x
}
fn main() {}

View file

@ -0,0 +1,26 @@
warning: not reporting region error due to -Znll
--> $DIR/ty-param-fn.rs:22:5
|
22 | x
| ^
warning: not reporting region error due to -Znll
--> $DIR/ty-param-fn.rs:38:5
|
38 | x
| ^
error: `T` does not outlive `'_#3r`
--> $DIR/ty-param-fn.rs:22:5
|
22 | x
| ^
error: `T` does not outlive `'_#4r`
--> $DIR/ty-param-fn.rs:38:5
|
38 | x
| ^
error: aborting due to 2 previous errors