Skip to content

Commit 7dd3fa3

Browse files
Move TerminatorKind::Assert trans to mir::statement.
1 parent ecba023 commit 7dd3fa3

File tree

2 files changed

+146
-127
lines changed

2 files changed

+146
-127
lines changed

src/librustc_trans/mir/block.rs

Lines changed: 8 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,15 @@
99
// except according to those terms.
1010

1111
use llvm::{self, ValueRef, BasicBlockRef};
12-
use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
13-
use rustc::middle::lang_items;
14-
use rustc::middle::const_val::ConstInt;
1512
use rustc::ty::{self, layout, TypeFoldable};
1613
use rustc::mir;
14+
use rustc::middle::const_val::ConstInt;
1715
use abi::{Abi, FnType, ArgType};
1816
use base::{self, Lifetime};
1917
use callee;
2018
use builder::Builder;
2119
use common::{self, Funclet};
22-
use common::{C_bool, C_str_slice, C_struct, C_u32, C_uint, C_undef};
23-
use consts;
20+
use common::{C_uint, C_undef};
2421
use machine::llalign_of_min;
2522
use meth;
2623
use monomorphize;
@@ -29,7 +26,6 @@ use type_of::{self, align_of};
2926
use type_::Type;
3027

3128
use rustc_data_structures::indexed_vec::IndexVec;
32-
use syntax::symbol::Symbol;
3329

3430
use std::cmp;
3531

@@ -272,124 +268,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
272268
}
273269

274270
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => {
275-
let cond = self.trans_operand(&bcx, cond).immediate();
276-
let mut const_cond = common::const_to_opt_u128(cond, false).map(|c| c == 1);
277-
278-
// This case can currently arise only from functions marked
279-
// with #[rustc_inherit_overflow_checks] and inlined from
280-
// another crate (mostly core::num generic/#[inline] fns),
281-
// while the current crate doesn't use overflow checks.
282-
// NOTE: Unlike binops, negation doesn't have its own
283-
// checked operation, just a comparison with the minimum
284-
// value, so we have to check for the assert message.
285-
if !bcx.ccx.check_overflow() {
286-
use rustc_const_math::ConstMathErr::Overflow;
287-
use rustc_const_math::Op::Neg;
288-
289-
if let mir::AssertMessage::Math(Overflow(Neg)) = *msg {
290-
const_cond = Some(expected);
291-
}
292-
}
293-
294-
// Don't translate the panic block if success if known.
295-
if const_cond == Some(expected) {
296-
funclet_br(self, bcx, target);
297-
return;
298-
}
299-
300-
// Pass the condition through llvm.expect for branch hinting.
301-
let expect = bcx.ccx.get_intrinsic(&"llvm.expect.i1");
302-
let cond = bcx.call(expect, &[cond, C_bool(bcx.ccx, expected)], None);
303-
304-
// Create the failure block and the conditional branch to it.
305-
let success_block = self.new_block("success");
306-
let panic_block = self.new_block("panic");
307-
if expected {
308-
bcx.cond_br(cond, success_block.llbb(), panic_block.llbb());
309-
} else {
310-
bcx.cond_br(cond, panic_block.llbb(), success_block.llbb());
311-
}
312-
313-
// After this point, bcx is the block for the call to panic.
314-
bcx = panic_block;
315-
self.set_debug_loc(&bcx, terminator.source_info);
316-
317-
// Get the location information.
318-
let loc = bcx.sess().codemap().lookup_char_pos(span.lo);
319-
let filename = Symbol::intern(&loc.file.name).as_str();
320-
let filename = C_str_slice(bcx.ccx, filename);
321-
let line = C_u32(bcx.ccx, loc.line as u32);
322-
323-
// Put together the arguments to the panic entry point.
324-
let (lang_item, args, const_err) = match *msg {
325-
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
326-
let len = self.trans_operand(&mut bcx, len).immediate();
327-
let index = self.trans_operand(&mut bcx, index).immediate();
328-
329-
let const_err = common::const_to_opt_u128(len, false)
330-
.and_then(|len| common::const_to_opt_u128(index, false)
331-
.map(|index| ErrKind::IndexOutOfBounds {
332-
len: len as u64,
333-
index: index as u64
334-
}));
335-
336-
let file_line = C_struct(bcx.ccx, &[filename, line], false);
337-
let align = llalign_of_min(bcx.ccx, common::val_ty(file_line));
338-
let file_line = consts::addr_of(bcx.ccx,
339-
file_line,
340-
align,
341-
"panic_bounds_check_loc");
342-
(lang_items::PanicBoundsCheckFnLangItem,
343-
vec![file_line, index, len],
344-
const_err)
345-
}
346-
mir::AssertMessage::Math(ref err) => {
347-
let msg_str = Symbol::intern(err.description()).as_str();
348-
let msg_str = C_str_slice(bcx.ccx, msg_str);
349-
let msg_file_line = C_struct(bcx.ccx,
350-
&[msg_str, filename, line],
351-
false);
352-
let align = llalign_of_min(bcx.ccx, common::val_ty(msg_file_line));
353-
let msg_file_line = consts::addr_of(bcx.ccx,
354-
msg_file_line,
355-
align,
356-
"panic_loc");
357-
(lang_items::PanicFnLangItem,
358-
vec![msg_file_line],
359-
Some(ErrKind::Math(err.clone())))
360-
}
361-
};
362-
363-
// If we know we always panic, and the error message
364-
// is also constant, then we can produce a warning.
365-
if const_cond == Some(!expected) {
366-
if let Some(err) = const_err {
367-
let err = ConstEvalErr{ span: span, kind: err };
368-
let mut diag = bcx.tcx().sess.struct_span_warn(
369-
span, "this expression will panic at run-time");
370-
note_const_eval_err(bcx.tcx(), &err, span, "expression", &mut diag);
371-
diag.emit();
372-
}
373-
}
374-
375-
// Obtain the panic entry point.
376-
let def_id = common::langcall(bcx.tcx(), Some(span), "", lang_item);
377-
let instance = ty::Instance::mono(bcx.tcx(), def_id);
378-
let llfn = callee::get_fn(bcx.ccx, instance);
379-
380-
// Translate the actual panic invoke/call.
381-
if let Some(unwind) = cleanup {
382-
bcx.invoke(llfn,
383-
&args,
384-
self.unreachable_block(),
385-
self.landing_pad_to(unwind),
386-
cleanup_bundle);
387-
} else {
388-
bcx.call(llfn, &args, cleanup_bundle);
389-
bcx.unreachable();
390-
}
391-
392-
success_block.br(self.blocks[target]);
271+
bcx = self.trans_assert(
272+
bcx, cond, expected, msg, cleanup, cleanup_bundle, terminator.source_info
273+
);
274+
funclet_br(self, bcx, target);
393275
}
394276

395277
mir::TerminatorKind::DropAndReplace { .. } => {
@@ -768,7 +650,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
768650
/// Return the landingpad wrapper around the given basic block
769651
///
770652
/// No-op in MSVC SEH scheme.
771-
fn landing_pad_to(&mut self, target_bb: mir::Block) -> BasicBlockRef {
653+
pub fn landing_pad_to(&mut self, target_bb: mir::Block) -> BasicBlockRef {
772654
if let Some(block) = self.landing_pads[target_bb] {
773655
return block;
774656
}
@@ -797,7 +679,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
797679
bcx.llbb()
798680
}
799681

800-
fn unreachable_block(&mut self) -> BasicBlockRef {
682+
pub fn unreachable_block(&mut self) -> BasicBlockRef {
801683
self.unreachable_block.unwrap_or_else(|| {
802684
let bl = self.new_block("unreachable");
803685
bl.unreachable();

src/librustc_trans/mir/statement.rs

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,20 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use llvm::OperandBundleDef;
1112
use rustc::mir;
13+
use rustc::ty;
14+
use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
15+
use rustc::middle::lang_items;
1216

1317
use base;
1418
use asm;
15-
use common;
19+
use common::{self, C_bool, C_str_slice, C_u32, C_struct};
1620
use builder::Builder;
21+
use syntax::symbol::Symbol;
22+
use machine::llalign_of_min;
23+
use consts;
24+
use callee;
1725

1826
use super::MirContext;
1927
use super::LocalRef;
@@ -103,4 +111,133 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
103111
}
104112
bcx
105113
}
114+
115+
pub fn trans_assert(
116+
&mut self,
117+
mut bcx: Builder<'a, 'tcx>,
118+
cond: &mir::Operand<'tcx>,
119+
expected: bool,
120+
msg: &mir::AssertMessage<'tcx>,
121+
cleanup: Option<mir::Block>,
122+
cleanup_bundle: Option<&OperandBundleDef>,
123+
source_info: mir::SourceInfo,
124+
) -> Builder<'a, 'tcx> {
125+
let cond = self.trans_operand(&bcx, cond).immediate();
126+
let mut const_cond = common::const_to_opt_u128(cond, false).map(|c| c == 1);
127+
128+
// This case can currently arise only from functions marked
129+
// with #[rustc_inherit_overflow_checks] and inlined from
130+
// another crate (mostly core::num generic/#[inline] fns),
131+
// while the current crate doesn't use overflow checks.
132+
// NOTE: Unlike binops, negation doesn't have its own
133+
// checked operation, just a comparison with the minimum
134+
// value, so we have to check for the assert message.
135+
if !bcx.ccx.check_overflow() {
136+
use rustc_const_math::ConstMathErr::Overflow;
137+
use rustc_const_math::Op::Neg;
138+
139+
if let mir::AssertMessage::Math(Overflow(Neg)) = *msg {
140+
const_cond = Some(expected);
141+
}
142+
}
143+
144+
// Don't translate the panic block if success if known.
145+
if const_cond == Some(expected) {
146+
return bcx;
147+
}
148+
149+
// Pass the condition through llvm.expect for branch hinting.
150+
let expect = bcx.ccx.get_intrinsic(&"llvm.expect.i1");
151+
let cond = bcx.call(expect, &[cond, C_bool(bcx.ccx, expected)], None);
152+
153+
// Create the failure block and the conditional branch to it.
154+
let success_block = self.new_block("success");
155+
let panic_block = self.new_block("panic");
156+
if expected {
157+
bcx.cond_br(cond, success_block.llbb(), panic_block.llbb());
158+
} else {
159+
bcx.cond_br(cond, panic_block.llbb(), success_block.llbb());
160+
}
161+
162+
// After this point, bcx is the block for the call to panic.
163+
bcx = panic_block;
164+
self.set_debug_loc(&bcx, source_info);
165+
166+
// Get the location information.
167+
let loc = bcx.sess().codemap().lookup_char_pos(source_info.span.lo);
168+
let filename = Symbol::intern(&loc.file.name).as_str();
169+
let filename = C_str_slice(bcx.ccx, filename);
170+
let line = C_u32(bcx.ccx, loc.line as u32);
171+
172+
// Put together the arguments to the panic entry point.
173+
let (lang_item, args, const_err) = match *msg {
174+
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
175+
let len = self.trans_operand(&mut bcx, len).immediate();
176+
let index = self.trans_operand(&mut bcx, index).immediate();
177+
178+
let const_err = common::const_to_opt_u128(len, false)
179+
.and_then(|len| common::const_to_opt_u128(index, false)
180+
.map(|index| ErrKind::IndexOutOfBounds {
181+
len: len as u64,
182+
index: index as u64
183+
}));
184+
185+
let file_line = C_struct(bcx.ccx, &[filename, line], false);
186+
let align = llalign_of_min(bcx.ccx, common::val_ty(file_line));
187+
let file_line = consts::addr_of(bcx.ccx,
188+
file_line,
189+
align,
190+
"panic_bounds_check_loc");
191+
(lang_items::PanicBoundsCheckFnLangItem,
192+
vec![file_line, index, len],
193+
const_err)
194+
}
195+
mir::AssertMessage::Math(ref err) => {
196+
let msg_str = Symbol::intern(err.description()).as_str();
197+
let msg_str = C_str_slice(bcx.ccx, msg_str);
198+
let msg_file_line = C_struct(bcx.ccx,
199+
&[msg_str, filename, line],
200+
false);
201+
let align = llalign_of_min(bcx.ccx, common::val_ty(msg_file_line));
202+
let msg_file_line = consts::addr_of(bcx.ccx,
203+
msg_file_line,
204+
align,
205+
"panic_loc");
206+
(lang_items::PanicFnLangItem,
207+
vec![msg_file_line],
208+
Some(ErrKind::Math(err.clone())))
209+
}
210+
};
211+
212+
// If we know we always panic, and the error message
213+
// is also constant, then we can produce a warning.
214+
if const_cond == Some(!expected) {
215+
if let Some(err) = const_err {
216+
let err = ConstEvalErr { span: source_info.span, kind: err };
217+
let mut diag = bcx.tcx().sess.struct_span_warn(
218+
source_info.span, "this expression will panic at run-time");
219+
note_const_eval_err(bcx.tcx(), &err, source_info.span, "expression", &mut diag);
220+
diag.emit();
221+
}
222+
}
223+
224+
// Obtain the panic entry point.
225+
let def_id = common::langcall(bcx.tcx(), Some(source_info.span), "", lang_item);
226+
let instance = ty::Instance::mono(bcx.tcx(), def_id);
227+
let llfn = callee::get_fn(bcx.ccx, instance);
228+
229+
// Translate the actual panic invoke/call.
230+
if let Some(unwind) = cleanup {
231+
bcx.invoke(llfn,
232+
&args,
233+
self.unreachable_block(),
234+
self.landing_pad_to(unwind),
235+
cleanup_bundle);
236+
} else {
237+
bcx.call(llfn, &args, cleanup_bundle);
238+
bcx.unreachable();
239+
}
240+
241+
success_block
242+
}
106243
}

0 commit comments

Comments
 (0)