Skip to content

Commit d8dddbf

Browse files
committed
Respect #[rustc_inherit_overflow_checks] in mir::build and trans.
1 parent 702c47b commit d8dddbf

File tree

5 files changed

+47
-42
lines changed

5 files changed

+47
-42
lines changed

src/librustc_mir/build/expr/as_rvalue.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
8080
ExprKind::Unary { op, arg } => {
8181
let arg = unpack!(block = this.as_operand(block, arg));
8282
// Check for -MIN on signed integers
83-
if op == UnOp::Neg && expr.ty.is_signed() && this.check_overflow() {
83+
if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
8484
let bool_ty = this.hir.bool_ty();
8585

8686
let minval = this.minval_literal(expr_span, expr.ty);
@@ -247,7 +247,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
247247
lhs: Operand<'tcx>, rhs: Operand<'tcx>) -> BlockAnd<Rvalue<'tcx>> {
248248
let scope_id = self.innermost_scope_id();
249249
let bool_ty = self.hir.bool_ty();
250-
if op.is_checkable() && ty.is_integral() && self.check_overflow() {
250+
if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
251251
let result_tup = self.hir.tcx().mk_tup(vec![ty, bool_ty]);
252252
let result_value = self.temp(result_tup);
253253

src/librustc_mir/build/mod.rs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
5555
cached_resume_block: Option<BasicBlock>,
5656
/// cached block with the RETURN terminator
5757
cached_return_block: Option<BasicBlock>,
58-
59-
has_warned_about_xcrate_overflows: bool
6058
}
6159

6260
struct CFG<'tcx> {
@@ -275,8 +273,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
275273
var_indices: FnvHashMap(),
276274
unit_temp: None,
277275
cached_resume_block: None,
278-
cached_return_block: None,
279-
has_warned_about_xcrate_overflows: false
276+
cached_return_block: None
280277
};
281278

282279
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
@@ -381,21 +378,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
381378
}
382379
}
383380
}
384-
385-
pub fn check_overflow(&mut self) -> bool {
386-
let check = self.hir.tcx().sess.opts.debugging_opts.force_overflow_checks
387-
.unwrap_or(self.hir.tcx().sess.opts.debug_assertions);
388-
389-
if !check && self.hir.may_be_inlined_cross_crate() {
390-
if !self.has_warned_about_xcrate_overflows {
391-
self.hir.tcx().sess.span_warn(self.fn_span,
392-
"overflow checks would be missing when used from another crate");
393-
self.has_warned_about_xcrate_overflows = true;
394-
}
395-
}
396-
397-
check
398-
}
399381
}
400382

401383
///////////////////////////////////////////////////////////////////////////

src/librustc_mir/hair/cx/mod.rs

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,50 +30,57 @@ use rustc::ty::{self, Ty, TyCtxt};
3030
use syntax::parse::token;
3131
use rustc::hir;
3232
use rustc_const_math::{ConstInt, ConstUsize};
33-
use syntax::attr;
33+
use syntax::attr::AttrMetaMethods;
3434

3535
#[derive(Copy, Clone)]
3636
pub struct Cx<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
3737
tcx: TyCtxt<'a, 'gcx, 'tcx>,
3838
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
3939
constness: hir::Constness,
4040

41-
/// True if this MIR can get inlined in other crates.
42-
inline: bool
41+
/// True if this constant/function needs overflow checks.
42+
check_overflow: bool
4343
}
4444

4545
impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
4646
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
4747
src: MirSource)
4848
-> Cx<'a, 'gcx, 'tcx> {
49-
let (constness, inline) = match src {
49+
let constness = match src {
5050
MirSource::Const(_) |
51-
MirSource::Static(..) => (hir::Constness::Const, false),
51+
MirSource::Static(..) => hir::Constness::Const,
5252
MirSource::Fn(id) => {
53-
let def_id = infcx.tcx.map.local_def_id(id);
5453
let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
5554
match fn_like.map(|f| f.kind()) {
56-
Some(FnKind::ItemFn(_, _, _, c, _, _, attrs)) => {
57-
let scheme = infcx.tcx.lookup_item_type(def_id);
58-
let any_types = !scheme.generics.types.is_empty();
59-
(c, any_types || attr::requests_inline(attrs))
60-
}
61-
Some(FnKind::Method(_, m, _, attrs)) => {
62-
let scheme = infcx.tcx.lookup_item_type(def_id);
63-
let any_types = !scheme.generics.types.is_empty();
64-
(m.constness, any_types || attr::requests_inline(attrs))
65-
}
66-
_ => (hir::Constness::NotConst, true)
55+
Some(FnKind::ItemFn(_, _, _, c, _, _, _)) => c,
56+
Some(FnKind::Method(_, m, _, _)) => m.constness,
57+
_ => hir::Constness::NotConst
6758
}
6859
}
6960
MirSource::Promoted(..) => bug!()
7061
};
7162

63+
let attrs = infcx.tcx.map.attrs(src.item_id());
64+
65+
// Some functions always have overflow checks enabled,
66+
// however, they may not get codegen'd, depending on
67+
// the settings for the crate they are translated in.
68+
let mut check_overflow = attrs.iter().any(|item| {
69+
item.check_name("rustc_inherit_overflow_checks")
70+
});
71+
72+
// Respect -Z force-overflow-checks=on and -C debug-assertions.
73+
check_overflow |= infcx.tcx.sess.opts.debugging_opts.force_overflow_checks
74+
.unwrap_or(infcx.tcx.sess.opts.debug_assertions);
75+
76+
// Constants and const fn's always need overflow checks.
77+
check_overflow |= constness == hir::Constness::Const;
78+
7279
Cx {
7380
tcx: infcx.tcx,
7481
infcx: infcx,
7582
constness: constness,
76-
inline: inline
83+
check_overflow: check_overflow
7784
}
7885
}
7986
}
@@ -186,8 +193,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
186193
self.tcx
187194
}
188195

189-
pub fn may_be_inlined_cross_crate(&self) -> bool {
190-
self.inline
196+
pub fn check_overflow(&self) -> bool {
197+
self.check_overflow
191198
}
192199
}
193200

src/librustc_trans/mir/rvalue.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc::mir::repr as mir;
1616
use asm;
1717
use base;
1818
use callee::Callee;
19-
use common::{self, val_ty, C_null, C_uint, BlockAndBuilder, Result};
19+
use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result};
2020
use datum::{Datum, Lvalue};
2121
use debuginfo::DebugLoc;
2222
use adt;
@@ -579,6 +579,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
579579
lhs: ValueRef,
580580
rhs: ValueRef,
581581
input_ty: Ty<'tcx>) -> OperandValue {
582+
// This case can currently arise only from functions marked
583+
// with #[rustc_inherit_overflow_checks] and inlined from
584+
// another crate (mostly core::num generic/#[inline] fns),
585+
// while the current crate doesn't use overflow checks.
586+
if !bcx.ccx().check_overflow() {
587+
let val = self.trans_scalar_binop(bcx, op, lhs, rhs, input_ty);
588+
return OperandValue::Pair(val, C_bool(bcx.ccx(), false));
589+
}
590+
582591
let (val, of) = match op {
583592
// These are checked using intrinsics
584593
mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => {

src/libsyntax/feature_gate.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,13 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
502502
is just used to make tests pass \
503503
and will never be stable",
504504
cfg_fn!(rustc_attrs))),
505+
("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs",
506+
"the `#[rustc_inherit_overflow_checks]` \
507+
attribute is just used to control \
508+
overflow checking behavior of several \
509+
libcore functions that are inlined \
510+
across crates and will never be stable",
511+
cfg_fn!(rustc_attrs))),
505512

506513
("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
507514
EXPLAIN_ALLOW_INTERNAL_UNSTABLE,

0 commit comments

Comments
 (0)