Skip to content

Commit 2be4cc0

Browse files
committed
Auto merge of #45538 - nikomatsakis:nll-liveness, r=pnkfelix
enable non-lexical lifetimes in the MIR borrow checker This PR, joint work with @spastorino, fills out the NLL infrastructure and integrates it with the borrow checker. **Don't get too excited:** it includes still a number of hacks (the subtyping code is particularly hacky). However, it *does* kinda' work. =) The final commit demonstrates this by including a test that -- with both the AST borrowck and MIR borrowck -- reports an error by default. But if you pass `-Znll`, you only get an error from the AST borrowck, demonstrating that the integration succeeds: ``` struct MyStruct { field: String } fn main() { let mut my_struct = MyStruct { field: format!("Hello") }; let value = &my_struct.field; if value.is_empty() { my_struct.field.push_str("Hello, world!"); //~^ ERROR cannot borrow (Ast) } } ```
2 parents a3f990d + aae3e74 commit 2be4cc0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2102
-622
lines changed

src/librustc/middle/region.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ pub struct BlockRemainder {
158158

159159
newtype_index!(FirstStatementIndex
160160
{
161-
DEBUG_NAME = "",
161+
DEBUG_FORMAT = "{}",
162162
MAX = SCOPE_DATA_REMAINDER_MAX,
163163
});
164164

src/librustc/mir/mod.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ pub enum BorrowKind {
417417

418418
newtype_index!(Local
419419
{
420-
DEBUG_NAME = "_",
420+
DEBUG_FORMAT = "_{}",
421421
const RETURN_POINTER = 0,
422422
});
423423

@@ -553,7 +553,7 @@ pub struct UpvarDecl {
553553
///////////////////////////////////////////////////////////////////////////
554554
// BasicBlock
555555

556-
newtype_index!(BasicBlock { DEBUG_NAME = "bb" });
556+
newtype_index!(BasicBlock { DEBUG_FORMAT = "bb{}" });
557557

558558
///////////////////////////////////////////////////////////////////////////
559559
// BasicBlockData and Terminator
@@ -1135,7 +1135,7 @@ pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Local, Ty<'tcx>
11351135
/// and the index is a local.
11361136
pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>;
11371137

1138-
newtype_index!(Field { DEBUG_NAME = "field" });
1138+
newtype_index!(Field { DEBUG_FORMAT = "field[{}]" });
11391139

11401140
impl<'tcx> Lvalue<'tcx> {
11411141
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> {
@@ -1202,7 +1202,7 @@ impl<'tcx> Debug for Lvalue<'tcx> {
12021202

12031203
newtype_index!(VisibilityScope
12041204
{
1205-
DEBUG_NAME = "scope",
1205+
DEBUG_FORMAT = "scope[{}]",
12061206
const ARGUMENT_VISIBILITY_SCOPE = 0,
12071207
});
12081208

@@ -1529,7 +1529,7 @@ pub struct Constant<'tcx> {
15291529
pub literal: Literal<'tcx>,
15301530
}
15311531

1532-
newtype_index!(Promoted { DEBUG_NAME = "promoted" });
1532+
newtype_index!(Promoted { DEBUG_FORMAT = "promoted[{}]" });
15331533

15341534
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
15351535
pub enum Literal<'tcx> {
@@ -1637,6 +1637,14 @@ impl fmt::Debug for Location {
16371637
}
16381638

16391639
impl Location {
1640+
/// Returns the location immediately after this one within the enclosing block.
1641+
///
1642+
/// Note that if this location represents a terminator, then the
1643+
/// resulting location would be out of bounds and invalid.
1644+
pub fn successor_within_block(&self) -> Location {
1645+
Location { block: self.block, statement_index: self.statement_index + 1 }
1646+
}
1647+
16401648
pub fn dominates(&self, other: &Location, dominators: &Dominators<BasicBlock>) -> bool {
16411649
if self.block == other.block {
16421650
self.statement_index <= other.statement_index

src/librustc/mir/transform.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ pub enum MirSource {
3939
GeneratorDrop(NodeId),
4040
}
4141

42-
impl<'a, 'tcx> MirSource {
43-
pub fn from_local_def_id(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> MirSource {
42+
impl<'a, 'gcx, 'tcx> MirSource {
43+
pub fn from_local_def_id(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> MirSource {
4444
let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id");
4545
Self::from_node(tcx, id)
4646
}
4747

48-
pub fn from_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId) -> MirSource {
48+
pub fn from_node(tcx: TyCtxt<'a, 'gcx, 'tcx>, id: NodeId) -> MirSource {
4949
use hir::*;
5050

5151
// Handle constants in enum discriminants, types, and repeat expressions.

src/librustc/ty/fold.rs

+37
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,43 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
218218
{
219219
value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
220220
}
221+
222+
pub fn for_each_free_region<T,F>(self,
223+
value: &T,
224+
callback: F)
225+
where F: FnMut(ty::Region<'tcx>),
226+
T: TypeFoldable<'tcx>,
227+
{
228+
value.visit_with(&mut RegionVisitor { current_depth: 0, callback });
229+
230+
struct RegionVisitor<F> {
231+
current_depth: u32,
232+
callback: F,
233+
}
234+
235+
impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F>
236+
where F : FnMut(ty::Region<'tcx>)
237+
{
238+
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
239+
self.current_depth += 1;
240+
t.skip_binder().visit_with(self);
241+
self.current_depth -= 1;
242+
243+
false // keep visiting
244+
}
245+
246+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
247+
match *r {
248+
ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
249+
/* ignore bound regions */
250+
}
251+
_ => (self.callback)(r),
252+
}
253+
254+
false // keep visiting
255+
}
256+
}
257+
}
221258
}
222259

223260
/// Folds over the substructure of a type, visiting its component

src/librustc_borrowck/borrowck/check_loans.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
484484
// 3. Where does old loan expire.
485485

486486
let previous_end_span =
487-
old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree).end_point();
487+
Some(old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree)
488+
.end_point());
488489

489490
let mut err = match (new_loan.kind, old_loan.kind) {
490491
(ty::MutBorrow, ty::MutBorrow) =>

src/librustc_data_structures/indexed_set.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,19 @@ pub struct IdxSet<T: Idx> {
5353
}
5454

5555
impl<T: Idx> fmt::Debug for IdxSetBuf<T> {
56-
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) }
56+
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
57+
w.debug_list()
58+
.entries(self.iter())
59+
.finish()
60+
}
5761
}
5862

5963
impl<T: Idx> fmt::Debug for IdxSet<T> {
60-
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) }
64+
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
65+
w.debug_list()
66+
.entries(self.iter())
67+
.finish()
68+
}
6169
}
6270

6371
impl<T: Idx> IdxSetBuf<T> {

src/librustc_data_structures/indexed_vec.rs

+19-16
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,22 @@ macro_rules! newtype_index {
4747
newtype_index!(
4848
@type[$name]
4949
@max[::std::u32::MAX]
50-
@debug_name[unsafe {::std::intrinsics::type_name::<$name>() }]);
50+
@debug_format["{}"]);
5151
);
5252

5353
// Define any constants
5454
($name:ident { $($tokens:tt)+ }) => (
5555
newtype_index!(
5656
@type[$name]
5757
@max[::std::u32::MAX]
58-
@debug_name[unsafe {::std::intrinsics::type_name::<$name>() }]
58+
@debug_format["{}"]
5959
$($tokens)+);
6060
);
6161

6262
// ---- private rules ----
6363

6464
// Base case, user-defined constants (if any) have already been defined
65-
(@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]) => (
65+
(@type[$type:ident] @max[$max:expr] @debug_format[$debug_format:expr]) => (
6666
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
6767
RustcEncodable, RustcDecodable)]
6868
pub struct $type(pub u32);
@@ -79,40 +79,43 @@ macro_rules! newtype_index {
7979

8080
impl ::std::fmt::Debug for $type {
8181
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
82-
write!(fmt, "{}{}", $debug_name, self.0)
82+
write!(fmt, $debug_format, self.0)
8383
}
8484
}
8585
);
8686

8787
// Rewrite final without comma to one that includes comma
88-
(@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]
88+
(@type[$type:ident] @max[$max:expr] @debug_format[$debug_format:expr]
8989
$name:ident = $constant:expr) => (
90-
newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $name = $constant,);
90+
newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $name = $constant,);
9191
);
9292

9393
// Rewrite final const without comma to one that includes comma
94-
(@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr]
94+
(@type[$type:ident] @max[$_max:expr] @debug_format[$debug_format:expr]
9595
const $name:ident = $constant:expr) => (
96-
newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] const $name = $constant,);
96+
newtype_index!(@type[$type]
97+
@max[$max]
98+
@debug_format[$debug_format]
99+
const $name = $constant,);
97100
);
98101

99102
// Replace existing default for max
100-
(@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr]
103+
(@type[$type:ident] @max[$_max:expr] @debug_format[$debug_format:expr]
101104
MAX = $max:expr, $($tokens:tt)*) => (
102-
newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*);
105+
newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $($tokens)*);
103106
);
104107

105-
// Replace existing default for debug_name
106-
(@type[$type:ident] @max[$max:expr] @debug_name[$_debug_name:expr]
107-
DEBUG_NAME = $debug_name:expr, $($tokens:tt)*) => (
108-
newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*);
108+
// Replace existing default for debug_format
109+
(@type[$type:ident] @max[$max:expr] @debug_format[$_debug_format:expr]
110+
DEBUG_FORMAT = $debug_format:expr, $($tokens:tt)*) => (
111+
newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $($tokens)*);
109112
);
110113

111114
// Assign a user-defined constant (as final param)
112-
(@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]
115+
(@type[$type:ident] @max[$max:expr] @debug_format[$debug_format:expr]
113116
const $name:ident = $constant:expr, $($tokens:tt)*) => (
114117
pub const $name: $type = $type($constant);
115-
newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*);
118+
newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $($tokens)*);
116119
);
117120
}
118121

src/librustc_driver/driver.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
10071007

10081008
passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
10091009
passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
1010-
passes.push_pass(MIR_VALIDATED, mir::transform::nll::NLL);
10111010

10121011
// borrowck runs between MIR_VALIDATED and MIR_OPTIMIZED.
10131012

0 commit comments

Comments
 (0)