mir: report when overflow checks would be missing cross-crate.

This commit is contained in:
Eduard Burtescu 2016-05-26 15:42:29 +03:00
parent cab35ff4b8
commit 4adc967ed1
4 changed files with 57 additions and 23 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 && this.check_overflow() && expr.ty.is_signed() {
if op == UnOp::Neg && expr.ty.is_signed() && this.check_overflow() {
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 self.check_overflow() && op.is_checkable() && ty.is_integral() {
if op.is_checkable() && ty.is_integral() && self.check_overflow() {
let result_tup = self.hir.tcx().mk_tup(vec![ty, bool_ty]);
let result_value = self.temp(result_tup);

View File

@ -55,6 +55,8 @@ 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> {
@ -273,7 +275,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
var_indices: FnvHashMap(),
unit_temp: None,
cached_resume_block: None,
cached_return_block: None
cached_return_block: None,
has_warned_about_xcrate_overflows: false
};
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
@ -379,9 +382,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
pub fn check_overflow(&self) -> bool {
self.hir.tcx().sess.opts.debugging_opts.force_overflow_checks.unwrap_or(
self.hir.tcx().sess.opts.debug_assertions)
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

@ -17,32 +17,63 @@
use hair::*;
use rustc::mir::repr::*;
use rustc::mir::transform::MirSource;
use rustc::middle::const_val::ConstVal;
use rustc_const_eval as const_eval;
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::FnKind;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::infer::InferCtxt;
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt};
use syntax::parse::token;
use rustc::hir;
use rustc_const_math::{ConstInt, ConstUsize};
use syntax::attr;
#[derive(Copy, Clone)]
pub struct Cx<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
constness: hir::Constness
constness: hir::Constness,
/// True if this MIR can get inlined in other crates.
inline: bool
}
impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
constness: hir::Constness)
src: MirSource)
-> Cx<'a, 'gcx, 'tcx> {
let (constness, inline) = match src {
MirSource::Const(_) |
MirSource::Static(..) => (hir::Constness::Const, false),
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)
}
}
MirSource::Promoted(..) => bug!()
};
Cx {
tcx: infcx.tcx,
infcx: infcx,
constness: constness,
inline: inline
}
}
}
@ -154,6 +185,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
self.tcx
}
pub fn may_be_inlined_cross_crate(&self) -> bool {
self.inline
}
}
mod block;

View File

@ -32,7 +32,6 @@ use rustc::ty::subst::Substs;
use rustc::util::nodemap::NodeMap;
use rustc::hir;
use rustc::hir::intravisit::{self, FnKind, Visitor};
use rustc::hir::map::blocks::FnLikeNode;
use syntax::ast;
use syntax::codemap::Span;
@ -116,20 +115,7 @@ impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> {
{
let src = self.src;
let mir = self.infcx.enter(|infcx| {
let constness = match src {
MirSource::Const(_) |
MirSource::Static(..) => hir::Constness::Const,
MirSource::Fn(id) => {
let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
match fn_like.map(|f| f.kind()) {
Some(FnKind::ItemFn(_, _, _, c, _, _, _)) => c,
Some(FnKind::Method(_, m, _, _)) => m.constness,
_ => hir::Constness::NotConst
}
}
MirSource::Promoted(..) => bug!()
};
let (mut mir, scope_auxiliary) = f(Cx::new(&infcx, constness));
let (mut mir, scope_auxiliary) = f(Cx::new(&infcx, src));
// Convert the Mir to global types.
let mut globalizer = GlobalizeMir {