Respect #[rustc_inherit_overflow_checks] in mir::build and trans.

This commit is contained in:
Eduard Burtescu 2016-05-26 20:02:56 +03:00
parent 702c47baae
commit d8dddbf201
5 changed files with 47 additions and 42 deletions

View File

@ -80,7 +80,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ExprKind::Unary { op, arg } => {
let arg = unpack!(block = this.as_operand(block, arg));
// Check for -MIN on signed integers
if op == UnOp::Neg && expr.ty.is_signed() && this.check_overflow() {
if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
let bool_ty = this.hir.bool_ty();
let minval = this.minval_literal(expr_span, expr.ty);
@ -247,7 +247,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
lhs: Operand<'tcx>, rhs: Operand<'tcx>) -> BlockAnd<Rvalue<'tcx>> {
let scope_id = self.innermost_scope_id();
let bool_ty = self.hir.bool_ty();
if op.is_checkable() && ty.is_integral() && self.check_overflow() {
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);

View File

@ -55,8 +55,6 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
cached_resume_block: Option<BasicBlock>,
/// cached block with the RETURN terminator
cached_return_block: Option<BasicBlock>,
has_warned_about_xcrate_overflows: bool
}
struct CFG<'tcx> {
@ -275,8 +273,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
var_indices: FnvHashMap(),
unit_temp: None,
cached_resume_block: None,
cached_return_block: None,
has_warned_about_xcrate_overflows: false
cached_return_block: None
};
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
@ -381,21 +378,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
}
pub fn check_overflow(&mut self) -> bool {
let check = self.hir.tcx().sess.opts.debugging_opts.force_overflow_checks
.unwrap_or(self.hir.tcx().sess.opts.debug_assertions);
if !check && self.hir.may_be_inlined_cross_crate() {
if !self.has_warned_about_xcrate_overflows {
self.hir.tcx().sess.span_warn(self.fn_span,
"overflow checks would be missing when used from another crate");
self.has_warned_about_xcrate_overflows = true;
}
}
check
}
}
///////////////////////////////////////////////////////////////////////////

View File

@ -30,7 +30,7 @@ use rustc::ty::{self, Ty, TyCtxt};
use syntax::parse::token;
use rustc::hir;
use rustc_const_math::{ConstInt, ConstUsize};
use syntax::attr;
use syntax::attr::AttrMetaMethods;
#[derive(Copy, Clone)]
pub struct Cx<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
@ -38,42 +38,49 @@ pub struct Cx<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
constness: hir::Constness,
/// True if this MIR can get inlined in other crates.
inline: bool
/// True if this constant/function needs overflow checks.
check_overflow: bool
}
impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
src: MirSource)
-> Cx<'a, 'gcx, 'tcx> {
let (constness, inline) = match src {
let constness = match src {
MirSource::Const(_) |
MirSource::Static(..) => (hir::Constness::Const, false),
MirSource::Static(..) => hir::Constness::Const,
MirSource::Fn(id) => {
let def_id = infcx.tcx.map.local_def_id(id);
let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
match fn_like.map(|f| f.kind()) {
Some(FnKind::ItemFn(_, _, _, c, _, _, attrs)) => {
let scheme = infcx.tcx.lookup_item_type(def_id);
let any_types = !scheme.generics.types.is_empty();
(c, any_types || attr::requests_inline(attrs))
}
Some(FnKind::Method(_, m, _, attrs)) => {
let scheme = infcx.tcx.lookup_item_type(def_id);
let any_types = !scheme.generics.types.is_empty();
(m.constness, any_types || attr::requests_inline(attrs))
}
_ => (hir::Constness::NotConst, true)
Some(FnKind::ItemFn(_, _, _, c, _, _, _)) => c,
Some(FnKind::Method(_, m, _, _)) => m.constness,
_ => hir::Constness::NotConst
}
}
MirSource::Promoted(..) => bug!()
};
let attrs = infcx.tcx.map.attrs(src.item_id());
// Some functions always have overflow checks enabled,
// however, they may not get codegen'd, depending on
// the settings for the crate they are translated in.
let mut check_overflow = attrs.iter().any(|item| {
item.check_name("rustc_inherit_overflow_checks")
});
// Respect -Z force-overflow-checks=on and -C debug-assertions.
check_overflow |= infcx.tcx.sess.opts.debugging_opts.force_overflow_checks
.unwrap_or(infcx.tcx.sess.opts.debug_assertions);
// Constants and const fn's always need overflow checks.
check_overflow |= constness == hir::Constness::Const;
Cx {
tcx: infcx.tcx,
infcx: infcx,
constness: constness,
inline: inline
check_overflow: check_overflow
}
}
}
@ -186,8 +193,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
self.tcx
}
pub fn may_be_inlined_cross_crate(&self) -> bool {
self.inline
pub fn check_overflow(&self) -> bool {
self.check_overflow
}
}

View File

@ -16,7 +16,7 @@ use rustc::mir::repr as mir;
use asm;
use base;
use callee::Callee;
use common::{self, val_ty, C_null, C_uint, BlockAndBuilder, Result};
use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result};
use datum::{Datum, Lvalue};
use debuginfo::DebugLoc;
use adt;
@ -579,6 +579,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
lhs: ValueRef,
rhs: ValueRef,
input_ty: Ty<'tcx>) -> OperandValue {
// This case can currently arise only from functions marked
// with #[rustc_inherit_overflow_checks] and inlined from
// another crate (mostly core::num generic/#[inline] fns),
// while the current crate doesn't use overflow checks.
if !bcx.ccx().check_overflow() {
let val = self.trans_scalar_binop(bcx, op, lhs, rhs, input_ty);
return OperandValue::Pair(val, C_bool(bcx.ccx(), false));
}
let (val, of) = match op {
// These are checked using intrinsics
mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => {

View File

@ -502,6 +502,13 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
is just used to make tests pass \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs",
"the `#[rustc_inherit_overflow_checks]` \
attribute is just used to control \
overflow checking behavior of several \
libcore functions that are inlined \
across crates and will never be stable",
cfg_fn!(rustc_attrs))),
("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
EXPLAIN_ALLOW_INTERNAL_UNSTABLE,