rustc: simplify constant cross-crate loading and rustc_passes::consts.
This commit is contained in:
parent
f89856be6c
commit
f64e73b6ec
24 changed files with 394 additions and 997 deletions
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()),
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue