Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement constant support in MIR. #33130

Merged
merged 12 commits into from
May 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mk/crates.mk
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ DEPS_rustc_lint := rustc log syntax rustc_const_eval
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
DEPS_rustc_metadata := rustc syntax rbml rustc_const_math
DEPS_rustc_passes := syntax rustc core rustc_const_eval
DEPS_rustc_mir := rustc syntax rustc_const_math rustc_const_eval
DEPS_rustc_mir := rustc syntax rustc_const_math rustc_const_eval rustc_bitflags
DEPS_rustc_resolve := arena rustc log syntax
DEPS_rustc_platform_intrinsics := std
DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub enum DepNode<D: Clone + Debug> {
IntrinsicCheck(D),
MatchCheck(D),
MirMapConstruction(D),
MirPass(D),
MirTypeck(D),
BorrowCheck(D),
RvalueCheck(D),
Expand Down Expand Up @@ -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),
Expand Down
82 changes: 68 additions & 14 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,31 @@ impl<'ast> DefCollector<'ast> {
f(self);
self.parent_def = parent;
}

fn visit_ast_const_integer(&mut self, expr: &'ast Expr) {
// Find the node which will be used after lowering.
if let ExprKind::Paren(ref inner) = expr.node {
return self.visit_ast_const_integer(inner);
}

// FIXME(eddyb) Closures should have separate
// function definition IDs and expression IDs.
if let ExprKind::Closure(..) = expr.node {
return;
}

self.create_def(expr.id, DefPathData::Initializer);
}

fn visit_hir_const_integer(&mut self, expr: &'ast hir::Expr) {
// FIXME(eddyb) Closures should have separate
// function definition IDs and expression IDs.
if let hir::ExprClosure(..) = expr.node {
return;
}

self.create_def(expr.id, DefPathData::Initializer);
}
}

impl<'ast> visit::Visitor<'ast> for DefCollector<'ast> {
Expand Down Expand Up @@ -126,14 +151,17 @@ impl<'ast> visit::Visitor<'ast> for DefCollector<'ast> {
let variant_def_index =
this.create_def(v.node.data.id(),
DefPathData::EnumVariant(v.node.name.name));

for (index, field) in v.node.data.fields().iter().enumerate() {
let name = field.ident.map(|ident| ident.name)
.unwrap_or(token::intern(&index.to_string()));
this.create_def_with_parent(Some(variant_def_index),
field.id,
DefPathData::Field(name));
}
this.with_parent(variant_def_index, |this| {
for (index, field) in v.node.data.fields().iter().enumerate() {
let name = field.ident.map(|ident| ident.name)
.unwrap_or_else(|| token::intern(&index.to_string()));
this.create_def(field.id, DefPathData::Field(name));
}

if let Some(ref expr) = v.node.disr_expr {
this.visit_ast_const_integer(expr);
}
});
}
}
ItemKind::Struct(ref struct_def, _) => {
Expand Down Expand Up @@ -221,6 +249,10 @@ impl<'ast> visit::Visitor<'ast> for DefCollector<'ast> {
fn visit_expr(&mut self, expr: &'ast Expr) {
let parent_def = self.parent_def;

if let ExprKind::Repeat(_, ref count) = expr.node {
self.visit_ast_const_integer(count);
}

if let ExprKind::Closure(..) = expr.node {
let def = self.create_def(expr.id, DefPathData::ClosureExpr);
self.parent_def = Some(def);
Expand All @@ -230,6 +262,13 @@ impl<'ast> visit::Visitor<'ast> for DefCollector<'ast> {
self.parent_def = parent_def;
}

fn visit_ty(&mut self, ty: &'ast Ty) {
if let TyKind::FixedLengthVec(_, ref length) = ty.node {
self.visit_ast_const_integer(length);
}
visit::walk_ty(self, ty);
}

fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name));
}
Expand Down Expand Up @@ -276,11 +315,15 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
this.create_def(v.node.data.id(),
DefPathData::EnumVariant(v.node.name));

for field in v.node.data.fields() {
this.create_def_with_parent(Some(variant_def_index),
field.id,
DefPathData::Field(field.name));
}
this.with_parent(variant_def_index, |this| {
for field in v.node.data.fields() {
this.create_def(field.id,
DefPathData::Field(field.name));
}
if let Some(ref expr) = v.node.disr_expr {
this.visit_hir_const_integer(expr);
}
});
}
}
hir::ItemStruct(ref struct_def, _) => {
Expand Down Expand Up @@ -365,6 +408,10 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
fn visit_expr(&mut self, expr: &'ast hir::Expr) {
let parent_def = self.parent_def;

if let hir::ExprRepeat(_, ref count) = expr.node {
self.visit_hir_const_integer(count);
}

if let hir::ExprClosure(..) = expr.node {
let def = self.create_def(expr.id, DefPathData::ClosureExpr);
self.parent_def = Some(def);
Expand All @@ -374,11 +421,18 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
self.parent_def = parent_def;
}

fn visit_ty(&mut self, ty: &'ast hir::Ty) {
if let hir::TyFixedLengthVec(_, ref length) = ty.node {
self.visit_hir_const_integer(length);
}
intravisit::walk_ty(self, ty);
}

fn visit_lifetime_def(&mut self, def: &'ast hir::LifetimeDef) {
self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name));
}

fn visit_macro_def(&mut self, macro_def: &'ast hir::MacroDef) {
self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name));
}
}
}
12 changes: 12 additions & 0 deletions src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,

Expand Down Expand Up @@ -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> {
Expand All @@ -1007,6 +1016,9 @@ impl<'tcx> Debug for Literal<'tcx> {
write!(fmt, "const ")?;
fmt_const_val(fmt, value)
}
Promoted { index } => {
write!(fmt, "promoted{}", index)
}
}
}
}
Expand Down
77 changes: 74 additions & 3 deletions src/librustc/mir/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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: _ } => {}
}
}

Expand Down
12 changes: 11 additions & 1 deletion src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use middle::cstore::{self, LOCAL_CRATE};
use hir::def::{self, Def, ExportMap};
use hir::def_id::DefId;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::region::{CodeExtent};
use middle::region::{CodeExtent, ROOT_CODE_EXTENT};
use traits;
use ty;
use ty::subst::{Subst, Substs, VecPerParamSpace};
Expand Down Expand Up @@ -1376,6 +1376,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
}
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemTy(..) |
hir::ItemImpl(..) |
hir::ItemConst(..) |
hir::ItemStatic(..) => {
Expand Down Expand Up @@ -1408,6 +1409,15 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
// This is a convenience to allow closures to work.
ParameterEnvironment::for_item(cx, cx.map.get_parent(id))
}
Some(ast_map::NodeForeignItem(item)) => {
let def_id = cx.map.local_def_id(id);
let scheme = cx.lookup_item_type(def_id);
let predicates = cx.lookup_predicates(def_id);
cx.construct_parameter_environment(item.span,
&scheme.generics,
&predicates,
ROOT_CODE_EXTENT)
}
_ => {
bug!("ParameterEnvironment::from_item(): \
`{}` is not an item",
Expand Down
7 changes: 2 additions & 5 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use rustc_privacy;
use rustc_plugin::registry::Registry;
use rustc_plugin as plugin;
use rustc::hir::lowering::{lower_crate, LoweringContext};
use rustc_passes::{no_asm, loops, consts, const_fn, rvalues, static_recursion};
use rustc_passes::{no_asm, loops, consts, rvalues, static_recursion};
use rustc_const_eval::check_match;
use super::Compilation;

Expand Down Expand Up @@ -726,10 +726,6 @@ pub fn phase_2_configure_and_expand(sess: &Session,
})
})?;

time(time_passes,
"const fn bodies and arguments",
|| const_fn::check_crate(sess, &krate))?;

if sess.opts.debugging_opts.input_stats {
println!("Post-expansion node count: {}", count_nodes(&krate));
}
Expand Down Expand Up @@ -903,6 +899,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
let mut passes = sess.mir_passes.borrow_mut();
// Push all the built-in passes.
passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks);
passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
passes.push_pass(box mir::transform::type_check::TypeckMir);
passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg);
passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks);
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_bitflags = { path = "../librustc_bitflags" }
syntax = { path = "../libsyntax" }
Loading