add closure requirement tests, improve debugging output

The overall format is now easier to read. Also, There is now graphviz
output, as well as a `#[rustc_regions]` annotation that dumps internal
state.
This commit is contained in:
Niko Matsakis 2017-11-22 17:39:46 -05:00
parent ab1c1bc6bc
commit 05441abd2b
51 changed files with 1702 additions and 77 deletions

View File

@ -14,6 +14,7 @@ use rustc::infer::InferCtxt;
use rustc::ty::{self, RegionKind, RegionVid};
use rustc::util::nodemap::FxHashMap;
use std::collections::BTreeSet;
use std::io;
use transform::MirSource;
use transform::type_check;
use util::liveness::{self, LivenessMode, LivenessResult, LocalSet};
@ -22,6 +23,7 @@ use dataflow::MaybeInitializedLvals;
use dataflow::move_paths::MoveData;
use util as mir_util;
use util::pretty::{self, ALIGN};
use self::mir_util::PassWhere;
mod constraint_generation;
@ -117,8 +119,19 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
let closure_region_requirements = regioncx.solve(infcx, &mir, def_id);
// Dump MIR results into a file, if that is enabled. This let us
// write unit-tests.
dump_mir_results(infcx, liveness, MirSource::item(def_id), &mir, &regioncx);
// write unit-tests, as well as helping with debugging.
dump_mir_results(
infcx,
liveness,
MirSource::item(def_id),
&mir,
&regioncx,
&closure_region_requirements,
);
// We also have a `#[rustc_nll]` annotation that causes us to dump
// information
dump_annotation(infcx, &mir, def_id, &regioncx, &closure_region_requirements);
(regioncx, closure_region_requirements)
}
@ -134,6 +147,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
source: MirSource,
mir: &Mir<'tcx>,
regioncx: &RegionInferenceContext,
closure_region_requirements: &Option<ClosureRegionRequirements>,
) {
if !mir_util::dump_enabled(infcx.tcx, "nll", source) {
return;
@ -168,9 +182,17 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
mir_util::dump_mir(infcx.tcx, None, "nll", &0, source, mir, |pass_where, out| {
match pass_where {
// Before the CFG, dump out the values for each region variable.
PassWhere::BeforeCFG => for region in regioncx.regions() {
writeln!(out, "| {:?}: {}", region, regioncx.region_value_str(region))?;
},
PassWhere::BeforeCFG => {
regioncx.dump_mir(out)?;
if let Some(closure_region_requirements) = closure_region_requirements {
writeln!(out, "|")?;
writeln!(out, "| Free Region Constraints")?;
for_each_region_constraint(closure_region_requirements, &mut |msg| {
writeln!(out, "| {}", msg)
})?;
}
}
// Before each basic block, dump out the values
// that are live on entry to the basic block.
@ -184,13 +206,90 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
&regular_liveness_per_location[&location],
&drop_liveness_per_location[&location],
);
writeln!(out, " | Live variables at {:?}: {}", location, s)?;
writeln!(
out,
"{:ALIGN$} | Live variables on entry to {:?}: {}",
"",
location,
s,
ALIGN = ALIGN
)?;
}
PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {}
}
Ok(())
});
// Also dump the inference graph constraints as a graphviz file.
let _: io::Result<()> = do catch {
let mut file =
pretty::create_dump_file(infcx.tcx, "regioncx.dot", None, "nll", &0, source)?;
regioncx.dump_graphviz(&mut file)
};
}
fn dump_annotation<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
mir_def_id: DefId,
regioncx: &RegionInferenceContext,
closure_region_requirements: &Option<ClosureRegionRequirements>,
) {
let tcx = infcx.tcx;
let base_def_id = tcx.closure_base_def_id(mir_def_id);
if !tcx.has_attr(base_def_id, "rustc_regions") {
return;
}
// When the enclosing function is tagged with `#[rustc_regions]`,
// we dump out various bits of state as warnings. This is useful
// for verifying that the compiler is behaving as expected. These
// warnings focus on the closure region requirements -- for
// viewing the intraprocedural state, the -Zdump-mir output is
// better.
if let Some(closure_region_requirements) = closure_region_requirements {
let mut err = tcx.sess
.diagnostic()
.span_note_diag(mir.span, "External requirements");
regioncx.annotate(&mut err);
err.note(&format!(
"number of external vids: {}",
closure_region_requirements.num_external_vids
));
// Dump the region constraints we are imposing *between* those
// newly created variables.
for_each_region_constraint(closure_region_requirements, &mut |msg| {
err.note(msg);
Ok(())
}).unwrap();
err.emit();
} else {
let mut err = tcx.sess
.diagnostic()
.span_note_diag(mir.span, "No external requirements");
regioncx.annotate(&mut err);
err.emit();
}
}
fn for_each_region_constraint(
closure_region_requirements: &ClosureRegionRequirements,
with_msg: &mut FnMut(&str) -> io::Result<()>,
) -> io::Result<()> {
for req in &closure_region_requirements.outlives_requirements {
with_msg(&format!(
"where {:?}: {:?}",
req.free_region,
req.outlived_free_region,
))?;
}
Ok(())
}
/// Right now, we piggy back on the `ReVar` to store our NLL inference

View File

@ -0,0 +1,48 @@
// 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.
//! As part of the NLL unit tests, you can annotate a function with
//! `#[rustc_regions]`, and we will emit information about the region
//! inference context and -- in particular -- the external constraints
//! that this region imposes on others. The methods in this file
//! handle the part about dumping the inference context internal
//! state.
use rustc::ty;
use rustc_errors::DiagnosticBuilder;
use super::RegionInferenceContext;
impl<'gcx, 'tcx> RegionInferenceContext<'tcx> {
/// Write out our state into the `.mir` files.
pub(crate) fn annotate(&self, err: &mut DiagnosticBuilder<'_>) {
match self.universal_regions.defining_ty.sty {
ty::TyClosure(def_id, substs) => {
err.note(&format!(
"defining type: {:?} with closure substs {:#?}",
def_id,
&substs.substs[..]
));
}
ty::TyFnDef(def_id, substs) => {
err.note(&format!(
"defining type: {:?} with substs {:#?}",
def_id,
&substs[..]
));
}
_ => {
err.note(&format!(
"defining type: {:?}",
self.universal_regions.defining_ty
));
}
}
}
}

View File

@ -0,0 +1,100 @@
// 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.
//! As part of generating the regions, if you enable `-Zdump-mir=nll`,
//! we will generate an annotated copy of the MIR that includes the
//! state of region inference. This code handles emitting the region
//! context internal state.
use std::io::{self, Write};
use super::{Constraint, RegionInferenceContext};
// Room for "'_#NNNNr" before things get misaligned.
// Easy enough to fix if this ever doesn't seem like
// enough.
const REGION_WIDTH: usize = 8;
impl<'tcx> RegionInferenceContext<'tcx> {
/// Write out our state into the `.mir` files.
pub(crate) fn dump_mir(&self, out: &mut Write) -> io::Result<()> {
writeln!(out, "| Free Region Mapping")?;
for region in self.regions() {
if self.definitions[region].is_universal {
let classification = self.universal_regions.region_classification(region).unwrap();
let outlived_by = self.universal_regions.regions_outlived_by(region);
writeln!(
out,
"| {r:rw$} | {c:cw$} | {ob}",
r = format!("{:?}", region),
rw = REGION_WIDTH,
c = format!("{:?}", classification),
cw = 8, // "External" at most
ob = format!("{:?}", outlived_by)
)?;
}
}
writeln!(out, "|")?;
writeln!(out, "| Inferred Region Values")?;
for region in self.regions() {
writeln!(
out,
"| {r:rw$} | {v}",
r = format!("{:?}", region),
rw = REGION_WIDTH,
v = self.region_value_str(region),
)?;
}
writeln!(out, "|")?;
writeln!(out, "| Inference Constraints")?;
self.for_each_constraint(&mut |msg| writeln!(out, "| {}", msg))?;
Ok(())
}
/// Debugging aid: Invokes the `with_msg` callback repeatedly with
/// our internal region constraints. These are dumped into the
/// -Zdump-mir file so that we can figure out why the region
/// inference resulted in the values that it did when debugging.
fn for_each_constraint(
&self,
with_msg: &mut FnMut(&str) -> io::Result<()>,
) -> io::Result<()> {
for region in self.definitions.indices() {
let value = self.region_value_str_from_matrix(&self.liveness_constraints, region);
if value != "{}" {
with_msg(&format!("{:?} live at {}", region, value))?;
}
}
let mut constraints: Vec<_> = self.constraints.iter().collect();
constraints.sort();
for constraint in &constraints {
let Constraint {
sup,
sub,
point,
span,
} = constraint;
with_msg(&format!(
"{:?}: {:?} @ {:?} due to {:?}",
sup,
sub,
point,
span
))?;
}
Ok(())
}
}

View File

@ -0,0 +1,71 @@
// Copyright 2014 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.
//! This module provides linkage between RegionInferenceContext and
//! libgraphviz traits, specialized to attaching borrowck analysis
//! data to rendered labels.
use dot::{self, IntoCow};
use rustc_data_structures::indexed_vec::Idx;
use std::borrow::Cow;
use std::io::{self, Write};
use super::*;
impl<'tcx> RegionInferenceContext<'tcx> {
/// Write out the region constraint graph.
pub(crate) fn dump_graphviz(&self, mut w: &mut Write) -> io::Result<()> {
dot::render(self, &mut w)
}
}
impl<'this, 'tcx> dot::Labeller<'this> for RegionInferenceContext<'tcx> {
type Node = RegionVid;
type Edge = Constraint;
fn graph_id(&'this self) -> dot::Id<'this> {
dot::Id::new(format!("RegionInferenceContext")).unwrap()
}
fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> {
dot::Id::new(format!("r{}", n.index())).unwrap()
}
fn node_shape(&'this self, _node: &RegionVid) -> Option<dot::LabelText<'this>> {
Some(dot::LabelText::LabelStr(Cow::Borrowed("box")))
}
fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
dot::LabelText::LabelStr(format!("{:?}", n).into_cow())
}
fn edge_label(&'this self, e: &Constraint) -> dot::LabelText<'this> {
dot::LabelText::LabelStr(format!("{:?}", e.point).into_cow())
}
}
impl<'this, 'tcx> dot::GraphWalk<'this> for RegionInferenceContext<'tcx> {
type Node = RegionVid;
type Edge = Constraint;
fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> {
let vids: Vec<RegionVid> = self.definitions.indices().collect();
vids.into_cow()
}
fn edges(&'this self) -> dot::Edges<'this, Constraint> {
(&self.constraints[..]).into_cow()
}
// Render `a: b` as `a <- b`, indicating the flow
// of data during inference.
fn source(&'this self, edge: &Constraint) -> RegionVid {
edge.sub
}
fn target(&'this self, edge: &Constraint) -> RegionVid {
edge.sup
}
}

View File

@ -25,6 +25,10 @@ use std::collections::BTreeMap;
use std::fmt;
use syntax_pos::Span;
mod annotation;
mod dump_mir;
mod graphviz;
pub struct RegionInferenceContext<'tcx> {
/// Contains the definition for every region variable. Region
/// variables are identified by their index (`RegionVid`). The

View File

@ -717,6 +717,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_regions", Normal, Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_regions]` attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_error", Whitelisted, Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_error]` attribute \

View File

@ -28,18 +28,18 @@ fn main() {
// START rustc.main.nll.0.mir
// | Live variables on entry to bb0: []
// bb0: {
// | Live variables at bb0[0]: []
// | Live variables on entry to bb0[0]: []
// StorageLive(_1);
// | Live variables at bb0[1]: []
// | Live variables on entry to bb0[1]: []
// _1 = const <std::boxed::Box<T>>::new(const 22usize) -> [return: bb2, unwind: bb1];
// }
// END rustc.main.nll.0.mir
// START rustc.main.nll.0.mir
// | Live variables on entry to bb2: [_1 (drop)]
// bb2: {
// | Live variables at bb2[0]: [_1 (drop)]
// | Live variables on entry to bb2[0]: [_1 (drop)]
// StorageLive(_2);
// | Live variables at bb2[1]: [_1 (drop)]
// | Live variables on entry to bb2[1]: [_1 (drop)]
// _2 = const can_panic() -> [return: bb3, unwind: bb4];
// }
// END rustc.main.nll.0.mir

View File

@ -27,15 +27,15 @@ fn main() {
// START rustc.main.nll.0.mir
// | Live variables on entry to bb2: []
// bb2: {
// | Live variables at bb2[0]: []
// | Live variables on entry to bb2[0]: []
// _1 = const 55usize;
// | Live variables at bb2[1]: [_1]
// | Live variables on entry to bb2[1]: [_1]
// StorageLive(_3);
// | Live variables at bb2[2]: [_1]
// | Live variables on entry to bb2[2]: [_1]
// StorageLive(_4);
// | Live variables at bb2[3]: [_1]
// | Live variables on entry to bb2[3]: [_1]
// _4 = _1;
// | Live variables at bb2[4]: [_4]
// | Live variables on entry to bb2[4]: [_4]
// _3 = const use_x(move _4) -> [return: bb3, unwind: bb1];
// }
// END rustc.main.nll.0.mir

View File

@ -31,18 +31,18 @@ fn main() {
// START rustc.main.nll.0.mir
// | Live variables on entry to bb3: [_1]
// bb3: {
// | Live variables at bb3[0]: [_1]
// | Live variables on entry to bb3[0]: [_1]
// StorageLive(_4);
// | Live variables at bb3[1]: [_1]
// | Live variables on entry to bb3[1]: [_1]
// _4 = _1;
// | Live variables at bb3[2]: [_4]
// | Live variables on entry to bb3[2]: [_4]
// _3 = const make_live(move _4) -> [return: bb5, unwind: bb1];
// }
// END rustc.main.nll.0.mir
// START rustc.main.nll.0.mir
// | Live variables on entry to bb4: []
// bb4: {
// | Live variables at bb4[0]: []
// | Live variables on entry to bb4[0]: []
// _5 = const make_dead() -> [return: bb6, unwind: bb1];
// }
// END rustc.main.nll.0.mir

View File

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

View File

@ -28,11 +28,10 @@ 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]}
// | '_#6r | {bb0[6], bb0[7], bb0[8], bb0[9], bb0[10], bb0[11], bb0[12], bb0[13], bb0[14]}
// ...
// | '_#8r | {bb0[11], bb0[12], bb0[13], bb0[14]}
// ...
// | '_#8r: {bb0[11], bb0[12], bb0[13], bb0[14]}
// END rustc.main.nll.0.mir
// START rustc.main.nll.0.mir
// let _2: &'_#6r mut i32;
// ...
// let _4: &'_#8r mut i32;

View File

@ -31,26 +31,26 @@ 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]}
// | '_#1r | {bb2[0], bb2[1], bb3[0], bb3[1]}
// | '_#2r | {bb2[1], bb3[0], bb3[1]}
// ...
// let _2: &'_#2r usize;
// END rustc.main.nll.0.mir
// START rustc.main.nll.0.mir
// bb2: {
// | Live variables at bb2[0]: [_1, _3]
// | Live variables on entry to bb2[0]: [_1, _3]
// _2 = &'_#1r _1[_3];
// | Live variables at bb2[1]: [_2]
// | Live variables on entry to bb2[1]: [_2]
// switchInt(const true) -> [0u8: bb4, otherwise: bb3];
// }
// END rustc.main.nll.0.mir
// START rustc.main.nll.0.mir
// bb3: {
// | Live variables at bb3[0]: [_2]
// | Live variables on entry to bb3[0]: [_2]
// StorageLive(_7);
// | Live variables at bb3[1]: [_2]
// | Live variables on entry to bb3[1]: [_2]
// _7 = (*_2);
// | Live variables at bb3[2]: [_7]
// | Live variables on entry to bb3[2]: [_7]
// _6 = const use_x(move _7) -> [return: bb5, unwind: bb1];
// }
// END rustc.main.nll.0.mir

View File

@ -44,5 +44,5 @@ 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]}
// | '_#5r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1]}
// END rustc.main.nll.0.mir

View File

@ -46,5 +46,5 @@ 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]}
// | '_#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]}
// END rustc.main.nll.0.mir

View File

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

View File

@ -32,9 +32,9 @@ 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]}
// | '_#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]}
// END rustc.main.nll.0.mir
// START rustc.main.nll.0.mir
// let _2: &'_#2r usize;

View File

@ -0,0 +1,50 @@
// 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 a structure which tries to store a pointer to `y` into
// `p` (indirectly) fails to compile.
#![feature(rustc_attrs)]
struct SomeStruct<'a, 'b: 'a> {
p: &'a mut &'b i32,
y: &'b i32,
}
fn test() {
let x = 44;
let mut p = &x;
{
let y = 22;
let closure = SomeStruct {
p: &mut p,
y: &y,
};
closure.invoke();
}
//~^ ERROR borrowed value does not live long enough [E0597]
deref(p);
}
impl<'a, 'b> SomeStruct<'a, 'b> {
fn invoke(self) {
*self.p = self.y;
}
}
fn deref(_: &i32) { }
fn main() { }

View File

@ -0,0 +1,13 @@
error[E0597]: borrowed value does not live long enough
--> $DIR/capture-ref-in-struct.rs:36:6
|
28 | let y = 22;
| - temporary value created here
...
36 | }
| ^ temporary value dropped here while still borrowed
|
= note: consider using a `let` binding to increase its lifetime
error: aborting due to previous error

View File

@ -0,0 +1,48 @@
// 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 closure that:
//
// - takes an argument `y`
// - stores `y` into another, longer-lived spot
//
// *but* the signature of the closure doesn't indicate that `y` lives
// long enough for that. The closure reports the error (and hence we
// see it before the closure's "external requirements" report).
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
#[rustc_regions]
fn test() {
let x = 44;
let mut p = &x;
{
let y = 22;
let mut closure = expect_sig(|p, y| *p = y);
//~^ ERROR free region `'_#4r` does not outlive free region `'_#3r`
//~| WARNING not reporting region error due to -Znll
closure(&mut p, &y);
}
deref(p);
}
fn expect_sig<F>(f: F) -> F
where F: FnMut(&mut &i32, &i32)
{
f
}
fn deref(_p: &i32) { }
fn main() { }

View File

@ -0,0 +1,40 @@
warning: not reporting region error due to -Znll
--> $DIR/escape-argument-callee.rs:31:50
|
31 | let mut closure = expect_sig(|p, y| *p = y);
| ^
error: free region `'_#4r` does not outlive free region `'_#3r`
--> $DIR/escape-argument-callee.rs:31:45
|
31 | let mut closure = expect_sig(|p, y| *p = y);
| ^^^^^^
note: External requirements
--> $DIR/escape-argument-callee.rs:31:38
|
31 | let mut closure = expect_sig(|p, y| *p = y);
| ^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:9 ~ escape_argument_callee[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(7666))) mut &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(7667))) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0(7668))) i32))
]
= note: number of external vids: 1
note: No external requirements
--> $DIR/escape-argument-callee.rs:25:1
|
25 | / fn test() {
26 | | let x = 44;
27 | | let mut p = &x;
28 | |
... |
37 | | deref(p);
38 | | }
| |_^
|
= note: defining type: DefId(0/0:3 ~ escape_argument_callee[317d]::test[0]) with substs []
error: aborting due to previous error

View File

@ -0,0 +1,50 @@
// 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 closure that:
//
// - takes an argument `y`
// - stores `y` into another, longer-lived spot
//
// but is invoked with a spot that doesn't live long
// enough to store `y`.
//
// The error is reported in the caller: invoking the closure links the
// lifetime of the borrow that is given as `y` and forces it to live
// too long.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
#[rustc_regions]
fn test() {
let x = 44;
let mut p = &x;
{
let y = 22;
let mut closure = expect_sig(|p, y| *p = y);
closure(&mut p, &y);
}
//~^ ERROR borrowed value does not live long enough [E0597]
deref(p);
}
fn expect_sig<F>(f: F) -> F
where F: for<'a, 'b> FnMut(&'a mut &'b i32, &'b i32)
{
f
}
fn deref(_p: &i32) { }
fn main() { }

View File

@ -0,0 +1,39 @@
note: External requirements
--> $DIR/escape-argument.rs:34:38
|
34 | let mut closure = expect_sig(|p, y| *p = y);
| ^^^^^^^^^^^^^
|
= note: defining type: DefId(0/1:9 ~ escape_argument[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(8634))) mut &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(8635))) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(8635))) i32))
]
= note: number of external vids: 1
note: No external requirements
--> $DIR/escape-argument.rs:28:1
|
28 | / fn test() {
29 | | let x = 44;
30 | | let mut p = &x;
31 | |
... |
39 | | deref(p);
40 | | }
| |_^
|
= note: defining type: DefId(0/0:3 ~ escape_argument[317d]::test[0]) with substs []
error[E0597]: borrowed value does not live long enough
--> $DIR/escape-argument.rs:36:6
|
33 | let y = 22;
| - temporary value created here
...
36 | }
| ^ temporary value dropped here while still borrowed
|
= note: consider using a `let` binding to increase its lifetime
error: aborting due to previous error

View File

@ -0,0 +1,43 @@
// 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.
// As in via-upvar, test closure that:
//
// - captures a variable `y`
// - stores reference to `y` into another, longer-lived spot
//
// except that the closure does so via a second closure.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
#[rustc_regions]
fn test() {
let x = 44;
let mut p = &x;
{
let y = 22;
let mut closure = || {
let mut closure1 = || p = &y;
closure1();
};
closure();
} //~ ERROR borrowed value does not live long enough
deref(p);
}
fn deref(_p: &i32) { }
fn main() { }

View File

@ -0,0 +1,61 @@
note: External requirements
--> $DIR/escape-upvar-nested.rs:31:32
|
31 | let mut closure1 = || p = &y;
| ^^^^^^^^^
|
= note: defining type: DefId(0/1:10 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]::{{closure}}[0]) with closure substs [
i16,
extern "rust-call" fn(()),
&'_#1r mut &'_#2r i32,
&'_#3r i32
]
= note: number of external vids: 4
= note: where '_#3r: '_#2r
note: External requirements
--> $DIR/escape-upvar-nested.rs:30:27
|
30 | let mut closure = || {
| ___________________________^
31 | | let mut closure1 = || p = &y;
32 | | closure1();
33 | | };
| |_________^
|
= note: defining type: DefId(0/1:9 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
extern "rust-call" fn(()),
&'_#1r mut &'_#2r i32,
&'_#3r i32
]
= note: number of external vids: 4
= note: where '_#3r: '_#2r
note: No external requirements
--> $DIR/escape-upvar-nested.rs:23:1
|
23 | / fn test() {
24 | | let x = 44;
25 | | let mut p = &x;
26 | |
... |
38 | | deref(p);
39 | | }
| |_^
|
= note: defining type: DefId(0/0:3 ~ escape_upvar_nested[317d]::test[0]) with substs []
error[E0597]: borrowed value does not live long enough
--> $DIR/escape-upvar-nested.rs:36:6
|
28 | let y = 22;
| - temporary value created here
...
36 | } //~ ERROR borrowed value does not live long enough
| ^ temporary value dropped here while still borrowed
|
= note: consider using a `let` binding to increase its lifetime
error: aborting due to previous error

View File

@ -0,0 +1,35 @@
// 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 closure that:
// - captures a variable `y`
// - stores reference to `y` into another, longer-lived spot
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
#[rustc_regions]
fn test() {
let x = 44;
let mut p = &x;
{
let y = 22;
let mut closure = || p = &y;
closure();
} //~ ERROR borrowed value does not live long enough
deref(p);
}
fn deref(_p: &i32) { }
fn main() { }

View File

@ -0,0 +1,42 @@
note: External requirements
--> $DIR/escape-upvar-ref.rs:26:27
|
26 | let mut closure = || p = &y;
| ^^^^^^^^^
|
= note: defining type: DefId(0/1:9 ~ escape_upvar_ref[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
extern "rust-call" fn(()),
&'_#1r mut &'_#2r i32,
&'_#3r i32
]
= note: number of external vids: 4
= note: where '_#3r: '_#2r
note: No external requirements
--> $DIR/escape-upvar-ref.rs:20:1
|
20 | / fn test() {
21 | | let x = 44;
22 | | let mut p = &x;
23 | |
... |
30 | | deref(p);
31 | | }
| |_^
|
= note: defining type: DefId(0/0:3 ~ escape_upvar_ref[317d]::test[0]) with substs []
error[E0597]: borrowed value does not live long enough
--> $DIR/escape-upvar-ref.rs:28:6
|
25 | let y = 22;
| - temporary value created here
...
28 | } //~ ERROR borrowed value does not live long enough
| ^ temporary value dropped here while still borrowed
|
= note: consider using a `let` binding to increase its lifetime
error: aborting due to previous error

View File

@ -0,0 +1,63 @@
// 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 where we fail to approximate due to demanding a postdom
// relationship between our upper bounds.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
use std::cell::Cell;
// Callee knows that:
//
// 'x: 'a
// 'x: 'b
// 'c: 'y
//
// we have to prove that `'x: 'y`. We currently can only approximate
// via a postdominator -- hence we fail to choose between `'a` and
// `'b` here and report the error in the closure.
fn establish_relationships<'a, 'b, 'c, F>(
_cell_a: Cell<&'a u32>,
_cell_b: Cell<&'b u32>,
_cell_c: Cell<&'c u32>,
_closure: F,
) where
F: for<'x, 'y> FnMut(
Cell<&'a &'x u32>, // shows that 'x: 'a
Cell<&'b &'x u32>, // shows that 'x: 'b
Cell<&'y &'c u32>, // shows that 'c: 'y
Cell<&'x u32>,
Cell<&'y u32>,
),
{
}
fn demand_y<'x, 'y>(_cell_x: Cell<&'x u32>, _cell_y: Cell<&'y u32>, _y: &'y u32) {}
#[rustc_regions]
fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
establish_relationships(
cell_a,
cell_b,
cell_c,
|_outlives1, _outlives2, _outlives3, x, y| {
// Only works if 'x: 'y:
let p = x.get();
//~^ WARN not reporting region error due to -Znll
demand_y(x, y, p)
//~^ ERROR free region `'_#5r` does not outlive free region `'_#6r`
},
);
}
fn main() {}

View File

@ -0,0 +1,46 @@
warning: not reporting region error due to -Znll
--> $DIR/propagate-approximated-fail-no-postdom.rs:55:21
|
55 | let p = x.get();
| ^^^^^^^
error: free region `'_#5r` does not outlive free region `'_#6r`
--> $DIR/propagate-approximated-fail-no-postdom.rs:57:25
|
57 | demand_y(x, y, p)
| ^
note: 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`
59 | | },
| |_________^
|
= note: defining type: DefId(0/1:20 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(9523))) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(9523))) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(9524))) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(9523))) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(9524))) u32>))
]
= note: number of external vids: 4
note: No external requirements
--> $DIR/propagate-approximated-fail-no-postdom.rs:48:1
|
48 | / fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
49 | | establish_relationships(
50 | | cell_a,
51 | | cell_b,
... |
60 | | );
61 | | }
| |_^
|
= note: defining type: DefId(0/0:6 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]) with substs []
error: aborting due to previous error

View File

@ -0,0 +1,64 @@
// 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.
// Rather convoluted setup where we infer a relationship between two
// free regions in the closure signature (`'a` and `'b`) on the basis
// of a relationship between two bound regions (`'x` and `'y`).
//
// The idea is that, thanks to invoking `demand_y`, `'x: 'y` must
// hold, where `'x` and `'y` are bound regions. The closure can't
// prove that directly, and because `'x` and `'y` are bound it cannot
// ask the caller to prove it either. But it has bounds on `'x` and
// `'y` in terms of `'a` and `'b`, and it can propagate a relationship
// between `'a` and `'b` to the caller.
//
// Note: the use of `Cell` here is to introduce invariance. One less
// variable.
//
// FIXME: The `supply` function *ought* to generate an error, but it
// currently does not. This is I believe a shortcoming of the MIR type
// checker: the closure inference is expressing the correct
// requirement, as you can see from the `#[rustc_regions]` output.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
use std::cell::Cell;
// Callee knows that:
//
// 'x: 'a
// 'b: 'y
//
// so if we are going to ensure that `'x: 'y`, then `'a: 'b` must
// hold.
fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
where
F: for<'x, 'y> FnMut(
&Cell<&'a &'x u32>, // shows that 'x: 'a
&Cell<&'y &'b u32>, // shows that 'b: 'y
&Cell<&'x u32>,
&Cell<&'y u32>,
),
{
}
fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
#[rustc_regions]
fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
// Only works if 'x: 'y:
demand_y(x, y, x.get())
});
}
fn main() {}

View File

@ -0,0 +1,36 @@
warning: not reporting region error due to -Znll
--> $DIR/propagate-approximated-ref.rs:60:9
|
60 | demand_y(x, y, x.get())
| ^^^^^^^^^^^^^^^^^^^^^^^
note: External requirements
--> $DIR/propagate-approximated-ref.rs:58:47
|
58 | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
| _______________________________________________^
59 | | // Only works if 'x: 'y:
60 | | demand_y(x, y, x.get())
61 | | });
| |_____^
|
= note: defining type: DefId(0/1:18 ~ propagate_approximated_ref[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(7696))) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(7697))) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0(7698))) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1(7699))) &'_#2r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2(9524))) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(7697))) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't3(9525))) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1(7699))) u32>))
]
= note: number of external vids: 3
= note: where '_#1r: '_#2r
note: No external requirements
--> $DIR/propagate-approximated-ref.rs:57:1
|
57 | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
58 | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
59 | | // Only works if 'x: 'y:
60 | | demand_y(x, y, x.get())
61 | | });
62 | | }
| |_^
|
= note: defining type: DefId(0/0:6 ~ propagate_approximated_ref[317d]::supply[0]) with substs []

View File

@ -0,0 +1,47 @@
// 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 a case where we fail to approximate one of the regions and
// hence report an error while checking the closure.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
use std::cell::Cell;
// Callee knows that:
//
// 'b: 'y
//
// but this doesn't really help us in proving that `'x: 'y`, so closure gets an error.
fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
where
F: for<'x, 'y> FnMut(
&Cell<&'y &'b u32>, // shows that 'b: 'y
&Cell<&'x u32>,
&Cell<&'y u32>,
),
{
}
fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
#[rustc_regions]
fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
// Only works if 'x: 'y:
demand_y(x, y, x.get())
//~^ WARN not reporting region error due to -Znll
//~| ERROR free region `'_#6r` does not outlive free region `'_#4r`
});
}
fn main() {}

View File

@ -0,0 +1,46 @@
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:21
|
41 | demand_y(x, y, x.get())
| ^
note: 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(7695))) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(7696))) &'_#1r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0(7697))) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1(9522))) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2(9523))) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(7696))) u32>))
]
= note: number of external vids: 2
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

@ -0,0 +1,46 @@
// 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 a case where we are forced to approximate one end-point with
// `'static`. Note that `'static` shows up in the stderr output as `'0`.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
use std::cell::Cell;
// Callee knows that:
//
// 'x: 'a
//
// so the only way we can ensure that `'x: 'y` is to show that
// `'a: 'static`.
fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
where
F: for<'x, 'y> FnMut(
&Cell<&'a &'x u32>, // shows that 'x: 'a
&Cell<&'x u32>,
&Cell<&'y u32>,
),
{
}
fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
#[rustc_regions]
fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
// Only works if 'x: 'y:
demand_y(x, y, x.get())
});
}
fn main() {}

View File

@ -0,0 +1,36 @@
warning: not reporting region error due to -Znll
--> $DIR/propagate-approximated-to-static.rs:42:9
|
42 | demand_y(x, y, x.get())
| ^^^^^^^^^^^^^^^^^^^^^^^
note: External requirements
--> $DIR/propagate-approximated-to-static.rs:40:47
|
40 | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
| _______________________________________________^
41 | | // Only works if 'x: 'y:
42 | | demand_y(x, y, x.get())
43 | | });
| |_____^
|
= note: defining type: DefId(0/1:18 ~ propagate_approximated_to_static[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(7695))) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(7696))) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0(7697))) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(7696))) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1(9522))) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2(9523))) u32>))
]
= note: number of external vids: 2
= note: where '_#1r: '_#0r
note: No external requirements
--> $DIR/propagate-approximated-to-static.rs:39:1
|
39 | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
40 | | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
41 | | // Only works if 'x: 'y:
42 | | demand_y(x, y, x.get())
43 | | });
44 | | }
| |_^
|
= note: defining type: DefId(0/0:6 ~ propagate_approximated_to_static[317d]::supply[0]) with substs []

View File

@ -0,0 +1,52 @@
// 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.
// A simpler variant of `outlives-from-argument` where cells are
// passed by value.
//
// This is simpler because there are no "extraneous" region
// relationships. In the 'main' variant, there are a number of
// anonymous regions as well.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
use std::cell::Cell;
// Callee knows that:
//
// 'x: 'a
// 'b: 'y
//
// so if we are going to ensure that `'x: 'y`, then `'a: 'b` must
// hold.
fn establish_relationships<'a, 'b, F>(_cell_a: Cell<&'a u32>, _cell_b: Cell<&'b u32>, _closure: F)
where
F: for<'x, 'y> FnMut(
Cell<&'a &'x u32>, // shows that 'x: 'a
Cell<&'y &'b u32>, // shows that 'b: 'y
Cell<&'x u32>,
Cell<&'y u32>,
),
{
}
fn demand_y<'x, 'y>(_outlives1: Cell<&&'x u32>, _outlives2: Cell<&'y &u32>, _y: &'y u32) {}
#[rustc_regions]
fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
// Only works if 'x: 'y:
demand_y(outlives1, outlives2, x.get())
});
}
fn main() {}

View File

@ -0,0 +1,36 @@
warning: not reporting region error due to -Znll
--> $DIR/propagate-approximated-val.rs:48:9
|
48 | demand_y(outlives1, outlives2, x.get())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: External requirements
--> $DIR/propagate-approximated-val.rs:46:45
|
46 | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
| _____________________________________________^
47 | | // Only works if 'x: 'y:
48 | | demand_y(outlives1, outlives2, x.get())
49 | | });
| |_____^
|
= note: defining type: DefId(0/1:18 ~ propagate_approximated_val[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(9519))) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(9520))) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(9519))) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(9520))) u32>))
]
= note: number of external vids: 3
= note: where '_#1r: '_#2r
note: No external requirements
--> $DIR/propagate-approximated-val.rs:45:1
|
45 | / fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
46 | | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
47 | | // Only works if 'x: 'y:
48 | | demand_y(outlives1, outlives2, x.get())
49 | | });
50 | | }
| |_^
|
= note: defining type: DefId(0/0:6 ~ propagate_approximated_val[317d]::test[0]) with substs []

View File

@ -0,0 +1,59 @@
// 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 where we might in theory be able to see that the relationship
// between two bound regions is true within closure and hence have no
// need to propagate; but in fact we do because identity of free
// regions is erased.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
use std::cell::Cell;
// In theory, callee knows that:
//
// 'x: 'a
// 'a: 'y
//
// and hence could satisfy that `'x: 'y` locally. However, in our
// checking, we ignore the precise free regions that come into the
// region and just assign each position a distinct universally bound
// region. Hence, we propagate a constraint to our caller that will
// wind up being solvable.
fn establish_relationships<'a, F>(
_cell_a: Cell<&'a u32>,
_closure: F,
) where
F: for<'x, 'y> FnMut(
Cell<&'a &'x u32>, // shows that 'x: 'a
Cell<&'y &'a u32>, // shows that 'a: 'y
Cell<&'x u32>,
Cell<&'y u32>,
),
{
}
fn demand_y<'x, 'y>(_cell_x: Cell<&'x u32>, _cell_y: Cell<&'y u32>, _y: &'y u32) {}
#[rustc_regions]
fn supply<'a>(cell_a: Cell<&'a u32>) {
establish_relationships(
cell_a,
|_outlives1, _outlives2, x, y| {
// Only works if 'x: 'y:
let p = x.get();
demand_y(x, y, p)
},
);
}
fn main() {}

View File

@ -0,0 +1,37 @@
warning: not reporting region error due to -Znll
--> $DIR/propagate-despite-same-free-region.rs:53:21
|
53 | let p = x.get();
| ^^^^^^^
note: External requirements
--> $DIR/propagate-despite-same-free-region.rs:51:9
|
51 | / |_outlives1, _outlives2, x, y| {
52 | | // Only works if 'x: 'y:
53 | | let p = x.get();
54 | | demand_y(x, y, p)
55 | | },
| |_________^
|
= note: defining type: DefId(0/1:16 ~ propagate_despite_same_free_region[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(9518))) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(9519))) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(9518))) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(9519))) u32>))
]
= note: number of external vids: 3
= note: where '_#1r: '_#2r
note: No external requirements
--> $DIR/propagate-despite-same-free-region.rs:48:1
|
48 | / fn supply<'a>(cell_a: Cell<&'a u32>) {
49 | | establish_relationships(
50 | | cell_a,
51 | | |_outlives1, _outlives2, x, y| {
... |
56 | | );
57 | | }
| |_^
|
= note: defining type: DefId(0/0:6 ~ propagate_despite_same_free_region[317d]::supply[0]) with substs []

View File

@ -0,0 +1,26 @@
// 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.
// Basic test for free regions in the NLL code. This test ought to
// report an error due to a reborrowing constraint. Right now, we get
// a variety of errors from the older, AST-based machinery (notably
// borrowck), and then we get the NLL error at the end.
// compile-flags:-Znll -Zborrowck=mir
fn foo<'a>(x: &'a u32) -> &'static u32
where 'static: 'a
{
&*x
//~^ WARN not reporting region error due to -Znll
//~| ERROR free region `'a` does not outlive free region `'static`
}
fn main() { }

View File

@ -0,0 +1,14 @@
warning: not reporting region error due to -Znll
--> $DIR/region-ebr-does-not-outlive-static.rs:21:5
|
21 | &*x
| ^^^
error: free region `'a` does not outlive free region `'static`
--> $DIR/region-ebr-does-not-outlive-static.rs:21:5
|
21 | &*x
| ^^^
error: aborting due to previous error

View File

@ -0,0 +1,25 @@
// 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.
// Basic test for free regions in the NLL code. This test ought to
// report an error due to a reborrowing constraint. Right now, we get
// a variety of errors from the older, AST-based machinery (notably
// borrowck), and then we get the NLL error at the end.
// compile-flags:-Znll
fn foo(x: &u32) -> &'static u32 {
&*x
//~^ WARN not reporting region error due to -Znll
//~| ERROR `*x` does not live long enough
//~| ERROR free region `'_#1r` does not outlive free region `'static`
}
fn main() { }

View File

@ -0,0 +1,32 @@
warning: not reporting region error due to -Znll
--> $DIR/region-lbr-anon-does-not-outlive-static.rs:19:5
|
19 | &*x
| ^^^
error[E0597]: `*x` does not live long enough
--> $DIR/region-lbr-anon-does-not-outlive-static.rs:19:6
|
19 | &*x
| ^^ does not live long enough
|
= note: borrowed value must be valid for the static lifetime...
note: ...but borrowed value is only valid for the anonymous lifetime #1 defined on the function body at 18:1
--> $DIR/region-lbr-anon-does-not-outlive-static.rs:18:1
|
18 | / fn foo(x: &u32) -> &'static u32 {
19 | | &*x
20 | | //~^ WARN not reporting region error due to -Znll
21 | | //~| ERROR `*x` does not live long enough
22 | | //~| ERROR free region `'_#1r` does not outlive free region `'static`
23 | | }
| |_^
error: free region `'_#1r` does not outlive free region `'static`
--> $DIR/region-lbr-anon-does-not-outlive-static.rs:19:5
|
19 | &*x
| ^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,24 @@
// 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.
// Basic test for free regions in the NLL code. This test ought to
// report an error due to a reborrowing constraint. Right now, we get
// a variety of errors from the older, AST-based machinery (notably
// borrowck), and then we get the NLL error at the end.
// compile-flags:-Znll -Zborrowck=mir
fn foo<'a>(x: &'a u32) -> &'static u32 {
&*x
//~^ WARN not reporting region error due to -Znll
//~| ERROR free region `'_#1r` does not outlive free region `'static`
}
fn main() { }

View File

@ -0,0 +1,14 @@
warning: not reporting region error due to -Znll
--> $DIR/region-lbr-named-does-not-outlive-static.rs:19:5
|
19 | &*x
| ^^^
error: free region `'_#1r` does not outlive free region `'static`
--> $DIR/region-lbr-named-does-not-outlive-static.rs:19:5
|
19 | &*x
| ^^^
error: aborting due to previous error

View File

@ -13,12 +13,12 @@
// a variety of errors from the older, AST-based machinery (notably
// borrowck), and then we get the NLL error at the end.
// compile-flags:-Znll
// compile-flags:-Znll -Zborrowck=mir
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 {
&*x //~ ERROR free region `'a` does not outlive `'b`
//~^ ERROR `*x` does not live long enough
//~| WARN not reporting region error due to -Znll
&*x
//~^ WARN not reporting region error due to -Znll
//~| ERROR free region `'_#1r` does not outlive free region `'_#2r`
}
fn main() { }

View File

@ -0,0 +1,14 @@
warning: not reporting region error due to -Znll
--> $DIR/region-lbr1-does-not-outlive-ebr2.rs:19:5
|
19 | &*x
| ^^^
error: free region `'_#1r` does not outlive free region `'_#2r`
--> $DIR/region-lbr1-does-not-outlive-ebr2.rs:19:5
|
19 | &*x
| ^^^
error: aborting due to previous error

View File

@ -0,0 +1,23 @@
// 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.
// Basic test for free regions in the NLL code. This test does not
// report an error because of the (implied) bound that `'b: 'a`.
// compile-flags:-Znll
// must-compile-successfully
#![allow(warnings)]
fn foo<'a, 'b>(x: &'a &'b u32) -> &'a u32 {
&**x
}
fn main() { }

View File

@ -0,0 +1,34 @@
// 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 closure that takes two references and is supposed to return
// the first, but actually returns the second. This should fail within
// the closure.
// compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
#[rustc_regions]
fn test() {
expect_sig(|a, b| b); // ought to return `a`
//~^ WARN not reporting region error due to -Znll
//~| ERROR free region `'_#3r` does not outlive free region `'_#2r`
}
fn expect_sig<F>(f: F) -> F
where F: for<'a> FnMut(&'a i32, &i32) -> &'a i32
{
f
}
fn deref(_p: &i32) { }
fn main() { }

View File

@ -0,0 +1,38 @@
warning: not reporting region error due to -Znll
--> $DIR/return-wrong-bound-region.rs:21:23
|
21 | expect_sig(|a, b| b); // ought to return `a`
| ^
error: free region `'_#3r` does not outlive free region `'_#2r`
--> $DIR/return-wrong-bound-region.rs:21:23
|
21 | expect_sig(|a, b| b); // ought to return `a`
| ^
note: External requirements
--> $DIR/return-wrong-bound-region.rs:21:16
|
21 | expect_sig(|a, b| b); // ought to return `a`
| ^^^^^^^^
|
= note: defining type: DefId(0/1:9 ~ return_wrong_bound_region[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(7661))) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's(8630))) i32)) -> &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r(7661))) i32
]
= note: number of external vids: 1
note: No external requirements
--> $DIR/return-wrong-bound-region.rs:20:1
|
20 | / fn test() {
21 | | expect_sig(|a, b| b); // ought to return `a`
22 | | //~^ WARN not reporting region error due to -Znll
23 | | //~| ERROR free region `'_#3r` does not outlive free region `'_#2r`
24 | | }
| |_^
|
= note: defining type: DefId(0/0:3 ~ return_wrong_bound_region[317d]::test[0]) with substs []
error: aborting due to previous error

View File

@ -0,0 +1,87 @@
note: External requirements
--> $DIR/via-upvar-nested.rs:24:28
|
24 | let closure1 = || p = &y;
| ^^^^^^^^^
|
= note: _0: ()
= note: _1: &mut [closure@$DIR/via-upvar-nested.rs:24:28: 24:37 p:&mut &i32, y:&i32]
note: External requirements
--> $DIR/via-upvar-nested.rs:23:27
|
23 | let mut closure = || {
| ___________________________^
24 | | let closure1 = || p = &y;
25 | | closure1();
26 | | };
| |_________^
|
= note: _0: ()
= note: _1: &mut [closure@$DIR/via-upvar-nested.rs:23:27: 26:10 p:&mut &i32, y:&i32]
= note: where '_#1r: '_#2r
error[E0596]: cannot borrow immutable item `closure1` as mutable (Mir)
--> $DIR/via-upvar-nested.rs:25:13
|
25 | closure1();
| ^^^^^^^^ cannot borrow as mutable
error[E0597]: `**y` does not live long enough (Ast)
--> $DIR/via-upvar-nested.rs:24:36
|
24 | let closure1 = || p = &y;
| -- ^ does not live long enough
| |
| capture occurs here
...
29 | }
| - borrowed value only lives until here
...
32 | }
| - borrowed value needs to live until here
error[E0596]: cannot borrow immutable local variable `closure1` as mutable (Ast)
--> $DIR/via-upvar-nested.rs:25:13
|
24 | let closure1 = || p = &y;
| -------- consider changing this to `mut closure1`
25 | closure1();
| ^^^^^^^^ cannot borrow mutably
note: No external requirements
--> $DIR/via-upvar-nested.rs:16:1
|
16 | / fn test() {
17 | | let x = 44;
18 | | let mut p = &x;
19 | |
... |
31 | | deref(p);
32 | | }
| |_^
error[E0597]: borrowed value does not live long enough (Mir)
--> $DIR/via-upvar-nested.rs:29:6
|
21 | let y = 22;
| - temporary value created here
...
29 | }
| ^ temporary value dropped here while still borrowed
|
= note: consider using a `let` binding to increase its lifetime
error[E0502]: cannot borrow `(*p)` as immutable because it is also borrowed as mutable (Mir)
--> $DIR/via-upvar-nested.rs:31:11
|
23 | let mut closure = || {
| -- mutable borrow occurs here
24 | let closure1 = || p = &y;
| - previous borrow occurs due to use of `(*p)` in closure
...
31 | deref(p);
| ^ immutable borrow occurs here
error: aborting due to 5 previous errors

View File

@ -1,31 +0,0 @@
warning: not reporting region error due to -Znll
--> $DIR/named-region-basic.rs:19:5
|
19 | &*x //~ ERROR free region `'a` does not outlive `'b`
| ^^^
error[E0597]: `*x` does not live long enough
--> $DIR/named-region-basic.rs:19:6
|
19 | &*x //~ ERROR free region `'a` does not outlive `'b`
| ^^ does not live long enough
|
= note: borrowed value must be valid for the static lifetime...
note: ...but borrowed value is only valid for the lifetime 'a as defined on the function body at 18:1
--> $DIR/named-region-basic.rs:18:1
|
18 | / fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 {
19 | | &*x //~ ERROR free region `'a` does not outlive `'b`
20 | | //~^ ERROR `*x` does not live long enough
21 | | //~| WARN not reporting region error due to -Znll
22 | | }
| |_^
error: free region `'a` does not outlive `'b`
--> $DIR/named-region-basic.rs:19:5
|
19 | &*x //~ ERROR free region `'a` does not outlive `'b`
| ^^^
error: aborting due to 2 previous errors