Auto merge of #33989 - eddyb:mir-viz, r=nikomatsakis

[MIR] Make scopes debuginfo-specific (visibility scopes).

Fixes #32949 by having MIR (visibility) scopes mimic the lexical structure.
Unlike #33235, this PR also removes all scopes without variable bindings.

Printing of scopes also changed, e.g. for:
```rust
fn foo(x: i32, y: i32) { let a = 0; let b = 0; let c = 0; }
```
Before my changes:
```rust
fn foo(arg0: i32, arg1: i32) -> () {
    let var0: i32;                       // "x" in scope 1 at <anon>:1:8: 1:9
    let var1: i32;                       // "y" in scope 1 at <anon>:1:16: 1:17
    let var2: i32;                       // "a" in scope 3 at <anon>:1:30: 1:31
    let var3: i32;                       // "b" in scope 6 at <anon>:1:41: 1:42
    let var4: i32;                       // "c" in scope 9 at <anon>:1:52: 1:53

    ...

    scope tree:
    0 1 2 3 {
        4 5
        6 {
            7 8
            9 10 11
        }
    }
}
```
After my changes:
```rust
fn foo(arg0: i32, arg1: i32) -> () {
    scope 1 {
        let var0: i32;                   // "x" in scope 1 at <anon>:1:8: 1:9
        let var1: i32;                   // "y" in scope 1 at <anon>:1:16: 1:17
        scope 2 {
            let var2: i32;               // "a" in scope 2 at <anon>:1:30: 1:31
            scope 3 {
                let var3: i32;           // "b" in scope 3 at <anon>:1:41: 1:42
                scope 4 {
                    let var4: i32;       // "c" in scope 4 at <anon>:1:52: 1:53
                }
            }
        }
    }

    ...
}
This commit is contained in:
bors 2016-06-08 13:51:57 -07:00
commit 0d531bfb88
30 changed files with 482 additions and 497 deletions

View file

@ -32,9 +32,9 @@ pub struct Mir<'tcx> {
/// that indexes into this vector.
pub basic_blocks: Vec<BasicBlockData<'tcx>>,
/// List of lexical scopes; these are referenced by statements and
/// used (eventually) for debuginfo. Indexed by a `ScopeId`.
pub scopes: Vec<ScopeData>,
/// List of visibility (lexical) scopes; these are referenced by statements
/// and used (eventually) for debuginfo. Indexed by a `VisibilityScope`.
pub visibility_scopes: Vec<VisibilityScopeData>,
/// Rvalues promoted from this function, such as borrows of constants.
/// Each of them is the Mir of a constant with the fn's type parameters
@ -100,6 +100,18 @@ impl<'tcx> IndexMut<BasicBlock> for Mir<'tcx> {
}
}
/// Grouped information about the source code origin of a MIR entity.
/// Intended to be inspected by diagnostics and debuginfo.
/// Most passes can work with it as a whole, within a single function.
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct SourceInfo {
/// Source span for the AST pertaining to this MIR entity.
pub span: Span,
/// The lexical visibility scope, i.e. which bindings can be seen.
pub scope: VisibilityScope
}
///////////////////////////////////////////////////////////////////////////
// Mutability and borrow kinds
@ -172,11 +184,8 @@ pub struct VarDecl<'tcx> {
/// type inferred for this variable (`let x: ty = ...`)
pub ty: Ty<'tcx>,
/// scope in which variable was declared
pub scope: ScopeId,
/// span where variable was declared
pub span: Span,
/// source information (span, scope, etc.) for the declaration
pub source_info: SourceInfo,
}
/// A "temp" is a temporary that we place on the stack. They are
@ -275,8 +284,7 @@ pub struct BasicBlockData<'tcx> {
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Terminator<'tcx> {
pub span: Span,
pub scope: ScopeId,
pub source_info: SourceInfo,
pub kind: TerminatorKind<'tcx>
}
@ -587,8 +595,7 @@ pub enum AssertMessage<'tcx> {
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct Statement<'tcx> {
pub span: Span,
pub scope: ScopeId,
pub source_info: SourceInfo,
pub kind: StatementKind<'tcx>,
}
@ -754,29 +761,32 @@ impl<'tcx> Debug for Lvalue<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Scopes
impl Index<ScopeId> for Vec<ScopeData> {
type Output = ScopeData;
impl Index<VisibilityScope> for Vec<VisibilityScopeData> {
type Output = VisibilityScopeData;
#[inline]
fn index(&self, index: ScopeId) -> &ScopeData {
fn index(&self, index: VisibilityScope) -> &VisibilityScopeData {
&self[index.index()]
}
}
impl IndexMut<ScopeId> for Vec<ScopeData> {
impl IndexMut<VisibilityScope> for Vec<VisibilityScopeData> {
#[inline]
fn index_mut(&mut self, index: ScopeId) -> &mut ScopeData {
fn index_mut(&mut self, index: VisibilityScope) -> &mut VisibilityScopeData {
&mut self[index.index()]
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct ScopeId(u32);
pub struct VisibilityScope(u32);
impl ScopeId {
pub fn new(index: usize) -> ScopeId {
/// The visibility scope all arguments go into.
pub const ARGUMENT_VISIBILITY_SCOPE: VisibilityScope = VisibilityScope(0);
impl VisibilityScope {
pub fn new(index: usize) -> VisibilityScope {
assert!(index < (u32::MAX as usize));
ScopeId(index as u32)
VisibilityScope(index as u32)
}
pub fn index(self) -> usize {
@ -785,9 +795,9 @@ impl ScopeId {
}
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ScopeData {
pub struct VisibilityScopeData {
pub span: Span,
pub parent_scope: Option<ScopeId>,
pub parent_scope: Option<VisibilityScope>,
}
///////////////////////////////////////////////////////////////////////////

View file

@ -97,9 +97,9 @@ macro_rules! make_mir_visitor {
self.super_basic_block_data(block, data);
}
fn visit_scope_data(&mut self,
scope_data: & $($mutability)* ScopeData) {
self.super_scope_data(scope_data);
fn visit_visibility_scope_data(&mut self,
scope_data: & $($mutability)* VisibilityScopeData) {
self.super_visibility_scope_data(scope_data);
}
fn visit_statement(&mut self,
@ -186,6 +186,11 @@ macro_rules! make_mir_visitor {
self.super_span(span);
}
fn visit_source_info(&mut self,
source_info: & $($mutability)* SourceInfo) {
self.super_source_info(source_info);
}
fn visit_fn_output(&mut self,
fn_output: & $($mutability)* FnOutput<'tcx>) {
self.super_fn_output(fn_output);
@ -236,9 +241,9 @@ macro_rules! make_mir_visitor {
self.super_arg_decl(arg_decl);
}
fn visit_scope_id(&mut self,
scope_id: & $($mutability)* ScopeId) {
self.super_scope_id(scope_id);
fn visit_visibility_scope(&mut self,
scope: & $($mutability)* VisibilityScope) {
self.super_visibility_scope(scope);
}
// The `super_xxx` methods comprise the default behavior and are
@ -248,7 +253,7 @@ macro_rules! make_mir_visitor {
mir: & $($mutability)* Mir<'tcx>) {
let Mir {
ref $($mutability)* basic_blocks,
ref $($mutability)* scopes,
ref $($mutability)* visibility_scopes,
promoted: _, // Visited by passes separately.
ref $($mutability)* return_ty,
ref $($mutability)* var_decls,
@ -263,8 +268,8 @@ macro_rules! make_mir_visitor {
self.visit_basic_block_data(block, data);
}
for scope in scopes {
self.visit_scope_data(scope);
for scope in visibility_scopes {
self.visit_visibility_scope_data(scope);
}
self.visit_fn_output(return_ty);
@ -302,16 +307,16 @@ macro_rules! make_mir_visitor {
}
}
fn super_scope_data(&mut self,
scope_data: & $($mutability)* ScopeData) {
let ScopeData {
fn super_visibility_scope_data(&mut self,
scope_data: & $($mutability)* VisibilityScopeData) {
let VisibilityScopeData {
ref $($mutability)* span,
ref $($mutability)* parent_scope,
} = *scope_data;
self.visit_span(span);
if let Some(ref $($mutability)* parent_scope) = *parent_scope {
self.visit_scope_id(parent_scope);
self.visit_visibility_scope(parent_scope);
}
}
@ -319,13 +324,11 @@ macro_rules! make_mir_visitor {
block: BasicBlock,
statement: & $($mutability)* Statement<'tcx>) {
let Statement {
ref $($mutability)* span,
ref $($mutability)* scope,
ref $($mutability)* source_info,
ref $($mutability)* kind,
} = *statement;
self.visit_span(span);
self.visit_scope_id(scope);
self.visit_source_info(source_info);
match *kind {
StatementKind::Assign(ref $($mutability)* lvalue,
ref $($mutability)* rvalue) => {
@ -346,13 +349,11 @@ macro_rules! make_mir_visitor {
block: BasicBlock,
terminator: &$($mutability)* Terminator<'tcx>) {
let Terminator {
ref $($mutability)* span,
ref $($mutability)* scope,
ref $($mutability)* source_info,
ref $($mutability)* kind,
} = *terminator;
self.visit_span(span);
self.visit_scope_id(scope);
self.visit_source_info(source_info);
self.visit_terminator_kind(block, kind);
}
@ -622,13 +623,11 @@ macro_rules! make_mir_visitor {
mutability: _,
name: _,
ref $($mutability)* ty,
ref $($mutability)* scope,
ref $($mutability)* span,
ref $($mutability)* source_info,
} = *var_decl;
self.visit_ty(ty);
self.visit_scope_id(scope);
self.visit_span(span);
self.visit_source_info(source_info);
}
fn super_temp_decl(&mut self,
@ -651,8 +650,8 @@ macro_rules! make_mir_visitor {
self.visit_ty(ty);
}
fn super_scope_id(&mut self,
_scope_id: & $($mutability)* ScopeId) {
fn super_visibility_scope(&mut self,
_scope: & $($mutability)* VisibilityScope) {
}
fn super_branch(&mut self,
@ -707,6 +706,16 @@ macro_rules! make_mir_visitor {
fn super_span(&mut self, _span: & $($mutability)* Span) {
}
fn super_source_info(&mut self, source_info: & $($mutability)* SourceInfo) {
let SourceInfo {
ref $($mutability)* span,
ref $($mutability)* scope,
} = *source_info;
self.visit_span(span);
self.visit_visibility_scope(scope);
}
fn super_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) {
match *fn_output {
FnOutput::FnConverging(ref $($mutability)* ty) => {

View file

@ -151,7 +151,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
terminator: &'a Option<repr::Terminator<'tcx>>)
-> Option<(&'a [repr::Operand<'tcx>], Span)> {
if let Some(repr::Terminator { ref kind, span, .. }) = *terminator {
if let Some(repr::Terminator { ref kind, source_info, .. }) = *terminator {
if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind
{
if let repr::Operand::Constant(ref func) = *oper
@ -161,7 +161,7 @@ fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let name = tcx.item_name(def_id);
if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
if name.as_str() == "rustc_peek" {
return Some((args, span));
return Some((args, source_info.span));
}
}
}

View file

@ -124,8 +124,7 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> {
#[derive(Copy, Clone, Debug)]
struct DropCtxt<'a, 'tcx: 'a> {
span: Span,
scope: ScopeId,
source_info: SourceInfo,
is_cleanup: bool,
init_data: &'a InitializationData,
@ -273,8 +272,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let init_data = self.initialization_data_at(loc);
let path = self.move_data().rev_lookup.find(location);
self.elaborate_drop(&DropCtxt {
span: terminator.span,
scope: terminator.scope,
source_info: terminator.source_info,
is_cleanup: data.is_cleanup,
init_data: &init_data,
lvalue: location,
@ -329,8 +327,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let assign = Statement {
kind: StatementKind::Assign(location.clone(), Rvalue::Use(value.clone())),
span: terminator.span,
scope: terminator.scope
source_info: terminator.source_info
};
let unwind = unwind.unwrap_or(self.patch.resume_block());
@ -367,8 +364,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let path = self.move_data().rev_lookup.find(location);
self.elaborate_drop(&DropCtxt {
span: terminator.span,
scope: terminator.scope,
source_info: terminator.source_info,
is_cleanup: data.is_cleanup,
init_data: &init_data,
lvalue: location,
@ -513,8 +509,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
debug!("drop_ladder: for std field {} ({:?})", i, lv);
self.elaborated_drop_block(&DropCtxt {
span: c.span,
scope: c.scope,
source_info: c.source_info,
is_cleanup: is_cleanup,
init_data: c.init_data,
lvalue: lv,
@ -527,8 +522,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
debug!("drop_ladder: for rest field {} ({:?})", i, lv);
let blk = self.complete_drop(&DropCtxt {
span: c.span,
scope: c.scope,
source_info: c.source_info,
is_cleanup: is_cleanup,
init_data: c.init_data,
lvalue: lv,
@ -785,7 +779,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
self.patch.new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
scope: c.scope, span: c.span, kind: k
source_info: c.source_info, kind: k
}),
is_cleanup: is_cleanup
})
@ -858,11 +852,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let mut statements = vec![];
if let Some(&flag) = self.drop_flags.get(&c.path) {
statements.push(Statement {
span: c.span,
scope: c.scope,
source_info: c.source_info,
kind: StatementKind::Assign(
Lvalue::Temp(flag),
self.constant_bool(c.span, false)
self.constant_bool(c.source_info.span, false)
)
});
}
@ -880,9 +873,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
self.patch.new_block(BasicBlockData {
statements: statements,
terminator: Some(Terminator {
scope: c.scope, span: c.span, kind: TerminatorKind::Call {
source_info: c.source_info, kind: TerminatorKind::Call {
func: Operand::Constant(Constant {
span: c.span,
span: c.source_info.span,
ty: fty,
literal: Literal::Item {
def_id: free_func,
@ -910,7 +903,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
ty::TyStruct(def, _) | ty::TyEnum(def, _) => {
if def.has_dtor() {
self.tcx.sess.span_warn(
c.span,
c.source_info.span,
&format!("dataflow bug??? moving out of type with dtor {:?}",
c));
true
@ -932,7 +925,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) {
if let Some(&flag) = self.drop_flags.get(&path) {
let span = self.patch.context_for_location(self.mir, loc).0;
let span = self.patch.source_info_for_location(self.mir, loc).span;
let val = self.constant_bool(span, val.value());
self.patch.add_assign(loc, Lvalue::Temp(flag), val);
}
@ -940,7 +933,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
fn drop_flags_on_init(&mut self) {
let loc = Location { block: START_BLOCK, index: 0 };
let span = self.patch.context_for_location(self.mir, loc).0;
let span = self.patch.source_info_for_location(self.mir, loc).span;
let false_ = self.constant_bool(span, false);
for flag in self.drop_flags.values() {
self.patch.add_assign(loc, Lvalue::Temp(*flag), false_.clone());

View file

@ -11,7 +11,6 @@
use super::gather_moves::Location;
use rustc::ty::Ty;
use rustc::mir::repr::*;
use syntax::codemap::Span;
use std::iter;
use std::u32;
@ -62,8 +61,10 @@ impl<'tcx> MirPatch<'tcx> {
result.new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
span: mir.span,
scope: ScopeId::new(0),
source_info: SourceInfo {
span: mir.span,
scope: ARGUMENT_VISIBILITY_SCOPE
},
kind: TerminatorKind::Resume
}),
is_cleanup: true
@ -154,31 +155,30 @@ impl<'tcx> MirPatch<'tcx> {
debug!("MirPatch: adding statement {:?} at loc {:?}+{}",
stmt, loc, delta);
loc.index += delta;
let (span, scope) = Self::context_for_index(
let source_info = Self::source_info_for_index(
mir.basic_block_data(loc.block), loc
);
mir.basic_block_data_mut(loc.block).statements.insert(
loc.index, Statement {
span: span,
scope: scope,
source_info: source_info,
kind: stmt
});
delta += 1;
}
}
pub fn context_for_index(data: &BasicBlockData, loc: Location) -> (Span, ScopeId) {
pub fn source_info_for_index(data: &BasicBlockData, loc: Location) -> SourceInfo {
match data.statements.get(loc.index) {
Some(stmt) => (stmt.span, stmt.scope),
None => (data.terminator().span, data.terminator().scope)
Some(stmt) => stmt.source_info,
None => data.terminator().source_info
}
}
pub fn context_for_location(&self, mir: &Mir, loc: Location) -> (Span, ScopeId) {
pub fn source_info_for_location(&self, mir: &Mir, loc: Location) -> SourceInfo {
let data = match loc.block.index().checked_sub(mir.basic_blocks.len()) {
Some(new) => &self.new_blocks[new],
None => mir.basic_block_data(loc.block)
};
Self::context_for_index(data, loc)
Self::source_info_for_index(data, loc)
}
}

View file

@ -22,7 +22,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ast_block: &'tcx hir::Block)
-> BlockAnd<()> {
let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block);
self.in_scope(extent, block, move |this, _| {
self.in_scope(extent, block, move |this| {
// This convoluted structure is to avoid using recursion as we walk down a list
// of statements. Basically, the structure we get back is something like:
//
@ -40,27 +40,40 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
//
// First we build all the statements in the block.
let mut let_extent_stack = Vec::with_capacity(8);
let outer_visibility_scope = this.visibility_scope;
for stmt in stmts {
let Stmt { span: _, kind } = this.hir.mirror(stmt);
match kind {
StmtKind::Expr { scope, expr } => {
unpack!(block = this.in_scope(scope, block, |this, _| {
unpack!(block = this.in_scope(scope, block, |this| {
let expr = this.hir.mirror(expr);
this.stmt_expr(block, expr)
}));
}
StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
let remainder_scope_id = this.push_scope(remainder_scope, block);
let tcx = this.hir.tcx();
// Enter the remainder scope, i.e. the bindings' destruction scope.
this.push_scope(remainder_scope, block);
let_extent_stack.push(remainder_scope);
unpack!(block = this.in_scope(init_scope, block, move |this, _| {
// FIXME #30046 ^~~~
if let Some(init) = initializer {
this.expr_into_pattern(block, remainder_scope_id, pattern, init)
} else {
this.declare_bindings(remainder_scope_id, &pattern);
block.unit()
}
}));
// Declare the bindings, which may create a visibility scope.
let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.map);
let remainder_span = remainder_span.unwrap_or(span);
let scope = this.declare_bindings(None, remainder_span, &pattern);
// Evaluate the initializer, if present.
if let Some(init) = initializer {
unpack!(block = this.in_scope(init_scope, block, move |this| {
// FIXME #30046 ^~~~
this.expr_into_pattern(block, pattern, init)
}));
}
// Enter the visibility scope, after evaluating the initializer.
if let Some(visibility_scope) = scope {
this.visibility_scope = visibility_scope;
}
}
}
}
@ -70,14 +83,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
unpack!(block = this.into(destination, block, expr));
} else if dest_is_unit {
// FIXME(#31472)
let scope_id = this.innermost_scope_id();
this.cfg.push_assign_unit(block, scope_id, span, destination);
let source_info = this.source_info(span);
this.cfg.push_assign_unit(block, source_info, destination);
}
// Finally, we pop all the let scopes before exiting out from the scope of block
// itself.
for extent in let_extent_stack.into_iter().rev() {
unpack!(block = this.pop_scope(extent, block));
}
// Restore the original visibility scope.
this.visibility_scope = outer_visibility_scope;
block.unit()
})
}

View file

@ -15,7 +15,6 @@
use build::{CFG, Location};
use rustc::mir::repr::*;
use syntax::codemap::Span;
impl<'tcx> CFG<'tcx> {
pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
@ -50,47 +49,41 @@ impl<'tcx> CFG<'tcx> {
pub fn push_assign(&mut self,
block: BasicBlock,
scope: ScopeId,
span: Span,
source_info: SourceInfo,
lvalue: &Lvalue<'tcx>,
rvalue: Rvalue<'tcx>) {
self.push(block, Statement {
scope: scope,
span: span,
source_info: source_info,
kind: StatementKind::Assign(lvalue.clone(), rvalue)
});
}
pub fn push_assign_constant(&mut self,
block: BasicBlock,
scope: ScopeId,
span: Span,
source_info: SourceInfo,
temp: &Lvalue<'tcx>,
constant: Constant<'tcx>) {
self.push_assign(block, scope, span, temp,
self.push_assign(block, source_info, temp,
Rvalue::Use(Operand::Constant(constant)));
}
pub fn push_assign_unit(&mut self,
block: BasicBlock,
scope: ScopeId,
span: Span,
source_info: SourceInfo,
lvalue: &Lvalue<'tcx>) {
self.push_assign(block, scope, span, lvalue, Rvalue::Aggregate(
self.push_assign(block, source_info, lvalue, Rvalue::Aggregate(
AggregateKind::Tuple, vec![]
));
}
pub fn terminate(&mut self,
block: BasicBlock,
scope: ScopeId,
span: Span,
source_info: SourceInfo,
kind: TerminatorKind<'tcx>) {
debug_assert!(self.block_data(block).terminator.is_none(),
"terminate: block {:?} already has a terminator set", block);
self.block_data_mut(block).terminator = Some(Terminator {
span: span,
scope: scope,
source_info: source_info,
kind: kind,
});
}

View file

@ -34,11 +34,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
debug!("expr_as_lvalue(block={:?}, expr={:?})", block, expr);
let this = self;
let scope_id = this.innermost_scope_id();
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
match expr.kind {
ExprKind::Scope { extent, value } => {
this.in_scope(extent, block, |this, _| this.as_lvalue(block, value))
this.in_scope(extent, block, |this| this.as_lvalue(block, value))
}
ExprKind::Field { lhs, name } => {
let lvalue = unpack!(block = this.as_lvalue(block, lhs));
@ -59,9 +59,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// bounds check:
let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
this.cfg.push_assign(block, scope_id, expr_span, // len = len(slice)
this.cfg.push_assign(block, source_info, // len = len(slice)
&len, Rvalue::Len(slice.clone()));
this.cfg.push_assign(block, scope_id, expr_span, // lt = idx < len
this.cfg.push_assign(block, source_info, // lt = idx < len
&lt, Rvalue::BinaryOp(BinOp::Lt,
idx.clone(),
Operand::Consume(len.clone())));

View file

@ -35,7 +35,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let this = self;
if let ExprKind::Scope { extent, value } = expr.kind {
return this.in_scope(extent, block, |this, _| this.as_operand(block, value));
return this.in_scope(extent, block, |this| this.as_operand(block, value));
}
let category = Category::of(&expr.kind).unwrap();

View file

@ -41,12 +41,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr);
let this = self;
let scope_id = this.innermost_scope_id();
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
match expr.kind {
ExprKind::Scope { extent, value } => {
this.in_scope(extent, block, |this, _| this.as_rvalue(block, value))
this.in_scope(extent, block, |this| this.as_rvalue(block, value))
}
ExprKind::InlineAsm { asm, outputs, inputs } => {
let outputs = outputs.into_iter().map(|output| {
@ -86,7 +86,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let minval = this.minval_literal(expr_span, expr.ty);
let is_min = this.temp(bool_ty);
this.cfg.push_assign(block, scope_id, expr_span, &is_min,
this.cfg.push_assign(block, source_info, &is_min,
Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval));
let err = ConstMathErr::Overflow(Op::Neg);
@ -99,8 +99,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let value = this.hir.mirror(value);
let result = this.temp(expr.ty);
// to start, malloc some memory of suitable type (thus far, uninitialized):
this.cfg.push_assign(block, scope_id, expr_span, &result, Rvalue::Box(value.ty));
this.in_scope(value_extents, block, |this, _| {
this.cfg.push_assign(block, source_info, &result, Rvalue::Box(value.ty));
this.in_scope(value_extents, block, |this| {
// schedule a shallow free of that memory, lest we unwind:
this.schedule_box_free(expr_span, value_extents, &result, value.ty);
// initialize the box contents:
@ -245,13 +245,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pub fn build_binary_op(&mut self, mut block: BasicBlock,
op: BinOp, span: Span, ty: ty::Ty<'tcx>,
lhs: Operand<'tcx>, rhs: Operand<'tcx>) -> BlockAnd<Rvalue<'tcx>> {
let scope_id = self.innermost_scope_id();
let source_info = self.source_info(span);
let bool_ty = self.hir.bool_ty();
if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
let result_tup = self.hir.tcx().mk_tup(vec![ty, bool_ty]);
let result_value = self.temp(result_tup);
self.cfg.push_assign(block, scope_id, span,
self.cfg.push_assign(block, source_info,
&result_value, Rvalue::CheckedBinaryOp(op,
lhs,
rhs));
@ -292,7 +292,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// Check for / 0
let is_zero = self.temp(bool_ty);
let zero = self.zero_literal(span, ty);
self.cfg.push_assign(block, scope_id, span, &is_zero,
self.cfg.push_assign(block, source_info, &is_zero,
Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero));
block = self.assert(block, Operand::Consume(is_zero), false,
@ -310,14 +310,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
self.cfg.push_assign(block, scope_id, span, &is_neg_1,
self.cfg.push_assign(block, source_info, &is_neg_1,
Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), neg_1));
self.cfg.push_assign(block, scope_id, span, &is_min,
self.cfg.push_assign(block, source_info, &is_min,
Rvalue::BinaryOp(BinOp::Eq, lhs.clone(), min));
let is_neg_1 = Operand::Consume(is_neg_1);
let is_min = Operand::Consume(is_min);
self.cfg.push_assign(block, scope_id, span, &of,
self.cfg.push_assign(block, source_info, &of,
Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min));
block = self.assert(block, Operand::Consume(of), false,

View file

@ -30,7 +30,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let this = self;
if let ExprKind::Scope { extent, value } = expr.kind {
return this.in_scope(extent, block, |this, _| this.as_temp(block, value));
return this.in_scope(extent, block, |this| this.as_temp(block, value));
}
let expr_ty = expr.ty.clone();
@ -49,8 +49,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Category::Lvalue => {
let lvalue = unpack!(block = this.as_lvalue(block, expr));
let rvalue = Rvalue::Use(Operand::Consume(lvalue));
let scope_id = this.innermost_scope_id();
this.cfg.push_assign(block, scope_id, expr_span, &temp, rvalue);
let source_info = this.source_info(expr_span);
this.cfg.push_assign(block, source_info, &temp, rvalue);
}
_ => {
unpack!(block = this.into(&temp, block, expr));

View file

@ -33,11 +33,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// just use the name `this` uniformly
let this = self;
let expr_span = expr.span;
let scope_id = this.innermost_scope_id();
let source_info = this.source_info(expr_span);
match expr.kind {
ExprKind::Scope { extent, value } => {
this.in_scope(extent, block, |this, _| this.into(destination, block, value))
this.in_scope(extent, block, |this| this.into(destination, block, value))
}
ExprKind::Block { body: ast_block } => {
this.ast_block(destination, expr.ty.is_nil(), block, ast_block)
@ -50,7 +50,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let mut then_block = this.cfg.start_new_block();
let mut else_block = this.cfg.start_new_block();
this.cfg.terminate(block, scope_id, expr_span, TerminatorKind::If {
this.cfg.terminate(block, source_info, TerminatorKind::If {
cond: operand,
targets: (then_block, else_block)
});
@ -61,19 +61,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} else {
// Body of the `if` expression without an `else` clause must return `()`, thus
// we implicitly generate a `else {}` if it is not specified.
let scope_id = this.innermost_scope_id();
this.cfg.push_assign_unit(else_block, scope_id, expr_span, destination);
this.cfg.push_assign_unit(else_block, source_info, destination);
else_block
};
let join_block = this.cfg.start_new_block();
this.cfg.terminate(then_block,
scope_id,
expr_span,
this.cfg.terminate(then_block, source_info,
TerminatorKind::Goto { target: join_block });
this.cfg.terminate(else_block,
scope_id,
expr_span,
this.cfg.terminate(else_block, source_info,
TerminatorKind::Goto { target: join_block });
join_block.unit()
@ -100,19 +95,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
LogicalOp::And => (else_block, false_block),
LogicalOp::Or => (true_block, else_block),
};
this.cfg.terminate(block,
scope_id,
expr_span,
this.cfg.terminate(block, source_info,
TerminatorKind::If { cond: lhs, targets: blocks });
let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
this.cfg.terminate(else_block, scope_id, expr_span, TerminatorKind::If {
this.cfg.terminate(else_block, source_info, TerminatorKind::If {
cond: rhs,
targets: (true_block, false_block)
});
this.cfg.push_assign_constant(
true_block, scope_id, expr_span, destination,
true_block, source_info, destination,
Constant {
span: expr_span,
ty: this.hir.bool_ty(),
@ -120,20 +113,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
});
this.cfg.push_assign_constant(
false_block, scope_id, expr_span, destination,
false_block, source_info, destination,
Constant {
span: expr_span,
ty: this.hir.bool_ty(),
literal: this.hir.false_literal(),
});
this.cfg.terminate(true_block,
scope_id,
expr_span,
this.cfg.terminate(true_block, source_info,
TerminatorKind::Goto { target: join_block });
this.cfg.terminate(false_block,
scope_id,
expr_span,
this.cfg.terminate(false_block, source_info,
TerminatorKind::Goto { target: join_block });
join_block.unit()
@ -158,9 +147,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let exit_block = this.cfg.start_new_block();
// start the loop
this.cfg.terminate(block,
scope_id,
expr_span,
this.cfg.terminate(block, source_info,
TerminatorKind::Goto { target: loop_block });
let might_break = this.in_loop_scope(loop_block, exit_block, move |this| {
@ -173,9 +160,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let loop_block_end;
let cond = unpack!(loop_block_end = this.as_operand(loop_block, cond_expr));
body_block = this.cfg.start_new_block();
this.cfg.terminate(loop_block_end,
scope_id,
expr_span,
this.cfg.terminate(loop_block_end, source_info,
TerminatorKind::If {
cond: cond,
targets: (body_block, exit_block)
@ -192,15 +177,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let tmp = this.get_unit_temp();
// Execute the body, branching back to the test.
let body_block_end = unpack!(this.into(&tmp, body_block, body));
this.cfg.terminate(body_block_end,
scope_id,
expr_span,
this.cfg.terminate(body_block_end, source_info,
TerminatorKind::Goto { target: loop_block });
});
// If the loop may reach its exit_block, we assign an empty tuple to the
// destination to keep the MIR well-formed.
if might_break {
this.cfg.push_assign_unit(exit_block, scope_id, expr_span, destination);
this.cfg.push_assign_unit(exit_block, source_info, destination);
}
exit_block.unit()
}
@ -219,7 +202,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let success = this.cfg.start_new_block();
let cleanup = this.diverge_cleanup();
this.cfg.terminate(block, scope_id, expr_span, TerminatorKind::Call {
this.cfg.terminate(block, source_info, TerminatorKind::Call {
func: fun,
args: args,
cleanup: cleanup,
@ -269,7 +252,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
});
let rvalue = unpack!(block = this.as_rvalue(block, expr));
this.cfg.push_assign(block, scope_id, expr_span, destination, rvalue);
this.cfg.push_assign(block, source_info, destination, rvalue);
block.unit()
}
}

View file

@ -20,18 +20,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<()> {
let this = self;
let expr_span = expr.span;
let scope_id = this.innermost_scope_id();
let source_info = this.source_info(expr.span);
// Handle a number of expressions that don't need a destination at all. This
// avoids needing a mountain of temporary `()` variables.
match expr.kind {
ExprKind::Scope { extent, value } => {
let value = this.hir.mirror(value);
this.in_scope(extent, block, |this, _| this.stmt_expr(block, value))
this.in_scope(extent, block, |this| this.stmt_expr(block, value))
}
ExprKind::Assign { lhs, rhs } => {
let lhs = this.hir.mirror(lhs);
let rhs = this.hir.mirror(rhs);
let scope_id = this.innermost_scope_id();
let lhs_span = lhs.span;
// Note: we evaluate assignments right-to-left. This
@ -50,7 +49,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} else {
let rhs = unpack!(block = this.as_rvalue(block, rhs));
let lhs = unpack!(block = this.as_lvalue(block, lhs));
this.cfg.push_assign(block, scope_id, expr_span, &lhs, rhs);
this.cfg.push_assign(block, source_info, &lhs, rhs);
block.unit()
}
}
@ -75,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// (overloaded ops should be desugared into a call).
let result = unpack!(block = this.build_binary_op(block, op, expr_span, lhs_ty,
Operand::Consume(lhs.clone()), rhs));
this.cfg.push_assign(block, scope_id, expr_span, &lhs, result);
this.cfg.push_assign(block, source_info, &lhs, result);
block.unit()
}
@ -93,8 +92,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
block = match value {
Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)),
None => {
this.cfg.push_assign_unit(block, scope_id,
expr_span, &Lvalue::ReturnPointer);
this.cfg.push_assign_unit(block, source_info, &Lvalue::ReturnPointer);
block
}
};
@ -104,7 +102,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
this.cfg.start_new_block().unit()
}
_ => {
let expr_span = expr.span;
let expr_ty = expr.ty;
let temp = this.temp(expr.ty.clone());
unpack!(block = this.into(&temp, block, expr));

View file

@ -44,21 +44,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
.collect(),
};
// Get the body expressions and their scopes, while declaring bindings.
let arm_bodies: Vec<_> = arms.iter().enumerate().map(|(i, arm)| {
// Assume that all expressions are wrapped in Scope.
// Get the arm bodies and their scopes, while declaring bindings.
let arm_bodies: Vec<_> = arms.iter().map(|arm| {
let body = self.hir.mirror(arm.body.clone());
match body.kind {
ExprKind::Scope { extent, value } => {
let scope_id = self.push_scope(extent, arm_blocks.blocks[i]);
self.declare_bindings(scope_id, &arm.patterns[0]);
(extent, self.scopes.pop().unwrap(), value)
}
_ => {
span_bug!(body.span, "arm body is not wrapped in Scope {:?}",
body.kind);
}
}
let scope = self.declare_bindings(None, body.span, &arm.patterns[0]);
(body, scope.unwrap_or(self.visibility_scope))
}).collect();
// assemble a list of candidates: there is one candidate per
@ -99,63 +89,46 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// all the arm blocks will rejoin here
let end_block = self.cfg.start_new_block();
let scope_id = self.innermost_scope_id();
for (arm_index, (extent, scope, body)) in arm_bodies.into_iter().enumerate() {
let outer_source_info = self.source_info(span);
for (arm_index, (body, visibility_scope)) in arm_bodies.into_iter().enumerate() {
let mut arm_block = arm_blocks.blocks[arm_index];
// Re-enter the scope we created the bindings in.
self.scopes.push(scope);
// Re-enter the visibility scope we created the bindings in.
self.visibility_scope = visibility_scope;
unpack!(arm_block = self.into(destination, arm_block, body));
unpack!(arm_block = self.pop_scope(extent, arm_block));
self.cfg.terminate(arm_block,
scope_id,
span,
self.cfg.terminate(arm_block, outer_source_info,
TerminatorKind::Goto { target: end_block });
}
self.visibility_scope = outer_source_info.scope;
end_block.unit()
}
pub fn expr_into_pattern(&mut self,
mut block: BasicBlock,
var_scope_id: ScopeId, // lifetime of vars
irrefutable_pat: Pattern<'tcx>,
initializer: ExprRef<'tcx>)
-> BlockAnd<()> {
// optimize the case of `let x = ...`
match *irrefutable_pat.kind {
PatternKind::Binding { mutability,
name,
mode: BindingMode::ByValue,
PatternKind::Binding { mode: BindingMode::ByValue,
var,
ty,
subpattern: None } => {
let index = self.declare_binding(var_scope_id,
mutability,
name,
var,
ty,
irrefutable_pat.span);
let lvalue = Lvalue::Var(index);
subpattern: None, .. } => {
let lvalue = Lvalue::Var(self.var_indices[&var]);
return self.into(&lvalue, block, initializer);
}
_ => {}
}
let lvalue = unpack!(block = self.as_lvalue(block, initializer));
self.lvalue_into_pattern(block,
var_scope_id,
irrefutable_pat,
&lvalue)
}
pub fn lvalue_into_pattern(&mut self,
mut block: BasicBlock,
var_scope_id: ScopeId,
irrefutable_pat: Pattern<'tcx>,
initializer: &Lvalue<'tcx>)
-> BlockAnd<()> {
// first, creating the bindings
self.declare_bindings(var_scope_id, &irrefutable_pat);
// create a dummy candidate
let mut candidate = Candidate {
span: irrefutable_pat.span,
@ -182,32 +155,47 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
block.unit()
}
pub fn declare_bindings(&mut self, var_scope_id: ScopeId, pattern: &Pattern<'tcx>) {
/// Declares the bindings of the given pattern and returns the visibility scope
/// for the bindings in this patterns, if such a scope had to be created.
/// NOTE: Declaring the bindings should always be done in their drop scope.
pub fn declare_bindings(&mut self,
mut var_scope: Option<VisibilityScope>,
scope_span: Span,
pattern: &Pattern<'tcx>)
-> Option<VisibilityScope> {
match *pattern.kind {
PatternKind::Binding { mutability, name, mode: _, var, ty, ref subpattern } => {
self.declare_binding(var_scope_id, mutability, name, var, ty, pattern.span);
if var_scope.is_none() {
var_scope = Some(self.new_visibility_scope(scope_span));
}
let source_info = SourceInfo {
span: pattern.span,
scope: var_scope.unwrap()
};
self.declare_binding(source_info, mutability, name, var, ty);
if let Some(subpattern) = subpattern.as_ref() {
self.declare_bindings(var_scope_id, subpattern);
var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
}
}
PatternKind::Array { ref prefix, ref slice, ref suffix } |
PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
for subpattern in prefix.iter().chain(slice).chain(suffix) {
self.declare_bindings(var_scope_id, subpattern);
var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
}
}
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
}
PatternKind::Deref { ref subpattern } => {
self.declare_bindings(var_scope_id, subpattern);
var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
}
PatternKind::Leaf { ref subpatterns } |
PatternKind::Variant { ref subpatterns, .. } => {
for subpattern in subpatterns {
self.declare_bindings(var_scope_id, &subpattern.pattern);
var_scope = self.declare_bindings(var_scope, scope_span, &subpattern.pattern);
}
}
}
var_scope
}
}
@ -396,17 +384,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
mut otherwise: Vec<BasicBlock>)
-> BasicBlock
{
let source_info = self.source_info(span);
otherwise.sort();
otherwise.dedup(); // variant switches can introduce duplicate target blocks
let scope_id = self.innermost_scope_id();
if otherwise.len() == 1 {
otherwise[0]
} else {
let join_block = self.cfg.start_new_block();
for block in otherwise {
self.cfg.terminate(block,
scope_id,
span,
self.cfg.terminate(block, source_info,
TerminatorKind::Goto { target: join_block });
}
join_block
@ -585,24 +571,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let arm_block = arm_blocks.blocks[candidate.arm_index];
let scope_id = self.innermost_scope_id();
if let Some(guard) = candidate.guard {
// the block to branch to if the guard fails; if there is no
// guard, this block is simply unreachable
let guard = self.hir.mirror(guard);
let guard_span = guard.span;
let source_info = self.source_info(guard.span);
let cond = unpack!(block = self.as_operand(block, guard));
let otherwise = self.cfg.start_new_block();
self.cfg.terminate(block,
scope_id,
guard_span,
self.cfg.terminate(block, source_info,
TerminatorKind::If { cond: cond,
targets: (arm_block, otherwise)});
Some(otherwise)
} else {
self.cfg.terminate(block,
scope_id,
candidate.span,
let source_info = self.source_info(candidate.span);
self.cfg.terminate(block, source_info,
TerminatorKind::Goto { target: arm_block });
None
}
@ -628,35 +610,33 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Rvalue::Ref(region, borrow_kind, binding.source),
};
let scope_id = self.innermost_scope_id();
self.cfg.push_assign(block, scope_id, binding.span,
let source_info = self.source_info(binding.span);
self.cfg.push_assign(block, source_info,
&Lvalue::Var(var_index), rvalue);
}
}
fn declare_binding(&mut self,
var_scope_id: ScopeId,
source_info: SourceInfo,
mutability: Mutability,
name: Name,
var_id: NodeId,
var_ty: Ty<'tcx>,
span: Span)
var_ty: Ty<'tcx>)
-> u32
{
debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, var_scope_id={:?}, span={:?})",
var_id, name, var_ty, var_scope_id, span);
debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})",
var_id, name, var_ty, source_info);
let index = self.var_decls.len();
self.var_decls.push(VarDecl::<'tcx> {
scope: var_scope_id,
source_info: source_info,
mutability: mutability,
name: name,
ty: var_ty.clone(),
span: span,
});
let index = index as u32;
let extent = self.scope_auxiliary[var_scope_id].extent;
self.schedule_drop(span, extent, &Lvalue::Var(index), var_ty);
let extent = self.extent_of_innermost_scope();
self.schedule_drop(source_info.span, extent, &Lvalue::Var(index), var_ty);
self.var_indices.insert(var_id, index);
debug!("declare_binding: index={:?}", index);

View file

@ -176,7 +176,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
lvalue: &Lvalue<'tcx>,
test: &Test<'tcx>)
-> Vec<BasicBlock> {
let scope_id = self.innermost_scope_id();
let source_info = self.source_info(test.span);
match test.kind {
TestKind::Switch { adt_def, ref variants } => {
let num_enum_variants = self.hir.num_variants(adt_def);
@ -193,7 +193,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}).collect();
debug!("num_enum_variants: {}, num tested variants: {}, variants: {:?}",
num_enum_variants, variants.iter().count(), variants);
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch {
self.cfg.terminate(block, source_info, TerminatorKind::Switch {
discr: lvalue.clone(),
adt_def: adt_def,
targets: target_blocks.clone()
@ -245,10 +245,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
};
self.cfg.terminate(block,
scope_id,
test.span,
term);
self.cfg.terminate(block, source_info, term);
targets
}
@ -265,7 +262,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
if let ty::TyArray(_, _) = mt.ty.sty {
ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8));
let val_slice = self.temp(ty);
self.cfg.push_assign(block, scope_id, test.span, &val_slice,
self.cfg.push_assign(block, source_info, &val_slice,
Rvalue::Cast(CastKind::Unsize, val, ty));
val = Operand::Consume(val_slice);
}
@ -280,7 +277,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
});
let slice = self.temp(ty);
self.cfg.push_assign(block, scope_id, test.span, &slice,
self.cfg.push_assign(block, source_info, &slice,
Rvalue::Cast(CastKind::Unsize, array, ty));
Operand::Consume(slice)
} else {
@ -301,7 +298,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let eq_result = self.temp(bool_ty);
let eq_block = self.cfg.start_new_block();
let cleanup = self.diverge_cleanup();
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Call {
self.cfg.terminate(block, source_info, TerminatorKind::Call {
func: Operand::Constant(Constant {
span: test.span,
ty: mty,
@ -314,7 +311,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// check the result
let block = self.cfg.start_new_block();
self.cfg.terminate(eq_block, scope_id, test.span, TerminatorKind::If {
self.cfg.terminate(eq_block, source_info, TerminatorKind::If {
cond: Operand::Consume(eq_result),
targets: (block, fail),
});
@ -344,17 +341,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty));
// actual = len(lvalue)
self.cfg.push_assign(block, scope_id, test.span,
self.cfg.push_assign(block, source_info,
&actual, Rvalue::Len(lvalue.clone()));
// expected = <N>
let expected = self.push_usize(block, scope_id, test.span, len);
let expected = self.push_usize(block, source_info, len);
// result = actual == expected OR result = actual < expected
self.cfg.push_assign(block,
scope_id,
test.span,
&result,
self.cfg.push_assign(block, source_info, &result,
Rvalue::BinaryOp(op,
Operand::Consume(actual),
Operand::Consume(expected)));
@ -362,7 +356,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// branch based on result
let target_blocks: Vec<_> = vec![self.cfg.start_new_block(),
self.cfg.start_new_block()];
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::If {
self.cfg.terminate(block, source_info, TerminatorKind::If {
cond: Operand::Consume(result),
targets: (target_blocks[0], target_blocks[1])
});
@ -383,13 +377,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let result = self.temp(bool_ty);
// result = op(left, right)
let scope_id = self.innermost_scope_id();
self.cfg.push_assign(block, scope_id, span, &result,
let source_info = self.source_info(span);
self.cfg.push_assign(block, source_info, &result,
Rvalue::BinaryOp(op, left, right));
// branch based on result
let target_block = self.cfg.start_new_block();
self.cfg.terminate(block, scope_id, span, TerminatorKind::If {
self.cfg.terminate(block, source_info, TerminatorKind::If {
cond: Operand::Consume(result),
targets: (target_block, fail_block)
});

View file

@ -65,8 +65,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
from_end: suffix_len,
};
let temp = self.temp(slice.ty.clone()); // no need to schedule drop, temp is always copy
let scope_id = self.innermost_scope_id();
self.cfg.push_assign(block, scope_id, slice.span, &temp, rvalue);
let source_info = self.source_info(slice.span);
self.cfg.push_assign(block, source_info, &temp, rvalue);
match_pairs.push(MatchPair::new(temp, slice));
}

View file

@ -103,16 +103,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pub fn push_usize(&mut self,
block: BasicBlock,
scope_id: ScopeId,
span: Span,
source_info: SourceInfo,
value: u64)
-> Lvalue<'tcx> {
let usize_ty = self.hir.usize_ty();
let temp = self.temp(usize_ty);
self.cfg.push_assign_constant(
block, scope_id, span, &temp,
block, source_info, &temp,
Constant {
span: span,
span: source_info.span,
ty: self.hir.usize_ty(),
literal: self.hir.usize_literal(value),
});

View file

@ -15,6 +15,7 @@ use rustc::mir::repr::*;
use rustc_data_structures::fnv::FnvHashMap;
use rustc::hir;
use std::ops::{Index, IndexMut};
use std::u32;
use syntax::abi::Abi;
use syntax::ast;
use syntax::codemap::Span;
@ -43,7 +44,8 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
/// the vector of all scopes that we have created thus far;
/// we track this for debuginfo later
scope_datas: Vec<ScopeData>,
visibility_scopes: Vec<VisibilityScopeData>,
visibility_scope: VisibilityScope,
var_decls: Vec<VarDecl<'tcx>>,
var_indices: FnvHashMap<ast::NodeId, u32>,
@ -61,6 +63,20 @@ struct CFG<'tcx> {
basic_blocks: Vec<BasicBlockData<'tcx>>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ScopeId(u32);
impl ScopeId {
pub fn new(index: usize) -> ScopeId {
assert!(index < (u32::MAX as usize));
ScopeId(index as u32)
}
pub fn index(self) -> usize {
self.0 as usize
}
}
/// For each scope, we track the extent (from the HIR) and a
/// single-entry-multiple-exit subgraph that contains all the
/// statements/terminators within it.
@ -179,17 +195,16 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
tcx.region_maps.lookup_code_extent(
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
let mut block = START_BLOCK;
let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block,
|builder, call_site_scope_id| {
let arg_decls = unpack!(block = builder.in_scope(arg_extent, block,
|builder, arg_scope_id| {
builder.args_and_body(block, return_ty, arguments, arg_scope_id, ast_block)
let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| {
builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block)
}));
let source_info = builder.source_info(span);
let return_block = builder.return_block();
builder.cfg.terminate(block, call_site_scope_id, span,
builder.cfg.terminate(block, source_info,
TerminatorKind::Goto { target: return_block });
builder.cfg.terminate(return_block, call_site_scope_id, span,
builder.cfg.terminate(return_block, source_info,
TerminatorKind::Return);
return_block.and(arg_decls)
}));
@ -241,14 +256,15 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
let extent = ROOT_CODE_EXTENT;
let mut block = START_BLOCK;
let _ = builder.in_scope(extent, block, |builder, call_site_scope_id| {
let _ = builder.in_scope(extent, block, |builder| {
let expr = builder.hir.mirror(ast_expr);
unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr));
let source_info = builder.source_info(span);
let return_block = builder.return_block();
builder.cfg.terminate(block, call_site_scope_id, span,
builder.cfg.terminate(block, source_info,
TerminatorKind::Goto { target: return_block });
builder.cfg.terminate(return_block, call_site_scope_id, span,
builder.cfg.terminate(return_block, source_info,
TerminatorKind::Return);
return_block.unit()
@ -265,7 +281,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
cfg: CFG { basic_blocks: vec![] },
fn_span: span,
scopes: vec![],
scope_datas: vec![],
visibility_scopes: vec![],
visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
loop_scopes: vec![],
temp_decls: vec![],
@ -277,6 +294,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
};
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
assert_eq!(builder.new_visibility_scope(span), ARGUMENT_VISIBILITY_SCOPE);
builder.visibility_scopes[ARGUMENT_VISIBILITY_SCOPE].parent_scope = None;
builder
}
@ -294,7 +313,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
(Mir {
basic_blocks: self.cfg.basic_blocks,
scopes: self.scope_datas,
visibility_scopes: self.visibility_scopes,
promoted: vec![],
var_decls: self.var_decls,
arg_decls: arg_decls,
@ -309,24 +328,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
mut block: BasicBlock,
return_ty: ty::FnOutput<'tcx>,
arguments: A,
argument_scope_id: ScopeId,
argument_extent: CodeExtent,
ast_block: &'gcx hir::Block)
-> BlockAnd<Vec<ArgDecl<'tcx>>>
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
{
// to start, translate the argument patterns and collect the argument types.
let mut scope = None;
let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
let lvalue = Lvalue::Arg(index as u32);
if let Some(pattern) = pattern {
let pattern = self.hir.irrefutable_pat(pattern);
unpack!(block = self.lvalue_into_pattern(block,
argument_scope_id,
pattern,
&lvalue));
scope = self.declare_bindings(scope, ast_block.span, &pattern);
unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
}
// Make sure we drop (parts of) the argument even when not matched on.
let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
argument_extent, &lvalue, ty);
@ -344,6 +361,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}).collect();
// Enter the argument pattern bindings visibility scope, if it exists.
if let Some(visibility_scope) = scope {
self.visibility_scope = visibility_scope;
}
// FIXME(#32959): temporary hack for the issue at hand
let return_is_unit = if let ty::FnConverging(t) = return_ty {
t.is_nil()

View file

@ -86,7 +86,7 @@ should go to.
*/
use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary};
use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId};
use rustc::middle::region::{CodeExtent, CodeExtentData};
use rustc::middle::lang_items;
use rustc::ty::subst::{Substs, Subst, VecPerParamSpace};
@ -98,9 +98,12 @@ use rustc::middle::const_val::ConstVal;
use rustc_const_math::ConstInt;
pub struct Scope<'tcx> {
/// the scope-id within the scope_datas
/// the scope-id within the scope_auxiliary
id: ScopeId,
/// The visibility scope this scope was created in.
visibility_scope: VisibilityScope,
/// the extent of this scope within source code; also stored in
/// `ScopeAuxiliary`, but kept here for convenience
extent: CodeExtent,
@ -204,6 +207,14 @@ impl<'tcx> Scope<'tcx> {
None
}
}
/// Given a span and this scope's visibility scope, make a SourceInfo.
fn source_info(&self, span: Span) -> SourceInfo {
SourceInfo {
span: span,
scope: self.visibility_scope
}
}
}
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@ -237,11 +248,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// Convenience wrapper that pushes a scope and then executes `f`
/// to build its contents, popping the scope afterwards.
pub fn in_scope<F, R>(&mut self, extent: CodeExtent, mut block: BasicBlock, f: F) -> BlockAnd<R>
where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>, ScopeId) -> BlockAnd<R>
where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
{
debug!("in_scope(extent={:?}, block={:?})", extent, block);
let id = self.push_scope(extent, block);
let rv = unpack!(block = f(self, id));
self.push_scope(extent, block);
let rv = unpack!(block = f(self));
unpack!(block = self.pop_scope(extent, block));
debug!("in_scope: exiting extent={:?} block={:?}", extent, block);
block.and(rv)
@ -251,17 +262,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// scope and call `pop_scope` afterwards. Note that these two
/// calls must be paired; using `in_scope` as a convenience
/// wrapper maybe preferable.
pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) -> ScopeId {
pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) {
debug!("push_scope({:?})", extent);
let parent_id = self.scopes.last().map(|s| s.id);
let id = ScopeId::new(self.scope_datas.len());
let tcx = self.hir.tcx();
self.scope_datas.push(ScopeData {
span: extent.span(&tcx.region_maps, &tcx.map).unwrap_or(DUMMY_SP),
parent_scope: parent_id,
});
let id = ScopeId::new(self.scope_auxiliary.vec.len());
let vis_scope = self.visibility_scope;
self.scopes.push(Scope {
id: id,
visibility_scope: vis_scope,
extent: extent,
drops: vec![],
free: None,
@ -272,7 +279,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
dom: self.cfg.current_location(entry),
postdoms: vec![]
});
id
}
/// Pops a scope, which should have extent `extent`, adding any
@ -320,7 +326,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
if let Some(ref free_data) = scope.free {
let next = self.cfg.start_new_block();
let free = build_free(self.hir.tcx(), &tmp, free_data, next);
self.cfg.terminate(block, scope.id, span, free);
self.cfg.terminate(block, scope.source_info(span), free);
block = next;
}
self.scope_auxiliary[scope.id]
@ -334,11 +340,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
.next()
.unwrap();
self.cfg.terminate(block,
scope.id,
span,
scope.source_info(span),
TerminatorKind::Goto { target: target });
}
/// Creates a new visibility scope, nested in the current one.
pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope {
let parent = self.visibility_scope;
let scope = VisibilityScope::new(self.visibility_scopes.len());
self.visibility_scopes.push(VisibilityScopeData {
span: span,
parent_scope: Some(parent),
});
scope
}
// Finding scopes
// ==============
/// Finds the loop scope for a given label. This is used for
@ -363,8 +379,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}.unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
}
pub fn innermost_scope_id(&self) -> ScopeId {
self.scopes.last().map(|scope| scope.id).unwrap()
/// Given a span and the current visibility scope, make a SourceInfo.
pub fn source_info(&self, span: Span) -> SourceInfo {
SourceInfo {
span: span,
scope: self.visibility_scope
}
}
pub fn extent_of_innermost_scope(&self) -> CodeExtent {
@ -481,7 +501,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
target
} else {
let resumeblk = cfg.start_new_cleanup_block();
cfg.terminate(resumeblk, scopes[0].id, self.fn_span, TerminatorKind::Resume);
cfg.terminate(resumeblk,
scopes[0].source_info(self.fn_span),
TerminatorKind::Resume);
*cached_resume_block = Some(resumeblk);
resumeblk
};
@ -502,12 +524,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
if !self.hir.needs_drop(ty) {
return block.unit();
}
let scope_id = self.innermost_scope_id();
let source_info = self.source_info(span);
let next_target = self.cfg.start_new_block();
let diverge_target = self.diverge_cleanup();
self.cfg.terminate(block,
scope_id,
span,
self.cfg.terminate(block, source_info,
TerminatorKind::Drop {
location: location,
target: next_target,
@ -522,12 +542,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
span: Span,
location: Lvalue<'tcx>,
value: Operand<'tcx>) -> BlockAnd<()> {
let scope_id = self.innermost_scope_id();
let source_info = self.source_info(span);
let next_target = self.cfg.start_new_block();
let diverge_target = self.diverge_cleanup();
self.cfg.terminate(block,
scope_id,
span,
self.cfg.terminate(block, source_info,
TerminatorKind::DropAndReplace {
location: location,
value: value,
@ -562,18 +580,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let elems = vec![Operand::Constant(message),
Operand::Constant(file),
Operand::Constant(line)];
let scope_id = self.innermost_scope_id();
let source_info = self.source_info(span);
// FIXME: We should have this as a constant, rather than a stack variable (to not pollute
// icache with cold branch code), however to achieve that we either have to rely on rvalue
// promotion or have some way, in MIR, to create constants.
self.cfg.push_assign(block, scope_id, span, &tuple, // [1]
self.cfg.push_assign(block, source_info, &tuple, // [1]
Rvalue::Aggregate(AggregateKind::Tuple, elems));
// [1] tuple = (message_arg, file_arg, line_arg);
// FIXME: is this region really correct here?
self.cfg.push_assign(block, scope_id, span, &tuple_ref, // tuple_ref = &tuple;
self.cfg.push_assign(block, source_info, &tuple_ref, // tuple_ref = &tuple;
Rvalue::Ref(region, BorrowKind::Shared, tuple));
let cleanup = self.diverge_cleanup();
self.cfg.terminate(block, scope_id, span, TerminatorKind::Call {
self.cfg.terminate(block, source_info, TerminatorKind::Call {
func: Operand::Constant(func),
args: vec![Operand::Consume(tuple_ref)],
cleanup: cleanup,
@ -590,12 +608,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
msg: AssertMessage<'tcx>,
span: Span)
-> BasicBlock {
let scope_id = self.innermost_scope_id();
let source_info = self.source_info(span);
let success_block = self.cfg.start_new_block();
let cleanup = self.diverge_cleanup();
self.cfg.terminate(block, scope_id, span,
self.cfg.terminate(block, source_info,
TerminatorKind::Assert {
cond: cond,
expected: expected,
@ -658,7 +676,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next()
});
let next = cfg.start_new_block();
cfg.terminate(block, scope.id, drop_data.span, TerminatorKind::Drop {
cfg.terminate(block, scope.source_info(drop_data.span), TerminatorKind::Drop {
location: drop_data.location.clone(),
target: next,
unwind: on_diverge
@ -688,15 +706,19 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
// remainder. If everything is cached, we'll just walk right to
// left reading the cached results but never created anything.
let visibility_scope = scope.visibility_scope;
let source_info = |span| SourceInfo {
span: span,
scope: visibility_scope
};
// Next, build up any free.
if let Some(ref mut free_data) = scope.free {
target = if let Some(cached_block) = free_data.cached_block {
cached_block
} else {
let into = cfg.start_new_cleanup_block();
cfg.terminate(into,
scope.id,
free_data.span,
cfg.terminate(into, source_info(free_data.span),
build_free(tcx, unit_temp, free_data, target));
free_data.cached_block = Some(into);
into
@ -711,9 +733,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
cached_block
} else {
let block = cfg.start_new_cleanup_block();
cfg.terminate(block,
scope.id,
drop_data.span,
cfg.terminate(block, source_info(drop_data.span),
TerminatorKind::Drop {
location: drop_data.location.clone(),
target: target,

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use build::{Location, ScopeAuxiliaryVec};
use build::{Location, ScopeAuxiliaryVec, ScopeId};
use rustc::hir;
use rustc::mir::repr::*;
use rustc::mir::transform::MirSource;
@ -18,7 +18,6 @@ use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use syntax::ast::NodeId;
use syntax::codemap::Span;
const INDENT: &'static str = " ";
/// Alignment for lining up comments following MIR statements
@ -139,20 +138,11 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
write_mir_intro(tcx, src, mir, w)?;
for block in mir.all_basic_blocks() {
write_basic_block(tcx, block, mir, w, &annotations)?;
if block.index() + 1 != mir.basic_blocks.len() {
writeln!(w, "")?;
}
}
// construct a scope tree and write it out
let mut scope_tree: FnvHashMap<Option<ScopeId>, Vec<ScopeId>> = FnvHashMap();
for (index, scope_data) in mir.scopes.iter().enumerate() {
scope_tree.entry(scope_data.parent_scope)
.or_insert(vec![])
.push(ScopeId::new(index));
}
writeln!(w, "{}scope tree:", INDENT)?;
write_scope_tree(tcx, mir, auxiliary, &scope_tree, w, None, 1, false)?;
writeln!(w, "")?;
writeln!(w, "}}")?;
Ok(())
}
@ -189,7 +179,7 @@ fn write_basic_block(tcx: TyCtxt,
writeln!(w, "{0:1$} // {2}",
indented_mir,
ALIGN,
comment(tcx, statement.scope, statement.span))?;
comment(tcx, statement.source_info))?;
current_location.statement_index += 1;
}
@ -199,71 +189,64 @@ fn write_basic_block(tcx: TyCtxt,
writeln!(w, "{0:1$} // {2}",
indented_terminator,
ALIGN,
comment(tcx, data.terminator().scope, data.terminator().span))?;
comment(tcx, data.terminator().source_info))?;
writeln!(w, "{}}}\n", INDENT)
}
fn comment(tcx: TyCtxt, scope: ScopeId, span: Span) -> String {
fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}
fn write_scope_tree(tcx: TyCtxt,
mir: &Mir,
auxiliary: Option<&ScopeAuxiliaryVec>,
scope_tree: &FnvHashMap<Option<ScopeId>, Vec<ScopeId>>,
scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
w: &mut Write,
parent: Option<ScopeId>,
depth: usize,
same_line: bool)
parent: VisibilityScope,
depth: usize)
-> io::Result<()> {
let indent = if same_line {
0
} else {
depth * INDENT.len()
};
let indent = depth * INDENT.len();
let children = match scope_tree.get(&parent) {
Some(childs) => childs,
None => return Ok(()),
};
for (index, &child) in children.iter().enumerate() {
if index == 0 && same_line {
// We know we're going to output a scope, so prefix it with a space to separate it from
// the previous scopes on this line
write!(w, " ")?;
for &child in children {
let data = &mir.visibility_scopes[child];
assert_eq!(data.parent_scope, Some(parent));
writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;
// User variable types (including the user's name in a comment).
for (i, var) in mir.var_decls.iter().enumerate() {
// Skip if not declared in this scope.
if var.source_info.scope != child {
continue;
}
let mut_str = if var.mutability == Mutability::Mut {
"mut "
} else {
""
};
let indent = indent + INDENT.len();
let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
INDENT,
indent,
mut_str,
Lvalue::Var(i as u32),
var.ty);
writeln!(w, "{0:1$} // \"{2}\" in {3}",
indented_var,
ALIGN,
var.name,
comment(tcx, var.source_info))?;
}
let data = &mir.scopes[child];
assert_eq!(data.parent_scope, parent);
write!(w, "{0:1$}{2}", "", indent, child.index())?;
write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;
let indent = indent + INDENT.len();
if let Some(auxiliary) = auxiliary {
let extent = auxiliary[child].extent;
let data = tcx.region_maps.code_extent_data(extent);
writeln!(w, "{0:1$}Extent: {2:?}", "", indent, data)?;
}
let child_count = scope_tree.get(&Some(child)).map(Vec::len).unwrap_or(0);
if child_count < 2 {
// Skip the braces when there's no or only a single subscope
write_scope_tree(tcx, mir, auxiliary, scope_tree, w,
Some(child), depth, true)?;
} else {
// 2 or more child scopes? Put them in braces and on new lines.
writeln!(w, " {{")?;
write_scope_tree(tcx, mir, auxiliary, scope_tree, w,
Some(child), depth + 1, false)?;
write!(w, "\n{0:1$}}}", "", depth * INDENT.len())?;
}
if !same_line && index + 1 < children.len() {
writeln!(w, "")?;
}
writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
}
Ok(())
@ -278,7 +261,23 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-> io::Result<()> {
write_mir_sig(tcx, src, mir, w)?;
writeln!(w, " {{")?;
write_mir_decls(tcx, mir, w)
// construct a scope tree and write it out
let mut scope_tree: FnvHashMap<VisibilityScope, Vec<VisibilityScope>> = FnvHashMap();
for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
if let Some(parent) = scope_data.parent_scope {
scope_tree.entry(parent)
.or_insert(vec![])
.push(VisibilityScope::new(index));
} else {
// Only the argument scope has no parent, because it's the root.
assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
}
}
write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;
write_mir_decls(mir, w)
}
fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
@ -318,29 +317,7 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
}
}
fn write_mir_decls(tcx: TyCtxt, mir: &Mir, w: &mut Write)
-> io::Result<()>
{
// User variable types (including the user's name in a comment).
for (i, var) in mir.var_decls.iter().enumerate() {
let mut_str = if var.mutability == Mutability::Mut {
"mut "
} else {
""
};
let indented_var = format!("{}let {}{:?}: {};",
INDENT,
mut_str,
Lvalue::Var(i as u32),
var.ty);
writeln!(w, "{0:1$} // \"{2}\" in {3}",
indented_var,
ALIGN,
var.name,
comment(tcx, var.scope, var.span))?;
}
fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
// Compiler-introduced temporary types.
for (i, temp) in mir.temp_decls.iter().enumerate() {
writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?;

View file

@ -66,15 +66,14 @@ impl<'tcx> MirPass<'tcx> for AddCallGuards {
destination: Some((_, ref mut destination)),
cleanup: Some(_),
..
}, span, scope
}, source_info
}) if pred_count[destination.index()] > 1 => {
// It's a critical edge, break it
let call_guard = BasicBlockData {
statements: vec![],
is_cleanup: data.is_cleanup,
terminator: Some(Terminator {
span: span,
scope: scope,
source_info: source_info,
kind: TerminatorKind::Goto { target: *destination }
})
};

View file

@ -117,16 +117,14 @@ impl<'tcx> Visitor<'tcx> for TempCollector {
}
}
fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) {
assert_eq!(self.location.block, bb);
self.span = statement.span;
self.super_statement(bb, statement);
self.location.statement_index += 1;
fn visit_source_info(&mut self, source_info: &SourceInfo) {
self.span = source_info.span;
}
fn visit_terminator(&mut self, bb: BasicBlock, terminator: &Terminator<'tcx>) {
self.span = terminator.span;
self.super_terminator(bb, terminator);
fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) {
assert_eq!(self.location.block, bb);
self.super_statement(bb, statement);
self.location.statement_index += 1;
}
fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
@ -167,8 +165,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
self.promoted.basic_blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
span: self.promoted.span,
scope: ScopeId::new(0),
source_info: SourceInfo {
span: self.promoted.span,
scope: ARGUMENT_VISIBILITY_SCOPE
},
kind: TerminatorKind::Return
}),
is_cleanup: false
@ -179,8 +179,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
fn assign(&mut self, dest: Lvalue<'tcx>, rvalue: Rvalue<'tcx>, span: Span) {
let data = self.promoted.basic_blocks.last_mut().unwrap();
data.statements.push(Statement {
span: span,
scope: ScopeId::new(0),
source_info: SourceInfo {
span: span,
scope: ARGUMENT_VISIBILITY_SCOPE
},
kind: StatementKind::Assign(dest, rvalue)
});
}
@ -214,7 +216,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
// First, take the Rvalue or Call out of the source MIR,
// or duplicate it, depending on keep_original.
let (mut rvalue, mut call) = (None, None);
let span = if stmt_idx < no_stmts {
let source_info = if stmt_idx < no_stmts {
let statement = &mut self.source[bb].statements[stmt_idx];
let StatementKind::Assign(_, ref mut rhs) = statement.kind;
if self.keep_original {
@ -223,11 +225,11 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
let unit = Rvalue::Aggregate(AggregateKind::Tuple, vec![]);
rvalue = Some(mem::replace(rhs, unit));
}
statement.span
statement.source_info
} else if self.keep_original {
let terminator = self.source[bb].terminator().clone();
call = Some(terminator.kind);
terminator.span
terminator.source_info
} else {
let terminator = self.source[bb].terminator_mut();
let target = match terminator.kind {
@ -242,13 +244,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
dest.take().unwrap().1
}
ref kind => {
span_bug!(terminator.span, "{:?} not promotable", kind);
span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
}
};
call = Some(mem::replace(&mut terminator.kind, TerminatorKind::Goto {
target: target
}));
terminator.span
terminator.source_info
};
// Then, recurse for components in the Rvalue or Call.
@ -266,7 +268,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
// Inject the Rvalue or Call into the promoted MIR.
if stmt_idx < no_stmts {
self.assign(new_temp, rvalue.unwrap(), span);
self.assign(new_temp, rvalue.unwrap(), source_info.span);
} else {
let last = self.promoted.basic_blocks.len() - 1;
let new_target = self.new_block();
@ -278,7 +280,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
_ => bug!()
}
let terminator = &mut self.promoted.basic_blocks[last].terminator_mut();
terminator.span = span;
terminator.source_info.span = source_info.span;
terminator.kind = call;
}
@ -346,7 +348,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
continue;
}
}
(statement.span, mir.lvalue_ty(tcx, dest).to_ty(tcx))
(statement.source_info.span, mir.lvalue_ty(tcx, dest).to_ty(tcx))
}
Candidate::ShuffleIndices(bb) => {
let terminator = mir[bb].terminator();
@ -355,11 +357,11 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
mir.operand_ty(tcx, &args[2])
}
_ => {
span_bug!(terminator.span,
span_bug!(terminator.source_info.span,
"expected simd_shuffleN call to promote");
}
};
(terminator.span, ty)
(terminator.source_info.span, ty)
}
};
@ -367,7 +369,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
source: mir,
promoted: Mir {
basic_blocks: vec![],
scopes: vec![ScopeData {
visibility_scopes: vec![VisibilityScopeData {
span: span,
parent_scope: None
}],

View file

@ -377,11 +377,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
let stmt_idx = location.statement_index;
// Get the span for the initialization.
if stmt_idx < data.statements.len() {
self.span = data.statements[stmt_idx].span;
let source_info = if stmt_idx < data.statements.len() {
data.statements[stmt_idx].source_info
} else {
self.span = data.terminator().span;
}
data.terminator().source_info
};
self.span = source_info.span;
// Treat this as a statement in the AST.
self.statement_like();
@ -830,7 +831,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
// Avoid a generic error for other uses of arguments.
if self.qualif.intersects(Qualif::FN_ARGUMENT) {
let decl = &self.mir.var_decls[index as usize];
span_err!(self.tcx.sess, decl.span, E0022,
span_err!(self.tcx.sess, decl.source_info.span, E0022,
"arguments of constant functions can only \
be immutable by-value bindings");
return;
@ -841,16 +842,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
self.assign(dest);
}
fn visit_source_info(&mut self, source_info: &SourceInfo) {
self.span = source_info.span;
}
fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) {
assert_eq!(self.location.block, bb);
self.span = statement.span;
self.nest(|this| this.super_statement(bb, statement));
self.location.statement_index += 1;
}
fn visit_terminator(&mut self, bb: BasicBlock, terminator: &Terminator<'tcx>) {
assert_eq!(self.location.block, bb);
self.span = terminator.span;
self.nest(|this| this.super_terminator(bb, terminator));
}

View file

@ -551,7 +551,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block: &BasicBlockData<'tcx>)
{
let is_cleanup = block.is_cleanup;
self.last_span = block.terminator().span;
self.last_span = block.terminator().source_info.span;
match block.terminator().kind {
TerminatorKind::Goto { target } =>
self.assert_iscleanup(mir, block, target, is_cleanup),
@ -617,8 +617,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
debug!("run_on_mir: {:?}", mir.span);
for block in &mir.basic_blocks {
for stmt in &block.statements {
if stmt.span != DUMMY_SP {
self.last_span = stmt.span;
if stmt.source_info.span != DUMMY_SP {
self.last_span = stmt.source_info.span;
}
self.check_stmt(mir, stmt);
}

View file

@ -16,7 +16,7 @@ use llvm;
use llvm::debuginfo::{DIScope, DISubprogram};
use common::{CrateContext, FunctionContext};
use rustc::hir::pat_util;
use rustc::mir::repr::{Mir, ScopeId};
use rustc::mir::repr::{Mir, VisibilityScope};
use rustc::util::nodemap::NodeMap;
use libc::c_uint;
@ -71,7 +71,7 @@ pub fn create_scope_map(cx: &CrateContext,
/// If debuginfo is disabled, the returned vector is empty.
pub fn create_mir_scopes(fcx: &FunctionContext) -> Vec<DIScope> {
let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn");
let mut scopes = vec![ptr::null_mut(); mir.scopes.len()];
let mut scopes = vec![ptr::null_mut(); mir.visibility_scopes.len()];
let fn_metadata = match fcx.debug_context {
FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata,
@ -82,14 +82,14 @@ pub fn create_mir_scopes(fcx: &FunctionContext) -> Vec<DIScope> {
};
// Find all the scopes with variables defined in them.
let mut has_variables = BitVector::new(mir.scopes.len());
let mut has_variables = BitVector::new(mir.visibility_scopes.len());
for var in &mir.var_decls {
has_variables.insert(var.scope.index());
has_variables.insert(var.source_info.scope.index());
}
// Instantiate all scopes.
for idx in 0..mir.scopes.len() {
let scope = ScopeId::new(idx);
for idx in 0..mir.visibility_scopes.len() {
let scope = VisibilityScope::new(idx);
make_mir_scope(fcx.ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
}
@ -100,14 +100,14 @@ fn make_mir_scope(ccx: &CrateContext,
mir: &Mir,
has_variables: &BitVector,
fn_metadata: DISubprogram,
scope: ScopeId,
scope: VisibilityScope,
scopes: &mut [DIScope]) {
let idx = scope.index();
if !scopes[idx].is_null() {
return;
}
let scope_data = &mir.scopes[scope];
let scope_data = &mir.visibility_scopes[scope];
let parent_scope = if let Some(parent) = scope_data.parent_scope {
make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes);
scopes[parent.index()]

View file

@ -106,8 +106,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let terminator = data.terminator();
debug!("trans_block: terminator: {:?}", terminator);
let debug_loc = DebugLoc::ScopeAt(self.scopes[terminator.scope.index()],
terminator.span);
let span = terminator.source_info.span;
let debug_loc = self.debug_loc(terminator.source_info);
debug_loc.apply_to_bcx(&bcx);
debug_loc.apply(bcx.fcx());
match terminator.kind {
@ -245,7 +245,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
bcx = panic_block.build();
// Get the location information.
let loc = bcx.sess().codemap().lookup_char_pos(terminator.span.lo);
let loc = bcx.sess().codemap().lookup_char_pos(span.lo);
let filename = token::intern_and_get_ident(&loc.file.name);
let filename = C_str_slice(bcx.ccx(), filename);
let line = C_u32(bcx.ccx(), loc.line as u32);
@ -296,15 +296,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
// is also constant, then we can produce a warning.
if const_cond == Some(!expected) {
if let Some(err) = const_err {
let _ = consts::const_err(bcx.ccx(),
terminator.span,
let _ = consts::const_err(bcx.ccx(), span,
Err::<(), _>(err),
consts::TrueConst::No);
}
}
// Obtain the panic entry point.
let def_id = common::langcall(bcx.tcx(), Some(terminator.span), "", lang_item);
let def_id = common::langcall(bcx.tcx(), Some(span), "", lang_item);
let callee = Callee::def(bcx.ccx(), def_id,
bcx.ccx().empty_substs_for_def_id(def_id));
let llfn = callee.reify(bcx.ccx()).val;
@ -417,8 +416,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
if is_shuffle && idx == 2 {
match *arg {
mir::Operand::Consume(_) => {
span_bug!(terminator.span,
"shuffle indices must be constant");
span_bug!(span, "shuffle indices must be constant");
}
mir::Operand::Constant(ref constant) => {
let val = self.trans_constant(&bcx, constant);

View file

@ -281,12 +281,13 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
loop {
let data = self.mir.basic_block_data(bb);
for statement in &data.statements {
let span = statement.source_info.span;
match statement.kind {
mir::StatementKind::Assign(ref dest, ref rvalue) => {
let ty = self.mir.lvalue_ty(tcx, dest);
let ty = self.monomorphize(&ty).to_ty(tcx);
match self.const_rvalue(rvalue, ty, statement.span) {
Ok(value) => self.store(dest, value, statement.span),
match self.const_rvalue(rvalue, ty, span) {
Ok(value) => self.store(dest, value, span),
Err(err) => if failure.is_ok() { failure = Err(err); }
}
}
@ -294,7 +295,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
}
let terminator = data.terminator();
let span = terminator.span;
let span = terminator.source_info.span;
bb = match terminator.kind {
mir::TerminatorKind::Drop { target, .. } | // No dropping.
mir::TerminatorKind::Goto { target } => target,

View file

@ -112,6 +112,12 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
scopes: Vec<DIScope>
}
impl<'blk, 'tcx> MirContext<'blk, 'tcx> {
pub fn debug_loc(&self, source_info: mir::SourceInfo) -> DebugLoc {
DebugLoc::ScopeAt(self.scopes[source_info.scope.index()], source_info.span)
}
}
enum TempRef<'tcx> {
Lvalue(LvalueRef<'tcx>),
Operand(Option<OperandRef<'tcx>>),
@ -166,12 +172,12 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
.map(|(mty, decl)| {
let lvalue = LvalueRef::alloca(&bcx, mty, &decl.name.as_str());
let scope = scopes[decl.scope.index()];
let scope = scopes[decl.source_info.scope.index()];
if !scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo {
bcx.with_block(|bcx| {
declare_local(bcx, decl.name, mty, scope,
VariableAccess::DirectVariable { alloca: lvalue.llval },
VariableKind::LocalVariable, decl.span);
VariableKind::LocalVariable, decl.source_info.span);
});
}
@ -271,16 +277,13 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
let mut idx = 0;
let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
// Get the argument scope assuming ScopeId(0) has no parent.
let arg_scope = mir.scopes.get(0).and_then(|data| {
let scope = scopes[0];
if data.parent_scope.is_none() && !scope.is_null() &&
bcx.sess().opts.debuginfo == FullDebugInfo {
Some(scope)
} else {
None
}
});
// Get the argument scope, if it exists and if we need it.
let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE.index()];
let arg_scope = if !arg_scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo {
Some(arg_scope)
} else {
None
};
mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| {
let arg_ty = bcx.monomorphize(&arg_decl.ty);

View file

@ -10,7 +10,6 @@
use rustc::mir::repr as mir;
use common::{self, BlockAndBuilder};
use debuginfo::DebugLoc;
use super::MirContext;
use super::TempRef;
@ -22,8 +21,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
-> BlockAndBuilder<'bcx, 'tcx> {
debug!("trans_statement(statement={:?})", statement);
let debug_loc = DebugLoc::ScopeAt(self.scopes[statement.scope.index()],
statement.span);
let debug_loc = self.debug_loc(statement.source_info);
debug_loc.apply_to_bcx(&bcx);
debug_loc.apply(bcx.fcx());
match statement.kind {
@ -46,7 +44,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let ty = bcx.monomorphize(&ty.to_ty(bcx.tcx()));
if !common::type_is_zero_size(bcx.ccx(), ty) {
span_bug!(statement.span,
span_bug!(statement.source_info.span,
"operand {:?} already assigned",
rvalue);
} else {

View file

@ -247,11 +247,10 @@
// lldb-command:continue
#![allow(dead_code, unused_assignments, unused_variables)]
#![feature(omit_gdb_pretty_printer_section, rustc_attrs)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn immediate_args(a: isize, b: bool, c: f64) {
println!("");
}
@ -268,51 +267,43 @@ struct BigStruct {
}
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn non_immediate_args(a: BigStruct, b: BigStruct) {
println!("");
}
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn binding(a: i64, b: u64, c: f64) {
let x = 0;
println!("");
}
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn assignment(mut a: u64, b: u64, c: f64) {
a = b;
println!("");
}
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn function_call(x: u64, y: u64, z: f64) {
println!("Hi!")
}
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn identifier(x: u64, y: u64, z: f64) -> u64 {
x
}
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn return_expr(x: u64, y: u64, z: f64) -> u64 {
return x;
}
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 {
x + y
}
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn if_expr(x: u64, y: u64, z: f64) -> u64 {
if x + y < 1000 {
x
@ -322,7 +313,6 @@ fn if_expr(x: u64, y: u64, z: f64) -> u64 {
}
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
while x + y < 1000 {
x += z
@ -331,7 +321,6 @@ fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
}
#[no_stack_check]
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 {
loop {
x += z;