Skip to content

Commit f1578d3

Browse files
committed
Auto merge of #32428 - nikomatsakis:scopes-in-mir, r=nagisa
Scopes in mir This PR adds scopes to MIR. There is a tree of scopes (each represented by a `ScopeId`). Every statement, variable, and terminator now has an associated scope and span. It also adds a `-Z dump-mir` switch one can use to conveniently examine the MIR as optimizations proceed. The intention is two-fold. First, to support MIR debug-info. This PR does not attempt to modify trans to make use of the scope information, however. Second, in a more temporary capacity, to support the goal of moving regionck and borowck into the MIR. To that end, the PR also constructs a "scope auxiliary" table storing the extent of each span (this is kept separate from the main MIR, since it contains node-ids) and the dom/post-dom of the region in the graph where the scope occurs. When we move to non-lexical lifetimes, I expect this auxiliary information to be discarded, but that is still some ways in the future (requires, at minimum, an RFC, and there are some thorny details to work out -- though I've got an in-progress draft). Right now, I'm just dropping this auxiliary information after it is constructed. I was debating for some time whether to add some sort of sanity tests, but decided to just open this PR instead, because I couldn't figure out what such a test would look like (and we don't have independent tests for this today beyond the regionck and borrowck tests). I'd prefer not to store the auxiliary data into any kind of "per-fn" map. Rather, I'd prefer that we do regionck/borrowck/whatever-else immediately after construction -- that is, we build the MIR for fn X and immediately thereafter do extended correctness checking on it. This will reduce peak memory usage and also ensure that the auxiliary data doesn't exist once optimizations begin. It also clarifies the transition point where static checks are complete and MIR can be more freely optimized. cc @rust-lang/compiler @nagisa
2 parents 40deb27 + 091a007 commit f1578d3

File tree

26 files changed

+1370
-453
lines changed

26 files changed

+1370
-453
lines changed

src/librustc/mir/repr.rs

+97-10
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ pub struct Mir<'tcx> {
3232
/// that indexes into this vector.
3333
pub basic_blocks: Vec<BasicBlockData<'tcx>>,
3434

35+
/// List of lexical scopes; these are referenced by statements and
36+
/// used (eventually) for debuginfo. Indexed by a `ScopeId`.
37+
pub scopes: Vec<ScopeData>,
38+
3539
/// Return type of the function.
3640
pub return_ty: FnOutput<'tcx>,
3741

@@ -152,9 +156,21 @@ pub enum BorrowKind {
152156
/// decl, a let, etc.
153157
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
154158
pub struct VarDecl<'tcx> {
159+
/// `let mut x` vs `let x`
155160
pub mutability: Mutability,
161+
162+
/// name that user gave the variable; not that, internally,
163+
/// mir references variables by index
156164
pub name: Name,
165+
166+
/// type inferred for this variable (`let x: ty = ...`)
157167
pub ty: Ty<'tcx>,
168+
169+
/// scope in which variable was declared
170+
pub scope: ScopeId,
171+
172+
/// span where variable was declared
173+
pub span: Span,
158174
}
159175

160176
/// A "temp" is a temporary that we place on the stack. They are
@@ -191,7 +207,7 @@ pub struct ArgDecl<'tcx> {
191207
/// list of the `Mir`.
192208
///
193209
/// (We use a `u32` internally just to save memory.)
194-
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
210+
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
195211
pub struct BasicBlock(u32);
196212

197213
impl BasicBlock {
@@ -217,13 +233,35 @@ impl Debug for BasicBlock {
217233

218234
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
219235
pub struct BasicBlockData<'tcx> {
236+
/// List of statements in this block.
220237
pub statements: Vec<Statement<'tcx>>,
238+
239+
/// Terminator for this block.
240+
///
241+
/// NB. This should generally ONLY be `None` during construction.
242+
/// Therefore, you should generally access it via the
243+
/// `terminator()` or `terminator_mut()` methods. The only
244+
/// exception is that certain passes, such as `simplify_cfg`, swap
245+
/// out the terminator temporarily with `None` while they continue
246+
/// to recurse over the set of basic blocks.
221247
pub terminator: Option<Terminator<'tcx>>,
248+
249+
/// If true, this block lies on an unwind path. This is used
250+
/// during trans where distinct kinds of basic blocks may be
251+
/// generated (particularly for MSVC cleanup). Unwind blocks must
252+
/// only branch to other unwind blocks.
222253
pub is_cleanup: bool,
223254
}
224255

256+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
257+
pub struct Terminator<'tcx> {
258+
pub span: Span,
259+
pub scope: ScopeId,
260+
pub kind: TerminatorKind<'tcx>
261+
}
262+
225263
#[derive(Clone, RustcEncodable, RustcDecodable)]
226-
pub enum Terminator<'tcx> {
264+
pub enum TerminatorKind<'tcx> {
227265
/// block should have one successor in the graph; we jump there
228266
Goto {
229267
target: BasicBlock,
@@ -293,7 +331,17 @@ pub enum Terminator<'tcx> {
293331

294332
impl<'tcx> Terminator<'tcx> {
295333
pub fn successors(&self) -> Cow<[BasicBlock]> {
296-
use self::Terminator::*;
334+
self.kind.successors()
335+
}
336+
337+
pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> {
338+
self.kind.successors_mut()
339+
}
340+
}
341+
342+
impl<'tcx> TerminatorKind<'tcx> {
343+
pub fn successors(&self) -> Cow<[BasicBlock]> {
344+
use self::TerminatorKind::*;
297345
match *self {
298346
Goto { target: ref b } => slice::ref_slice(b).into_cow(),
299347
If { targets: (b1, b2), .. } => vec![b1, b2].into_cow(),
@@ -314,7 +362,7 @@ impl<'tcx> Terminator<'tcx> {
314362
// FIXME: no mootable cow. I’m honestly not sure what a “cow” between `&mut [BasicBlock]` and
315363
// `Vec<&mut BasicBlock>` would look like in the first place.
316364
pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> {
317-
use self::Terminator::*;
365+
use self::TerminatorKind::*;
318366
match *self {
319367
Goto { target: ref mut b } => vec![b],
320368
If { targets: (ref mut b1, ref mut b2), .. } => vec![b1, b2],
@@ -354,7 +402,7 @@ impl<'tcx> BasicBlockData<'tcx> {
354402
}
355403
}
356404

357-
impl<'tcx> Debug for Terminator<'tcx> {
405+
impl<'tcx> Debug for TerminatorKind<'tcx> {
358406
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
359407
self.fmt_head(fmt)?;
360408
let successors = self.successors();
@@ -381,12 +429,12 @@ impl<'tcx> Debug for Terminator<'tcx> {
381429
}
382430
}
383431

384-
impl<'tcx> Terminator<'tcx> {
432+
impl<'tcx> TerminatorKind<'tcx> {
385433
/// Write the "head" part of the terminator; that is, its name and the data it uses to pick the
386434
/// successor basic block, if any. The only information not inlcuded is the list of possible
387435
/// successors, which may be rendered differently between the text and the graphviz format.
388436
pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
389-
use self::Terminator::*;
437+
use self::TerminatorKind::*;
390438
match *self {
391439
Goto { .. } => write!(fmt, "goto"),
392440
If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
@@ -413,7 +461,7 @@ impl<'tcx> Terminator<'tcx> {
413461

414462
/// Return the list of labels for the edges to the successor basic blocks.
415463
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
416-
use self::Terminator::*;
464+
use self::TerminatorKind::*;
417465
match *self {
418466
Return | Resume => vec![],
419467
Goto { .. } => vec!["".into()],
@@ -452,6 +500,7 @@ impl<'tcx> Terminator<'tcx> {
452500
#[derive(Clone, RustcEncodable, RustcDecodable)]
453501
pub struct Statement<'tcx> {
454502
pub span: Span,
503+
pub scope: ScopeId,
455504
pub kind: StatementKind<'tcx>,
456505
}
457506

@@ -468,6 +517,7 @@ impl<'tcx> Debug for Statement<'tcx> {
468517
}
469518
}
470519
}
520+
471521
///////////////////////////////////////////////////////////////////////////
472522
// Lvalues
473523

@@ -613,13 +663,50 @@ impl<'tcx> Debug for Lvalue<'tcx> {
613663
}
614664
}
615665

666+
///////////////////////////////////////////////////////////////////////////
667+
// Scopes
668+
669+
impl Index<ScopeId> for Vec<ScopeData> {
670+
type Output = ScopeData;
671+
672+
#[inline]
673+
fn index(&self, index: ScopeId) -> &ScopeData {
674+
&self[index.index()]
675+
}
676+
}
677+
678+
impl IndexMut<ScopeId> for Vec<ScopeData> {
679+
#[inline]
680+
fn index_mut(&mut self, index: ScopeId) -> &mut ScopeData {
681+
&mut self[index.index()]
682+
}
683+
}
684+
685+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
686+
pub struct ScopeId(u32);
687+
688+
impl ScopeId {
689+
pub fn new(index: usize) -> ScopeId {
690+
assert!(index < (u32::MAX as usize));
691+
ScopeId(index as u32)
692+
}
693+
694+
pub fn index(self) -> usize {
695+
self.0 as usize
696+
}
697+
}
698+
699+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
700+
pub struct ScopeData {
701+
pub parent_scope: Option<ScopeId>,
702+
}
703+
616704
///////////////////////////////////////////////////////////////////////////
617705
// Operands
618-
//
706+
619707
/// These are values that can appear inside an rvalue (or an index
620708
/// lvalue). They are intentionally limited to prevent rvalues from
621709
/// being nested in one another.
622-
623710
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
624711
pub enum Operand<'tcx> {
625712
Consume(Lvalue<'tcx>),

0 commit comments

Comments
 (0)