From d434688516f809cff835e76eb6cba07d23e48a2d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 2 May 2016 23:11:19 +0300 Subject: [PATCH] mir: build MIR for constants and static initializers. --- src/librustc/hir/map/def_collector.rs | 80 +++++++++++++++++++++----- src/librustc/ty/mod.rs | 12 +++- src/librustc_mir/build/expr/as_temp.rs | 13 ++--- src/librustc_mir/build/mod.rs | 29 +++++++++- src/librustc_mir/mir_map.rs | 66 ++++++++++++++++++++- 5 files changed, 176 insertions(+), 24 deletions(-) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 053d32305be0..640ef48493a2 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -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)); + 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)); + } - 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)); - } + 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,6 +421,13 @@ 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)); } @@ -381,4 +435,4 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> { fn visit_macro_def(&mut self, macro_def: &'ast hir::MacroDef) { self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name)); } -} \ No newline at end of file +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3e3dae3b3e98..174f626498b1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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", diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index a2f7d2c9d725..a4f4e44b1b13 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -35,13 +35,12 @@ impl<'a,'tcx> Builder<'a,'tcx> { let expr_ty = expr.ty.clone(); let temp = this.temp(expr_ty.clone()); - let temp_lifetime = match expr.temp_lifetime { - Some(t) => t, - None => { - span_bug!(expr.span, "no temp_lifetime for expr"); - } - }; - this.schedule_drop(expr.span, temp_lifetime, &temp, expr_ty); + // In constants, temp_lifetime is None. We should not need to drop + // anything because no values with a destructor can be created in + // a constant at this time, even if the type may need dropping. + if let Some(temp_lifetime) = expr.temp_lifetime { + this.schedule_drop(expr.span, temp_lifetime, &temp, expr_ty); + } // Careful here not to cause an infinite cycle. If we always // called `into`, then for lvalues like `x.f`, it would diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 004a2aada6a5..89c89e6e2e37 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -9,7 +9,7 @@ // except according to those terms. use hair::cx::Cx; -use rustc::middle::region::{CodeExtent, CodeExtentData}; +use rustc::middle::region::{CodeExtent, CodeExtentData, ROOT_CODE_EXTENT}; use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use rustc_data_structures::fnv::FnvHashMap; @@ -232,6 +232,33 @@ pub fn construct_fn<'a, 'tcx, A>(hir: Cx<'a,'tcx>, builder.finish(upvar_decls, arg_decls, return_ty) } +pub fn construct_const<'a, 'tcx>(hir: Cx<'a,'tcx>, + item_id: ast::NodeId, + ast_expr: &'tcx hir::Expr) + -> (Mir<'tcx>, ScopeAuxiliaryVec) { + let tcx = hir.tcx(); + let span = tcx.map.span(item_id); + let mut builder = Builder::new(hir, span); + + let extent = ROOT_CODE_EXTENT; + let mut block = START_BLOCK; + let _ = builder.in_scope(extent, block, |builder, call_site_scope_id| { + let expr = builder.hir.mirror(ast_expr); + unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr)); + + let return_block = builder.return_block(); + builder.cfg.terminate(block, call_site_scope_id, span, + TerminatorKind::Goto { target: return_block }); + builder.cfg.terminate(return_block, call_site_scope_id, span, + TerminatorKind::Return); + + return_block.unit() + }); + + let ty = tcx.expr_ty_adjusted(ast_expr); + builder.finish(vec![], vec![], ty::FnConverging(ty)) +} + impl<'a,'tcx> Builder<'a,'tcx> { fn new(hir: Cx<'a, 'tcx>, span: Span) -> Builder<'a, 'tcx> { let mut builder = Builder { diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index dad1f1572881..e6b795531d93 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -16,8 +16,6 @@ //! - `#[rustc_mir(graphviz="file.gv")]` //! - `#[rustc_mir(pretty="file.mir")]` -extern crate syntax; - use build; use rustc::dep_graph::DepNode; use rustc::mir::repr::Mir; @@ -72,9 +70,73 @@ impl<'a, 'tcx> BuildMir<'a, 'tcx> { assert!(self.map.map.insert(id, mir).is_none()) } + + fn build_const_integer(&mut self, expr: &'tcx hir::Expr) { + // FIXME(eddyb) Closures should have separate + // function definition IDs and expression IDs. + // Type-checking should not let closures get + // this far in an integer constant position. + if let hir::ExprClosure(..) = expr.node { + return; + } + self.build(expr.id, |cx| build::construct_const(cx, expr.id, expr)); + } } 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)); + } + _ => {} + } + intravisit::walk_item(self, item); + } + + // 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)); + } + intravisit::walk_trait_item(self, item); + } + + // 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)); + } + intravisit::walk_impl_item(self, item); + } + + // Repeat counts, i.e. [expr; constant]. + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { + if let hir::ExprRepeat(_, ref count) = expr.node { + self.build_const_integer(count); + } + intravisit::walk_expr(self, expr); + } + + // Array lengths, i.e. [T; constant]. + fn visit_ty(&mut self, ty: &'tcx hir::Ty) { + if let hir::TyFixedLengthVec(_, ref length) = ty.node { + self.build_const_integer(length); + } + intravisit::walk_ty(self, ty); + } + + // Enum variant discriminant values. + fn visit_variant(&mut self, v: &'tcx hir::Variant, + g: &'tcx hir::Generics, item_id: ast::NodeId) { + if let Some(ref expr) = v.node.disr_expr { + self.build_const_integer(expr); + } + intravisit::walk_variant(self, v, g, item_id); + } + fn visit_fn(&mut self, fk: intravisit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,