diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 62fea3c6aa83..cc95d5946a80 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -230,6 +230,8 @@ pub struct BasicBlockData<'tcx> { #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct Terminator<'tcx> { + pub span: Span, + pub scope: ScopeId, pub kind: TerminatorKind<'tcx> } diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 7ada408361d0..ef48a408e79a 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -44,9 +44,10 @@ impl<'a,'tcx> Builder<'a,'tcx> { StmtKind::Expr { scope, expr } => { unpack!(block = this.in_scope(scope, block, |this, _| { let expr = this.hir.mirror(expr); + let expr_span = expr.span; let temp = this.temp(expr.ty.clone()); unpack!(block = this.into(&temp, block, expr)); - unpack!(block = this.build_drop(block, temp)); + unpack!(block = this.build_drop(block, expr_span, temp)); block.unit() })); } diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index ed99364a0f23..4859257f291c 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -83,11 +83,15 @@ impl<'tcx> CFG<'tcx> { pub fn terminate(&mut self, block: BasicBlock, + scope: ScopeId, + span: Span, 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 { - kind: kind + span: span, + scope: scope, + kind: kind, }); } } diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index fa864625f7f3..0c9323f4af37 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -68,6 +68,8 @@ impl<'a,'tcx> Builder<'a,'tcx> { let (success, failure) = (this.cfg.start_new_block(), this.cfg.start_new_block()); this.cfg.terminate(block, + scope_id, + expr_span, TerminatorKind::If { cond: Operand::Consume(lt), targets: (success, failure), diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 0ce2494ee35e..9992e904dea1 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -53,7 +53,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { let mut then_block = this.cfg.start_new_block(); let mut else_block = this.cfg.start_new_block(); - this.cfg.terminate(block, TerminatorKind::If { + this.cfg.terminate(block, scope_id, expr_span, TerminatorKind::If { cond: operand, targets: (then_block, else_block) }); @@ -70,8 +70,14 @@ impl<'a,'tcx> Builder<'a,'tcx> { }; let join_block = this.cfg.start_new_block(); - this.cfg.terminate(then_block, TerminatorKind::Goto { target: join_block }); - this.cfg.terminate(else_block, TerminatorKind::Goto { target: join_block }); + this.cfg.terminate(then_block, + scope_id, + expr_span, + TerminatorKind::Goto { target: join_block }); + this.cfg.terminate(else_block, + scope_id, + expr_span, + TerminatorKind::Goto { target: join_block }); join_block.unit() } @@ -97,10 +103,13 @@ impl<'a,'tcx> Builder<'a,'tcx> { LogicalOp::And => (else_block, false_block), LogicalOp::Or => (true_block, else_block), }; - this.cfg.terminate(block, TerminatorKind::If { cond: lhs, targets: blocks }); + this.cfg.terminate(block, + scope_id, + expr_span, + TerminatorKind::If { cond: lhs, targets: blocks }); let rhs = unpack!(else_block = this.as_operand(else_block, rhs)); - this.cfg.terminate(else_block, TerminatorKind::If { + this.cfg.terminate(else_block, scope_id, expr_span, TerminatorKind::If { cond: rhs, targets: (true_block, false_block) }); @@ -121,8 +130,14 @@ impl<'a,'tcx> Builder<'a,'tcx> { literal: this.hir.false_literal(), }); - this.cfg.terminate(true_block, TerminatorKind::Goto { target: join_block }); - this.cfg.terminate(false_block, TerminatorKind::Goto { target: join_block }); + this.cfg.terminate(true_block, + scope_id, + expr_span, + TerminatorKind::Goto { target: join_block }); + this.cfg.terminate(false_block, + scope_id, + expr_span, + TerminatorKind::Goto { target: join_block }); join_block.unit() } @@ -146,7 +161,10 @@ impl<'a,'tcx> Builder<'a,'tcx> { let exit_block = this.cfg.start_new_block(); // start the loop - this.cfg.terminate(block, TerminatorKind::Goto { target: loop_block }); + this.cfg.terminate(block, + scope_id, + expr_span, + TerminatorKind::Goto { target: loop_block }); let might_break = this.in_loop_scope(loop_block, exit_block, move |this| { // conduct the test, if necessary @@ -159,6 +177,8 @@ impl<'a,'tcx> Builder<'a,'tcx> { 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, TerminatorKind::If { cond: cond, targets: (body_block, exit_block) @@ -175,7 +195,10 @@ impl<'a,'tcx> Builder<'a,'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, TerminatorKind::Goto { target: loop_block }); + this.cfg.terminate(body_block_end, + scope_id, + expr_span, + 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. @@ -188,9 +211,11 @@ impl<'a,'tcx> Builder<'a,'tcx> { // Note: we evaluate assignments right-to-left. This // is better for borrowck interaction with overloaded // operators like x[j] = x[i]. + let lhs = this.hir.mirror(lhs); + let lhs_span = lhs.span; let rhs = unpack!(block = this.as_operand(block, rhs)); let lhs = unpack!(block = this.as_lvalue(block, lhs)); - unpack!(block = this.build_drop(block, lhs.clone())); + unpack!(block = this.build_drop(block, lhs_span, lhs.clone())); this.cfg.push_assign(block, scope_id, expr_span, &lhs, Rvalue::Use(rhs)); block.unit() } @@ -254,7 +279,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { let success = this.cfg.start_new_block(); let cleanup = this.diverge_cleanup(); - this.cfg.terminate(block, TerminatorKind::Call { + this.cfg.terminate(block, scope_id, expr_span, TerminatorKind::Call { func: fun, args: args, cleanup: cleanup, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 2018d7255f5e..9414752fbd86 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -71,6 +71,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { }) .map(|(arm_index, pattern, guard)| { Candidate { + span: pattern.span, match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)], bindings: vec![], guard: guard, @@ -87,7 +88,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // an empty vector to be returned here, but the algorithm is // not entirely precise if !otherwise.is_empty() { - let join_block = self.join_otherwise_blocks(otherwise); + let join_block = self.join_otherwise_blocks(span, otherwise); self.panic(join_block, "something about matches algorithm not being precise", span); } @@ -97,7 +98,10 @@ impl<'a,'tcx> Builder<'a,'tcx> { for (arm_index, arm_body) in arm_bodies.into_iter().enumerate() { let mut arm_block = arm_blocks.blocks[arm_index]; unpack!(arm_block = self.into(destination, arm_block, arm_body)); - self.cfg.terminate(arm_block, TerminatorKind::Goto { target: end_block }); + self.cfg.terminate(arm_block, + var_scope_id, + span, + TerminatorKind::Goto { target: end_block }); } end_block.unit() @@ -146,6 +150,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // create a dummy candidate let mut candidate = Candidate { + span: irrefutable_pat.span, match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)], bindings: vec![], guard: None, @@ -206,6 +211,9 @@ struct ArmBlocks { #[derive(Clone, Debug)] pub struct Candidate<'pat, 'tcx:'pat> { + // span of the original pattern that gave rise to this candidate + span: Span, + // all of these must be satisfied... match_pairs: Vec>, @@ -370,20 +378,25 @@ impl<'a,'tcx> Builder<'a,'tcx> { } // Otherwise, let's process those remaining candidates. - let join_block = self.join_otherwise_blocks(otherwise); + let join_block = self.join_otherwise_blocks(span, otherwise); self.match_candidates(span, arm_blocks, untested_candidates, join_block) } fn join_otherwise_blocks(&mut self, + span: Span, otherwise: Vec) -> BasicBlock { + 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, TerminatorKind::Goto { target: join_block }); + self.cfg.terminate(block, + scope_id, + span, + TerminatorKind::Goto { target: join_block }); } join_block } @@ -550,16 +563,25 @@ impl<'a,'tcx> Builder<'a,'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 cond = unpack!(block = self.as_operand(block, guard)); let otherwise = self.cfg.start_new_block(); - self.cfg.terminate(block, TerminatorKind::If { cond: cond, - targets: (arm_block, otherwise)}); + self.cfg.terminate(block, + scope_id, + guard_span, + TerminatorKind::If { cond: cond, + targets: (arm_block, otherwise)}); Some(otherwise) } else { - self.cfg.terminate(block, TerminatorKind::Goto { target: arm_block }); + self.cfg.terminate(block, + scope_id, + candidate.span, + TerminatorKind::Goto { target: arm_block }); None } } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 74402ccba348..3e374c07b46b 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -153,7 +153,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { let target_blocks: Vec<_> = (0..num_enum_variants).map(|_| self.cfg.start_new_block()) .collect(); - self.cfg.terminate(block, TerminatorKind::Switch { + self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch { discr: lvalue.clone(), adt_def: adt_def, targets: target_blocks.clone() @@ -168,12 +168,15 @@ impl<'a,'tcx> Builder<'a,'tcx> { .map(|_| self.cfg.start_new_block()) .chain(Some(otherwise)) .collect(); - self.cfg.terminate(block, TerminatorKind::SwitchInt { - discr: lvalue.clone(), - switch_ty: switch_ty, - values: options.clone(), - targets: targets.clone(), - }); + self.cfg.terminate(block, + scope_id, + test.span, + TerminatorKind::SwitchInt { + discr: lvalue.clone(), + switch_ty: switch_ty, + values: options.clone(), + targets: targets.clone(), + }); targets } @@ -226,7 +229,7 @@ impl<'a,'tcx> Builder<'a,'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, Terminator::Call { + self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Call { func: Operand::Constant(Constant { span: test.span, ty: mty, @@ -239,7 +242,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // check the result let block = self.cfg.start_new_block(); - self.cfg.terminate(eq_block, Terminator::If { + self.cfg.terminate(eq_block, scope_id, test.span, TerminatorKind::If { cond: Operand::Consume(eq_result), targets: (block, fail), }); @@ -286,7 +289,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // branch based on result let target_blocks: Vec<_> = vec![self.cfg.start_new_block(), self.cfg.start_new_block()]; - self.cfg.terminate(block, TerminatorKind::If { + self.cfg.terminate(block, scope_id, test.span, TerminatorKind::If { cond: Operand::Consume(result), targets: (target_blocks[0], target_blocks[1]) }); @@ -313,7 +316,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // branch based on result let target_block = self.cfg.start_new_block(); - self.cfg.terminate(block, TerminatorKind::If { + self.cfg.terminate(block, scope_id, span, TerminatorKind::If { cond: Operand::Consume(result), targets: (target_block, fail_block) }); @@ -466,6 +469,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { .map(|(_, mp)| mp.clone()) .collect(); Candidate { + span: candidate.span, match_pairs: other_match_pairs, bindings: candidate.bindings.clone(), guard: candidate.guard.clone(), @@ -507,6 +511,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { let all_match_pairs = consequent_match_pairs.chain(other_match_pairs).collect(); Candidate { + span: candidate.span, match_pairs: all_match_pairs, bindings: candidate.bindings.clone(), guard: candidate.guard.clone(), diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 44bbb2e3f193..416c078f4a95 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -160,14 +160,17 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>, assert_eq!(builder.cfg.start_new_block(), END_BLOCK); let mut block = START_BLOCK; - let arg_decls = unpack!(block = builder.args_and_body(block, - implicit_arguments, - explicit_arguments, - argument_extent, - ast_block)); + let (arg_decls, arg_scope_id) = + unpack!(block = builder.args_and_body(block, + implicit_arguments, + explicit_arguments, + argument_extent, + ast_block)); - builder.cfg.terminate(block, TerminatorKind::Goto { target: END_BLOCK }); - builder.cfg.terminate(END_BLOCK, TerminatorKind::Return); + builder.cfg.terminate(block, arg_scope_id, span, + TerminatorKind::Goto { target: END_BLOCK }); + builder.cfg.terminate(END_BLOCK, arg_scope_id, span, + TerminatorKind::Return); MirPlusPlus { mir: Mir { @@ -190,7 +193,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>, argument_extent: CodeExtent, ast_block: &'tcx hir::Block) - -> BlockAnd>> + -> BlockAnd<(Vec>, ScopeId)> { self.in_scope(argument_extent, block, |this, argument_scope_id| { // to start, translate the argument patterns and collect the argument types. @@ -219,7 +222,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // start the first basic block and translate the body unpack!(block = this.ast_block(&Lvalue::ReturnPointer, block, ast_block)); - block.and(arg_decls) + block.and((arg_decls, argument_scope_id)) }) } diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index c6d24591d2ac..e7066ff083e2 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -116,6 +116,7 @@ pub struct Scope<'tcx> { } struct DropData<'tcx> { + span: Span, value: Lvalue<'tcx>, // NB: per-drop “cache” is necessary for the build_scope_drops function below. /// The cached block for the cleanups-on-diverge path. This block contains code to run the @@ -288,14 +289,19 @@ impl<'a,'tcx> Builder<'a,'tcx> { if let Some(ref free_data) = scope.free { let next = self.cfg.start_new_block(); let free = build_free(self.hir.tcx(), tmp.clone(), free_data, next); - self.cfg.terminate(block, free); + self.cfg.terminate(block, scope.id, span, free); block = next; } self.scope_auxiliary[scope.id.index()] .postdoms .push(self.cfg.current_location(block)); } - self.cfg.terminate(block, TerminatorKind::Goto { target: target }); + + let scope_id = self.innermost_scope_id(); + self.cfg.terminate(block, + scope_id, + span, + TerminatorKind::Goto { target: target }); } // Finding scopes @@ -351,6 +357,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // No need to invalidate any caches here. The just-scheduled drop will branch into // the drop that comes before it in the vector. scope.drops.push(DropData { + span: span, value: lvalue.clone(), cached_block: None }); @@ -429,14 +436,22 @@ impl<'a,'tcx> Builder<'a,'tcx> { } /// Utility function for *non*-scope code to build their own drops - pub fn build_drop(&mut self, block: BasicBlock, value: Lvalue<'tcx>) -> BlockAnd<()> { + pub fn build_drop(&mut self, + block: BasicBlock, + span: Span, + value: Lvalue<'tcx>) + -> BlockAnd<()> { + let scope_id = self.innermost_scope_id(); let next_target = self.cfg.start_new_block(); let diverge_target = self.diverge_cleanup(); - self.cfg.terminate(block, TerminatorKind::Drop { - value: value, - target: next_target, - unwind: diverge_target, - }); + self.cfg.terminate(block, + scope_id, + span, + TerminatorKind::Drop { + value: value, + target: next_target, + unwind: diverge_target, + }); next_target.unit() } @@ -445,10 +460,10 @@ impl<'a,'tcx> Builder<'a,'tcx> { // ========= // FIXME: should be moved into their own module pub fn panic_bounds_check(&mut self, - block: BasicBlock, - index: Operand<'tcx>, - len: Operand<'tcx>, - span: Span) { + block: BasicBlock, + index: Operand<'tcx>, + len: Operand<'tcx>, + span: Span) { // fn(&(filename: &'static str, line: u32), index: usize, length: usize) -> ! let region = ty::ReStatic; // FIXME(mir-borrowck): use a better region? let func = self.lang_function(lang_items::PanicBoundsCheckFnLangItem); @@ -474,7 +489,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { self.cfg.push_assign(block, scope_id, span, &tuple_ref, // tuple_ref = &tuple; Rvalue::Ref(region, BorrowKind::Shared, tuple)); let cleanup = self.diverge_cleanup(); - self.cfg.terminate(block, TerminatorKind::Call { + self.cfg.terminate(block, scope_id, span, TerminatorKind::Call { func: Operand::Constant(func), args: vec![Operand::Consume(tuple_ref), index, len], destination: None, @@ -516,7 +531,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { self.cfg.push_assign(block, scope_id, span, &tuple_ref, // tuple_ref = &tuple; Rvalue::Ref(region, BorrowKind::Shared, tuple)); let cleanup = self.diverge_cleanup(); - self.cfg.terminate(block, TerminatorKind::Call { + self.cfg.terminate(block, scope_id, span, TerminatorKind::Call { func: Operand::Constant(func), args: vec![Operand::Consume(tuple_ref)], cleanup: cleanup, @@ -575,7 +590,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, TerminatorKind::Drop { + cfg.terminate(block, scope.id, drop_data.span, TerminatorKind::Drop { value: drop_data.value.clone(), target: next, unwind: on_diverge @@ -599,12 +614,15 @@ fn build_diverge_scope<'tcx>(tcx: &TyCtxt<'tcx>, let mut last_drop_block = None; for drop_data in scope.drops.iter_mut().rev() { if let Some(cached_block) = drop_data.cached_block { - if let Some((previous_block, previous_value)) = previous { - cfg.terminate(previous_block, TerminatorKind::Drop { - value: previous_value, - target: cached_block, - unwind: None - }); + if let Some((previous_block, previous_span, previous_value)) = previous { + cfg.terminate(previous_block, + scope.id, + previous_span, + TerminatorKind::Drop { + value: previous_value, + target: cached_block, + unwind: None + }); return last_drop_block.unwrap(); } else { return cached_block; @@ -612,23 +630,26 @@ fn build_diverge_scope<'tcx>(tcx: &TyCtxt<'tcx>, } else { let block = cfg.start_new_cleanup_block(); drop_data.cached_block = Some(block); - if let Some((previous_block, previous_value)) = previous { - cfg.terminate(previous_block, TerminatorKind::Drop { - value: previous_value, - target: block, - unwind: None - }); + if let Some((previous_block, previous_span, previous_value)) = previous { + cfg.terminate(previous_block, + scope.id, + previous_span, + TerminatorKind::Drop { + value: previous_value, + target: block, + unwind: None + }); } else { last_drop_block = Some(block); } - previous = Some((block, drop_data.value.clone())); + previous = Some((block, drop_data.span, drop_data.value.clone())); } } // Prepare the end target for this chain. let mut target = target.unwrap_or_else(||{ let b = cfg.start_new_cleanup_block(); - cfg.terminate(b, TerminatorKind::Resume); + cfg.terminate(b, scope.id, DUMMY_SP, TerminatorKind::Resume); // TODO b }); @@ -638,19 +659,25 @@ fn build_diverge_scope<'tcx>(tcx: &TyCtxt<'tcx>, cached_block } else { let into = cfg.start_new_cleanup_block(); - cfg.terminate(into, build_free(tcx, unit_temp, free_data, target)); + cfg.terminate(into, + scope.id, + free_data.span, + build_free(tcx, unit_temp, free_data, target)); free_data.cached_block = Some(into); into } }; - if let Some((previous_block, previous_value)) = previous { + if let Some((previous_block, previous_span, previous_value)) = previous { // Finally, branch into that just-built `target` from the `previous_block`. - cfg.terminate(previous_block, TerminatorKind::Drop { - value: previous_value, - target: target, - unwind: None - }); + cfg.terminate(previous_block, + scope.id, + previous_span, + TerminatorKind::Drop { + value: previous_value, + target: target, + unwind: None + }); last_drop_block.unwrap() } else { // If `previous.is_none()`, there were no drops in this scope – we return the