diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 3d698abc83f4..4ff299efb955 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -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, ®ioncx); + // write unit-tests, as well as helping with debugging. + dump_mir_results( + infcx, + liveness, + MirSource::item(def_id), + &mir, + ®ioncx, + &closure_region_requirements, + ); + + // We also have a `#[rustc_nll]` annotation that causes us to dump + // information + dump_annotation(infcx, &mir, def_id, ®ioncx, &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, ) { 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>( ®ular_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, +) { + 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 diff --git a/src/librustc_mir/borrow_check/nll/region_infer/annotation.rs b/src/librustc_mir/borrow_check/nll/region_infer/annotation.rs new file mode 100644 index 000000000000..906efaef887c --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/region_infer/annotation.rs @@ -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 or the MIT license +// , 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 + )); + } + } + } +} diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs new file mode 100644 index 000000000000..5477308bde94 --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs @@ -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 or the MIT license +// , 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(()) + } +} + diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs new file mode 100644 index 000000000000..7923b159d80d --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs @@ -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 or the MIT license +// , 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> { + 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 = 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 + } +} diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 171deb3e1d75..b2e2ccc5d0b7 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -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 diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e5296e7d88cd..22cef25320ed 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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 \ diff --git a/src/test/mir-opt/nll/liveness-call-subtlety.rs b/src/test/mir-opt/nll/liveness-call-subtlety.rs index e4dd99f5a1e7..09288cf69ff5 100644 --- a/src/test/mir-opt/nll/liveness-call-subtlety.rs +++ b/src/test/mir-opt/nll/liveness-call-subtlety.rs @@ -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 >::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 diff --git a/src/test/mir-opt/nll/liveness-drop-intra-block.rs b/src/test/mir-opt/nll/liveness-drop-intra-block.rs index 8dae77380671..b060222a95f1 100644 --- a/src/test/mir-opt/nll/liveness-drop-intra-block.rs +++ b/src/test/mir-opt/nll/liveness-drop-intra-block.rs @@ -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 diff --git a/src/test/mir-opt/nll/liveness-interblock.rs b/src/test/mir-opt/nll/liveness-interblock.rs index 5d799d3d90b4..671f5e5292aa 100644 --- a/src/test/mir-opt/nll/liveness-interblock.rs +++ b/src/test/mir-opt/nll/liveness-interblock.rs @@ -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 diff --git a/src/test/mir-opt/nll/named-lifetimes-basic.rs b/src/test/mir-opt/nll/named-lifetimes-basic.rs index 7039de727faa..0c42585a528e 100644 --- a/src/test/mir-opt/nll/named-lifetimes-basic.rs +++ b/src/test/mir-opt/nll/named-lifetimes-basic.rs @@ -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 diff --git a/src/test/mir-opt/nll/reborrow-basic.rs b/src/test/mir-opt/nll/reborrow-basic.rs index f51e839e4fc3..d203472f20c7 100644 --- a/src/test/mir-opt/nll/reborrow-basic.rs +++ b/src/test/mir-opt/nll/reborrow-basic.rs @@ -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; diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs index cfbc51f9e186..c04cedbc04b4 100644 --- a/src/test/mir-opt/nll/region-liveness-basic.rs +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -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 diff --git a/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs index 04a30dc284d7..e2ad49a44362 100644 --- a/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs +++ b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs @@ -44,5 +44,5 @@ unsafe impl<#[may_dangle] T> Drop for Wrap { // 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 diff --git a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs index 5569fe7f5748..e0272a51d03d 100644 --- a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs +++ b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs @@ -46,5 +46,5 @@ impl Drop for Wrap { // 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 diff --git a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs index 679f31fdab90..8aa0eb1a3a90 100644 --- a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs +++ b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs @@ -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; // ... diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index 471d77aefac6..2bc165bd3c4a 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -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; diff --git a/src/test/ui/nll/capture-ref-in-struct.rs b/src/test/ui/nll/capture-ref-in-struct.rs new file mode 100644 index 000000000000..00a0c94d2218 --- /dev/null +++ b/src/test/ui/nll/capture-ref-in-struct.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/ui/nll/capture-ref-in-struct.stderr b/src/test/ui/nll/capture-ref-in-struct.stderr new file mode 100644 index 000000000000..f10e52e05f19 --- /dev/null +++ b/src/test/ui/nll/capture-ref-in-struct.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.rs b/src/test/ui/nll/closure-requirements/escape-argument-callee.rs new file mode 100644 index 000000000000..dae8c8422401 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.rs @@ -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 or the MIT license +// , 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 + where F: FnMut(&mut &i32, &i32) +{ + f +} + +fn deref(_p: &i32) { } + +fn main() { } diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr new file mode 100644 index 000000000000..a0587c797df6 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/escape-argument.rs b/src/test/ui/nll/closure-requirements/escape-argument.rs new file mode 100644 index 000000000000..da6d60e00ead --- /dev/null +++ b/src/test/ui/nll/closure-requirements/escape-argument.rs @@ -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 or the MIT license +// , 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 + where F: for<'a, 'b> FnMut(&'a mut &'b i32, &'b i32) +{ + f +} + +fn deref(_p: &i32) { } + +fn main() { } diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr new file mode 100644 index 000000000000..653c46124624 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.rs b/src/test/ui/nll/closure-requirements/escape-upvar-nested.rs new file mode 100644 index 000000000000..6a94f244ea68 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr new file mode 100644 index 000000000000..201590f01f38 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.rs b/src/test/ui/nll/closure-requirements/escape-upvar-ref.rs new file mode 100644 index 000000000000..5d14501cdbba --- /dev/null +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr new file mode 100644 index 000000000000..0a182fbc278e --- /dev/null +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs new file mode 100644 index 000000000000..c2f071cc029e --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr new file mode 100644 index 000000000000..c52701d0bf86 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.rs new file mode 100644 index 000000000000..a18b618a0534 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr new file mode 100644 index 000000000000..6cdbd87a833f --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -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 [] + diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.rs new file mode 100644 index 000000000000..8a6384d95ca0 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr new file mode 100644 index 000000000000..8d62e49adc58 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-to-static.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-to-static.rs new file mode 100644 index 000000000000..5e669b3d3c1c --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-to-static.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-to-static.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-to-static.stderr new file mode 100644 index 000000000000..d40643305e66 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-to-static.stderr @@ -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 [] + diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-val.rs new file mode 100644 index 000000000000..48d446b00af8 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr new file mode 100644 index 000000000000..77514543e15f --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -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 [] + diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.rs b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.rs new file mode 100644 index 000000000000..a28b5f4c0f94 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr new file mode 100644 index 000000000000..87fda8c4e160 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -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 [] + diff --git a/src/test/ui/nll/closure-requirements/region-ebr-does-not-outlive-static.rs b/src/test/ui/nll/closure-requirements/region-ebr-does-not-outlive-static.rs new file mode 100644 index 000000000000..fc8b48b85513 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/region-ebr-does-not-outlive-static.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/ui/nll/closure-requirements/region-ebr-does-not-outlive-static.stderr b/src/test/ui/nll/closure-requirements/region-ebr-does-not-outlive-static.stderr new file mode 100644 index 000000000000..d3fbbb81df92 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/region-ebr-does-not-outlive-static.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs b/src/test/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs new file mode 100644 index 000000000000..ec661bfb8e5f --- /dev/null +++ b/src/test/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr b/src/test/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr new file mode 100644 index 000000000000..d5d4a5642ea8 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs b/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs new file mode 100644 index 000000000000..f70441c08d84 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr b/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr new file mode 100644 index 000000000000..a54e7b612c14 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr @@ -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 + diff --git a/src/test/ui/nll/named-region-basic.rs b/src/test/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs similarity index 81% rename from src/test/ui/nll/named-region-basic.rs rename to src/test/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs index 001ce41c2779..94a234bc3d37 100644 --- a/src/test/ui/nll/named-region-basic.rs +++ b/src/test/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs @@ -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() { } diff --git a/src/test/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr b/src/test/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr new file mode 100644 index 000000000000..c1b2f4403094 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs b/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs new file mode 100644 index 000000000000..d63fd04cd2b7 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.rs b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.rs new file mode 100644 index 000000000000..9314bbf94322 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.rs @@ -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 or the MIT license +// , 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 + where F: for<'a> FnMut(&'a i32, &i32) -> &'a i32 +{ + f +} + +fn deref(_p: &i32) { } + +fn main() { } diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr new file mode 100644 index 000000000000..ba0c6cd895c7 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -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 + diff --git a/src/test/ui/nll/closure-requirements/via-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/via-upvar-nested.stderr new file mode 100644 index 000000000000..ba06888943b9 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/via-upvar-nested.stderr @@ -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 + diff --git a/src/test/ui/nll/named-region-basic.stderr b/src/test/ui/nll/named-region-basic.stderr deleted file mode 100644 index 9c1de6c366cc..000000000000 --- a/src/test/ui/nll/named-region-basic.stderr +++ /dev/null @@ -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 -