about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorFlorian Diebold <flodiebold@gmail.com>2016-11-01 18:57:13 +0100
committerFlorian Diebold <florian.diebold@freiheit.com>2016-11-29 13:04:27 +0100
commit16eedd2a781ebc5944916bc34d50383c4c3acc1e (patch)
tree2581d8bef174a619e0783cb70cfb2362b53defed /src
parent1ac338c2a78aa73182916e9425398359ccaf103a (diff)
downloadrust-16eedd2a781ebc5944916bc34d50383c4c3acc1e.tar.gz
rust-16eedd2a781ebc5944916bc34d50383c4c3acc1e.zip
Save bodies of functions for inlining into other crates
This is quite hacky and I hope to refactor it a bit, but at least it
seems to work.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/map/blocks.rs25
-rw-r--r--src/librustc/hir/map/mod.rs22
-rw-r--r--src/librustc/middle/cstore.rs114
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs16
-rw-r--r--src/librustc_const_eval/eval.rs51
-rw-r--r--src/librustc_metadata/astencode.rs20
-rw-r--r--src/librustc_metadata/cstore_impl.rs26
-rw-r--r--src/librustc_metadata/encoder.rs8
-rw-r--r--src/librustc_mir/hair/cx/mod.rs7
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs14
-rw-r--r--src/librustc_passes/consts.rs18
11 files changed, 178 insertions, 143 deletions
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 0adeb90e697..e4c5fd27b91 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -25,6 +25,7 @@ use hir as ast;
 use hir::map::{self, Node};
 use hir::{Expr, FnDecl};
 use hir::intravisit::FnKind;
+use middle::cstore::{InlinedItem, InlinedItemKind};
 use syntax::abi;
 use syntax::ast::{Attribute, Name, NodeId};
 use syntax_pos::Span;
@@ -151,6 +152,7 @@ impl<'a> FnLikeNode<'a> {
             map::NodeTraitItem(tm) => tm.is_fn_like(),
             map::NodeImplItem(_) => true,
             map::NodeExpr(e) => e.is_fn_like(),
+            map::NodeInlinedItem(ii) => ii.is_fn(),
             _ => false
         };
         if fn_like {
@@ -173,12 +175,18 @@ impl<'a> FnLikeNode<'a> {
     }
 
     pub fn body(self) -> ast::ExprId {
+        if let map::NodeInlinedItem(ii) = self.node {
+            return ast::ExprId(ii.body.id);
+        }
         self.handle(|i: ItemFnParts<'a>|  i.body,
                     |_, _, _: &'a ast::MethodSig, _, body: ast::ExprId, _, _|  body,
                     |c: ClosureParts<'a>| c.body)
     }
 
     pub fn decl(self) -> &'a FnDecl {
+        if let map::NodeInlinedItem(&InlinedItem { kind: InlinedItemKind::Fn(ref decl), .. }) = self.node {
+            return &decl;
+        }
         self.handle(|i: ItemFnParts<'a>|  &*i.decl,
                     |_, _, sig: &'a ast::MethodSig, _, _, _, _|  &sig.decl,
                     |c: ClosureParts<'a>| c.decl)
@@ -196,6 +204,21 @@ impl<'a> FnLikeNode<'a> {
                     |c: ClosureParts|    c.id)
     }
 
+    pub fn constness(self) -> ast::Constness {
+        if let map::NodeInlinedItem(..) = self.node {
+            return ast::Constness::Const;
+        }
+        match self.kind() {
+            FnKind::ItemFn(_, _, _, constness, ..) => {
+                constness
+            }
+            FnKind::Method(_, m, ..) => {
+                m.constness
+            }
+            _ => ast::Constness::NotConst
+        }
+    }
+
     pub fn kind(self) -> FnKind<'a> {
         let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
             FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis, p.attrs)
@@ -254,7 +277,7 @@ impl<'a> FnLikeNode<'a> {
                         bug!("impl method FnLikeNode that is not fn-like")
                     }
                 }
-            }
+            },
             map::NodeExpr(e) => match e.node {
                 ast::ExprClosure(_, ref decl, block, _fn_decl_span) =>
                     closure(ClosureParts::new(&decl, block, e.id, e.span, &e.attrs)),
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 7ef98fcce7e..33cdb428220 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -18,7 +18,6 @@ pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
 use dep_graph::{DepGraph, DepNode};
 
 use middle::cstore::InlinedItem;
-use middle::cstore::InlinedItem as II;
 use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
 
 use syntax::abi::Abi;
@@ -61,6 +60,8 @@ pub enum Node<'ast> {
     NodeLifetime(&'ast Lifetime),
     NodeTyParam(&'ast TyParam),
     NodeVisibility(&'ast Visibility),
+
+    NodeInlinedItem(&'ast InlinedItem),
 }
 
 /// Represents an entry and its parent NodeID.
@@ -120,6 +121,8 @@ impl<'ast> MapEntry<'ast> {
             NodeLifetime(n) => EntryLifetime(p, n),
             NodeTyParam(n) => EntryTyParam(p, n),
             NodeVisibility(n) => EntryVisibility(p, n),
+
+            NodeInlinedItem(n) => RootInlinedParent(n),
         }
     }
 
@@ -168,6 +171,7 @@ impl<'ast> MapEntry<'ast> {
             EntryLifetime(_, n) => NodeLifetime(n),
             EntryTyParam(_, n) => NodeTyParam(n),
             EntryVisibility(_, n) => NodeVisibility(n),
+            RootInlinedParent(n) => NodeInlinedItem(n),
             _ => return None
         })
     }
@@ -328,12 +332,8 @@ impl<'ast> Map<'ast> {
                     EntryVisibility(p, _) =>
                         id = p,
 
-                    RootInlinedParent(parent) => match *parent {
-                        InlinedItem::Item(def_id, _) |
-                        InlinedItem::TraitItem(def_id, _) |
-                        InlinedItem::ImplItem(def_id, _) =>
-                            return DepNode::MetaData(def_id)
-                    },
+                    RootInlinedParent(parent) =>
+                        return DepNode::MetaData(parent.def_id),
 
                     RootCrate =>
                         bug!("node {} has crate ancestor but is inlined", id0),
@@ -556,8 +556,7 @@ impl<'ast> Map<'ast> {
     pub fn get_parent_did(&self, id: NodeId) -> DefId {
         let parent = self.get_parent(id);
         match self.find_entry(parent) {
-            Some(RootInlinedParent(&II::TraitItem(did, _))) |
-            Some(RootInlinedParent(&II::ImplItem(did, _))) => did,
+            Some(RootInlinedParent(ii)) => ii.def_id, // TODO: is this wrong for items?
             _ => self.local_def_id(parent)
         }
     }
@@ -962,6 +961,8 @@ impl<'a> NodePrinter for pprust::State<'a> {
             // printing.
             NodeLocal(_)       => bug!("cannot print isolated Local"),
             NodeStructCtor(_)  => bug!("cannot print isolated StructCtor"),
+
+            NodeInlinedItem(_) => bug!("cannot print inlined item"),
         }
     }
 }
@@ -1075,6 +1076,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
         Some(NodeVisibility(ref vis)) => {
             format!("visibility {:?}{}", vis, id_str)
         }
+        Some(NodeInlinedItem(_)) => {
+            format!("inlined item {}", id_str)
+        }
         None => {
             format!("unknown node{}", id_str)
         }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 0867e75b9ca..17085e31bfe 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -43,7 +43,7 @@ use syntax::symbol::Symbol;
 use syntax_pos::Span;
 use rustc_back::target::Target;
 use hir;
-use hir::intravisit::Visitor;
+use hir::intravisit::{self, Visitor};
 use rustc_back::PanicStrategy;
 
 pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
@@ -137,18 +137,100 @@ pub struct NativeLibrary {
 /// part of the AST that we parse from a file, but it becomes part of the tree
 /// that we trans.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum InlinedItem {
-    Item(DefId /* def-id in source crate */, P<hir::Item>),
-    TraitItem(DefId /* impl id */, P<hir::TraitItem>),
-    ImplItem(DefId /* impl id */, P<hir::ImplItem>)
+pub struct InlinedItem {
+    pub def_id: DefId,
+    pub body: P<hir::Expr>,
+    pub kind: InlinedItemKind,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum InlinedItemKind {
+    Const(P<hir::Ty>),
+    Fn(P<hir::FnDecl>)
+}
+
+/// A borrowed version of `hir::InlinedItem`. This is what's encoded when saving
+/// a crate; it then gets read as an InlinedItem.
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, Hash, Debug)]
+pub struct InlinedItemRef<'a> {
+    pub def_id: DefId,
+    pub body: &'a hir::Expr,
+    pub kind: InlinedItemKindRef<'a>,
 }
 
-/// A borrowed version of `hir::InlinedItem`.
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, Hash, Debug)]
-pub enum InlinedItemRef<'a> {
-    Item(DefId, &'a hir::Item),
-    TraitItem(DefId, &'a hir::TraitItem),
-    ImplItem(DefId, &'a hir::ImplItem)
+pub enum InlinedItemKindRef<'a> {
+    Const(&'a hir::Ty),
+    Fn(&'a hir::FnDecl)
+}
+
+impl<'a> InlinedItemRef<'a> {
+    pub fn from_item<'ast: 'a>(def_id: DefId, item: &'a hir::Item, map: &hir_map::Map<'ast>) -> InlinedItemRef<'a> {
+        let (body, kind) = match item.node {
+            hir::ItemFn(ref decl, _, _, _, _, body_id) => (map.expr(body_id), InlinedItemKindRef::Fn(&decl)),
+            hir::ItemConst(ref ty, ref body) => (&**body, InlinedItemKindRef::Const(ty)),
+            _ => bug!("InlinedItemRef::from_item wrong kind")
+        };
+        InlinedItemRef {
+            def_id: def_id,
+            body: body,
+            kind: kind
+        }
+    }
+
+    pub fn from_trait_item(def_id: DefId, item: &'a hir::TraitItem, _map: &hir_map::Map) -> InlinedItemRef<'a> {
+        let (body, kind) = match item.node {
+            hir::ConstTraitItem(ref ty, Some(ref body)) => (&**body, InlinedItemKindRef::Const(ty)),
+            _ => bug!("InlinedItemRef::from_trait_item wrong kind")
+        };
+        InlinedItemRef {
+            def_id: def_id,
+            body: body,
+            kind: kind
+        }
+    }
+
+    pub fn from_impl_item<'ast: 'a>(def_id: DefId, item: &'a hir::ImplItem, map: &hir_map::Map<'ast>) -> InlinedItemRef<'a> {
+        let (body, kind) = match item.node {
+            hir::ImplItemKind::Method(ref sig, body_id) => (map.expr(body_id), InlinedItemKindRef::Fn(&sig.decl)),
+            hir::ImplItemKind::Const(ref ty, ref body) => (&**body, InlinedItemKindRef::Const(ty)),
+            _ => bug!("InlinedItemRef::from_impl_item wrong kind")
+        };
+        InlinedItemRef {
+            def_id: def_id,
+            body: body,
+            kind: kind
+        }
+    }
+
+    pub fn visit<V>(&self, visitor: &mut V)
+        where V: Visitor<'a>
+    {
+        visitor.visit_expr(&self.body);
+        match self.kind {
+            InlinedItemKindRef::Const(ty) => visitor.visit_ty(ty),
+            InlinedItemKindRef::Fn(decl) => intravisit::walk_fn_decl(visitor, decl)
+        }
+    }
+}
+
+impl InlinedItem {
+    pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
+        where V: Visitor<'ast>
+    {
+        visitor.visit_expr(&self.body);
+        match self.kind {
+            InlinedItemKind::Const(ref ty) => visitor.visit_ty(ty),
+            InlinedItemKind::Fn(ref decl) => intravisit::walk_fn_decl(visitor, decl)
+        }
+    }
+
+    pub fn is_fn(&self) -> bool {
+        match self.kind {
+            InlinedItemKind::Const(_) => false,
+            InlinedItemKind::Fn(_) => true
+        }
+    }
 }
 
 pub enum LoadedMacro {
@@ -292,18 +374,6 @@ pub trait CrateStore<'tcx> {
     fn metadata_encoding_version(&self) -> &[u8];
 }
 
-impl InlinedItem {
-    pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
-        where V: Visitor<'ast>
-    {
-        match *self {
-            InlinedItem::Item(_, ref i) => visitor.visit_item(&i),
-            InlinedItem::TraitItem(_, ref ti) => visitor.visit_trait_item(ti),
-            InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii),
-        }
-    }
-}
-
 // FIXME: find a better place for this?
 pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
     let mut err_count = 0;
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 8f2afa7f808..96faf97d609 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -30,7 +30,7 @@ use syntax_pos::Span;
 use rustc::hir;
 use rustc::hir::Expr;
 use rustc::hir::intravisit;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::intravisit::{Visitor, NestedVisitMode};
 
 use self::restrictions::RestrictionResult;
 
@@ -520,8 +520,12 @@ struct StaticInitializerCtxt<'a, 'tcx: 'a> {
     item_id: ast::NodeId
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
-    fn visit_expr(&mut self, ex: &Expr) {
+impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> {
+    fn nested_visit_map(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.bccx.tcx.map, NestedVisitMode::OnlyBodies))
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx Expr) {
         if let hir::ExprAddrOf(mutbl, ref base) = ex.node {
             let param_env = ty::ParameterEnvironment::for_item(self.bccx.tcx,
                                                                self.item_id);
@@ -542,9 +546,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
     }
 }
 
-pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt,
-                                          item_id: ast::NodeId,
-                                          expr: &hir::Expr) {
+pub fn gather_loans_in_static_initializer<'a, 'tcx>(bccx: &mut BorrowckCtxt<'a, 'tcx>,
+                                                    item_id: ast::NodeId,
+                                                    expr: &'tcx hir::Expr) {
 
     debug!("gather_loans_in_static_initializer(expr={:?})", expr);
 
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 61986efbf4f..fb5cff56950 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -17,7 +17,7 @@ use self::EvalHint::*;
 
 use rustc::hir::map as ast_map;
 use rustc::hir::map::blocks::FnLikeNode;
-use rustc::middle::cstore::InlinedItem;
+use rustc::middle::cstore::{InlinedItem, InlinedItemKind};
 use rustc::traits;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
@@ -141,33 +141,9 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
         let mut used_substs = false;
         let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
-            Some((&InlinedItem::Item(_, ref item), _)) => match item.node {
-                hir::ItemConst(ref ty, ref const_expr) => {
-                    Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
-                },
-                _ => None
-            },
-            Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
-                hir::ConstTraitItem(..) => {
-                    used_substs = true;
-                    if let Some(substs) = substs {
-                        // As mentioned in the comments above for in-crate
-                        // constants, we only try to find the expression for
-                        // a trait-associated const if the caller gives us
-                        // the substitutions for the reference to it.
-                        resolve_trait_associated_const(tcx, ti, trait_id, substs)
-                    } else {
-                        None
-                    }
-                }
-                _ => None
-            },
-            Some((&InlinedItem::ImplItem(_, ref ii), _)) => match ii.node {
-                hir::ImplItemKind::Const(ref ty, ref expr) => {
-                    Some((&**expr, tcx.ast_ty_to_prim_ty(ty)))
-                },
-                _ => None
-            },
+            Some((&InlinedItem { body: ref const_expr, kind: InlinedItemKind::Const(ref ty), .. }, _)) => {
+                Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
+            }
             _ => None
         };
         // If we used the substitutions, particularly to choose an impl
@@ -197,8 +173,7 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
-        Some((&InlinedItem::Item(_, ref item), _)) => Some(item.id),
-        Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id),
+        Some((&InlinedItem { kind: InlinedItemKind::Fn(_), .. }, node_id)) => Some(node_id),
         _ => None
     };
     tcx.extern_const_fns.borrow_mut().insert(def_id,
@@ -224,18 +199,10 @@ pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
         None => return None
     };
 
-    match fn_like.kind() {
-        FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => {
-            Some(fn_like)
-        }
-        FnKind::Method(_, m, ..) => {
-            if m.constness == hir::Constness::Const {
-                Some(fn_like)
-            } else {
-                None
-            }
-        }
-        _ => None
+    if fn_like.constness() == hir::Constness::Const {
+        Some(fn_like)
+    } else {
+        None
     }
 }
 
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index 69e1ecb5f81..8a24062f8f3 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -46,11 +46,7 @@ enum TableEntry<'tcx> {
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     pub fn encode_inlined_item(&mut self, ii: InlinedItemRef<'tcx>) -> Lazy<Ast<'tcx>> {
         let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
-        match ii {
-            InlinedItemRef::Item(_, i) => id_visitor.visit_item(i),
-            InlinedItemRef::TraitItem(_, ti) => id_visitor.visit_trait_item(ti),
-            InlinedItemRef::ImplItem(_, ii) => id_visitor.visit_impl_item(ii),
-        }
+        ii.visit(&mut id_visitor);
 
         let ii_pos = self.position();
         ii.encode(self).unwrap();
@@ -61,11 +57,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 ecx: self,
                 count: 0,
             };
-            match ii {
-                InlinedItemRef::Item(_, i) => visitor.visit_item(i),
-                InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti),
-                InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii),
-            }
+            ii.visit(&mut visitor);
             visitor.count
         };
 
@@ -127,17 +119,13 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
                      }];
 
     let ii = ast.item.decode((cdata, tcx, id_ranges));
+    let item_node_id = tcx.sess.next_node_id();
     let ii = ast_map::map_decoded_item(&tcx.map,
                                        parent_def_path,
                                        parent_did,
                                        ii,
-                                       tcx.sess.next_node_id());
+                                       item_node_id);
 
-    let item_node_id = match ii {
-        &InlinedItem::Item(_, ref i) => i.id,
-        &InlinedItem::TraitItem(_, ref ti) => ti.id,
-        &InlinedItem::ImplItem(_, ref ii) => ii.id,
-    };
     let inlined_did = tcx.map.local_def_id(item_node_id);
     let ty = tcx.item_type(orig_did);
     let generics = tcx.item_generics(orig_did);
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 4b90d925972..573b2f6d2a6 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -443,12 +443,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
 
         let find_inlined_item_root = |inlined_item_id| {
             let mut node = inlined_item_id;
-            let mut path = Vec::with_capacity(10);
 
             // If we can't find the inline root after a thousand hops, we can
             // be pretty sure there's something wrong with the HIR map.
             for _ in 0 .. 1000 {
-                path.push(node);
                 let parent_node = tcx.map.get_parent_node(node);
                 if parent_node == node {
                     return node;
@@ -464,27 +462,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
                     .borrow_mut()
                     .insert(def_id, None);
             }
-            Some(&InlinedItem::Item(d, ref item)) => {
-                assert_eq!(d, def_id);
-                let inlined_root_node_id = find_inlined_item_root(item.id);
-                cache_inlined_item(def_id, item.id, inlined_root_node_id);
-            }
-            Some(&InlinedItem::TraitItem(_, ref trait_item)) => {
-                let inlined_root_node_id = find_inlined_item_root(trait_item.id);
-                cache_inlined_item(def_id, trait_item.id, inlined_root_node_id);
-
-                // Associated consts already have to be evaluated in `typeck`, so
-                // the logic to do that already exists in `middle`. In order to
-                // reuse that code, it needs to be able to look up the traits for
-                // inlined items.
-                let ty_trait_item = tcx.associated_item(def_id).clone();
-                let trait_item_def_id = tcx.map.local_def_id(trait_item.id);
-                tcx.associated_items.borrow_mut()
-                   .insert(trait_item_def_id, ty_trait_item);
-            }
-            Some(&InlinedItem::ImplItem(_, ref impl_item)) => {
-                let inlined_root_node_id = find_inlined_item_root(impl_item.id);
-                cache_inlined_item(def_id, impl_item.id, inlined_root_node_id);
+            Some(&InlinedItem { ref body, .. }) => {
+                let inlined_root_node_id = find_inlined_item_root(body.id);
+                cache_inlined_item(def_id, inlined_root_node_id, inlined_root_node_id);
             }
         }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index ca730afc52a..afb88cf3ddf 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -518,7 +518,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
             ast: if trait_item.kind == ty::AssociatedKind::Const {
                 let trait_def_id = trait_item.container.id();
-                Some(self.encode_inlined_item(InlinedItemRef::TraitItem(trait_def_id, ast_item)))
+                Some(self.encode_inlined_item(InlinedItemRef::from_trait_item(trait_def_id, ast_item, &tcx.map)))
             } else {
                 None
             },
@@ -527,6 +527,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+        let tcx = self.tcx;
+
         let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
         let ast_item = self.tcx.map.expect_impl_item(node_id);
         let impl_item = self.tcx.associated_item(def_id);
@@ -587,7 +589,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             predicates: Some(self.encode_predicates(def_id)),
 
             ast: if ast {
-                Some(self.encode_inlined_item(InlinedItemRef::ImplItem(impl_def_id, ast_item)))
+                Some(self.encode_inlined_item(InlinedItemRef::from_impl_item(impl_def_id, ast_item, &tcx.map)))
             } else {
                 None
             },
@@ -817,7 +819,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             ast: match item.node {
                 hir::ItemConst(..) |
                 hir::ItemFn(_, _, hir::Constness::Const, ..) => {
-                    Some(self.encode_inlined_item(InlinedItemRef::Item(def_id, item)))
+                    Some(self.encode_inlined_item(InlinedItemRef::from_item(def_id, item, &tcx.map)))
                 }
                 _ => None,
             },
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index cfeac606f03..32639cc3f86 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -23,7 +23,6 @@ use rustc_const_eval as const_eval;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::dep_graph::DepNode;
 use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::FnKind;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::infer::InferCtxt;
 use rustc::ty::subst::Subst;
@@ -51,11 +50,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             MirSource::Static(..) => hir::Constness::Const,
             MirSource::Fn(id) => {
                 let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
-                match fn_like.map(|f| f.kind()) {
-                    Some(FnKind::ItemFn(_, _, _, c, ..)) => c,
-                    Some(FnKind::Method(_, m, ..)) => m.constness,
-                    _ => hir::Constness::NotConst
-                }
+                fn_like.map_or(hir::Constness::NotConst, |f| f.constness())
             }
             MirSource::Promoted(..) => bug!()
         };
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 4ff2beb3fdb..57929879f94 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -19,7 +19,6 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use rustc::hir;
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::FnKind;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::traits::{self, Reveal};
 use rustc::ty::{self, TyCtxt, Ty};
@@ -116,15 +115,10 @@ impl fmt::Display for Mode {
 
 pub fn is_const_fn(tcx: TyCtxt, def_id: DefId) -> bool {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
-        let fn_like = FnLikeNode::from_node(tcx.map.get(node_id));
-        match fn_like.map(|f| f.kind()) {
-            Some(FnKind::ItemFn(_, _, _, c, ..)) => {
-                c == hir::Constness::Const
-            }
-            Some(FnKind::Method(_, m, ..)) => {
-                m.constness == hir::Constness::Const
-            }
-            _ => false
+        if let Some(fn_like) = FnLikeNode::from_node(tcx.map.get(node_id)) {
+            fn_like.constness() == hir::Constness::Const
+        } else {
+            false
         }
     } else {
         tcx.sess.cstore.is_const_fn(def_id)
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 626af7db325..729cc773568 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -181,11 +181,19 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
     /// Returns true if the call is to a const fn or method.
     fn handle_const_fn_call(&mut self, _expr: &hir::Expr, def_id: DefId, ret_ty: Ty<'gcx>) -> bool {
         if let Some(fn_like) = lookup_const_fn_by_id(self.tcx, def_id) {
-            let qualif = self.fn_like(fn_like.kind(),
-                                      fn_like.decl(),
-                                      fn_like.body(),
-                                      fn_like.span(),
-                                      fn_like.id());
+            let qualif = match self.tcx.const_qualif_map.borrow_mut().entry(fn_like.body().node_id()) {
+                Entry::Occupied(entry) => Some(*entry.get()),
+                _ => None
+            };
+
+            let qualif = qualif.unwrap_or_else(|| {
+                self.fn_like(fn_like.kind(),
+                             fn_like.decl(),
+                             fn_like.body(),
+                             fn_like.span(),
+                             fn_like.id())
+            });
+
             self.add_qualif(qualif);
 
             if ret_ty.type_contents(self.tcx).interior_unsafe() {