Respect #[rustc_inherit_overflow_checks] in mir::build and trans.
This commit is contained in:
parent
702c47baae
commit
d8dddbf201
@ -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);
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 => {
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user