Skip to content

Commit 5757e65

Browse files
committed
scaffolding for borrowck on MIR.
emit (via debug!) scary message from `fn borrowck_mir` until basic prototype is in place. Gather children of move paths and set their kill bits in dataflow. (Each node has a link to the child that is first among its siblings.) Hooked in libgraphviz based rendering, including of borrowck dataflow state. doing this well required some refactoring of the code, so I cleaned it up more generally (adding comments to explain what its trying to do and how it is doing it). Update: this newer version addresses most review comments (at least the ones that were largely mechanical changes), but I left the more interesting revisions to separate followup commits (in this same PR).
1 parent 213d579 commit 5757e65

File tree

14 files changed

+1777
-31
lines changed

14 files changed

+1777
-31
lines changed

mk/crates.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\
9797
log graphviz rustc_llvm rustc_back rustc_data_structures\
9898
rustc_const_eval
9999
DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
100-
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
100+
DEPS_rustc_borrowck := rustc rustc_front rustc_mir log graphviz syntax
101101
DEPS_rustc_data_structures := std log serialize
102102
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
103103
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \

src/librustc/middle/dataflow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ fn set_bit(words: &mut [usize], bit: usize) -> bool {
653653
let word = bit / usize_bits;
654654
let bit_in_word = bit % usize_bits;
655655
let bit_mask = 1 << bit_in_word;
656-
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, word);
656+
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
657657
let oldv = words[word];
658658
let newv = oldv | bit_mask;
659659
words[word] = newv;

src/librustc/mir/repr.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -499,13 +499,13 @@ pub enum Lvalue<'tcx> {
499499
/// or `*B` or `B[index]`. Note that it is parameterized because it is
500500
/// shared between `Constant` and `Lvalue`. See the aliases
501501
/// `LvalueProjection` etc below.
502-
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
502+
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
503503
pub struct Projection<'tcx, B, V> {
504504
pub base: B,
505505
pub elem: ProjectionElem<'tcx, V>,
506506
}
507507

508-
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
508+
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
509509
pub enum ProjectionElem<'tcx, V> {
510510
Deref,
511511
Field(Field, Ty<'tcx>),
@@ -857,7 +857,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
857857
/// this does not necessarily mean that they are "==" in Rust -- in
858858
/// particular one must be wary of `NaN`!
859859
860-
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
860+
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
861861
pub struct Constant<'tcx> {
862862
pub span: Span,
863863
pub ty: Ty<'tcx>,
@@ -877,7 +877,7 @@ impl<'tcx> Debug for TypedConstVal<'tcx> {
877877
}
878878
}
879879

880-
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
880+
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
881881
pub enum Literal<'tcx> {
882882
Item {
883883
def_id: DefId,

src/librustc_borrowck/bitslice.rs

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::mem;
12+
13+
/// `BitSlice` provides helper methods for treating a `[usize]`
14+
/// as a bitvector.
15+
pub trait BitSlice {
16+
fn set_bit(&mut self, idx: usize) -> bool;
17+
fn get_bit(&self, idx: usize) -> bool;
18+
}
19+
20+
impl BitSlice for [usize] {
21+
fn set_bit(&mut self, idx: usize) -> bool {
22+
let words = self;
23+
debug!("set_bit: words={} idx={}",
24+
bits_to_string(words, words.len() * mem::size_of::<usize>()), bit_str(idx));
25+
let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
26+
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
27+
let oldv = words[word];
28+
let newv = oldv | bit_mask;
29+
words[word] = newv;
30+
oldv != newv
31+
}
32+
33+
fn get_bit(&self, idx: usize) -> bool {
34+
let words = self;
35+
let BitLookup { word, bit_mask, .. } = bit_lookup(idx);
36+
(words[word] & bit_mask) != 0
37+
}
38+
}
39+
40+
struct BitLookup { word: usize, bit_in_word: usize, bit_mask: usize }
41+
42+
#[inline]
43+
fn bit_lookup(bit: usize) -> BitLookup {
44+
let usize_bits = mem::size_of::<usize>() * 8;
45+
let word = bit / usize_bits;
46+
let bit_in_word = bit % usize_bits;
47+
let bit_mask = 1 << bit_in_word;
48+
BitLookup { word: word, bit_in_word: bit_in_word, bit_mask: bit_mask }
49+
}
50+
51+
52+
fn bit_str(bit: usize) -> String {
53+
let byte = bit >> 8;
54+
let lobits = 1 << (bit & 0xFF);
55+
format!("[{}:{}-{:02x}]", bit, byte, lobits)
56+
}
57+
58+
pub fn bits_to_string(words: &[usize], bytes: usize) -> String {
59+
let mut result = String::new();
60+
let mut sep = '[';
61+
62+
// Note: this is a little endian printout of bytes.
63+
64+
let mut i = 0;
65+
for &word in words.iter() {
66+
let mut v = word;
67+
for _ in 0..mem::size_of::<usize>() {
68+
let byte = v & 0xFF;
69+
if i >= bytes {
70+
assert!(byte == 0);
71+
} else {
72+
result.push(sep);
73+
result.push_str(&format!("{:02x}", byte));
74+
}
75+
v >>= 8;
76+
i += 1;
77+
sep = '-';
78+
}
79+
}
80+
result.push(']');
81+
return result
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! The move-analysis portion of borrowck needs to work in an abstract
12+
//! domain of lifted Lvalues. Most of the Lvalue variants fall into a
13+
//! one-to-one mapping between the concrete and abstract (e.g. a
14+
//! field-deref on a local-variable, `x.field`, has the same meaning
15+
//! in both domains). Indexed-Projections are the exception: `a[x]`
16+
//! needs to be treated as mapping to the same move path as `a[y]` as
17+
//! well as `a[13]`, et cetera.
18+
//!
19+
//! (In theory the analysis could be extended to work with sets of
20+
//! paths, so that `a[0]` and `a[13]` could be kept distinct, while
21+
//! `a[x]` would still overlap them both. But that is not this
22+
//! representation does today.)
23+
24+
use rustc::mir::repr::{Lvalue, LvalueElem};
25+
use rustc::mir::repr::{Operand, Projection, ProjectionElem};
26+
27+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
28+
pub struct AbstractOperand;
29+
pub type AbstractProjection<'tcx> =
30+
Projection<'tcx, Lvalue<'tcx>, AbstractOperand>;
31+
pub type AbstractElem<'tcx> =
32+
ProjectionElem<'tcx, AbstractOperand>;
33+
34+
pub trait Lift {
35+
type Abstract;
36+
fn lift(&self) -> Self::Abstract;
37+
}
38+
impl<'tcx> Lift for Operand<'tcx> {
39+
type Abstract = AbstractOperand;
40+
fn lift(&self) -> Self::Abstract { AbstractOperand }
41+
}
42+
impl<'tcx> Lift for LvalueElem<'tcx> {
43+
type Abstract = AbstractElem<'tcx>;
44+
fn lift(&self) -> Self::Abstract {
45+
match *self {
46+
ProjectionElem::Deref =>
47+
ProjectionElem::Deref,
48+
ProjectionElem::Field(ref f, ty) =>
49+
ProjectionElem::Field(f.clone(), ty.clone()),
50+
ProjectionElem::Index(ref i) =>
51+
ProjectionElem::Index(i.lift()),
52+
ProjectionElem::ConstantIndex {offset,min_length,from_end} =>
53+
ProjectionElem::ConstantIndex {
54+
offset: offset,
55+
min_length: min_length,
56+
from_end: from_end
57+
},
58+
ProjectionElem::Downcast(a, u) =>
59+
ProjectionElem::Downcast(a.clone(), u.clone()),
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)