Skip to content

Commit f2c983b

Browse files
Aatcheddyb
authored andcommitted
Add a with_cond method
Factors out the common pattern across the several places that do arithmetic checks
1 parent 73f3054 commit f2c983b

File tree

3 files changed

+54
-46
lines changed

3 files changed

+54
-46
lines changed

src/librustc_mir/build/block.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use build::{BlockAnd, BlockAndExtension, Builder};
1212
use hair::*;
1313
use rustc::mir::repr::*;
1414
use rustc::hir;
15+
use syntax::codemap::Span;
1516

1617
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1718
pub fn ast_block(&mut self,
@@ -81,4 +82,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
8182
block.unit()
8283
})
8384
}
85+
86+
// Helper method for generating MIR inside a conditional block.
87+
pub fn with_cond<F>(&mut self, block: BasicBlock, span: Span,
88+
cond: Operand<'tcx>, f: F) -> BasicBlock
89+
where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>, BasicBlock) -> BasicBlock {
90+
let scope_id = self.innermost_scope_id();
91+
92+
let then_block = self.cfg.start_new_block();
93+
let else_block = self.cfg.start_new_block();
94+
95+
self.cfg.terminate(block, scope_id, span,
96+
TerminatorKind::If {
97+
cond: cond,
98+
targets: (then_block, else_block)
99+
});
100+
101+
let after = f(self, then_block);
102+
103+
// If the returned block isn't terminated, add a branch to the "else"
104+
// block
105+
if !self.cfg.terminated(after) {
106+
self.cfg.terminate(after, scope_id, span,
107+
TerminatorKind::Goto { target: else_block });
108+
}
109+
110+
else_block
111+
}
84112
}

src/librustc_mir/build/cfg.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,17 @@ impl<'tcx> CFG<'tcx> {
8686
scope: ScopeId,
8787
span: Span,
8888
kind: TerminatorKind<'tcx>) {
89-
debug_assert!(self.block_data(block).terminator.is_none(),
89+
debug_assert!(!self.terminated(block),
9090
"terminate: block {:?} already has a terminator set", block);
9191
self.block_data_mut(block).terminator = Some(Terminator {
9292
span: span,
9393
scope: scope,
9494
kind: kind,
9595
});
9696
}
97+
98+
/// Returns whether or not the given block has been terminated or not
99+
pub fn terminated(&self, block: BasicBlock) -> bool {
100+
self.block_data(block).terminator.is_some()
101+
}
97102
}

src/librustc_mir/build/expr/as_rvalue.rs

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
8888
this.cfg.push_assign(block, scope_id, expr_span, &is_min,
8989
Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval));
9090

91-
let of_block = this.cfg.start_new_block();
92-
let ok_block = this.cfg.start_new_block();
93-
94-
this.cfg.terminate(block, scope_id, expr_span,
95-
TerminatorKind::If {
96-
cond: Operand::Consume(is_min),
97-
targets: (of_block, ok_block)
98-
});
99-
100-
this.panic(of_block, "attempted to negate with overflow", expr_span);
101-
102-
block = ok_block;
91+
block = this.with_cond(
92+
block, expr_span, Operand::Consume(is_min), |this, block| {
93+
this.panic(block, "attempted to negate with overflow", expr_span);
94+
block
95+
});
10396
}
10497
block.and(Rvalue::UnaryOp(op, arg))
10598
}
@@ -268,21 +261,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
268261
let val = result_value.clone().field(val_fld, ty);
269262
let of = result_value.field(of_fld, bool_ty);
270263

271-
let success = self.cfg.start_new_block();
272-
let failure = self.cfg.start_new_block();
273-
274-
self.cfg.terminate(block, scope_id, span,
275-
TerminatorKind::If {
276-
cond: Operand::Consume(of),
277-
targets: (failure, success)
278-
});
279264
let msg = if op == BinOp::Shl || op == BinOp::Shr {
280265
"shift operation overflowed"
281266
} else {
282267
"arithmetic operation overflowed"
283268
};
284-
self.panic(failure, msg, span);
285-
success.and(Rvalue::Use(Operand::Consume(val)))
269+
270+
block = self.with_cond(block, span, Operand::Consume(of), |this, block| {
271+
this.panic(block, msg, span);
272+
block
273+
});
274+
275+
block.and(Rvalue::Use(Operand::Consume(val)))
286276
} else {
287277
if ty.is_integral() && (op == BinOp::Div || op == BinOp::Rem) {
288278
// Checking division and remainder is more complex, since we 1. always check
@@ -302,17 +292,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
302292
self.cfg.push_assign(block, scope_id, span, &is_zero,
303293
Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero));
304294

305-
let zero_block = self.cfg.start_new_block();
306-
let ok_block = self.cfg.start_new_block();
307-
308-
self.cfg.terminate(block, scope_id, span,
309-
TerminatorKind::If {
310-
cond: Operand::Consume(is_zero),
311-
targets: (zero_block, ok_block)
312-
});
313-
314-
self.panic(zero_block, zero_msg, span);
315-
block = ok_block;
295+
block = self.with_cond(block, span, Operand::Consume(is_zero), |this, block| {
296+
this.panic(block, zero_msg, span);
297+
block
298+
});
316299

317300
// We only need to check for the overflow in one case:
318301
// MIN / -1, and only for signed values.
@@ -336,18 +319,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
336319
self.cfg.push_assign(block, scope_id, span, &of,
337320
Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min));
338321

339-
let of_block = self.cfg.start_new_block();
340-
let ok_block = self.cfg.start_new_block();
341-
342-
self.cfg.terminate(block, scope_id, span,
343-
TerminatorKind::If {
344-
cond: Operand::Consume(of),
345-
targets: (of_block, ok_block)
346-
});
347-
348-
self.panic(of_block, overflow_msg, span);
349-
350-
block = ok_block;
322+
block = self.with_cond(block, span, Operand::Consume(of), |this, block| {
323+
this.panic(block, overflow_msg, span);
324+
block
325+
});
351326
}
352327
}
353328

0 commit comments

Comments
 (0)