about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-05-26 20:02:56 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-06-05 14:41:03 +0300
commitd8dddbf2014f92cadfbf14e75a71c345a9e12498 (patch)
treeae12f6d9ab02d568792b580e6f6b7040bb12dd34
parent702c47baae8e417d5ca377acb886893e902f2afa (diff)
downloadrust-d8dddbf2014f92cadfbf14e75a71c345a9e12498.tar.gz
rust-d8dddbf2014f92cadfbf14e75a71c345a9e12498.zip
Respect #[rustc_inherit_overflow_checks] in mir::build and trans.
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs4
-rw-r--r--src/librustc_mir/build/mod.rs20
-rw-r--r--src/librustc_mir/hair/cx/mod.rs47
-rw-r--r--src/librustc_trans/mir/rvalue.rs11
-rw-r--r--src/libsyntax/feature_gate.rs7
5 files changed, 47 insertions, 42 deletions
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index bb7a628f3ba..67cf5473f79 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -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);
 
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index f3b1a871388..9d7818a9ba4 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -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
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 659a326e852..25860ae7ef1 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -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
     }
 }
 
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index d019677d0e6..3e3908845e3 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -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 => {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index c11347f5762..86c4a33896d 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -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,