about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-05-02 23:11:19 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-05-07 07:15:01 +0300
commitd434688516f809cff835e76eb6cba07d23e48a2d (patch)
treed4998321b13b48726e08e2a62c56aa5c0596da4b
parentcde2f5f11639edb2f943b6caa5f3b930c0c4f214 (diff)
downloadrust-d434688516f809cff835e76eb6cba07d23e48a2d.tar.gz
rust-d434688516f809cff835e76eb6cba07d23e48a2d.zip
mir: build MIR for constants and static initializers.
-rw-r--r--src/librustc/hir/map/def_collector.rs82
-rw-r--r--src/librustc/ty/mod.rs12
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs13
-rw-r--r--src/librustc_mir/build/mod.rs29
-rw-r--r--src/librustc_mir/mir_map.rs66
5 files changed, 177 insertions, 25 deletions
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 053d32305be..640ef48493a 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));
-
-                        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,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 3e3dae3b3e9..174f626498b 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 a2f7d2c9d72..a4f4e44b1b1 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 004a2aada6a..89c89e6e2e3 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 dad1f157288..e6b795531d9 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,