1
Fork 0

rustc: simplify constant cross-crate loading and rustc_passes::consts.

This commit is contained in:
Eduard-Mihai Burtescu 2016-12-20 23:05:21 +02:00
parent f89856be6c
commit f64e73b6ec
24 changed files with 394 additions and 997 deletions

View file

@ -11,7 +11,6 @@
use super::*; use super::*;
use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::intravisit::{Visitor, NestedVisitorMap};
use middle::cstore::InlinedItem;
use std::iter::repeat; use std::iter::repeat;
use syntax::ast::{NodeId, CRATE_NODE_ID}; use syntax::ast::{NodeId, CRATE_NODE_ID};
use syntax_pos::Span; use syntax_pos::Span;
@ -21,7 +20,7 @@ pub struct NodeCollector<'ast> {
/// The crate /// The crate
pub krate: &'ast Crate, pub krate: &'ast Crate,
/// The node map /// The node map
pub map: Vec<MapEntry<'ast>>, pub(super) map: Vec<MapEntry<'ast>>,
/// The parent of this node /// The parent of this node
pub parent_node: NodeId, pub parent_node: NodeId,
/// If true, completely ignore nested items. We set this when loading /// If true, completely ignore nested items. We set this when loading
@ -43,11 +42,11 @@ impl<'ast> NodeCollector<'ast> {
collector collector
} }
pub fn extend(krate: &'ast Crate, pub(super) fn extend(krate: &'ast Crate,
parent: &'ast InlinedItem, parent: &'ast InlinedItem,
parent_node: NodeId, parent_node: NodeId,
map: Vec<MapEntry<'ast>>) map: Vec<MapEntry<'ast>>)
-> NodeCollector<'ast> { -> NodeCollector<'ast> {
let mut collector = NodeCollector { let mut collector = NodeCollector {
krate: krate, krate: krate,
map: map, map: map,

View file

@ -17,7 +17,6 @@ pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
use dep_graph::{DepGraph, DepNode}; use dep_graph::{DepGraph, DepNode};
use middle::cstore::InlinedItem;
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
use syntax::abi::Abi; use syntax::abi::Abi;
@ -26,6 +25,7 @@ use syntax::codemap::Spanned;
use syntax_pos::Span; use syntax_pos::Span;
use hir::*; use hir::*;
use hir::intravisit::Visitor;
use hir::print as pprust; use hir::print as pprust;
use arena::TypedArena; use arena::TypedArena;
@ -38,6 +38,15 @@ mod collector;
mod def_collector; mod def_collector;
pub mod definitions; pub mod definitions;
/// The data we save and restore about an inlined item or method. This is not
/// part of the AST that we parse from a file, but it becomes part of the tree
/// that we trans.
#[derive(Debug)]
struct InlinedItem {
def_id: DefId,
body: Body,
}
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum Node<'ast> { pub enum Node<'ast> {
NodeItem(&'ast Item), NodeItem(&'ast Item),
@ -60,14 +69,12 @@ pub enum Node<'ast> {
NodeLifetime(&'ast Lifetime), NodeLifetime(&'ast Lifetime),
NodeTyParam(&'ast TyParam), NodeTyParam(&'ast TyParam),
NodeVisibility(&'ast Visibility), NodeVisibility(&'ast Visibility),
NodeInlinedItem(&'ast InlinedItem),
} }
/// Represents an entry and its parent NodeID. /// Represents an entry and its parent NodeID.
/// The odd layout is to bring down the total size. /// The odd layout is to bring down the total size.
#[derive(Copy, Debug)] #[derive(Copy, Debug)]
pub enum MapEntry<'ast> { enum MapEntry<'ast> {
/// Placeholder for holes in the map. /// Placeholder for holes in the map.
NotPresent, NotPresent,
@ -121,8 +128,6 @@ impl<'ast> MapEntry<'ast> {
NodeLifetime(n) => EntryLifetime(p, n), NodeLifetime(n) => EntryLifetime(p, n),
NodeTyParam(n) => EntryTyParam(p, n), NodeTyParam(n) => EntryTyParam(p, n),
NodeVisibility(n) => EntryVisibility(p, n), NodeVisibility(n) => EntryVisibility(p, n),
NodeInlinedItem(n) => RootInlinedParent(n),
} }
} }
@ -171,10 +176,49 @@ impl<'ast> MapEntry<'ast> {
EntryLifetime(_, n) => NodeLifetime(n), EntryLifetime(_, n) => NodeLifetime(n),
EntryTyParam(_, n) => NodeTyParam(n), EntryTyParam(_, n) => NodeTyParam(n),
EntryVisibility(_, n) => NodeVisibility(n), EntryVisibility(_, n) => NodeVisibility(n),
RootInlinedParent(n) => NodeInlinedItem(n),
_ => return None _ => return None
}) })
} }
fn is_body_owner(self, node_id: NodeId) -> bool {
match self {
EntryItem(_, item) => {
match item.node {
ItemConst(_, body) |
ItemStatic(.., body) |
ItemFn(_, _, _, _, _, body) => body.node_id == node_id,
_ => false
}
}
EntryTraitItem(_, item) => {
match item.node {
TraitItemKind::Const(_, Some(body)) |
TraitItemKind::Method(_, TraitMethod::Provided(body)) => {
body.node_id == node_id
}
_ => false
}
}
EntryImplItem(_, item) => {
match item.node {
ImplItemKind::Const(_, body) |
ImplItemKind::Method(_, body) => body.node_id == node_id,
_ => false
}
}
EntryExpr(_, expr) => {
match expr.node {
ExprClosure(.., body, _) => body.node_id == node_id,
_ => false
}
}
_ => false
}
}
} }
/// Stores a crate and any number of inlined items from other crates. /// Stores a crate and any number of inlined items from other crates.
@ -250,42 +294,19 @@ impl<'ast> Map<'ast> {
if !self.is_inlined_node_id(id) { if !self.is_inlined_node_id(id) {
let mut last_expr = None; let mut last_expr = None;
loop { loop {
match map[id.as_usize()] { let entry = map[id.as_usize()];
EntryItem(_, item) => { match entry {
assert_eq!(id, item.id); EntryItem(..) |
let def_id = self.local_def_id(id); EntryTraitItem(..) |
EntryImplItem(..) => {
if let Some(last_id) = last_expr { if let Some(last_id) = last_expr {
// The body of the item may have a separate dep node // The body may have a separate dep node
if self.is_item_body(last_id, item) { if entry.is_body_owner(last_id) {
let def_id = self.local_def_id(id);
return DepNode::HirBody(def_id); return DepNode::HirBody(def_id);
} }
} }
return DepNode::Hir(def_id); return DepNode::Hir(self.local_def_id(id));
}
EntryTraitItem(_, item) => {
let def_id = self.local_def_id(id);
if let Some(last_id) = last_expr {
// The body of the item may have a separate dep node
if self.is_trait_item_body(last_id, item) {
return DepNode::HirBody(def_id);
}
}
return DepNode::Hir(def_id);
}
EntryImplItem(_, item) => {
let def_id = self.local_def_id(id);
if let Some(last_id) = last_expr {
// The body of the item may have a separate dep node
if self.is_impl_item_body(last_id, item) {
return DepNode::HirBody(def_id);
}
}
return DepNode::Hir(def_id);
} }
EntryVariant(p, v) => { EntryVariant(p, v) => {
@ -377,33 +398,6 @@ impl<'ast> Map<'ast> {
} }
} }
fn is_item_body(&self, node_id: NodeId, item: &Item) -> bool {
match item.node {
ItemConst(_, body) |
ItemStatic(.., body) |
ItemFn(_, _, _, _, _, body) => body.node_id == node_id,
_ => false
}
}
fn is_trait_item_body(&self, node_id: NodeId, item: &TraitItem) -> bool {
match item.node {
TraitItemKind::Const(_, Some(body)) |
TraitItemKind::Method(_, TraitMethod::Provided(body)) => {
body.node_id == node_id
}
_ => false
}
}
fn is_impl_item_body(&self, node_id: NodeId, item: &ImplItem) -> bool {
match item.node {
ImplItemKind::Const(_, body) |
ImplItemKind::Method(_, body) => body.node_id == node_id,
_ => false
}
}
pub fn num_local_def_ids(&self) -> usize { pub fn num_local_def_ids(&self) -> usize {
self.definitions.len() self.definitions.len()
} }
@ -483,6 +477,23 @@ impl<'ast> Map<'ast> {
self.forest.krate.body(id) self.forest.krate.body(id)
} }
/// Returns the `NodeId` that corresponds to the definition of
/// which this is the body of, i.e. a `fn`, `const` or `static`
/// item (possibly associated), or a closure, or the body itself
/// for embedded constant expressions (e.g. `N` in `[T; N]`).
pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId {
let parent = self.get_parent_node(node_id);
if self.map.borrow()[parent.as_usize()].is_body_owner(node_id) {
parent
} else {
node_id
}
}
pub fn body_owner_def_id(&self, id: BodyId) -> DefId {
self.local_def_id(self.body_owner(id))
}
/// Get the attributes on the krate. This is preferable to /// Get the attributes on the krate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter /// invoking `krate.attrs` because it registers a tighter
/// dep-graph access. /// dep-graph access.
@ -726,9 +737,9 @@ impl<'ast> Map<'ast> {
} }
} }
pub fn expect_inlined_item(&self, id: NodeId) -> &'ast InlinedItem { pub fn expect_inlined_body(&self, id: NodeId) -> &'ast Body {
match self.find_entry(id) { match self.find_entry(id) {
Some(RootInlinedParent(inlined_item)) => inlined_item, Some(RootInlinedParent(inlined_item)) => &inlined_item.body,
_ => bug!("expected inlined item, found {}", self.node_to_string(id)), _ => bug!("expected inlined item, found {}", self.node_to_string(id)),
} }
} }
@ -969,24 +980,28 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
} }
} }
/// Used for items loaded from external crate that are being inlined into this /// Used for bodies loaded from external crate that are being inlined into this
/// crate. /// crate.
pub fn map_decoded_item<'ast>(map: &Map<'ast>, pub fn map_decoded_body<'ast>(map: &Map<'ast>,
ii: InlinedItem, def_id: DefId,
ii_parent_id: NodeId) body: Body,
-> &'ast InlinedItem { parent_id: NodeId)
-> &'ast Body {
let _ignore = map.forest.dep_graph.in_ignore(); let _ignore = map.forest.dep_graph.in_ignore();
let ii = map.forest.inlined_items.alloc(ii); let ii = map.forest.inlined_items.alloc(InlinedItem {
def_id: def_id,
body: body
});
let mut collector = NodeCollector::extend(map.krate(), let mut collector = NodeCollector::extend(map.krate(),
ii, ii,
ii_parent_id, parent_id,
mem::replace(&mut *map.map.borrow_mut(), vec![])); mem::replace(&mut *map.map.borrow_mut(), vec![]));
ii.visit(&mut collector); collector.visit_body(&ii.body);
*map.map.borrow_mut() = collector.map; *map.map.borrow_mut() = collector.map;
ii &ii.body
} }
pub trait NodePrinter { pub trait NodePrinter {
@ -1016,8 +1031,6 @@ impl<'a> NodePrinter for pprust::State<'a> {
// printing. // printing.
NodeLocal(_) => bug!("cannot print isolated Local"), NodeLocal(_) => bug!("cannot print isolated Local"),
NodeStructCtor(_) => bug!("cannot print isolated StructCtor"), NodeStructCtor(_) => bug!("cannot print isolated StructCtor"),
NodeInlinedItem(_) => bug!("cannot print inlined item"),
} }
} }
} }
@ -1131,9 +1144,6 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
Some(NodeVisibility(ref vis)) => { Some(NodeVisibility(ref vis)) => {
format!("visibility {:?}{}", vis, id_str) format!("visibility {:?}{}", vis, id_str)
} }
Some(NodeInlinedItem(_)) => {
format!("inlined item {}", id_str)
}
None => { None => {
format!("unknown node{}", id_str) format!("unknown node{}", id_str)
} }

View file

@ -33,6 +33,7 @@
#![cfg_attr(stage0, feature(item_like_imports))] #![cfg_attr(stage0, feature(item_like_imports))]
#![feature(libc)] #![feature(libc)]
#![feature(nonzero)] #![feature(nonzero)]
#![feature(pub_restricted)]
#![feature(quote)] #![feature(quote)]
#![feature(rustc_diagnostic_macros)] #![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)] #![feature(rustc_private)]
@ -80,9 +81,8 @@ pub mod lint;
pub mod middle { pub mod middle {
pub mod astconv_util; pub mod astconv_util;
pub mod expr_use_visitor; // STAGE0: increase glitch immunity pub mod expr_use_visitor;
pub mod const_val; pub mod const_val;
pub mod const_qualif;
pub mod cstore; pub mod cstore;
pub mod dataflow; pub mod dataflow;
pub mod dead; pub mod dead;

View file

@ -1,44 +0,0 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Const qualification, from partial to completely promotable.
bitflags! {
#[derive(RustcEncodable, RustcDecodable)]
flags ConstQualif: u8 {
// Inner mutability (can not be placed behind a reference) or behind
// &mut in a non-global expression. Can be copied from static memory.
const MUTABLE_MEM = 1 << 0,
// Constant value with a type that implements Drop. Can be copied
// from static memory, similar to MUTABLE_MEM.
const NEEDS_DROP = 1 << 1,
// Even if the value can be placed in static memory, copying it from
// there is more expensive than in-place instantiation, and/or it may
// be too large. This applies to [T; N] and everything containing it.
// N.B.: references need to clear this flag to not end up on the stack.
const PREFER_IN_PLACE = 1 << 2,
// May use more than 0 bytes of memory, doesn't impact the constness
// directly, but is not allowed to be borrowed mutably in a constant.
const NON_ZERO_SIZED = 1 << 3,
// Actually borrowed, has to always be in static memory. Does not
// propagate, and requires the expression to behave like a 'static
// lvalue. The set of expressions with this flag is the minimum
// that have to be promoted.
const HAS_STATIC_BORROWS = 1 << 4,
// Invalid const for miscellaneous reasons (e.g. not implemented).
const NOT_CONST = 1 << 5,
// Borrowing the expression won't produce &'static T if any of these
// bits are set, though the value could be copied from static memory
// if `NOT_CONST` isn't set.
const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
ConstQualif::NEEDS_DROP.bits |
ConstQualif::NOT_CONST.bits
}
}

View file

@ -42,7 +42,6 @@ use syntax::symbol::Symbol;
use syntax_pos::Span; use syntax_pos::Span;
use rustc_back::target::Target; use rustc_back::target::Target;
use hir; use hir;
use hir::intravisit::Visitor;
use rustc_back::PanicStrategy; use rustc_back::PanicStrategy;
pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown}; pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
@ -133,86 +132,6 @@ pub struct NativeLibrary {
pub foreign_items: Vec<DefIndex>, pub foreign_items: Vec<DefIndex>,
} }
/// The data we save and restore about an inlined item or method. This is not
/// 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 struct InlinedItem {
pub def_id: DefId,
pub body: hir::Body,
}
/// A borrowed version of `hir::InlinedItem`. This is what's encoded when saving
/// a crate; it then gets read as an InlinedItem.
#[derive(Clone, PartialEq, Eq, RustcEncodable, Hash, Debug)]
pub struct InlinedItemRef<'a> {
pub def_id: DefId,
pub body: &'a hir::Body,
}
impl<'a, 'tcx> InlinedItemRef<'tcx> {
pub fn from_item(def_id: DefId,
item: &hir::Item,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> InlinedItemRef<'tcx> {
let body_id = match item.node {
hir::ItemFn(.., body_id) |
hir::ItemConst(_, body_id) => body_id,
_ => bug!("InlinedItemRef::from_item wrong kind")
};
InlinedItemRef {
def_id: def_id,
body: tcx.map.body(body_id),
}
}
pub fn from_trait_item(def_id: DefId,
item: &hir::TraitItem,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> InlinedItemRef<'tcx> {
let body_id = match item.node {
hir::TraitItemKind::Const(_, Some(body_id)) => body_id,
hir::TraitItemKind::Const(_, None) => {
bug!("InlinedItemRef::from_trait_item called for const without body")
},
_ => bug!("InlinedItemRef::from_trait_item wrong kind")
};
InlinedItemRef {
def_id: def_id,
body: tcx.map.body(body_id),
}
}
pub fn from_impl_item(def_id: DefId,
item: &hir::ImplItem,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> InlinedItemRef<'tcx> {
let body_id = match item.node {
hir::ImplItemKind::Method(_, body_id) |
hir::ImplItemKind::Const(_, body_id) => body_id,
_ => bug!("InlinedItemRef::from_impl_item wrong kind")
};
InlinedItemRef {
def_id: def_id,
body: tcx.map.body(body_id),
}
}
pub fn visit<V>(&self, visitor: &mut V)
where V: Visitor<'tcx>
{
visitor.visit_body(self.body);
}
}
impl InlinedItem {
pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
where V: Visitor<'ast>
{
visitor.visit_body(&self.body);
}
}
pub enum LoadedMacro { pub enum LoadedMacro {
MacroRules(ast::MacroDef), MacroRules(ast::MacroDef),
ProcMacro(Rc<SyntaxExtension>), ProcMacro(Rc<SyntaxExtension>),
@ -329,10 +248,9 @@ pub trait CrateStore<'tcx> {
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro; fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
// misc. metadata // misc. metadata
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<(&'tcx InlinedItem, ast::NodeId)>; -> Option<&'tcx hir::Body>;
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId>; fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool;
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId>;
fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>; fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>;
fn is_item_mir_available(&self, def: DefId) -> bool; fn is_item_mir_available(&self, def: DefId) -> bool;
@ -499,15 +417,12 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") } fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
// misc. metadata // misc. metadata
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<(&'tcx InlinedItem, ast::NodeId)> { -> Option<&'tcx hir::Body> {
bug!("maybe_get_item_ast") bug!("maybe_get_item_body")
} }
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> { fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
bug!("local_node_for_inlined_defid") bug!("const_is_rvalue_promotable_to_static")
}
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
bug!("defid_for_inlined_node")
} }
fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)

View file

@ -287,7 +287,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
} }
} }
pub fn walk_fn(&mut self, body: &hir::Body) { pub fn consume_body(&mut self, body: &hir::Body) {
for arg in &body.arguments { for arg in &body.arguments {
let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));

View file

@ -73,7 +73,6 @@ use self::Aliasability::*;
use hir::def_id::DefId; use hir::def_id::DefId;
use hir::map as ast_map; use hir::map as ast_map;
use infer::InferCtxt; use infer::InferCtxt;
use middle::const_qualif::ConstQualif;
use hir::def::{Def, CtorKind}; use hir::def::{Def, CtorKind};
use ty::adjustment; use ty::adjustment;
use ty::{self, Ty, TyCtxt}; use ty::{self, Ty, TyCtxt};
@ -773,23 +772,23 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
span: Span, span: Span,
expr_ty: Ty<'tcx>) expr_ty: Ty<'tcx>)
-> cmt<'tcx> { -> cmt<'tcx> {
let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned() let promotable = self.tcx().rvalue_promotable_to_static.borrow().get(&id).cloned()
.unwrap_or(ConstQualif::NOT_CONST); .unwrap_or(false);
// Only promote `[T; 0]` before an RFC for rvalue promotions // Only promote `[T; 0]` before an RFC for rvalue promotions
// is accepted. // is accepted.
let qualif = match expr_ty.sty { let promotable = match expr_ty.sty {
ty::TyArray(_, 0) => qualif, ty::TyArray(_, 0) => true,
_ => ConstQualif::NOT_CONST _ => promotable & false
}; };
// Compute maximum lifetime of this rvalue. This is 'static if // Compute maximum lifetime of this rvalue. This is 'static if
// we can promote to a constant, otherwise equal to enclosing temp // we can promote to a constant, otherwise equal to enclosing temp
// lifetime. // lifetime.
let re = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) { let re = if promotable {
self.temporary_scope(id)
} else {
self.tcx().mk_region(ty::ReStatic) self.tcx().mk_region(ty::ReStatic)
} else {
self.temporary_scope(id)
}; };
let ret = self.cat_rvalue(id, span, re, expr_ty); let ret = self.cat_rvalue(id, span, re, expr_ty);
debug!("cat_rvalue_node ret {:?}", ret); debug!("cat_rvalue_node ret {:?}", ret);

View file

@ -508,14 +508,6 @@ pub struct GlobalCtxt<'tcx> {
/// FIXME(arielb1): why is this separate from populated_external_types? /// FIXME(arielb1): why is this separate from populated_external_types?
pub populated_external_primitive_impls: RefCell<DefIdSet>, pub populated_external_primitive_impls: RefCell<DefIdSet>,
/// Cache used by const_eval when decoding external constants.
/// Contains `None` when the constant has been fetched but doesn't exist.
/// Constains `Some(expr_id, type)` otherwise.
/// `type` is `None` in case it's not a primitive type
pub extern_const_statics: RefCell<DefIdMap<Option<(NodeId, Option<Ty<'tcx>>)>>>,
/// Cache used by const_eval when decoding extern const fns
pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
/// Maps any item's def-id to its stability index. /// Maps any item's def-id to its stability index.
pub stability: RefCell<stability::Index<'tcx>>, pub stability: RefCell<stability::Index<'tcx>>,
@ -537,8 +529,8 @@ pub struct GlobalCtxt<'tcx> {
/// Caches the representation hints for struct definitions. /// Caches the representation hints for struct definitions.
repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>, repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>,
/// Maps Expr NodeId's to their constant qualification. /// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
pub const_qualif_map: RefCell<NodeMap<middle::const_qualif::ConstQualif>>, pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
/// Caches CoerceUnsized kinds for impls on custom types. /// Caches CoerceUnsized kinds for impls on custom types.
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>, pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
@ -787,13 +779,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
used_trait_imports: RefCell::new(NodeSet()), used_trait_imports: RefCell::new(NodeSet()),
populated_external_types: RefCell::new(DefIdSet()), populated_external_types: RefCell::new(DefIdSet()),
populated_external_primitive_impls: RefCell::new(DefIdSet()), populated_external_primitive_impls: RefCell::new(DefIdSet()),
extern_const_statics: RefCell::new(DefIdMap()),
extern_const_fns: RefCell::new(DefIdMap()),
stability: RefCell::new(stability), stability: RefCell::new(stability),
selection_cache: traits::SelectionCache::new(), selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(), evaluation_cache: traits::EvaluationCache::new(),
repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
const_qualif_map: RefCell::new(NodeMap()), rvalue_promotable_to_static: RefCell::new(NodeMap()),
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
cast_kinds: RefCell::new(NodeMap()), cast_kinds: RefCell::new(NodeMap()),
fragment_infos: RefCell::new(DefIdMap()), fragment_infos: RefCell::new(DefIdMap()),

View file

@ -201,7 +201,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
all_loans: all_loans, all_loans: all_loans,
param_env: &infcx.parameter_environment param_env: &infcx.parameter_environment
}; };
euv::ExprUseVisitor::new(&mut clcx, &infcx).walk_fn(body); euv::ExprUseVisitor::new(&mut clcx, &infcx).consume_body(body);
} }
#[derive(PartialEq)] #[derive(PartialEq)]

View file

@ -54,7 +54,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id); let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env); let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
euv::ExprUseVisitor::new(&mut glcx, &infcx).walk_fn(body); euv::ExprUseVisitor::new(&mut glcx, &infcx).consume_body(body);
glcx.report_potential_errors(); glcx.report_potential_errors();
let GatherLoanCtxt { all_loans, move_data, .. } = glcx; let GatherLoanCtxt { all_loans, move_data, .. } = glcx;

View file

@ -17,7 +17,6 @@ use self::EvalHint::*;
use rustc::hir::map as ast_map; use rustc::hir::map as ast_map;
use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::cstore::InlinedItem;
use rustc::traits; use rustc::traits;
use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
@ -139,21 +138,10 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Some(_) => None Some(_) => None
} }
} else { } else {
match tcx.extern_const_statics.borrow().get(&def_id) { let expr_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
Some(&None) => return None, (&body.value, Some(tcx.sess.cstore.item_type(tcx, def_id)))
Some(&Some((expr_id, ty))) => { });
return Some((tcx.map.expect_expr(expr_id), ty)); match tcx.sess.cstore.describe_def(def_id) {
}
None => {}
}
let mut used_substs = false;
let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
Some((&InlinedItem { ref body, .. }, _)) => {
Some((&body.value, Some(tcx.sess.cstore.item_type(tcx, def_id))))
}
_ => None
};
let expr_ty = match tcx.sess.cstore.describe_def(def_id) {
Some(Def::AssociatedConst(_)) => { Some(Def::AssociatedConst(_)) => {
let trait_id = tcx.sess.cstore.trait_of_item(def_id); let trait_id = tcx.sess.cstore.trait_of_item(def_id);
// As mentioned in the comments above for in-crate // As mentioned in the comments above for in-crate
@ -161,8 +149,6 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// trait-associated const if the caller gives us the // trait-associated const if the caller gives us the
// substitutions for the reference to it. // substitutions for the reference to it.
if let Some(trait_id) = trait_id { if let Some(trait_id) = trait_id {
used_substs = true;
if let Some(substs) = substs { if let Some(substs) = substs {
resolve_trait_associated_const(tcx, def_id, expr_ty, trait_id, substs) resolve_trait_associated_const(tcx, def_id, expr_ty, trait_id, substs)
} else { } else {
@ -174,70 +160,27 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}, },
Some(Def::Const(..)) => expr_ty, Some(Def::Const(..)) => expr_ty,
_ => None _ => None
};
// If we used the substitutions, particularly to choose an impl
// of a trait-associated const, don't cache that, because the next
// lookup with the same def_id may yield a different result.
if !used_substs {
tcx.extern_const_statics
.borrow_mut()
.insert(def_id, expr_ty.map(|(e, t)| (e.id, t)));
} }
expr_ty
} }
} }
fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
def_id: DefId) -> Option<&'tcx hir::Body>
-> Option<ast::NodeId> {
match tcx.extern_const_fns.borrow().get(&def_id) {
Some(&ast::DUMMY_NODE_ID) => return None,
Some(&fn_id) => return Some(fn_id),
None => {}
}
if !tcx.sess.cstore.is_const_fn(def_id) {
tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID);
return None;
}
let fn_id = tcx.sess.cstore.maybe_get_item_ast(tcx, def_id).map(|t| t.1);
tcx.extern_const_fns.borrow_mut().insert(def_id,
fn_id.unwrap_or(ast::DUMMY_NODE_ID));
fn_id
}
pub enum ConstFnNode<'tcx> {
Local(FnLikeNode<'tcx>),
Inlined(&'tcx InlinedItem)
}
pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> Option<ConstFnNode<'tcx>>
{ {
let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) { if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
node_id FnLikeNode::from_node(tcx.map.get(node_id)).and_then(|fn_like| {
} else { if fn_like.constness() == hir::Constness::Const {
if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) { Some(tcx.map.body(fn_like.body()))
if let ast_map::NodeInlinedItem(ii) = tcx.map.get(fn_id) {
return Some(ConstFnNode::Inlined(ii));
} else { } else {
bug!("Got const fn from external crate, but it's not inlined") None
} }
} else { })
return None;
}
};
let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) {
Some(fn_like) => fn_like,
None => return None
};
if fn_like.constness() == hir::Constness::Const {
Some(ConstFnNode::Local(fn_like))
} else { } else {
None if tcx.sess.cstore.is_const_fn(def_id) {
tcx.sess.cstore.maybe_get_item_body(tcx, def_id)
} else {
None
}
} }
} }
@ -871,8 +814,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
callee => signal!(e, CallOn(callee)), callee => signal!(e, CallOn(callee)),
}; };
let body = match lookup_const_fn_by_id(tcx, did) { let body = match lookup_const_fn_by_id(tcx, did) {
Some(ConstFnNode::Inlined(ii)) => &ii.body, Some(body) => body,
Some(ConstFnNode::Local(fn_like)) => tcx.map.body(fn_like.body()),
None => signal!(e, NonConstPath), None => signal!(e, NonConstPath),
}; };

View file

@ -16,8 +16,7 @@ use cstore::CrateMetadata;
use encoder::EncodeContext; use encoder::EncodeContext;
use schema::*; use schema::*;
use rustc::middle::cstore::{InlinedItem, InlinedItemRef}; use rustc::hir;
use rustc::middle::const_qualif::ConstQualif;
use rustc::hir::def::Def; use rustc::hir::def::Def;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::ty::{self, TyCtxt, Ty}; use rustc::ty::{self, TyCtxt, Ty};
@ -29,8 +28,9 @@ use rustc_serialize::Encodable;
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
pub struct Ast<'tcx> { pub struct Ast<'tcx> {
id_range: IdRange, id_range: IdRange,
item: Lazy<InlinedItem>, body: Lazy<hir::Body>,
side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)>, side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)>,
pub rvalue_promotable_to_static: bool,
} }
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
@ -39,16 +39,17 @@ enum TableEntry<'tcx> {
NodeType(Ty<'tcx>), NodeType(Ty<'tcx>),
ItemSubsts(ty::ItemSubsts<'tcx>), ItemSubsts(ty::ItemSubsts<'tcx>),
Adjustment(ty::adjustment::Adjustment<'tcx>), Adjustment(ty::adjustment::Adjustment<'tcx>),
ConstQualif(ConstQualif),
} }
impl<'a, 'tcx> EncodeContext<'a, 'tcx> { impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
pub fn encode_inlined_item(&mut self, ii: InlinedItemRef<'tcx>) -> Lazy<Ast<'tcx>> { pub fn encode_body(&mut self, body: hir::BodyId) -> Lazy<Ast<'tcx>> {
let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map); let body = self.tcx.map.body(body);
ii.visit(&mut id_visitor);
let ii_pos = self.position(); let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
ii.encode(self).unwrap(); id_visitor.visit_body(body);
let body_pos = self.position();
body.encode(self).unwrap();
let tables_pos = self.position(); let tables_pos = self.position();
let tables_count = { let tables_count = {
@ -56,14 +57,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
ecx: self, ecx: self,
count: 0, count: 0,
}; };
ii.visit(&mut visitor); visitor.visit_body(body);
visitor.count visitor.count
}; };
let rvalue_promotable_to_static =
self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id];
self.lazy(&Ast { self.lazy(&Ast {
id_range: id_visitor.result(), id_range: id_visitor.result(),
item: Lazy::with_position(ii_pos), body: Lazy::with_position(body_pos),
side_tables: LazySeq::with_position_and_length(tables_pos, tables_count), side_tables: LazySeq::with_position_and_length(tables_pos, tables_count),
rvalue_promotable_to_static: rvalue_promotable_to_static
}) })
} }
} }
@ -94,18 +99,17 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> {
encode(tcx.tables().node_types.get(&id).cloned().map(TableEntry::NodeType)); encode(tcx.tables().node_types.get(&id).cloned().map(TableEntry::NodeType));
encode(tcx.tables().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts)); encode(tcx.tables().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts));
encode(tcx.tables().adjustments.get(&id).cloned().map(TableEntry::Adjustment)); encode(tcx.tables().adjustments.get(&id).cloned().map(TableEntry::Adjustment));
encode(tcx.const_qualif_map.borrow().get(&id).cloned().map(TableEntry::ConstQualif));
} }
} }
/// Decodes an item from its AST in the cdata's metadata and adds it to the /// Decodes an item's body from its AST in the cdata's metadata and adds it to the
/// ast-map. /// ast-map.
pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, pub fn decode_body<'a, 'tcx>(cdata: &CrateMetadata,
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
ast: Ast<'tcx>, def_id: DefId,
orig_did: DefId) ast: Ast<'tcx>)
-> &'tcx InlinedItem { -> &'tcx hir::Body {
debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did)); debug!("> Decoding inlined fn: {}", tcx.item_path_str(def_id));
let cnt = ast.id_range.max.as_usize() - ast.id_range.min.as_usize(); let cnt = ast.id_range.max.as_usize() - ast.id_range.min.as_usize();
let start = tcx.sess.reserve_node_ids(cnt); let start = tcx.sess.reserve_node_ids(cnt);
@ -115,12 +119,6 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
max: ast::NodeId::new(start.as_usize() + cnt), max: ast::NodeId::new(start.as_usize() + cnt),
}]; }];
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,
ii,
item_node_id);
for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) { for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) {
match entry { match entry {
TableEntry::TypeRelativeDef(def) => { TableEntry::TypeRelativeDef(def) => {
@ -135,11 +133,9 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
TableEntry::Adjustment(adj) => { TableEntry::Adjustment(adj) => {
tcx.tables.borrow_mut().adjustments.insert(id, adj); tcx.tables.borrow_mut().adjustments.insert(id, adj);
} }
TableEntry::ConstQualif(qualif) => {
tcx.const_qualif_map.borrow_mut().insert(id, qualif);
}
} }
} }
ii let body = ast.body.decode((cdata, tcx, id_ranges));
ast_map::map_decoded_body(&tcx.map, def_id, body, tcx.sess.next_node_id())
} }

View file

@ -88,13 +88,6 @@ pub struct CrateMetadata {
pub dllimport_foreign_items: FxHashSet<DefIndex>, pub dllimport_foreign_items: FxHashSet<DefIndex>,
} }
pub struct CachedInlinedItem {
/// The NodeId of the RootInlinedParent HIR map entry
pub inlined_root: ast::NodeId,
/// The local NodeId of the inlined entity
pub item_id: ast::NodeId,
}
pub struct CStore { pub struct CStore {
pub dep_graph: DepGraph, pub dep_graph: DepGraph,
metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>, metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
@ -104,8 +97,7 @@ pub struct CStore {
used_link_args: RefCell<Vec<String>>, used_link_args: RefCell<Vec<String>>,
statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>, statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>, pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>, pub inlined_item_cache: RefCell<DefIdMap<Option<ast::NodeId>>>,
pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
pub visible_parent_map: RefCell<DefIdMap<DefId>>, pub visible_parent_map: RefCell<DefIdMap<DefId>>,
} }
@ -121,7 +113,6 @@ impl CStore {
dllimport_foreign_items: RefCell::new(FxHashSet()), dllimport_foreign_items: RefCell::new(FxHashSet()),
visible_parent_map: RefCell::new(FxHashMap()), visible_parent_map: RefCell::new(FxHashMap()),
inlined_item_cache: RefCell::new(FxHashMap()), inlined_item_cache: RefCell::new(FxHashMap()),
defid_for_inlined_node: RefCell::new(FxHashMap()),
} }
} }

View file

@ -13,7 +13,7 @@ use encoder;
use locator; use locator;
use schema; use schema;
use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, LibSource, DepKind, ExternCrate}; use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro}; use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
use rustc::hir::def::{self, Def}; use rustc::hir::def::{self, Def};
use rustc::middle::lang_items; use rustc::middle::lang_items;
@ -427,94 +427,37 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
}) })
} }
fn maybe_get_item_ast<'a>(&'tcx self, fn maybe_get_item_body<'a>(&'tcx self,
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId) def_id: DefId)
-> Option<(&'tcx InlinedItem, ast::NodeId)> -> Option<&'tcx hir::Body>
{ {
self.dep_graph.read(DepNode::MetaData(def_id)); self.dep_graph.read(DepNode::MetaData(def_id));
match self.inlined_item_cache.borrow().get(&def_id) { if let Some(&cached) = self.inlined_item_cache.borrow().get(&def_id) {
Some(&None) => { return cached.map(|root_id| {
return None; // Not inlinable
}
Some(&Some(ref cached_inlined_item)) => {
// Already inline // Already inline
debug!("maybe_get_item_ast({}): already inline as node id {}", debug!("maybe_get_item_body({}): already inline", tcx.item_path_str(def_id));
tcx.item_path_str(def_id), cached_inlined_item.item_id); tcx.map.expect_inlined_body(root_id)
return Some((tcx.map.expect_inlined_item(cached_inlined_item.inlined_root), });
cached_inlined_item.item_id));
}
None => {
// Not seen yet
}
} }
debug!("maybe_get_item_ast({}): inlining item", tcx.item_path_str(def_id)); debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id));
let inlined = self.get_crate_data(def_id.krate).maybe_get_item_ast(tcx, def_id.index); let inlined = self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index);
let cache_inlined_item = |original_def_id, inlined_item_id, inlined_root_node_id| { self.inlined_item_cache.borrow_mut().insert(def_id, inlined.map(|body| {
let cache_entry = cstore::CachedInlinedItem { let root_id = tcx.map.get_parent_node(body.value.id);
inlined_root: inlined_root_node_id, assert_eq!(tcx.map.get_parent_node(root_id), root_id);
item_id: inlined_item_id, root_id
}; }));
self.inlined_item_cache
.borrow_mut()
.insert(original_def_id, Some(cache_entry));
self.defid_for_inlined_node
.borrow_mut()
.insert(inlined_item_id, original_def_id);
};
let find_inlined_item_root = |inlined_item_id| { inlined
let mut node = inlined_item_id;
// 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 {
let parent_node = tcx.map.get_parent_node(node);
if parent_node == node {
return node;
}
node = parent_node;
}
bug!("cycle in HIR map parent chain")
};
match inlined {
None => {
self.inlined_item_cache
.borrow_mut()
.insert(def_id, None);
}
Some(&InlinedItem { ref body, .. }) => {
let inlined_root_node_id = find_inlined_item_root(body.value.id);
cache_inlined_item(def_id, inlined_root_node_id, inlined_root_node_id);
}
}
// We can be sure to hit the cache now
return self.maybe_get_item_ast(tcx, def_id);
} }
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> { fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
assert!(!def_id.is_local()); self.dep_graph.read(DepNode::MetaData(def));
match self.inlined_item_cache.borrow().get(&def_id) { self.get_crate_data(def.krate).const_is_rvalue_promotable_to_static(def.index)
Some(&Some(ref cached_inlined_item)) => {
Some(cached_inlined_item.item_id)
}
Some(&None) => {
None
}
_ => {
bug!("Trying to lookup inlined NodeId for unexpected item");
}
}
}
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
self.defid_for_inlined_node.borrow().get(&node_id).map(|x| *x)
} }
fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx> { fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx> {

View file

@ -10,7 +10,7 @@
// Decoding metadata from a single crate's metadata // Decoding metadata from a single crate's metadata
use astencode::decode_inlined_item; use astencode::decode_body;
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary}; use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
use schema::*; use schema::*;
@ -18,7 +18,7 @@ use rustc::hir::map::{DefKey, DefPath, DefPathData};
use rustc::hir; use rustc::hir;
use rustc::hir::intravisit::IdRange; use rustc::hir::intravisit::IdRange;
use rustc::middle::cstore::{InlinedItem, LinkagePreference}; use rustc::middle::cstore::LinkagePreference;
use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::middle::lang_items; use rustc::middle::lang_items;
@ -819,20 +819,21 @@ impl<'a, 'tcx> CrateMetadata {
} }
} }
pub fn maybe_get_item_ast(&self, pub fn maybe_get_item_body(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
id: DefIndex) id: DefIndex)
-> Option<&'tcx InlinedItem> { -> Option<&'tcx hir::Body> {
debug!("Looking up item: {:?}", id);
if self.is_proc_macro(id) { return None; } if self.is_proc_macro(id) { return None; }
let item_doc = self.entry(id); self.entry(id).ast.map(|ast| {
let item_did = self.local_def_id(id); decode_body(self, tcx, self.local_def_id(id), ast.decode(self))
item_doc.ast.map(|ast| {
let ast = ast.decode(self);
decode_inlined_item(self, tcx, ast, item_did)
}) })
} }
pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool {
self.entry(id).ast.expect("const item missing `ast`")
.decode(self).rvalue_promotable_to_static
}
pub fn is_item_mir_available(&self, id: DefIndex) -> bool { pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
!self.is_proc_macro(id) && !self.is_proc_macro(id) &&
self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some() self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()

View file

@ -12,8 +12,7 @@ use cstore;
use index::Index; use index::Index;
use schema::*; use schema::*;
use rustc::middle::cstore::{InlinedItemRef, LinkMeta}; use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary};
use rustc::middle::cstore::{LinkagePreference, NativeLibrary};
use rustc::hir::def; use rustc::hir::def;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
use rustc::hir::map::definitions::DefPathTable; use rustc::hir::map::definitions::DefPathTable;
@ -495,13 +494,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
generics: Some(self.encode_generics(def_id)), generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)), predicates: Some(self.encode_predicates(def_id)),
ast: if let hir::TraitItemKind::Const(_, Some(_)) = ast_item.node { ast: if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node {
// We only save the HIR for associated consts with bodies Some(self.encode_body(body))
// (InlinedItemRef::from_trait_item panics otherwise)
let trait_def_id = trait_item.container.id();
Some(self.encode_inlined_item(
InlinedItemRef::from_trait_item(trait_def_id, ast_item, tcx)
))
} else { } else {
None None
}, },
@ -510,12 +504,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'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 node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
let ast_item = self.tcx.map.expect_impl_item(node_id); let ast_item = self.tcx.map.expect_impl_item(node_id);
let impl_item = self.tcx.associated_item(def_id); let impl_item = self.tcx.associated_item(def_id);
let impl_def_id = impl_item.container.id();
let container = match impl_item.defaultness { let container = match impl_item.defaultness {
hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault, hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault,
@ -544,17 +535,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
ty::AssociatedKind::Type => EntryKind::AssociatedType(container) ty::AssociatedKind::Type => EntryKind::AssociatedType(container)
}; };
let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const { let (ast, mir) = if let hir::ImplItemKind::Const(_, body) = ast_item.node {
(true, true) (Some(body), true)
} else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { } else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
let generics = self.tcx.item_generics(def_id); let generics = self.tcx.item_generics(def_id);
let types = generics.parent_types as usize + generics.types.len(); let types = generics.parent_types as usize + generics.types.len();
let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs); let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs);
let is_const_fn = sig.constness == hir::Constness::Const; let is_const_fn = sig.constness == hir::Constness::Const;
let ast = if is_const_fn { Some(body) } else { None };
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
(is_const_fn, needs_inline || is_const_fn || always_encode_mir) (ast, needs_inline || is_const_fn || always_encode_mir)
} else { } else {
(false, false) (None, false)
}; };
Entry { Entry {
@ -572,13 +564,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
generics: Some(self.encode_generics(def_id)), generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)), predicates: Some(self.encode_predicates(def_id)),
ast: if ast { ast: ast.map(|body| self.encode_body(body)),
Some(self.encode_inlined_item(
InlinedItemRef::from_impl_item(impl_def_id, ast_item, tcx)
))
} else {
None
},
mir: if mir { self.encode_mir(def_id) } else { None }, mir: if mir { self.encode_mir(def_id) } else { None },
} }
} }
@ -809,11 +795,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}, },
ast: match item.node { ast: match item.node {
hir::ItemConst(..) | hir::ItemConst(_, body) |
hir::ItemFn(_, _, hir::Constness::Const, ..) => { hir::ItemFn(_, _, hir::Constness::Const, _, _, body) => {
Some(self.encode_inlined_item( Some(self.encode_body(body))
InlinedItemRef::from_item(def_id, item, tcx)
))
} }
_ => None, _ => None,
}, },

View file

@ -26,8 +26,8 @@
use rustc::dep_graph::DepNode; use rustc::dep_graph::DepNode;
use rustc::ty::cast::CastKind; use rustc::ty::cast::CastKind;
use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs}; use rustc_const_eval::{ConstEvalErr, compare_lit_exprs};
use rustc_const_eval::{ConstFnNode, eval_const_expr_partial, lookup_const_by_id}; use rustc_const_eval::{eval_const_expr_partial};
use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math}; use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath}; use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
use rustc_const_eval::ErrKind::UnresolvedPath; use rustc_const_eval::ErrKind::UnresolvedPath;
@ -35,85 +35,36 @@ use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_math::{ConstMathErr, Op}; use rustc_const_math::{ConstMathErr, Op};
use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::expr_use_visitor as euv; use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization; use rustc::middle::mem_categorization::Categorization;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::Reveal; use rustc::traits::Reveal;
use rustc::util::common::ErrorReported; use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap; use rustc::util::nodemap::NodeSet;
use rustc::middle::const_qualif::ConstQualif;
use rustc::lint::builtin::CONST_ERR; use rustc::lint::builtin::CONST_ERR;
use rustc::hir::{self, PatKind}; use rustc::hir::{self, PatKind};
use syntax::ast; use syntax::ast;
use syntax_pos::Span; use syntax_pos::Span;
use rustc::hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::mem;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum Mode {
Const,
ConstFn,
Static,
StaticMut,
// An expression that occurs outside of any constant context
// (i.e. `const`, `static`, array lengths, etc.). The value
// can be variable at runtime, but will be promotable to
// static memory if we can prove it is actually constant.
Var,
}
struct CheckCrateVisitor<'a, 'tcx: 'a> { struct CheckCrateVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
mode: Mode, in_fn: bool,
qualif: ConstQualif, promotable: bool,
rvalue_borrows: NodeMap<hir::Mutability>, mut_rvalue_borrows: NodeSet,
param_env: ty::ParameterEnvironment<'tcx>,
} }
impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R fn check_const_eval(&self, expr: &'gcx hir::Expr) {
where F: FnOnce(&mut CheckCrateVisitor<'a, 'gcx>) -> R
{
let (old_mode, old_qualif) = (self.mode, self.qualif);
self.mode = mode;
self.qualif = ConstQualif::empty();
let r = f(self);
self.mode = old_mode;
self.qualif = old_qualif;
r
}
fn with_euv<F, R>(&mut self, item_id: Option<ast::NodeId>, f: F) -> R
where F: for<'b, 'tcx> FnOnce(&mut euv::ExprUseVisitor<'b, 'gcx, 'tcx>) -> R
{
let param_env = match item_id {
Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
None => self.tcx.empty_parameter_environment(),
};
self.tcx
.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable)
.enter(|infcx| f(&mut euv::ExprUseVisitor::new(self, &infcx)))
}
fn global_body(&mut self, mode: Mode, body: hir::BodyId) -> ConstQualif {
let expr = &self.tcx.map.body(body).value;
self.global_expr(mode, expr)
}
fn global_expr(&mut self, mode: Mode, expr: &'gcx hir::Expr) -> ConstQualif {
assert!(mode != Mode::Var);
match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
Entry::Occupied(entry) => return *entry.get(),
Entry::Vacant(entry) => {
// Prevent infinite recursion on re-entry.
entry.insert(ConstQualif::empty());
}
}
if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) { if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) {
match err.kind { match err.kind {
UnimplementedConstVal(_) => {} UnimplementedConstVal(_) => {}
@ -129,184 +80,78 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
} }
} }
} }
self.with_mode(mode, |this| {
this.with_euv(None, |euv| euv.consume_expr(expr));
this.visit_expr(expr);
this.qualif
})
} }
fn fn_like(&mut self, // Adds the worst effect out of all the values of one type.
fk: FnKind<'gcx>, fn add_type(&mut self, ty: Ty<'gcx>) {
fd: &'gcx hir::FnDecl, if ty.type_contents(self.tcx).interior_unsafe() {
b: hir::BodyId, self.promotable = false;
s: Span,
fn_id: ast::NodeId)
-> ConstQualif {
match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
Entry::Occupied(entry) => return *entry.get(),
Entry::Vacant(entry) => {
// Prevent infinite recursion on re-entry.
entry.insert(ConstQualif::empty());
}
} }
let mode = match fk { if self.tcx.type_needs_drop_given_env(ty, &self.param_env) {
FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) self.promotable = false;
=> Mode::ConstFn, }
FnKind::Method(_, m, ..) => { }
if m.constness == hir::Constness::Const {
Mode::ConstFn fn handle_const_fn_call(&mut self, def_id: DefId, ret_ty: Ty<'gcx>) {
} else { self.add_type(ret_ty);
Mode::Var
} self.promotable &= if let Some(fn_id) = self.tcx.map.as_local_node_id(def_id) {
} FnLikeNode::from_node(self.tcx.map.get(fn_id)).map_or(false, |fn_like| {
_ => Mode::Var, fn_like.constness() == hir::Constness::Const
})
} else {
self.tcx.sess.cstore.is_const_fn(def_id)
}; };
let qualif = self.with_mode(mode, |this| {
let body = this.tcx.map.body(b);
this.with_euv(Some(fn_id), |euv| euv.walk_fn(body));
intravisit::walk_fn(this, fk, fd, b, s, fn_id);
this.qualif
});
// Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
// and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
qualif
}
fn add_qualif(&mut self, qualif: ConstQualif) {
self.qualif = self.qualif | qualif;
}
/// 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 {
match lookup_const_fn_by_id(self.tcx, def_id) {
Some(ConstFnNode::Local(fn_like)) => {
let qualif = 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() {
self.add_qualif(ConstQualif::MUTABLE_MEM);
}
true
},
Some(ConstFnNode::Inlined(ii)) => {
let node_id = ii.body.value.id;
let qualif = match self.tcx.const_qualif_map.borrow_mut().entry(node_id) {
Entry::Occupied(entry) => *entry.get(),
_ => bug!("const qualif entry missing for inlined item")
};
self.add_qualif(qualif);
if ret_ty.type_contents(self.tcx).interior_unsafe() {
self.add_qualif(ConstQualif::MUTABLE_MEM);
}
true
},
None => false
}
}
fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
match self.rvalue_borrows.entry(id) {
Entry::Occupied(mut entry) => {
// Merge the two borrows, taking the most demanding
// one, mutability-wise.
if mutbl == hir::MutMutable {
entry.insert(mutbl);
}
}
Entry::Vacant(entry) => {
entry.insert(mutbl);
}
}
} }
} }
impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::OnlyBodies(&self.tcx.map) NestedVisitorMap::None
} }
fn visit_item(&mut self, i: &'tcx hir::Item) { fn visit_nested_body(&mut self, body: hir::BodyId) {
debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id)); match self.tcx.rvalue_promotable_to_static.borrow_mut().entry(body.node_id) {
assert_eq!(self.mode, Mode::Var); Entry::Occupied(_) => return,
match i.node { Entry::Vacant(entry) => {
hir::ItemStatic(_, hir::MutImmutable, expr) => { // Prevent infinite recursion on re-entry.
self.global_body(Mode::Static, expr); entry.insert(false);
}
hir::ItemStatic(_, hir::MutMutable, expr) => {
self.global_body(Mode::StaticMut, expr);
}
hir::ItemConst(_, expr) => {
self.global_body(Mode::Const, expr);
}
hir::ItemEnum(ref enum_definition, _) => {
for var in &enum_definition.variants {
if let Some(ex) = var.node.disr_expr {
self.global_body(Mode::Const, ex);
}
}
}
_ => {
intravisit::walk_item(self, i);
} }
} }
}
fn visit_trait_item(&mut self, t: &'tcx hir::TraitItem) { let item_id = self.tcx.map.body_owner(body);
match t.node {
hir::TraitItemKind::Const(_, default) => { let outer_in_fn = self.in_fn;
if let Some(expr) = default { self.in_fn = match MirSource::from_node(self.tcx, item_id) {
self.global_body(Mode::Const, expr); MirSource::Fn(_) => true,
} else { _ => false
intravisit::walk_trait_item(self, t); };
}
} let body = self.tcx.map.body(body);
_ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)), if !self.in_fn {
self.check_const_eval(&body.value);
} }
}
fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) { let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
match i.node { let outer_param_env = mem::replace(&mut self.param_env, param_env);
hir::ImplItemKind::Const(_, expr) => { self.tcx.infer_ctxt(None, Some(self.param_env.clone()), Reveal::NotSpecializable)
self.global_body(Mode::Const, expr); .enter(|infcx| euv::ExprUseVisitor::new(self, &infcx).consume_body(body));
}
_ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
}
}
fn visit_fn(&mut self, self.visit_body(body);
fk: FnKind<'tcx>,
fd: &'tcx hir::FnDecl, self.param_env = outer_param_env;
b: hir::BodyId, self.in_fn = outer_in_fn;
s: Span,
fn_id: ast::NodeId) {
self.fn_like(fk, fd, b, s, fn_id);
} }
fn visit_pat(&mut self, p: &'tcx hir::Pat) { fn visit_pat(&mut self, p: &'tcx hir::Pat) {
match p.node { match p.node {
PatKind::Lit(ref lit) => { PatKind::Lit(ref lit) => {
self.global_expr(Mode::Const, &lit); self.check_const_eval(lit);
} }
PatKind::Range(ref start, ref end) => { PatKind::Range(ref start, ref end) => {
self.global_expr(Mode::Const, &start); self.check_const_eval(start);
self.global_expr(Mode::Const, &end); self.check_const_eval(end);
match compare_lit_exprs(self.tcx, p.span, start, end) { match compare_lit_exprs(self.tcx, p.span, start, end) {
Ok(Ordering::Less) | Ok(Ordering::Less) |
@ -320,119 +165,60 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
Err(ErrorReported) => {} Err(ErrorReported) => {}
} }
} }
_ => intravisit::walk_pat(self, p), _ => {}
} }
intravisit::walk_pat(self, p);
} }
fn visit_block(&mut self, block: &'tcx hir::Block) { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
// Check all statements in the block match stmt.node {
for stmt in &block.stmts { hir::StmtDecl(ref decl, _) => {
match stmt.node { match decl.node {
hir::StmtDecl(ref decl, _) => { hir::DeclLocal(_) => {
match decl.node { self.promotable = false;
hir::DeclLocal(_) => {}
// Item statements are allowed
hir::DeclItem(_) => continue,
} }
// Item statements are allowed
hir::DeclItem(_) => {}
} }
hir::StmtExpr(..) => {}
hir::StmtSemi(..) => {}
} }
self.add_qualif(ConstQualif::NOT_CONST); hir::StmtExpr(..) |
hir::StmtSemi(..) => {
self.promotable = false;
}
} }
intravisit::walk_block(self, block); intravisit::walk_stmt(self, stmt);
} }
fn visit_expr(&mut self, ex: &'tcx hir::Expr) { fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
let mut outer = self.qualif; let outer = self.promotable;
self.qualif = ConstQualif::empty(); self.promotable = true;
let node_ty = self.tcx.tables().node_id_to_type(ex.id); let node_ty = self.tcx.tables().node_id_to_type(ex.id);
check_expr(self, ex, node_ty); check_expr(self, ex, node_ty);
check_adjustments(self, ex); check_adjustments(self, ex);
// Special-case some expressions to avoid certain flags bubbling up. if let hir::ExprMatch(ref discr, ref arms, _) = ex.node {
match ex.node { // Compute the most demanding borrow from all the arms'
hir::ExprCall(ref callee, ref args) => { // patterns and set that on the discriminator.
for arg in args { let mut mut_borrow = false;
self.visit_expr(&arg) for pat in arms.iter().flat_map(|arm| &arm.pats) {
} if self.mut_rvalue_borrows.remove(&pat.id) {
mut_borrow = true;
let inner = self.qualif;
self.visit_expr(&callee);
// The callee's size doesn't count in the call.
let added = self.qualif - inner;
self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
}
hir::ExprRepeat(ref element, _) => {
self.visit_expr(&element);
// The count is checked elsewhere (typeck).
let count = match node_ty.sty {
ty::TyArray(_, n) => n,
_ => bug!(),
};
// [element; 0] is always zero-sized.
if count == 0 {
self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
} }
} }
hir::ExprMatch(ref discr, ref arms, _) => { if mut_borrow {
// Compute the most demanding borrow from all the arms' self.mut_rvalue_borrows.insert(discr.id);
// patterns and set that on the discriminator.
let mut borrow = None;
for pat in arms.iter().flat_map(|arm| &arm.pats) {
let pat_borrow = self.rvalue_borrows.remove(&pat.id);
match (borrow, pat_borrow) {
(None, _) |
(_, Some(hir::MutMutable)) => {
borrow = pat_borrow;
}
_ => {}
}
}
if let Some(mutbl) = borrow {
self.record_borrow(discr.id, mutbl);
}
intravisit::walk_expr(self, ex);
} }
_ => intravisit::walk_expr(self, ex),
} }
intravisit::walk_expr(self, ex);
// Handle borrows on (or inside the autorefs of) this expression. // Handle borrows on (or inside the autorefs of) this expression.
match self.rvalue_borrows.remove(&ex.id) { if self.mut_rvalue_borrows.remove(&ex.id) {
Some(hir::MutImmutable) => { self.promotable = false;
// Constants cannot be borrowed if they contain interior mutability as
// it means that our "silent insertion of statics" could change
// initializer values (very bad).
// If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
// propagated from another error, so erroring again would be just noise.
let tc = node_ty.type_contents(self.tcx);
if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
outer = outer | ConstQualif::NOT_CONST;
}
// If the reference has to be 'static, avoid in-place initialization
// as that will end up pointing to the stack instead.
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
}
}
Some(hir::MutMutable) => {
// `&mut expr` means expr could be mutated, unless it's zero-sized.
if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
if self.mode == Mode::Var {
outer = outer | ConstQualif::NOT_CONST;
self.add_qualif(ConstQualif::MUTABLE_MEM);
}
}
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
}
}
None => {}
} }
if self.mode == Mode::Var && !self.qualif.intersects(ConstQualif::NOT_CONST) { if self.in_fn && self.promotable {
match eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) { match eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) {
Ok(_) => {} Ok(_) => {}
Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) | Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
@ -453,9 +239,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
} }
} }
self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif); self.tcx.rvalue_promotable_to_static.borrow_mut().insert(ex.id, self.promotable);
// Don't propagate certain flags. self.promotable &= outer;
self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
} }
} }
@ -468,7 +253,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) { fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
match node_ty.sty { match node_ty.sty {
ty::TyAdt(def, _) if def.has_dtor() => { ty::TyAdt(def, _) if def.has_dtor() => {
v.add_qualif(ConstQualif::NEEDS_DROP); v.promotable = false;
} }
_ => {} _ => {}
} }
@ -478,17 +263,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
hir::ExprUnary(..) | hir::ExprUnary(..) |
hir::ExprBinary(..) | hir::ExprBinary(..) |
hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => { hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => {
v.add_qualif(ConstQualif::NOT_CONST); v.promotable = false;
} }
hir::ExprBox(_) => { hir::ExprBox(_) => {
v.add_qualif(ConstQualif::NOT_CONST); v.promotable = false;
} }
hir::ExprUnary(op, ref inner) => { hir::ExprUnary(op, ref inner) => {
match v.tcx.tables().node_id_to_type(inner.id).sty { match v.tcx.tables().node_id_to_type(inner.id).sty {
ty::TyRawPtr(_) => { ty::TyRawPtr(_) => {
assert!(op == hir::UnDeref); assert!(op == hir::UnDeref);
v.add_qualif(ConstQualif::NOT_CONST); v.promotable = false;
} }
_ => {} _ => {}
} }
@ -500,7 +285,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
op.node == hir::BiLe || op.node == hir::BiLt || op.node == hir::BiLe || op.node == hir::BiLt ||
op.node == hir::BiGe || op.node == hir::BiGt); op.node == hir::BiGe || op.node == hir::BiGt);
v.add_qualif(ConstQualif::NOT_CONST); v.promotable = false;
} }
_ => {} _ => {}
} }
@ -510,7 +295,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
match v.tcx.cast_kinds.borrow().get(&from.id) { match v.tcx.cast_kinds.borrow().get(&from.id) {
None => span_bug!(e.span, "no kind for cast"), None => span_bug!(e.span, "no kind for cast"),
Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => { Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
v.add_qualif(ConstQualif::NOT_CONST); v.promotable = false;
} }
_ => {} _ => {}
} }
@ -518,33 +303,24 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
hir::ExprPath(ref qpath) => { hir::ExprPath(ref qpath) => {
let def = v.tcx.tables().qpath_def(qpath, e.id); let def = v.tcx.tables().qpath_def(qpath, e.id);
match def { match def {
Def::VariantCtor(_, CtorKind::Const) => {
// Size is determined by the whole enum, may be non-zero.
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
Def::VariantCtor(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::StructCtor(..) |
Def::Fn(..) | Def::Method(..) => {} Def::Fn(..) | Def::Method(..) => {}
Def::Static(..) => { Def::AssociatedConst(_) => v.add_type(node_ty),
match v.mode { Def::Const(did) => {
Mode::Static | Mode::StaticMut => {} v.promotable &= if let Some(node_id) = v.tcx.map.as_local_node_id(did) {
Mode::Const | Mode::ConstFn => {} match v.tcx.map.expect_item(node_id).node {
Mode::Var => v.add_qualif(ConstQualif::NOT_CONST) hir::ItemConst(_, body) => {
} v.visit_nested_body(body);
} v.tcx.rvalue_promotable_to_static.borrow()[&body.node_id]
Def::Const(did) | Def::AssociatedConst(did) => { }
let substs = Some(v.tcx.tables().node_id_item_substs(e.id) _ => false
.unwrap_or_else(|| v.tcx.intern_substs(&[]))); }
if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) { } else {
let inner = v.global_expr(Mode::Const, expr); v.tcx.sess.cstore.const_is_rvalue_promotable_to_static(did)
v.add_qualif(inner); };
}
}
Def::Local(..) if v.mode == Mode::ConstFn => {
// Sadly, we can't determine whether the types are zero-sized.
v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
} }
_ => { _ => {
v.add_qualif(ConstQualif::NOT_CONST); v.promotable = false;
} }
} }
} }
@ -565,65 +341,48 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
} else { } else {
Def::Err Def::Err
}; };
let is_const = match def { match def {
Def::StructCtor(_, CtorKind::Fn) | Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) => { Def::VariantCtor(_, CtorKind::Fn) => {}
// `NON_ZERO_SIZED` is about the call result, not about the ctor itself.
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
true
}
Def::Fn(did) => { Def::Fn(did) => {
v.handle_const_fn_call(e, did, node_ty) v.handle_const_fn_call(did, node_ty)
} }
Def::Method(did) => { Def::Method(did) => {
match v.tcx.associated_item(did).container { match v.tcx.associated_item(did).container {
ty::ImplContainer(_) => { ty::ImplContainer(_) => {
v.handle_const_fn_call(e, did, node_ty) v.handle_const_fn_call(did, node_ty)
} }
ty::TraitContainer(_) => false ty::TraitContainer(_) => v.promotable = false
} }
} }
_ => false _ => v.promotable = false
};
if !is_const {
v.add_qualif(ConstQualif::NOT_CONST);
} }
} }
hir::ExprMethodCall(..) => { hir::ExprMethodCall(..) => {
let method = v.tcx.tables().method_map[&method_call]; let method = v.tcx.tables().method_map[&method_call];
let is_const = match v.tcx.associated_item(method.def_id).container { match v.tcx.associated_item(method.def_id).container {
ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty), ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty),
ty::TraitContainer(_) => false ty::TraitContainer(_) => v.promotable = false
};
if !is_const {
v.add_qualif(ConstQualif::NOT_CONST);
} }
} }
hir::ExprStruct(..) => { hir::ExprStruct(..) => {
if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty { if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty {
// unsafe_cell_type doesn't necessarily exist with no_core // unsafe_cell_type doesn't necessarily exist with no_core
if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() { if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
v.add_qualif(ConstQualif::MUTABLE_MEM); v.promotable = false;
} }
} }
} }
hir::ExprLit(_) | hir::ExprLit(_) |
hir::ExprAddrOf(..) => { hir::ExprAddrOf(..) |
v.add_qualif(ConstQualif::NON_ZERO_SIZED); hir::ExprRepeat(..) => {}
}
hir::ExprRepeat(..) => {
v.add_qualif(ConstQualif::PREFER_IN_PLACE);
}
hir::ExprClosure(..) => { hir::ExprClosure(..) => {
// Paths in constant contexts cannot refer to local variables, // Paths in constant contexts cannot refer to local variables,
// as there are none, and thus closures can't have upvars there. // as there are none, and thus closures can't have upvars there.
if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) { if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
assert!(v.mode == Mode::Var, v.promotable = false;
"global closures can't capture anything");
v.add_qualif(ConstQualif::NOT_CONST);
} }
} }
@ -652,7 +411,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
hir::ExprAssign(..) | hir::ExprAssign(..) |
hir::ExprAssignOp(..) | hir::ExprAssignOp(..) |
hir::ExprInlineAsm(..) => { hir::ExprInlineAsm(..) => {
v.add_qualif(ConstQualif::NOT_CONST); v.promotable = false;
} }
} }
} }
@ -671,7 +430,7 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
Some(Adjust::DerefRef { autoderefs, .. }) => { Some(Adjust::DerefRef { autoderefs, .. }) => {
if (0..autoderefs as u32) if (0..autoderefs as u32)
.any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) { .any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) {
v.add_qualif(ConstQualif::NOT_CONST); v.promotable = false;
} }
} }
} }
@ -681,9 +440,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.visit_all_item_likes_in_krate(DepNode::CheckConst, tcx.visit_all_item_likes_in_krate(DepNode::CheckConst,
&mut CheckCrateVisitor { &mut CheckCrateVisitor {
tcx: tcx, tcx: tcx,
mode: Mode::Var, in_fn: false,
qualif: ConstQualif::NOT_CONST, promotable: false,
rvalue_borrows: NodeMap(), mut_rvalue_borrows: NodeSet(),
param_env: tcx.empty_parameter_environment(),
}.as_deep_visitor()); }.as_deep_visitor());
tcx.sess.abort_if_errors(); tcx.sess.abort_if_errors();
} }
@ -692,24 +452,9 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
fn consume(&mut self, fn consume(&mut self,
_consume_id: ast::NodeId, _consume_id: ast::NodeId,
_consume_span: Span, _consume_span: Span,
cmt: mc::cmt, _cmt: mc::cmt,
_mode: euv::ConsumeMode) { _mode: euv::ConsumeMode) {}
let mut cur = &cmt;
loop {
match cur.cat {
Categorization::StaticItem => {
break;
}
Categorization::Deref(ref cmt, ..) |
Categorization::Downcast(ref cmt, _) |
Categorization::Interior(ref cmt, _) => cur = cmt,
Categorization::Rvalue(..) |
Categorization::Upvar(..) |
Categorization::Local(..) => break,
}
}
}
fn borrow(&mut self, fn borrow(&mut self,
borrow_id: ast::NodeId, borrow_id: ast::NodeId,
_borrow_span: Span, _borrow_span: Span,
@ -736,21 +481,9 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
// Ignore the dummy immutable borrow created by EUV. // Ignore the dummy immutable borrow created by EUV.
break; break;
} }
let mutbl = bk.to_mutbl_lossy(); if bk.to_mutbl_lossy() == hir::MutMutable {
if mutbl == hir::MutMutable && self.mode == Mode::StaticMut { self.mut_rvalue_borrows.insert(borrow_id);
// Mutable slices are the only `&mut` allowed in
// globals, but only in `static mut`, nowhere else.
// FIXME: This exception is really weird... there isn't
// any fundamental reason to restrict this based on
// type of the expression. `&mut [1]` has exactly the
// same representation as &mut 1.
match cmt.ty.sty {
ty::TyArray(..) |
ty::TySlice(_) => break,
_ => {}
}
} }
self.record_borrow(borrow_id, mutbl);
break; break;
} }
Categorization::StaticItem => { Categorization::StaticItem => {

View file

@ -52,7 +52,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
}; };
let body = infcx.tcx.map.body(b); let body = infcx.tcx.map.body(b);
let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx); let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
euv.walk_fn(body); euv.consume_body(body);
}); });
intravisit::walk_fn(self, fk, fd, b, s, fn_id) intravisit::walk_fn(self, fk, fd, b, s, fn_id)
} }

View file

@ -202,8 +202,6 @@ use rustc::mir::{self, Location};
use rustc::mir::visit as mir_visit; use rustc::mir::visit as mir_visit;
use rustc::mir::visit::Visitor as MirVisitor; use rustc::mir::visit::Visitor as MirVisitor;
use rustc_const_eval as const_eval;
use syntax::abi::Abi; use syntax::abi::Abi;
use syntax_pos::DUMMY_SP; use syntax_pos::DUMMY_SP;
use base::custom_coerce_unsize_info; use base::custom_coerce_unsize_info;
@ -344,19 +342,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
recursion_depth_reset = None; recursion_depth_reset = None;
// Scan the MIR in order to find function calls, closures, and collect_neighbours(scx, Instance::mono(scx, def_id), &mut neighbors);
// drop-glue
let mir = scx.tcx().item_mir(def_id);
let empty_substs = scx.empty_substs_for_def_id(def_id);
let visitor = MirNeighborCollector {
scx: scx,
mir: &mir,
output: &mut neighbors,
param_substs: empty_substs
};
visit_mir_and_promoted(visitor, &mir);
} }
TransItem::Fn(instance) => { TransItem::Fn(instance) => {
// Keep track of the monomorphization recursion depth // Keep track of the monomorphization recursion depth
@ -365,18 +351,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
recursion_depths)); recursion_depths));
check_type_length_limit(scx.tcx(), instance); check_type_length_limit(scx.tcx(), instance);
// Scan the MIR in order to find function calls, closures, and collect_neighbours(scx, instance, &mut neighbors);
// drop-glue
let mir = scx.tcx().item_mir(instance.def);
let visitor = MirNeighborCollector {
scx: scx,
mir: &mir,
output: &mut neighbors,
param_substs: instance.substs
};
visit_mir_and_promoted(visitor, &mir);
} }
} }
@ -563,33 +538,12 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
// This is not a callee, but we still have to look for // This is not a callee, but we still have to look for
// references to `const` items // references to `const` items
if let mir::Literal::Item { def_id, substs } = constant.literal { if let mir::Literal::Item { def_id, substs } = constant.literal {
let tcx = self.scx.tcx();
let substs = monomorphize::apply_param_substs(self.scx, let substs = monomorphize::apply_param_substs(self.scx,
self.param_substs, self.param_substs,
&substs); &substs);
// If the constant referred to here is an associated let instance = Instance::new(def_id, substs).resolve_const(self.scx);
// item of a trait, we need to resolve it to the actual collect_neighbours(self.scx, instance, self.output);
// constant in the corresponding impl. Luckily
// const_eval::lookup_const_by_id() does that for us.
if let Some((expr, _)) = const_eval::lookup_const_by_id(tcx,
def_id,
Some(substs)) {
// The hir::Expr we get here is the initializer of
// the constant, what we really want is the item
// DefId.
let const_node_id = tcx.map.get_parent(expr.id);
let def_id = if tcx.map.is_inlined_node_id(const_node_id) {
tcx.sess.cstore.defid_for_inlined_node(const_node_id).unwrap()
} else {
tcx.map.local_def_id(const_node_id)
};
collect_const_item_neighbours(self.scx,
def_id,
substs,
self.output);
}
} }
None None
@ -1233,29 +1187,20 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
} }
} }
// There are no translation items for constants themselves but their /// Scan the MIR in order to find function calls, closures, and drop-glue
// initializers might still contain something that produces translation items, fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
// such as cast that introduce a new vtable. instance: Instance<'tcx>,
fn collect_const_item_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, output: &mut Vec<TransItem<'tcx>>)
def_id: DefId,
substs: &'tcx Substs<'tcx>,
output: &mut Vec<TransItem<'tcx>>)
{ {
// Scan the MIR in order to find function calls, closures, and let mir = scx.tcx().item_mir(instance.def);
// drop-glue
let mir = scx.tcx().item_mir(def_id);
let visitor = MirNeighborCollector { let mut visitor = MirNeighborCollector {
scx: scx, scx: scx,
mir: &mir, mir: &mir,
output: output, output: output,
param_substs: substs param_substs: instance.substs
}; };
visit_mir_and_promoted(visitor, &mir);
}
fn visit_mir_and_promoted<'tcx, V: MirVisitor<'tcx>>(mut visitor: V, mir: &mir::Mir<'tcx>) {
visitor.visit_mir(&mir); visitor.visit_mir(&mir);
for promoted in &mir.promoted { for promoted in &mir.promoted {
visitor.visit_mir(promoted); visitor.visit_mir(promoted);

View file

@ -737,14 +737,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local().drop_glues &self.local().drop_glues
} }
pub fn local_node_for_inlined_defid<'a>(&'a self, def_id: DefId) -> Option<ast::NodeId> {
self.sess().cstore.local_node_for_inlined_defid(def_id)
}
pub fn defid_for_inlined_node<'a>(&'a self, node_id: ast::NodeId) -> Option<DefId> {
self.sess().cstore.defid_for_inlined_node(node_id)
}
pub fn instances<'a>(&'a self) -> &'a RefCell<FxHashMap<Instance<'tcx>, ValueRef>> { pub fn instances<'a>(&'a self) -> &'a RefCell<FxHashMap<Instance<'tcx>, ValueRef>> {
&self.local().instances &self.local().instances
} }

View file

@ -18,7 +18,6 @@ use rustc::hir::def_id::DefId;
use rustc::infer::TransNormalize; use rustc::infer::TransNormalize;
use rustc::mir; use rustc::mir;
use rustc::mir::tcx::LvalueTy; use rustc::mir::tcx::LvalueTy;
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::cast::{CastTy, IntTy}; use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
@ -36,7 +35,7 @@ use type_::Type;
use value::Value; use value::Value;
use syntax::ast; use syntax::ast;
use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::Span;
use std::fmt; use std::fmt;
use std::ptr; use std::ptr;
@ -238,24 +237,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
} }
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>, fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
mut instance: Instance<'tcx>, instance: Instance<'tcx>,
args: IndexVec<mir::Local, Const<'tcx>>) args: IndexVec<mir::Local, Const<'tcx>>)
-> Result<Const<'tcx>, ConstEvalErr> { -> Result<Const<'tcx>, ConstEvalErr> {
// Try to resolve associated constants. let instance = instance.resolve_const(ccx.shared());
if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
let trait_ref = ty::TraitRef::new(trait_id, instance.substs);
let trait_ref = ty::Binder(trait_ref);
let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
if let traits::VtableImpl(vtable_impl) = vtable {
let name = ccx.tcx().item_name(instance.def);
let ac = ccx.tcx().associated_items(vtable_impl.impl_def_id)
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
if let Some(ac) = ac {
instance = Instance::new(ac.def_id, vtable_impl.substs);
}
}
}
let mir = ccx.tcx().item_mir(instance.def); let mir = ccx.tcx().item_mir(instance.def);
MirConstContext::new(ccx, &mir, instance.substs, args).trans() MirConstContext::new(ccx, &mir, instance.substs, args).trans()
} }

View file

@ -11,11 +11,15 @@
use common::*; use common::*;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::infer::TransNormalize; use rustc::infer::TransNormalize;
use rustc::traits;
use rustc::ty::fold::{TypeFolder, TypeFoldable}; use rustc::ty::fold::{TypeFolder, TypeFoldable};
use rustc::ty::subst::{Subst, Substs}; use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::ppaux; use rustc::util::ppaux;
use rustc::util::common::MemoizationMap; use rustc::util::common::MemoizationMap;
use syntax::codemap::DUMMY_SP;
use std::fmt; use std::fmt;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@ -30,15 +34,35 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
} }
} }
impl<'tcx> Instance<'tcx> { impl<'a, 'tcx> Instance<'tcx> {
pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
-> Instance<'tcx> { -> Instance<'tcx> {
assert!(substs.regions().all(|&r| r == ty::ReErased)); assert!(substs.regions().all(|&r| r == ty::ReErased));
Instance { def: def_id, substs: substs } Instance { def: def_id, substs: substs }
} }
pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
pub fn mono(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
Instance::new(def_id, scx.empty_substs_for_def_id(def_id)) Instance::new(def_id, scx.empty_substs_for_def_id(def_id))
} }
/// For associated constants from traits, return the impl definition.
pub fn resolve_const(&self, scx: &SharedCrateContext<'a, 'tcx>) -> Self {
if let Some(trait_id) = scx.tcx().trait_of_item(self.def) {
let trait_ref = ty::TraitRef::new(trait_id, self.substs);
let trait_ref = ty::Binder(trait_ref);
let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref);
if let traits::VtableImpl(vtable_impl) = vtable {
let name = scx.tcx().item_name(self.def);
let ac = scx.tcx().associated_items(vtable_impl.impl_def_id)
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
if let Some(ac) = ac {
return Instance::new(ac.def_id, vtable_impl.substs);
}
}
}
*self
}
} }
/// Monomorphizes a type from the AST by first applying the in-scope /// Monomorphizes a type from the AST by first applying the in-scope

View file

@ -171,7 +171,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
mc::MemCategorizationOptions { mc::MemCategorizationOptions {
during_closure_kind_inference: true during_closure_kind_inference: true
}); });
euv.walk_fn(body); euv.consume_body(body);
} }
// Now that we've analyzed the closure, we know how each // Now that we've analyzed the closure, we know how each

View file

@ -21,8 +21,6 @@ use rustc::hir::print as pprust;
use rustc::ty; use rustc::ty;
use rustc::util::nodemap::FxHashSet; use rustc::util::nodemap::FxHashSet;
use rustc_const_eval::lookup_const_by_id;
use core::{DocContext, DocAccessLevels}; use core::{DocContext, DocAccessLevels};
use doctree; use doctree;
use clean::{self, GetDefId}; use clean::{self, GetDefId};
@ -346,7 +344,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
ty::AssociatedKind::Const => { ty::AssociatedKind::Const => {
let default = if item.defaultness.has_value() { let default = if item.defaultness.has_value() {
Some(pprust::expr_to_string( Some(pprust::expr_to_string(
lookup_const_by_id(tcx, item.def_id, None).unwrap().0)) &tcx.sess.cstore.maybe_get_item_body(tcx, item.def_id).unwrap().value))
} else { } else {
None None
}; };
@ -477,16 +475,10 @@ fn build_module(cx: &DocContext, did: DefId) -> clean::Module {
} }
fn build_const(cx: &DocContext, did: DefId) -> clean::Constant { fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
let (expr, ty) = lookup_const_by_id(cx.tcx, did, None).unwrap_or_else(|| {
panic!("expected lookup_const_by_id to succeed for {:?}", did);
});
debug!("converting constant expr {:?} to snippet", expr);
let sn = pprust::expr_to_string(expr);
debug!("got snippet {}", sn);
clean::Constant { clean::Constant {
type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| cx.tcx.item_type(did).clean(cx)), type_: cx.tcx.item_type(did).clean(cx),
expr: sn expr: pprust::expr_to_string(
&cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap().value)
} }
} }