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
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
@@ -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
2 changes: 2 additions & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
@@ -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),
82 changes: 68 additions & 14 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
@@ -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> {
@@ -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, _) => {
@@ -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);
@@ -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));
}
@@ -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, _) => {
@@ -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);
@@ -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
@@ -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)
}
}
}
}
77 changes: 74 additions & 3 deletions src/librustc/mir/transform.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
}
4 changes: 3 additions & 1 deletion src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
@@ -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: _ } => {}
}
}

12 changes: 11 additions & 1 deletion src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -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};
@@ -1376,6 +1376,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
}
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemTy(..) |
hir::ItemImpl(..) |
hir::ItemConst(..) |
hir::ItemStatic(..) => {
@@ -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",
7 changes: 2 additions & 5 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
@@ -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;

@@ -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));
}
@@ -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);
3 changes: 3 additions & 0 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
@@ -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
});
1 change: 1 addition & 0 deletions src/librustc_mir/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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