mir: prepare for rvalue promotion support.

This commit is contained in:
Eduard Burtescu 2016-05-03 00:26:41 +03:00
parent e1eca0a110
commit 14efbf1481
17 changed files with 237 additions and 96 deletions

View File

@ -64,6 +64,7 @@ pub enum DepNode<D: Clone + Debug> {
IntrinsicCheck(D),
MatchCheck(D),
MirMapConstruction(D),
MirPass(D),
MirTypeck(D),
BorrowCheck(D),
RvalueCheck(D),
@ -186,6 +187,7 @@ impl<D: Clone + Debug> DepNode<D> {
IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
MatchCheck(ref d) => op(d).map(MatchCheck),
MirMapConstruction(ref d) => op(d).map(MirMapConstruction),
MirPass(ref d) => op(d).map(MirPass),
MirTypeck(ref d) => op(d).map(MirTypeck),
BorrowCheck(ref d) => op(d).map(BorrowCheck),
RvalueCheck(ref d) => op(d).map(RvalueCheck),

View File

@ -36,6 +36,11 @@ pub struct Mir<'tcx> {
/// used (eventually) for debuginfo. Indexed by a `ScopeId`.
pub scopes: Vec<ScopeData>,
/// Rvalues promoted from this function, such as borrows of constants.
/// Each of them is the Mir of a constant with the fn's type parameters
/// in scope, but no vars or args and a separate set of temps.
pub promoted: Vec<Mir<'tcx>>,
/// Return type of the function.
pub return_ty: FnOutput<'tcx>,
@ -987,6 +992,10 @@ pub enum Literal<'tcx> {
Value {
value: ConstVal,
},
Promoted {
// Index into the `promoted` vector of `Mir`.
index: usize
},
}
impl<'tcx> Debug for Constant<'tcx> {
@ -1007,6 +1016,9 @@ impl<'tcx> Debug for Literal<'tcx> {
write!(fmt, "const ")?;
fmt_const_val(fmt, value)
}
Promoted { index } => {
write!(fmt, "promoted{}", index)
}
}
}
}

View File

@ -8,31 +8,102 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use dep_graph::DepNode;
use hir;
use hir::map::DefPathData;
use hir::def_id::DefId;
use mir::mir_map::MirMap;
use mir::repr::Mir;
use ty::TyCtxt;
use syntax::ast::NodeId;
/// Where a specific Mir comes from.
#[derive(Copy, Clone)]
pub enum MirSource {
/// Functions and methods.
Fn(NodeId),
/// Constants and associated constants.
Const(NodeId),
/// Initializer of a `static` item.
Static(NodeId, hir::Mutability),
/// Promoted rvalues within a function.
Promoted(NodeId, usize)
}
impl MirSource {
pub fn from_node(tcx: &TyCtxt, id: NodeId) -> MirSource {
use hir::*;
// Handle constants in enum discriminants, types, and repeat expressions.
let def_id = tcx.map.local_def_id(id);
let def_key = tcx.def_key(def_id);
if def_key.disambiguated_data.data == DefPathData::Initializer {
return MirSource::Const(id);
}
match tcx.map.get(id) {
map::NodeItem(&Item { node: ItemConst(..), .. }) |
map::NodeTraitItem(&TraitItem { node: ConstTraitItem(..), .. }) |
map::NodeImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) => {
MirSource::Const(id)
}
map::NodeItem(&Item { node: ItemStatic(_, m, _), .. }) => {
MirSource::Static(id, m)
}
// Default to function if it's not a constant or static.
_ => MirSource::Fn(id)
}
}
pub fn item_id(&self) -> NodeId {
match *self {
MirSource::Fn(id) |
MirSource::Const(id) |
MirSource::Static(id, _) |
MirSource::Promoted(id, _) => id
}
}
}
/// Various information about pass.
pub trait Pass {
// fn name() for printouts of various sorts?
// fn should_run(Session) to check if pass should run?
fn dep_node(&self, def_id: DefId) -> DepNode<DefId> {
DepNode::MirPass(def_id)
}
}
/// A pass which inspects the whole MirMap.
pub trait MirMapPass<'tcx>: Pass {
fn run_pass(&mut self, cx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>);
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>);
}
/// A pass which inspects Mir of functions in isolation.
pub trait MirPass<'tcx>: Pass {
fn run_pass(&mut self, cx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>);
fn run_pass_on_promoted(&mut self, tcx: &TyCtxt<'tcx>,
item_id: NodeId, index: usize,
mir: &mut Mir<'tcx>) {
self.run_pass(tcx, MirSource::Promoted(item_id, index), mir);
}
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, src: MirSource, mir: &mut Mir<'tcx>);
}
impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) {
for (&id, mir) in &mut map.map {
MirPass::run_pass(self, tcx, id, mir);
let def_id = tcx.map.local_def_id(id);
let _task = tcx.dep_graph.in_task(self.dep_node(def_id));
let src = MirSource::from_node(tcx, id);
MirPass::run_pass(self, tcx, src, mir);
for (i, mir) in mir.promoted.iter_mut().enumerate() {
self.run_pass_on_promoted(tcx, id, i, mir);
}
}
}
}

View File

@ -244,6 +244,7 @@ macro_rules! make_mir_visitor {
let Mir {
ref $($mutability)* basic_blocks,
ref $($mutability)* scopes,
promoted: _, // Visited by passes separately.
ref $($mutability)* return_ty,
ref $($mutability)* var_decls,
ref $($mutability)* arg_decls,
@ -649,10 +650,11 @@ macro_rules! make_mir_visitor {
ref $($mutability)* substs } => {
self.visit_def_id(def_id);
self.visit_substs(substs);
},
}
Literal::Value { ref $($mutability)* value } => {
self.visit_const_val(value);
}
Literal::Promoted { index: _ } => {}
}
}

View File

@ -855,6 +855,9 @@ pub fn maybe_get_item_mir<'tcx>(cdata: Cmd,
};
def_id_and_span_translator.visit_mir(&mut mir);
for promoted in &mut mir.promoted {
def_id_and_span_translator.visit_mir(promoted);
}
mir
});

View File

@ -296,6 +296,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
(Mir {
basic_blocks: self.cfg.basic_blocks,
scopes: self.scope_datas,
promoted: vec![],
var_decls: self.var_decls,
arg_decls: arg_decls,
temp_decls: self.temp_decls,

View File

@ -19,6 +19,7 @@
use build;
use rustc::dep_graph::DepNode;
use rustc::mir::repr::Mir;
use rustc::mir::transform::MirSource;
use pretty;
use hair::cx::Cx;
@ -55,10 +56,10 @@ struct BuildMir<'a, 'tcx: 'a> {
}
impl<'a, 'tcx> BuildMir<'a, 'tcx> {
fn build<F>(&mut self, id: ast::NodeId, f: F)
fn build<F>(&mut self, src: MirSource, f: F)
where F: for<'b> FnOnce(Cx<'b, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec)
{
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
let param_env = ty::ParameterEnvironment::for_item(self.tcx, src.item_id());
let infcx = infer::new_infer_ctxt(self.tcx,
&self.tcx.tables,
Some(param_env),
@ -66,9 +67,9 @@ impl<'a, 'tcx> BuildMir<'a, 'tcx> {
let (mir, scope_auxiliary) = f(Cx::new(&infcx));
pretty::dump_mir(self.tcx, "mir_map", &0, id, &mir, Some(&scope_auxiliary));
pretty::dump_mir(self.tcx, "mir_map", &0, src, &mir, Some(&scope_auxiliary));
assert!(self.map.map.insert(id, mir).is_none())
assert!(self.map.map.insert(src.item_id(), mir).is_none())
}
fn build_const_integer(&mut self, expr: &'tcx hir::Expr) {
@ -79,7 +80,9 @@ impl<'a, 'tcx> BuildMir<'a, 'tcx> {
if let hir::ExprClosure(..) = expr.node {
return;
}
self.build(expr.id, |cx| build::construct_const(cx, expr.id, expr));
self.build(MirSource::Const(expr.id), |cx| {
build::construct_const(cx, expr.id, expr)
});
}
}
@ -87,9 +90,15 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
// Const and static items.
fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node {
hir::ItemConst(_, ref expr) |
hir::ItemStatic(_, _, ref expr) => {
self.build(item.id, |cx| build::construct_const(cx, item.id, expr));
hir::ItemConst(_, ref expr) => {
self.build(MirSource::Const(item.id), |cx| {
build::construct_const(cx, item.id, expr)
});
}
hir::ItemStatic(_, m, ref expr) => {
self.build(MirSource::Static(item.id, m), |cx| {
build::construct_const(cx, item.id, expr)
});
}
_ => {}
}
@ -99,7 +108,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
// Trait associated const defaults.
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
self.build(item.id, |cx| build::construct_const(cx, item.id, expr));
self.build(MirSource::Const(item.id), |cx| {
build::construct_const(cx, item.id, expr)
});
}
intravisit::walk_trait_item(self, item);
}
@ -107,7 +118,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
// Impl associated const.
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
if let hir::ImplItemKind::Const(_, ref expr) = item.node {
self.build(item.id, |cx| build::construct_const(cx, item.id, expr));
self.build(MirSource::Const(item.id), |cx| {
build::construct_const(cx, item.id, expr)
});
}
intravisit::walk_impl_item(self, item);
}
@ -166,7 +179,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
(fn_sig.inputs[index], Some(&*arg.pat))
});
self.build(id, |cx| {
self.build(MirSource::Fn(id), |cx| {
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
build::construct_fn(cx, id, arguments, fn_sig.output, body)
});

View File

@ -9,7 +9,9 @@
// except according to those terms.
use build::{Location, ScopeAuxiliaryVec};
use rustc::hir;
use rustc::mir::repr::*;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::fnv::FnvHashMap;
use std::fmt::Display;
@ -37,13 +39,14 @@ const INDENT: &'static str = " ";
pub fn dump_mir<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
pass_name: &str,
disambiguator: &Display,
node_id: NodeId,
src: MirSource,
mir: &Mir<'tcx>,
auxiliary: Option<&ScopeAuxiliaryVec>) {
let filters = match tcx.sess.opts.debugging_opts.dump_mir {
None => return,
Some(ref filters) => filters,
};
let node_id = src.item_id();
let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
let is_matched =
filters.split("&")
@ -64,7 +67,7 @@ pub fn dump_mir<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
try!(writeln!(file, "// pass_name = {}", pass_name));
try!(writeln!(file, "// disambiguator = {}", disambiguator));
try!(writeln!(file, ""));
try!(write_mir_fn(tcx, node_id, mir, &mut file, auxiliary));
try!(write_mir_fn(tcx, src, mir, &mut file, auxiliary));
Ok(())
});
}
@ -76,8 +79,13 @@ pub fn write_mir_pretty<'a, 'tcx, I>(tcx: &TyCtxt<'tcx>,
-> io::Result<()>
where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
{
for (&node_id, mir) in iter {
write_mir_fn(tcx, node_id, mir, w, None)?;
for (&id, mir) in iter {
let src = MirSource::from_node(tcx, id);
write_mir_fn(tcx, src, mir, w, None)?;
for (i, mir) in mir.promoted.iter().enumerate() {
write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?;
}
}
Ok(())
}
@ -88,7 +96,7 @@ enum Annotation {
}
pub fn write_mir_fn<'tcx>(tcx: &TyCtxt<'tcx>,
node_id: NodeId,
src: MirSource,
mir: &Mir<'tcx>,
w: &mut Write,
auxiliary: Option<&ScopeAuxiliaryVec>)
@ -111,7 +119,7 @@ pub fn write_mir_fn<'tcx>(tcx: &TyCtxt<'tcx>,
}
}
write_mir_intro(tcx, node_id, mir, w)?;
write_mir_intro(tcx, src, mir, w)?;
for block in mir.all_basic_blocks() {
write_basic_block(tcx, block, mir, w, &annotations)?;
}
@ -214,24 +222,39 @@ fn write_scope_tree(tcx: &TyCtxt,
/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro(tcx: &TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write)
fn write_mir_intro(tcx: &TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
-> io::Result<()> {
write!(w, "fn {}(", tcx.node_path_str(nid))?;
// fn argument types.
for (i, arg) in mir.arg_decls.iter().enumerate() {
if i > 0 {
write!(w, ", ")?;
}
write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?;
match src {
MirSource::Fn(_) => write!(w, "fn")?,
MirSource::Const(_) => write!(w, "const")?,
MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
MirSource::Promoted(_, i) => write!(w, "promoted{} in", i)?
}
write!(w, ") -> ")?;
write!(w, " {}", tcx.node_path_str(src.item_id()))?;
// fn return type.
match mir.return_ty {
ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?,
ty::FnOutput::FnDiverging => write!(w, "!")?,
if let MirSource::Fn(_) = src {
write!(w, "(")?;
// fn argument types.
for (i, arg) in mir.arg_decls.iter().enumerate() {
if i > 0 {
write!(w, ", ")?;
}
write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?;
}
write!(w, ") -> ")?;
// fn return type.
match mir.return_ty {
ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?,
ty::FnOutput::FnDiverging => write!(w, "!")?,
}
} else {
assert!(mir.arg_decls.is_empty());
write!(w, ": {} =", mir.return_ty.unwrap())?;
}
writeln!(w, " {{")?;

View File

@ -10,8 +10,7 @@
use rustc::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::mir::transform::{MirPass, Pass};
use syntax::ast::NodeId;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc_data_structures::bitvec::BitVector;
@ -43,7 +42,7 @@ pub struct BreakCriticalEdges;
*/
impl<'tcx> MirPass<'tcx> for BreakCriticalEdges {
fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
break_critical_edges(mir);
}
}

View File

@ -16,8 +16,7 @@ use rustc::ty::subst::Substs;
use rustc::ty::{Ty, TyCtxt};
use rustc::mir::repr::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::transform::{MirPass, Pass};
use syntax::ast::NodeId;
use rustc::mir::transform::{MirPass, MirSource, Pass};
struct EraseRegionsVisitor<'a, 'tcx: 'a> {
tcx: &'a TyCtxt<'tcx>,
@ -47,7 +46,7 @@ pub struct EraseRegions;
impl Pass for EraseRegions {}
impl<'tcx> MirPass<'tcx> for EraseRegions {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
EraseRegionsVisitor::new(tcx).visit_mir(mir);
}
}

View File

@ -14,8 +14,7 @@
use rustc::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::transform::{Pass, MirPass};
use syntax::ast::NodeId;
use rustc::mir::transform::{Pass, MirPass, MirSource};
pub struct NoLandingPads;
@ -42,7 +41,7 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
}
impl<'tcx> MirPass<'tcx> for NoLandingPads {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
if tcx.sess.no_landing_pads() {
self.visit_mir(mir);
}

View File

@ -35,13 +35,12 @@
use rustc_data_structures::bitvec::BitVector;
use rustc::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::mir::transform::{Pass, MirPass};
use syntax::ast::NodeId;
use rustc::mir::transform::{Pass, MirPass, MirSource};
pub struct RemoveDeadBlocks;
impl<'tcx> MirPass<'tcx> for RemoveDeadBlocks {
fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
let mut seen = BitVector::new(mir.basic_blocks.len());
// This block is always required.
seen.insert(START_BLOCK.index());

View File

@ -11,9 +11,8 @@
use rustc::middle::const_val::ConstVal;
use rustc::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::mir::transform::{MirPass, Pass};
use rustc::mir::transform::{MirPass, MirSource, Pass};
use pretty;
use syntax::ast::NodeId;
use super::remove_dead_blocks::RemoveDeadBlocks;
@ -112,15 +111,15 @@ impl SimplifyCfg {
}
impl<'tcx> MirPass<'tcx> for SimplifyCfg {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>) {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
let mut counter = 0;
let mut changed = true;
while changed {
pretty::dump_mir(tcx, "simplify_cfg", &counter, id, mir, None);
pretty::dump_mir(tcx, "simplify_cfg", &counter, src, mir, None);
counter += 1;
changed = self.simplify_branches(mir);
changed |= self.remove_goto_chains(mir);
RemoveDeadBlocks.run_pass(tcx, id, mir);
RemoveDeadBlocks.run_pass(tcx, src, mir);
}
// FIXME: Should probably be moved into some kind of pass manager
mir.basic_blocks.shrink_to_fit();

View File

@ -12,16 +12,16 @@
#![allow(unreachable_code)]
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
use rustc::infer::{self, InferCtxt, InferOk};
use rustc::traits::{self, ProjectionMode};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::mir::repr::*;
use rustc::mir::tcx::LvalueTy;
use rustc::mir::transform::{MirPass, Pass};
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::visit::{self, Visitor};
use std::fmt;
use syntax::ast::NodeId;
use syntax::codemap::{Span, DUMMY_SP};
macro_rules! span_mirbug {
@ -578,15 +578,13 @@ impl TypeckMir {
}
impl<'tcx> MirPass<'tcx> for TypeckMir {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>) {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
if tcx.sess.err_count() > 0 {
// compiling a broken program can obviously result in a
// broken MIR, so try not to report duplicate errors.
return;
}
let def_id = tcx.map.local_def_id(id);
let _task = tcx.dep_graph.in_task(DepNode::MirTypeck(def_id));
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
let infcx = infer::new_infer_ctxt(tcx,
&tcx.tables,
Some(param_env),
@ -605,4 +603,8 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
}
}
impl Pass for TypeckMir {}
impl Pass for TypeckMir {
fn dep_node(&self, def_id: DefId) -> DepNode<DefId> {
DepNode::MirTypeck(def_id)
}
}

View File

@ -414,6 +414,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
};
visitor.visit_mir(&mir);
for promoted in &mir.promoted {
visitor.visit_mir(promoted);
}
}
}

View File

@ -35,7 +35,7 @@ use syntax::codemap::{Span, DUMMY_SP};
use std::ptr;
use super::operand::{OperandRef, OperandValue};
use super::{CachedMir, MirContext};
use super::MirContext;
/// A sized constant rvalue.
/// The LLVM type might not be the same for a single Rust type,
@ -179,7 +179,7 @@ impl<'tcx> ConstLvalue<'tcx> {
/// FIXME(eddyb) use miri and lower its allocations to LLVM.
struct MirConstContext<'a, 'tcx: 'a> {
ccx: &'a CrateContext<'a, 'tcx>,
mir: CachedMir<'a, 'tcx>,
mir: &'a mir::Mir<'tcx>,
/// Type parameters for const fn and associated constants.
substs: &'tcx Substs<'tcx>,
@ -200,10 +200,25 @@ struct MirConstContext<'a, 'tcx: 'a> {
impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
fn new(ccx: &'a CrateContext<'a, 'tcx>,
mut instance: Instance<'tcx>,
mir: &'a mir::Mir<'tcx>,
substs: &'tcx Substs<'tcx>,
args: Vec<Const<'tcx>>)
-> MirConstContext<'a, 'tcx> {
MirConstContext {
ccx: ccx,
mir: mir,
substs: substs,
args: args,
vars: vec![None; mir.var_decls.len()],
temps: vec![None; mir.temp_decls.len()],
return_value: None
}
}
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
mut instance: Instance<'tcx>,
args: Vec<Const<'tcx>>)
-> Result<Const<'tcx>, ConstEvalFailure> {
// Try to resolve associated constants.
if instance.substs.self_ty().is_some() {
// Only trait items can have a Self parameter.
@ -226,15 +241,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
let mir = ccx.get_mir(instance.def).unwrap_or_else(|| {
bug!("missing constant MIR for {}", instance)
});
MirConstContext {
ccx: ccx,
substs: instance.substs,
args: args,
vars: vec![None; mir.var_decls.len()],
temps: vec![None; mir.temp_decls.len()],
return_value: None,
mir: mir
}
MirConstContext::new(ccx, &mir, instance.substs, args).trans()
}
fn monomorphize<T>(&self, value: &T) -> T
@ -247,10 +254,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalFailure> {
let tcx = self.ccx.tcx();
let mir = self.mir.clone();
let mut bb = mir::START_BLOCK;
loop {
let data = mir.basic_block_data(bb);
let data = self.mir.basic_block_data(bb);
for statement in &data.statements {
match statement.kind {
mir::StatementKind::Assign(ref dest, ref rvalue) => {
@ -284,7 +290,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
}
mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
let fn_ty = mir.operand_ty(tcx, func);
let fn_ty = self.mir.operand_ty(tcx, func);
let fn_ty = self.monomorphize(&fn_ty);
let instance = match fn_ty.sty {
ty::TyFnDef(def_id, substs, _) => {
@ -304,7 +310,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
let args = args.iter().map(|arg| {
self.const_operand(arg, span)
}).collect::<Result<Vec<_>, _>>()?;
let value = MirConstContext::new(self.ccx, instance, args).trans()?;
let value = MirConstContext::trans_def(self.ccx, instance, args)?;
if let Some((ref dest, target)) = *destination {
self.store(dest, value, span);
target
@ -432,7 +438,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
let substs = self.ccx.tcx().mk_substs(self.monomorphize(substs));
let instance = Instance::new(def_id, substs);
MirConstContext::new(self.ccx, instance, vec![]).trans()
MirConstContext::trans_def(self.ccx, instance, vec![])
}
mir::Literal::Promoted { index } => {
let mir = &self.mir.promoted[index];
MirConstContext::new(self.ccx, mir, self.substs, vec![]).trans()
}
mir::Literal::Value { value } => {
Ok(Const::from_constval(self.ccx, value, ty))
@ -792,7 +802,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
-> OperandRef<'tcx>
{
let ty = bcx.monomorphize(&constant.ty);
let val = match constant.literal.clone() {
let result = match constant.literal.clone() {
mir::Literal::Item { def_id, substs } => {
// Shortcut for zero-sized types, including function item
// types, which would not work with MirConstContext.
@ -806,22 +816,28 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let substs = bcx.tcx().mk_substs(bcx.monomorphize(substs));
let instance = Instance::new(def_id, substs);
match MirConstContext::new(bcx.ccx(), instance, vec![]).trans() {
Ok(v) => v,
Err(ConstEvalFailure::Compiletime(_)) => {
// We've errored, so we don't have to produce working code.
let llty = type_of::type_of(bcx.ccx(), ty);
Const::new(C_undef(llty), ty)
}
Err(ConstEvalFailure::Runtime(err)) => {
span_bug!(constant.span,
"MIR constant {:?} results in runtime panic: {}",
constant, err.description())
}
}
MirConstContext::trans_def(bcx.ccx(), instance, vec![])
}
mir::Literal::Promoted { index } => {
let mir = &self.mir.promoted[index];
MirConstContext::new(bcx.ccx(), mir, bcx.fcx().param_substs, vec![]).trans()
}
mir::Literal::Value { value } => {
Const::from_constval(bcx.ccx(), value, ty)
Ok(Const::from_constval(bcx.ccx(), value, ty))
}
};
let val = match result {
Ok(v) => v,
Err(ConstEvalFailure::Compiletime(_)) => {
// We've errored, so we don't have to produce working code.
let llty = type_of::type_of(bcx.ccx(), ty);
Const::new(C_undef(llty), ty)
}
Err(ConstEvalFailure::Runtime(err)) => {
span_bug!(constant.span,
"MIR constant {:?} results in runtime panic: {}",
constant, err.description())
}
};
@ -839,5 +855,5 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
-> Result<ValueRef, ConstEvalFailure> {
let instance = Instance::mono(ccx.tcx(), def_id);
MirConstContext::new(ccx, instance, vec![]).trans().map(|c| c.llval)
MirConstContext::trans_def(ccx, instance, vec![]).map(|c| c.llval)
}

View File

@ -18,7 +18,7 @@ extern crate rustc_plugin;
extern crate rustc_const_math;
extern crate syntax;
use rustc::mir::transform::{self, MirPass};
use rustc::mir::transform::{self, MirPass, MirSource};
use rustc::mir::repr::{Mir, Literal};
use rustc::mir::visit::MutVisitor;
use rustc::ty;
@ -26,13 +26,11 @@ use rustc::middle::const_val::ConstVal;
use rustc_const_math::ConstInt;
use rustc_plugin::Registry;
use syntax::ast::NodeId;
struct Pass;
impl transform::Pass for Pass {}
impl<'tcx> MirPass<'tcx> for Pass {
fn run_pass(&mut self, _: &ty::TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
fn run_pass(&mut self, _: &ty::TyCtxt<'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
Visitor.visit_mir(mir)
}
}