depth: 1
submodules: false
+osx_image: xcode8.2
+
matrix:
include:
# Linux builders, all docker images
# Install build tools needed for Rust. If you're building a 32-bit compiler,
# then replace "x86_64" below with "i686". If you've already got git, python,
# or CMake installed and in PATH you can remove them from this list. Note
- # that it is important that the `python2` and `cmake` packages **not** used.
- # The build has historically been known to fail with these packages.
+ # that it is important that you do **not** use the 'python2' and 'cmake'
+ # packages from the 'msys2' subsystem. The build has historically been known
+ # to fail with these packages.
$ pacman -S git \
make \
diffutils \
("RUSTC_REAL", "RUSTC_LIBDIR")
};
let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
+ let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
if let Some(target) = target {
// The stage0 compiler has a special sysroot distinct from what we
// actually downloaded, so we just always pass the `--sysroot` option.
- cmd.arg("--sysroot").arg(env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"));
+ cmd.arg("--sysroot").arg(sysroot);
// When we build Rust dylibs they're all intended for intermediate
// usage, so make sure we pass the -Cprefer-dynamic flag instead of
let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set");
let libdir = env::var_os("RUSTC_LIBDIR").expect("RUSTC_LIBDIR was not set");
let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
+ let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
let mut dylib_path = bootstrap::util::dylib_path();
dylib_path.insert(0, PathBuf::from(libdir));
.arg(format!("stage{}", stage))
.arg("--cfg")
.arg("dox")
+ .arg("--sysroot")
+ .arg(sysroot)
.env(bootstrap::util::dylib_path_var(),
env::join_paths(&dylib_path).unwrap());
std::process::exit(match cmd.status() {
}
need_cmd("cmake".as_ref());
if build.config.ninja {
- need_cmd("ninja".as_ref())
+ // Some Linux distros rename `ninja` to `ninja-build`.
+ // CMake can work with either binary name.
+ if have_cmd("ninja-build".as_ref()).is_none() {
+ need_cmd("ninja".as_ref());
+ }
}
break
}
} else {
&self.build.config.target
};
- // If --target was specified but --host wasn't specified, don't run
- // any host-only tests
+ // Determine the actual targets participating in this rule.
+ // NOTE: We should keep the full projection from build triple to
+ // the hosts for the dist steps, now that the hosts array above is
+ // truncated to avoid duplication of work in that case. Therefore
+ // the original non-shadowed hosts array is used below.
let arr = if rule.host {
- if self.build.flags.target.len() > 0 &&
- self.build.flags.host.len() == 0 {
- &hosts[..0]
+ // If --target was specified but --host wasn't specified,
+ // don't run any host-only tests. Also, respect any `--host`
+ // overrides as done for `hosts`.
+ if self.build.flags.host.len() > 0 {
+ &self.build.flags.host[..]
+ } else if self.build.flags.target.len() > 0 {
+ &[]
} else {
- hosts
+ &self.build.config.host[..]
}
} else {
targets
set -ex
ANDROID_EMULATOR_FORCE_32BIT=true \
- emulator @arm-18 -no-window -partition-size 2047 &
+ nohup nohup emulator @arm-18 -no-window -partition-size 2047 \
+ 0<&- &>/dev/null &
+adb wait-for-device
exec "$@"
}
#[cfg(not(test))]
+#[cfg(stage0)]
#[lang = "exchange_free"]
#[inline]
unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) {
name = "collectionstest"
path = "../libcollectionstest/lib.rs"
-[[bench]]
-name = "collectionstest"
-path = "../libcollectionstest/lib.rs"
+# FIXME: need to extract benchmarks to separate crate
+#[[bench]]
+#name = "collectionstest"
+#path = "../libcollectionstest/lib.rs"
name = "coretest"
path = "../libcoretest/lib.rs"
-[[bench]]
-name = "coretest"
-path = "../libcoretest/lib.rs"
+# FIXME: need to extract benchmarks to a separate crate
+#[[bench]]
+#name = "coretest"
+#path = "../libcoretest/lib.rs"
authors = ["The Rust Project Developers"]
name = "proc_macro_tokens"
version = "0.0.0"
+build = false
[lib]
path = "lib.rs"
self.opt_expr(base, field_cfg)
}
- hir::ExprRepeat(ref elem, ref count) => {
- self.straightline(expr, pred, [elem, count].iter().map(|&e| &**e))
- }
-
hir::ExprAssign(ref l, ref r) |
hir::ExprAssignOp(_, ref l, ref r) => {
self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
hir::ExprType(ref e, _) |
hir::ExprUnary(_, ref e) |
hir::ExprField(ref e, _) |
- hir::ExprTupField(ref e, _) => {
+ hir::ExprTupField(ref e, _) |
+ hir::ExprRepeat(ref e, _) => {
self.straightline(expr, pred, Some(&**e).into_iter())
}
}
}
+ /// True if we are actually building the full dep-graph.
+ #[inline]
+ pub fn is_fully_enabled(&self) -> bool {
+ self.data.thread.is_fully_enabled()
+ }
+
pub fn query(&self) -> DepGraphQuery<DefId> {
self.data.thread.query()
}
debug!("Ended task {:?}", task_id);
}
+ fn visit_trait_item(&mut self, i: &'tcx hir::TraitItem) {
+ let trait_item_def_id = self.tcx.map.local_def_id(i.id);
+ let task_id = (self.dep_node_fn)(trait_item_def_id);
+ let _task = self.tcx.dep_graph.in_task(task_id.clone());
+ debug!("Started task {:?}", task_id);
+ self.tcx.dep_graph.read(DepNode::Hir(trait_item_def_id));
+ self.visitor.visit_trait_item(i);
+ debug!("Ended task {:?}", task_id);
+ }
+
fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
let impl_item_def_id = self.tcx.map.local_def_id(i.id);
let task_id = (self.dep_node_fn)(impl_item_def_id);
}
}
+ /// Like `visit_nested_item()`, but for trait items. See
+ /// `visit_nested_item()` for advice on when to override this
+ /// method.
+ #[allow(unused_variables)]
+ fn visit_nested_trait_item(&mut self, id: TraitItemId) {
+ let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id));
+ if let Some(item) = opt_item {
+ self.visit_trait_item(item);
+ }
+ }
+
/// Like `visit_nested_item()`, but for impl items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
/// visit_nested_item, does nothing by default unless you override
/// `nested_visit_map` to return `Some(_)`, in which case it will walk the
/// body.
- fn visit_body(&mut self, id: ExprId) {
- let opt_expr = self.nested_visit_map().intra().map(|map| map.expr(id));
- if let Some(expr) = opt_expr {
- self.visit_expr(expr);
+ fn visit_nested_body(&mut self, id: BodyId) {
+ let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));
+ if let Some(body) = opt_body {
+ self.visit_body(body);
}
}
walk_item(self, i)
}
+ fn visit_body(&mut self, b: &'v Body) {
+ walk_body(self, b);
+ }
+
/// When invoking `visit_all_item_likes()`, you need to supply an
/// item-like visitor. This method converts a "intra-visit"
/// visitor into an item-like visitor that walks the entire tree.
fn visit_expr(&mut self, ex: &'v Expr) {
walk_expr(self, ex)
}
- fn visit_expr_post(&mut self, _ex: &'v Expr) {
- }
fn visit_ty(&mut self, t: &'v Ty) {
walk_ty(self, t)
}
fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) {
walk_where_predicate(self, predicate)
}
- fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: ExprId, s: Span, id: NodeId) {
+ fn visit_fn_decl(&mut self, fd: &'v FnDecl) {
+ walk_fn_decl(self, fd)
+ }
+ fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: BodyId, s: Span, id: NodeId) {
walk_fn(self, fk, fd, b, s, id)
}
fn visit_trait_item(&mut self, ti: &'v TraitItem) {
walk_trait_item(self, ti)
}
+ fn visit_trait_item_ref(&mut self, ii: &'v TraitItemRef) {
+ walk_trait_item_ref(self, ii)
+ }
fn visit_impl_item(&mut self, ii: &'v ImplItem) {
walk_impl_item(self, ii)
}
}
}
+pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
+ for argument in &body.arguments {
+ visitor.visit_id(argument.id);
+ visitor.visit_pat(&argument.pat);
+ }
+ visitor.visit_expr(&body.value);
+}
+
pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
visitor.visit_id(local.id);
visitor.visit_pat(&local.pat);
visitor.visit_id(item.id);
visitor.visit_path(path, item.id);
}
- ItemStatic(ref typ, _, ref expr) |
- ItemConst(ref typ, ref expr) => {
+ ItemStatic(ref typ, _, body) |
+ ItemConst(ref typ, body) => {
visitor.visit_id(item.id);
visitor.visit_ty(typ);
- visitor.visit_expr(expr);
+ visitor.visit_nested_body(body);
}
ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => {
visitor.visit_fn(FnKind::ItemFn(item.name,
visitor.visit_generics(type_parameters);
walk_list!(visitor, visit_trait_ref, opt_trait_reference);
visitor.visit_ty(typ);
- for impl_item_ref in impl_item_refs {
- visitor.visit_impl_item_ref(impl_item_ref);
- }
+ walk_list!(visitor, visit_impl_item_ref, impl_item_refs);
}
ItemStruct(ref struct_definition, ref generics) |
ItemUnion(ref struct_definition, ref generics) => {
visitor.visit_id(item.id);
visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);
}
- ItemTrait(_, ref generics, ref bounds, ref methods) => {
+ ItemTrait(_, ref generics, ref bounds, ref trait_item_refs) => {
visitor.visit_id(item.id);
visitor.visit_generics(generics);
walk_list!(visitor, visit_ty_param_bound, bounds);
- walk_list!(visitor, visit_trait_item, methods);
+ walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
}
}
walk_list!(visitor, visit_attribute, &item.attrs);
generics,
parent_item_id,
variant.span);
- walk_list!(visitor, visit_expr, &variant.node.disr_expr);
+ walk_list!(visitor, visit_nested_body, variant.node.disr_expr);
walk_list!(visitor, visit_attribute, &variant.node.attrs);
}
walk_list!(visitor, visit_ty, tuple_element_types);
}
TyBareFn(ref function_declaration) => {
- walk_fn_decl(visitor, &function_declaration.decl);
+ visitor.visit_fn_decl(&function_declaration.decl);
walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes);
}
TyPath(ref qpath) => {
visitor.visit_ty(ty);
walk_list!(visitor, visit_ty_param_bound, bounds);
}
- TyArray(ref ty, ref expression) => {
+ TyArray(ref ty, length) => {
visitor.visit_ty(ty);
- visitor.visit_expr(expression)
+ visitor.visit_nested_body(length)
}
TyPolyTraitRef(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
TyImplTrait(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
}
- TyTypeof(ref expression) => {
- visitor.visit_expr(expression)
+ TyTypeof(expression) => {
+ visitor.visit_nested_body(expression)
}
TyInfer => {}
}
visitor.visit_name(foreign_item.span, foreign_item.name);
match foreign_item.node {
- ForeignItemFn(ref function_declaration, ref generics) => {
- walk_fn_decl(visitor, function_declaration);
- visitor.visit_generics(generics)
+ ForeignItemFn(ref function_declaration, ref names, ref generics) => {
+ visitor.visit_generics(generics);
+ visitor.visit_fn_decl(function_declaration);
+ for name in names {
+ visitor.visit_name(name.span, name.node);
+ }
}
ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ),
}
}
pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
- for argument in &function_declaration.inputs {
- visitor.visit_id(argument.id);
- visitor.visit_pat(&argument.pat);
- visitor.visit_ty(&argument.ty)
- }
- walk_fn_ret_ty(visitor, &function_declaration.output)
-}
-
-pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
- for argument in &function_declaration.inputs {
- visitor.visit_id(argument.id);
- visitor.visit_ty(&argument.ty)
+ for ty in &function_declaration.inputs {
+ visitor.visit_ty(ty)
}
walk_fn_ret_ty(visitor, &function_declaration.output)
}
pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
function_kind: FnKind<'v>,
function_declaration: &'v FnDecl,
- body_id: ExprId,
+ body_id: BodyId,
_span: Span,
id: NodeId) {
visitor.visit_id(id);
- walk_fn_decl(visitor, function_declaration);
- walk_fn_kind(visitor, function_kind);
- visitor.visit_body(body_id)
-}
-
-pub fn walk_fn_with_body<'v, V: Visitor<'v>>(visitor: &mut V,
- function_kind: FnKind<'v>,
- function_declaration: &'v FnDecl,
- body: &'v Expr,
- _span: Span,
- id: NodeId) {
- visitor.visit_id(id);
- walk_fn_decl(visitor, function_declaration);
+ visitor.visit_fn_decl(function_declaration);
walk_fn_kind(visitor, function_kind);
- visitor.visit_expr(body)
+ visitor.visit_nested_body(body_id)
}
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
visitor.visit_name(trait_item.span, trait_item.name);
walk_list!(visitor, visit_attribute, &trait_item.attrs);
match trait_item.node {
- ConstTraitItem(ref ty, ref default) => {
+ TraitItemKind::Const(ref ty, default) => {
visitor.visit_id(trait_item.id);
visitor.visit_ty(ty);
- walk_list!(visitor, visit_expr, default);
+ walk_list!(visitor, visit_nested_body, default);
}
- MethodTraitItem(ref sig, None) => {
+ TraitItemKind::Method(ref sig, TraitMethod::Required(ref names)) => {
visitor.visit_id(trait_item.id);
visitor.visit_generics(&sig.generics);
- walk_fn_decl(visitor, &sig.decl);
+ visitor.visit_fn_decl(&sig.decl);
+ for name in names {
+ visitor.visit_name(name.span, name.node);
+ }
}
- MethodTraitItem(ref sig, Some(body_id)) => {
+ TraitItemKind::Method(ref sig, TraitMethod::Provided(body_id)) => {
visitor.visit_fn(FnKind::Method(trait_item.name,
sig,
None,
trait_item.span,
trait_item.id);
}
- TypeTraitItem(ref bounds, ref default) => {
+ TraitItemKind::Type(ref bounds, ref default) => {
visitor.visit_id(trait_item.id);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_ty, default);
}
}
+pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) {
+ // NB: Deliberately force a compilation error if/when new fields are added.
+ let TraitItemRef { id, name, ref kind, span, ref defaultness } = *trait_item_ref;
+ visitor.visit_nested_trait_item(id);
+ visitor.visit_name(span, name);
+ visitor.visit_associated_item_kind(kind);
+ visitor.visit_defaultness(defaultness);
+}
+
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) {
// NB: Deliberately force a compilation error if/when new fields are added.
let ImplItem { id: _, name, ref vis, ref defaultness, ref attrs, ref node, span } = *impl_item;
visitor.visit_defaultness(defaultness);
walk_list!(visitor, visit_attribute, attrs);
match *node {
- ImplItemKind::Const(ref ty, ref expr) => {
+ ImplItemKind::Const(ref ty, body) => {
visitor.visit_id(impl_item.id);
visitor.visit_ty(ty);
- visitor.visit_expr(expr);
+ visitor.visit_nested_body(body);
}
ImplItemKind::Method(ref sig, body_id) => {
visitor.visit_fn(FnKind::Method(impl_item.name,
ExprArray(ref subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);
}
- ExprRepeat(ref element, ref count) => {
+ ExprRepeat(ref element, count) => {
visitor.visit_expr(element);
- visitor.visit_expr(count)
+ visitor.visit_nested_body(count)
}
ExprStruct(ref qpath, ref fields, ref optional_base) => {
visitor.visit_qpath(qpath, expression.id, expression.span);
}
}
}
-
- visitor.visit_expr_post(expression)
}
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
self.result.add(id);
}
}
-
-/// Computes the id range for a single fn body, ignoring nested items.
-pub fn compute_id_range_for_fn_body<'v>(fk: FnKind<'v>,
- decl: &'v FnDecl,
- body: &'v Expr,
- sp: Span,
- id: NodeId,
- map: &map::Map<'v>)
- -> IdRange {
- let mut visitor = IdRangeComputingVisitor::new(map);
- walk_fn_with_body(&mut visitor, fk, decl, body, sp, id);
- visitor.result()
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::{Item, ImplItem};
+use super::{Item, ImplItem, TraitItem};
use super::intravisit::Visitor;
/// The "item-like visitor" visitor defines only the top-level methods
/// needed.
pub trait ItemLikeVisitor<'hir> {
fn visit_item(&mut self, item: &'hir Item);
+ fn visit_trait_item(&mut self, trait_item: &'hir TraitItem);
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem);
}
self.visitor.visit_item(item);
}
+ fn visit_trait_item(&mut self, trait_item: &'hir TraitItem) {
+ self.visitor.visit_trait_item(trait_item);
+ }
+
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem) {
self.visitor.visit_impl_item(impl_item);
}
use hir::def_id::{DefIndex, DefId};
use hir::def::{Def, PathResolution};
use session::Session;
-use util::nodemap::NodeMap;
-use rustc_data_structures::fnv::FnvHashMap;
+use util::nodemap::{NodeMap, FxHashMap};
use std::collections::BTreeMap;
use std::iter;
-use std::mem;
use syntax::ast::*;
use syntax::errors;
// the form of a DefIndex) so that if we create a new node which introduces
// a definition, then we can properly create the def id.
parent_def: Option<DefIndex>,
- exprs: FnvHashMap<hir::ExprId, hir::Expr>,
resolver: &'a mut Resolver,
/// The items being lowered are collected here.
items: BTreeMap<NodeId, hir::Item>,
+ trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
+ bodies: FxHashMap<hir::BodyId, hir::Body>,
}
pub trait Resolver {
crate_root: std_inject::injected_crate_name(krate),
sess: sess,
parent_def: None,
- exprs: FnvHashMap(),
resolver: resolver,
items: BTreeMap::new(),
+ trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
+ bodies: FxHashMap(),
}.lower_crate(krate)
}
span: c.span,
exported_macros: exported_macros,
items: self.items,
+ trait_items: self.trait_items,
impl_items: self.impl_items,
- exprs: mem::replace(&mut self.exprs, FnvHashMap()),
+ bodies: self.bodies,
}
}
visit::walk_item(self, item);
}
+ fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
+ let id = hir::TraitItemId { node_id: item.id };
+ let hir_item = self.lctx.lower_trait_item(item);
+ self.lctx.trait_items.insert(id, hir_item);
+ visit::walk_trait_item(self, item);
+ }
+
fn visit_impl_item(&mut self, item: &'lcx ImplItem) {
- let id = self.lctx.lower_impl_item_ref(item).id;
+ let id = hir::ImplItemId { node_id: item.id };
let hir_item = self.lctx.lower_impl_item(item);
self.lctx.impl_items.insert(id, hir_item);
visit::walk_impl_item(self, item);
visit::walk_crate(&mut item_lowerer, c);
}
- fn record_expr(&mut self, expr: hir::Expr) -> hir::ExprId {
- let id = hir::ExprId(expr.id);
- self.exprs.insert(id, expr);
+ fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>)
+ -> hir::BodyId {
+ let body = hir::Body {
+ arguments: decl.map_or(hir_vec![], |decl| {
+ decl.inputs.iter().map(|x| self.lower_arg(x)).collect()
+ }),
+ value: value
+ };
+ let id = body.id();
+ self.bodies.insert(id, body);
id
}
P(hir::Ty {
id: t.id,
node: match t.node {
- TyKind::Infer | TyKind::ImplicitSelf => hir::TyInfer,
+ TyKind::Infer => hir::TyInfer,
TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
TyKind::Rptr(ref region, ref mt) => {
TyKind::Path(ref qself, ref path) => {
hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit))
}
+ TyKind::ImplicitSelf => {
+ hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
+ def: self.expect_full_def(t.id),
+ segments: hir_vec![hir::PathSegment {
+ name: keywords::SelfType.name(),
+ parameters: hir::PathParameters::none()
+ }],
+ span: t.span,
+ })))
+ }
TyKind::ObjectSum(ref ty, ref bounds) => {
hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
}
- TyKind::Array(ref ty, ref e) => {
- hir::TyArray(self.lower_ty(ty), P(self.lower_expr(e)))
+ TyKind::Array(ref ty, ref length) => {
+ let length = self.lower_expr(length);
+ hir::TyArray(self.lower_ty(ty),
+ self.record_body(length, None))
}
TyKind::Typeof(ref expr) => {
- hir::TyTypeof(P(self.lower_expr(expr)))
+ let expr = self.lower_expr(expr);
+ hir::TyTypeof(self.record_body(expr, None))
}
TyKind::PolyTraitRef(ref bounds) => {
hir::TyPolyTraitRef(self.lower_bounds(bounds))
name: v.node.name.name,
attrs: self.lower_attrs(&v.node.attrs),
data: self.lower_variant_data(&v.node.data),
- disr_expr: v.node.disr_expr.as_ref().map(|e| P(self.lower_expr(e))),
+ disr_expr: v.node.disr_expr.as_ref().map(|e| {
+ let e = self.lower_expr(e);
+ self.record_body(e, None)
+ }),
},
span: v.span,
}
hir::Arg {
id: arg.id,
pat: self.lower_pat(&arg.pat),
- ty: self.lower_ty(&arg.ty),
}
}
+ fn lower_fn_args_to_names(&mut self, decl: &FnDecl)
+ -> hir::HirVec<Spanned<Name>> {
+ decl.inputs.iter().map(|arg| {
+ match arg.pat.node {
+ PatKind::Ident(_, ident, None) => {
+ respan(ident.span, ident.node.name)
+ }
+ _ => respan(arg.pat.span, keywords::Invalid.name()),
+ }
+ }).collect()
+ }
+
fn lower_fn_decl(&mut self, decl: &FnDecl) -> P<hir::FnDecl> {
P(hir::FnDecl {
- inputs: decl.inputs.iter().map(|x| self.lower_arg(x)).collect(),
+ inputs: decl.inputs.iter().map(|arg| self.lower_ty(&arg.ty)).collect(),
output: match decl.output {
FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)),
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
hir::ItemUse(path, kind)
}
ItemKind::Static(ref t, m, ref e) => {
+ let value = self.lower_expr(e);
hir::ItemStatic(self.lower_ty(t),
self.lower_mutability(m),
- P(self.lower_expr(e)))
+ self.record_body(value, None))
}
ItemKind::Const(ref t, ref e) => {
- hir::ItemConst(self.lower_ty(t), P(self.lower_expr(e)))
+ let value = self.lower_expr(e);
+ hir::ItemConst(self.lower_ty(t),
+ self.record_body(value, None))
}
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
let body = self.lower_block(body);
let body = self.expr_block(body, ThinVec::new());
- let body_id = self.record_expr(body);
+ let body_id = self.record_body(body, Some(decl));
hir::ItemFn(self.lower_fn_decl(decl),
self.lower_unsafety(unsafety),
self.lower_constness(constness),
}
ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => {
let bounds = self.lower_bounds(bounds);
- let items = items.iter().map(|item| self.lower_trait_item(item)).collect();
+ let items = items.iter().map(|item| self.lower_trait_item_ref(item)).collect();
hir::ItemTrait(self.lower_unsafety(unsafety),
self.lower_generics(generics),
bounds,
attrs: this.lower_attrs(&i.attrs),
node: match i.node {
TraitItemKind::Const(ref ty, ref default) => {
- hir::ConstTraitItem(this.lower_ty(ty),
- default.as_ref().map(|x| P(this.lower_expr(x))))
- }
- TraitItemKind::Method(ref sig, ref body) => {
- hir::MethodTraitItem(this.lower_method_sig(sig),
- body.as_ref().map(|x| {
- let body = this.lower_block(x);
- let expr = this.expr_block(body, ThinVec::new());
- this.record_expr(expr)
+ hir::TraitItemKind::Const(this.lower_ty(ty),
+ default.as_ref().map(|x| {
+ let value = this.lower_expr(x);
+ this.record_body(value, None)
}))
}
+ TraitItemKind::Method(ref sig, None) => {
+ let names = this.lower_fn_args_to_names(&sig.decl);
+ hir::TraitItemKind::Method(this.lower_method_sig(sig),
+ hir::TraitMethod::Required(names))
+ }
+ TraitItemKind::Method(ref sig, Some(ref body)) => {
+ let body = this.lower_block(body);
+ let expr = this.expr_block(body, ThinVec::new());
+ let body_id = this.record_body(expr, Some(&sig.decl));
+ hir::TraitItemKind::Method(this.lower_method_sig(sig),
+ hir::TraitMethod::Provided(body_id))
+ }
TraitItemKind::Type(ref bounds, ref default) => {
- hir::TypeTraitItem(this.lower_bounds(bounds),
- default.as_ref().map(|x| this.lower_ty(x)))
+ hir::TraitItemKind::Type(this.lower_bounds(bounds),
+ default.as_ref().map(|x| this.lower_ty(x)))
}
TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
},
})
}
+ fn lower_trait_item_ref(&mut self, i: &TraitItem) -> hir::TraitItemRef {
+ let (kind, has_default) = match i.node {
+ TraitItemKind::Const(_, ref default) => {
+ (hir::AssociatedItemKind::Const, default.is_some())
+ }
+ TraitItemKind::Type(_, ref default) => {
+ (hir::AssociatedItemKind::Type, default.is_some())
+ }
+ TraitItemKind::Method(ref sig, ref default) => {
+ (hir::AssociatedItemKind::Method {
+ has_self: sig.decl.has_self(),
+ }, default.is_some())
+ }
+ TraitItemKind::Macro(..) => unimplemented!(),
+ };
+ hir::TraitItemRef {
+ id: hir::TraitItemId { node_id: i.id },
+ name: i.ident.name,
+ span: i.span,
+ defaultness: self.lower_defaultness(Defaultness::Default, has_default),
+ kind: kind,
+ }
+ }
+
fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
self.with_parent_def(i.id, |this| {
hir::ImplItem {
defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
node: match i.node {
ImplItemKind::Const(ref ty, ref expr) => {
- hir::ImplItemKind::Const(this.lower_ty(ty), P(this.lower_expr(expr)))
+ let value = this.lower_expr(expr);
+ let body_id = this.record_body(value, None);
+ hir::ImplItemKind::Const(this.lower_ty(ty), body_id)
}
ImplItemKind::Method(ref sig, ref body) => {
let body = this.lower_block(body);
let expr = this.expr_block(body, ThinVec::new());
- let expr_id = this.record_expr(expr);
- hir::ImplItemKind::Method(this.lower_method_sig(sig), expr_id)
+ let body_id = this.record_body(expr, Some(&sig.decl));
+ hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id)
}
ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
- has_self: sig.decl.get_self().is_some(),
+ has_self: sig.decl.has_self(),
},
ImplItemKind::Macro(..) => unimplemented!(),
},
attrs: this.lower_attrs(&i.attrs),
node: match i.node {
ForeignItemKind::Fn(ref fdec, ref generics) => {
- hir::ForeignItemFn(this.lower_fn_decl(fdec), this.lower_generics(generics))
+ hir::ForeignItemFn(this.lower_fn_decl(fdec),
+ this.lower_fn_args_to_names(fdec),
+ this.lower_generics(generics))
}
ForeignItemKind::Static(ref t, m) => {
hir::ForeignItemStatic(this.lower_ty(t), m)
}
fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig {
- let hir_sig = hir::MethodSig {
+ hir::MethodSig {
generics: self.lower_generics(&sig.generics),
abi: sig.abi,
unsafety: self.lower_unsafety(sig.unsafety),
constness: self.lower_constness(sig.constness),
decl: self.lower_fn_decl(&sig.decl),
- };
- // Check for `self: _` and `self: &_`
- if let Some(SelfKind::Explicit(..)) = sig.decl.get_self().map(|eself| eself.node) {
- match hir_sig.decl.get_self().map(|eself| eself.node) {
- Some(hir::SelfKind::Value(..)) | Some(hir::SelfKind::Region(..)) => {
- self.diagnostic().span_err(sig.decl.inputs[0].ty.span,
- "the type placeholder `_` is not allowed within types on item signatures");
- }
- _ => {}
- }
}
- hir_sig
}
fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
}
ExprKind::Repeat(ref expr, ref count) => {
let expr = P(self.lower_expr(expr));
- let count = P(self.lower_expr(count));
- hir::ExprRepeat(expr, count)
+ let count = self.lower_expr(count);
+ hir::ExprRepeat(expr, self.record_body(count, None))
}
ExprKind::Tup(ref elts) => {
hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect())
let expr = this.lower_expr(body);
hir::ExprClosure(this.lower_capture_clause(capture_clause),
this.lower_fn_decl(decl),
- this.record_expr(expr),
+ this.record_body(expr, Some(decl)),
fn_decl_span)
})
}
// `::std::option::Option::Some(<pat>) => <body>`
let pat_arm = {
let body_block = self.lower_block(body);
- let body_span = body_block.span;
- let body_expr = P(hir::Expr {
- id: self.next_id(),
- node: hir::ExprBlock(body_block),
- span: body_span,
- attrs: ThinVec::new(),
- });
+ let body_expr = P(self.expr_block(body_block, ThinVec::new()));
let pat = self.lower_pat(pat);
let some_pat = self.pat_some(e.span, pat);
/// Components shared by fn-like things (fn items, methods, closures).
pub struct FnParts<'a> {
pub decl: &'a FnDecl,
- pub body: ast::ExprId,
+ pub body: ast::BodyId,
pub kind: FnKind<'a>,
pub span: Span,
pub id: NodeId,
impl MaybeFnLike for ast::TraitItem {
fn is_fn_like(&self) -> bool {
- match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, }
+ match self.node {
+ ast::TraitItemKind::Method(_, ast::TraitMethod::Provided(_)) => true,
+ _ => false,
+ }
}
}
abi: abi::Abi,
vis: &'a ast::Visibility,
generics: &'a ast::Generics,
- body: ast::ExprId,
+ body: ast::BodyId,
id: NodeId,
span: Span,
attrs: &'a [Attribute],
/// for use when implementing FnLikeNode operations.
struct ClosureParts<'a> {
decl: &'a FnDecl,
- body: ast::ExprId,
+ body: ast::BodyId,
id: NodeId,
span: Span,
attrs: &'a [Attribute],
}
impl<'a> ClosureParts<'a> {
- fn new(d: &'a FnDecl, b: ast::ExprId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
+ fn new(d: &'a FnDecl, b: ast::BodyId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
ClosureParts {
decl: d,
body: b,
}
}
- pub fn body(self) -> ast::ExprId {
+ pub fn body(self) -> ast::BodyId {
self.handle(|i: ItemFnParts<'a>| i.body,
- |_, _, _: &'a ast::MethodSig, _, body: ast::ExprId, _, _| body,
+ |_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _| body,
|c: ClosureParts<'a>| c.body)
}
Name,
&'a ast::MethodSig,
Option<&'a ast::Visibility>,
- ast::ExprId,
+ ast::BodyId,
Span,
&'a [Attribute])
-> A,
_ => bug!("item FnLikeNode that is not fn-like"),
},
map::NodeTraitItem(ti) => match ti.node {
- ast::MethodTraitItem(ref sig, Some(body)) => {
+ ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
method(ti.id, ti.name, sig, None, body, ti.span, &ti.attrs)
}
_ => bug!("trait method FnLikeNode that is not fn-like"),
use super::*;
use hir::intravisit::{Visitor, NestedVisitorMap};
-use middle::cstore::InlinedItem;
use std::iter::repeat;
use syntax::ast::{NodeId, CRATE_NODE_ID};
use syntax_pos::Span;
/// The crate
pub krate: &'ast Crate,
/// The node map
- pub map: Vec<MapEntry<'ast>>,
+ pub(super) map: Vec<MapEntry<'ast>>,
/// The parent of this node
pub parent_node: NodeId,
/// If true, completely ignore nested items. We set this when loading
collector
}
- pub fn extend(krate: &'ast Crate,
- parent: &'ast InlinedItem,
- parent_node: NodeId,
- map: Vec<MapEntry<'ast>>)
- -> NodeCollector<'ast> {
+ pub(super) fn extend(krate: &'ast Crate,
+ parent: &'ast InlinedItem,
+ parent_node: NodeId,
+ map: Vec<MapEntry<'ast>>)
+ -> NodeCollector<'ast> {
let mut collector = NodeCollector {
krate: krate,
map: map,
}
}
+ fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
+ if !self.ignore_nested_items {
+ self.visit_trait_item(self.krate.trait_item(item_id))
+ }
+ }
+
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
- self.visit_impl_item(self.krate.impl_item(item_id))
+ if !self.ignore_nested_items {
+ self.visit_impl_item(self.krate.impl_item(item_id))
+ }
}
- fn visit_body(&mut self, id: ExprId) {
- self.visit_expr(self.krate.expr(id))
+ fn visit_nested_body(&mut self, id: BodyId) {
+ if !self.ignore_nested_items {
+ self.visit_body(self.krate.body(id))
+ }
}
fn visit_item(&mut self, i: &'ast Item) {
self.with_parent(i.id, |this| {
match i.node {
- ItemEnum(ref enum_definition, _) => {
- for v in &enum_definition.variants {
- this.insert(v.node.data.id(), NodeVariant(v));
- }
- }
ItemStruct(ref struct_def, _) => {
// If this is a tuple-like struct, register the constructor.
if !struct_def.is_struct() {
}
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
- b: ExprId, s: Span, id: NodeId) {
+ b: BodyId, s: Span, id: NodeId) {
assert_eq!(self.parent_node, id);
intravisit::walk_fn(self, fk, fd, b, s, id);
}
self.insert_entry(macro_def.id, NotPresent);
}
+ fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) {
+ let id = v.node.data.id();
+ self.insert(id, NodeVariant(v));
+ self.with_parent(id, |this| {
+ intravisit::walk_variant(this, v, g, item_id);
+ });
+ }
+
fn visit_struct_field(&mut self, field: &'ast StructField) {
self.insert(field.id, NodeField(field));
self.with_parent(field.id, |this| {
use syntax::visit;
use syntax::symbol::{Symbol, keywords};
-/// Creates def ids for nodes in the HIR.
+/// Creates def ids for nodes in the AST.
pub struct DefCollector<'a> {
definitions: &'a mut Definitions,
parent_def: Option<DefIndex>,
}
}
-
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum DefPathData {
// Root: these should only be used for the root nodes, because
data,
self.table.def_key(self.node_to_def_index[&node_id]));
- assert!(parent.is_some() ^ (data == DefPathData::CrateRoot));
+ assert_eq!(parent.is_some(), data != DefPathData::CrateRoot);
// Find a unique DefKey. This basically means incrementing the disambiguator
// until we get no match.
use dep_graph::{DepGraph, DepNode};
-use middle::cstore::InlinedItem;
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
use syntax::abi::Abi;
use syntax_pos::Span;
use hir::*;
-use hir::print as pprust;
+use hir::intravisit::Visitor;
+use hir::print::Nested;
use arena::TypedArena;
use std::cell::RefCell;
mod def_collector;
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)]
pub enum Node<'ast> {
NodeItem(&'ast Item),
NodeLifetime(&'ast Lifetime),
NodeTyParam(&'ast TyParam),
NodeVisibility(&'ast Visibility),
-
- NodeInlinedItem(&'ast InlinedItem),
}
/// Represents an entry and its parent NodeID.
/// The odd layout is to bring down the total size.
#[derive(Copy, Debug)]
-pub enum MapEntry<'ast> {
+enum MapEntry<'ast> {
/// Placeholder for holes in the map.
NotPresent,
NodeLifetime(n) => EntryLifetime(p, n),
NodeTyParam(n) => EntryTyParam(p, n),
NodeVisibility(n) => EntryVisibility(p, n),
-
- NodeInlinedItem(n) => RootInlinedParent(n),
}
}
EntryLifetime(_, n) => NodeLifetime(n),
EntryTyParam(_, n) => NodeTyParam(n),
EntryVisibility(_, n) => NodeVisibility(n),
- RootInlinedParent(n) => NodeInlinedItem(n),
_ => 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.
if !self.is_inlined_node_id(id) {
let mut last_expr = None;
loop {
- match map[id.as_usize()] {
- EntryItem(_, item) => {
- assert_eq!(id, item.id);
- let def_id = self.local_def_id(id);
-
+ let entry = map[id.as_usize()];
+ match entry {
+ EntryItem(..) |
+ EntryTraitItem(..) |
+ EntryImplItem(..) => {
if let Some(last_id) = last_expr {
- // The body of the item may have a separate dep node
- // (Note that trait items don't currently have
- // their own dep node, so there's also just one
- // HirBody node for all the items)
- if self.is_body(last_id, item) {
+ // The body may have a separate dep node
+ if entry.is_body_owner(last_id) {
+ let def_id = self.local_def_id(id);
return DepNode::HirBody(def_id);
}
}
- return DepNode::Hir(def_id);
+ return DepNode::Hir(self.local_def_id(id));
}
- EntryImplItem(_, item) => {
- let def_id = self.local_def_id(id);
+ EntryVariant(p, v) => {
+ id = p;
- 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) {
+ if last_expr.is_some() {
+ if v.node.disr_expr.map(|e| e.node_id) == last_expr {
+ // The enum parent holds both Hir and HirBody nodes.
+ let def_id = self.local_def_id(id);
return DepNode::HirBody(def_id);
}
}
- return DepNode::Hir(def_id);
}
EntryForeignItem(p, _) |
- EntryTraitItem(p, _) |
- EntryVariant(p, _) |
EntryField(p, _) |
EntryStmt(p, _) |
EntryTy(p, _) |
bug!("node {} has inlined ancestor but is not inlined", id0),
NotPresent =>
- // Some nodes, notably struct fields, are not
+ // Some nodes, notably macro definitions, are not
// present in the map for whatever reason, but
// they *do* have def-ids. So if we encounter an
// empty hole, check for that case.
}
}
- fn is_body(&self, node_id: NodeId, item: &Item) -> bool {
- match item.node {
- ItemFn(_, _, _, _, _, body) => body.node_id() == node_id,
- // Since trait items currently don't get their own dep nodes,
- // we check here whether node_id is the body of any of the items.
- // If they get their own dep nodes, this can go away
- ItemTrait(_, _, _, ref trait_items) => {
- trait_items.iter().any(|trait_item| { match trait_item.node {
- MethodTraitItem(_, Some(body)) => body.node_id() == node_id,
- _ => false
- }})
- }
- _ => false
- }
- }
-
- fn is_impl_item_body(&self, node_id: NodeId, item: &ImplItem) -> bool {
- match item.node {
- ImplItemKind::Method(_, body) => body.node_id() == node_id,
- _ => false
- }
- }
-
pub fn num_local_def_ids(&self) -> usize {
self.definitions.len()
}
self.forest.krate()
}
+ pub fn trait_item(&self, id: TraitItemId) -> &'ast TraitItem {
+ self.read(id.node_id);
+
+ // NB: intentionally bypass `self.forest.krate()` so that we
+ // do not trigger a read of the whole krate here
+ self.forest.krate.trait_item(id)
+ }
+
pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem {
self.read(id.node_id);
self.forest.krate.impl_item(id)
}
+ pub fn body(&self, id: BodyId) -> &'ast Body {
+ self.read(id.node_id);
+
+ // NB: intentionally bypass `self.forest.krate()` so that we
+ // do not trigger a read of the whole krate here
+ 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
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.
}
}
- 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) {
- Some(RootInlinedParent(inlined_item)) => inlined_item,
+ Some(RootInlinedParent(inlined_item)) => &inlined_item.body,
_ => bug!("expected inlined item, found {}", self.node_to_string(id)),
}
}
- pub fn expr(&self, id: ExprId) -> &'ast Expr {
- self.expect_expr(id.node_id())
- }
-
/// Returns the name associated with the given NodeId's AST.
pub fn name(&self, id: NodeId) -> Name {
match self.get(id) {
Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v),
Some(RootCrate) => self.forest.krate.span,
- Some(RootInlinedParent(parent)) => parent.body.span,
+ Some(RootInlinedParent(parent)) => parent.body.value.span,
Some(NotPresent) | None => {
bug!("hir::map::Map::span: id not in map: {:?}", id)
}
pub fn node_to_user_string(&self, id: NodeId) -> String {
node_id_to_string(self, id, false)
}
+
+ pub fn node_to_pretty_string(&self, id: NodeId) -> String {
+ print::to_string(self, |s| s.print_node(self.get(id)))
+ }
}
pub struct NodesMatchingSuffix<'a, 'ast:'a> {
}
}
-/// 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.
-pub fn map_decoded_item<'ast>(map: &Map<'ast>,
- ii: InlinedItem,
- ii_parent_id: NodeId)
- -> &'ast InlinedItem {
+pub fn map_decoded_body<'ast>(map: &Map<'ast>,
+ def_id: DefId,
+ body: Body,
+ parent_id: NodeId)
+ -> &'ast Body {
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(),
ii,
- ii_parent_id,
+ parent_id,
mem::replace(&mut *map.map.borrow_mut(), vec![]));
- ii.visit(&mut collector);
+ collector.visit_body(&ii.body);
*map.map.borrow_mut() = collector.map;
- ii
+ &ii.body
}
-pub trait NodePrinter {
- fn print_node(&mut self, node: &Node) -> io::Result<()>;
+/// Identical to the `PpAnn` implementation for `hir::Crate`,
+/// except it avoids creating a dependency on the whole crate.
+impl<'ast> print::PpAnn for Map<'ast> {
+ fn nested(&self, state: &mut print::State, nested: print::Nested) -> io::Result<()> {
+ match nested {
+ Nested::Item(id) => state.print_item(self.expect_item(id.id)),
+ Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
+ Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
+ Nested::Body(id) => state.print_expr(&self.body(id).value),
+ Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat)
+ }
+ }
}
-impl<'a> NodePrinter for pprust::State<'a> {
- fn print_node(&mut self, node: &Node) -> io::Result<()> {
- match *node {
+impl<'a> print::State<'a> {
+ pub fn print_node(&mut self, node: Node) -> io::Result<()> {
+ match node {
NodeItem(a) => self.print_item(&a),
NodeForeignItem(a) => self.print_foreign_item(&a),
NodeTraitItem(a) => self.print_trait_item(a),
NodeStmt(a) => self.print_stmt(&a),
NodeTy(a) => self.print_type(&a),
NodeTraitRef(a) => self.print_trait_ref(&a),
+ NodeLocal(a) |
NodePat(a) => self.print_pat(&a),
- NodeBlock(a) => self.print_block(&a),
+ NodeBlock(a) => {
+ use syntax::print::pprust::PrintState;
+
+ // containing cbox, will be closed by print-block at }
+ self.cbox(print::indent_unit)?;
+ // head-ibox, will be closed by print-block after {
+ self.ibox(0)?;
+ self.print_block(&a)
+ }
NodeLifetime(a) => self.print_lifetime(&a),
NodeVisibility(a) => self.print_visibility(&a),
NodeTyParam(_) => bug!("cannot print TyParam"),
// these cases do not carry enough information in the
// ast_map to reconstruct their full structure for pretty
// printing.
- NodeLocal(_) => bug!("cannot print isolated Local"),
NodeStructCtor(_) => bug!("cannot print isolated StructCtor"),
-
- NodeInlinedItem(_) => bug!("cannot print inlined item"),
}
}
}
}
Some(NodeTraitItem(ti)) => {
let kind = match ti.node {
- ConstTraitItem(..) => "assoc constant",
- MethodTraitItem(..) => "trait method",
- TypeTraitItem(..) => "assoc type",
+ TraitItemKind::Const(..) => "assoc constant",
+ TraitItemKind::Method(..) => "trait method",
+ TraitItemKind::Type(..) => "assoc type",
};
format!("{} {} in {}{}", kind, ti.name, path_str(), id_str)
field.name,
path_str(), id_str)
}
- Some(NodeExpr(ref expr)) => {
- format!("expr {}{}", pprust::expr_to_string(&expr), id_str)
+ Some(NodeExpr(_)) => {
+ format!("expr {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodeStmt(ref stmt)) => {
- format!("stmt {}{}", pprust::stmt_to_string(&stmt), id_str)
+ Some(NodeStmt(_)) => {
+ format!("stmt {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodeTy(ref ty)) => {
- format!("type {}{}", pprust::ty_to_string(&ty), id_str)
+ Some(NodeTy(_)) => {
+ format!("type {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodeTraitRef(ref tr)) => {
- format!("trait_ref {}{}", pprust::path_to_string(&tr.path), id_str)
+ Some(NodeTraitRef(_)) => {
+ format!("trait_ref {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodeLocal(ref pat)) => {
- format!("local {}{}", pprust::pat_to_string(&pat), id_str)
+ Some(NodeLocal(_)) => {
+ format!("local {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodePat(ref pat)) => {
- format!("pat {}{}", pprust::pat_to_string(&pat), id_str)
+ Some(NodePat(_)) => {
+ format!("pat {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodeBlock(ref block)) => {
- format!("block {}{}", pprust::block_to_string(&block), id_str)
+ Some(NodeBlock(_)) => {
+ format!("block {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeStructCtor(_)) => {
format!("struct_ctor {}{}", path_str(), id_str)
}
- Some(NodeLifetime(ref l)) => {
- format!("lifetime {}{}",
- pprust::lifetime_to_string(&l), id_str)
+ Some(NodeLifetime(_)) => {
+ format!("lifetime {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeTyParam(ref ty_param)) => {
format!("typaram {:?}{}", ty_param, id_str)
Some(NodeVisibility(ref vis)) => {
format!("visibility {:?}{}", vis, id_str)
}
- Some(NodeInlinedItem(_)) => {
- format!("inlined item {}", id_str)
- }
None => {
format!("unknown node{}", id_str)
}
pub use self::Mutability::*;
pub use self::PrimTy::*;
pub use self::Stmt_::*;
-pub use self::TraitItem_::*;
pub use self::Ty_::*;
pub use self::TyParamBound::*;
pub use self::UnOp::*;
use hir::def::Def;
use hir::def_id::DefId;
-use util::nodemap::{NodeMap, FxHashSet};
-use rustc_data_structures::fnv::FnvHashMap;
+use util::nodemap::{NodeMap, FxHashMap, FxHashSet};
-use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP};
-use syntax::codemap::{self, respan, Spanned};
+use syntax_pos::{Span, ExpnId, DUMMY_SP};
+use syntax::codemap::{self, Spanned};
use syntax::abi::Abi;
use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
write!(f,
"lifetime({}: {})",
self.id,
- print::lifetime_to_string(self))
+ print::to_string(print::NO_ANN, |s| s.print_lifetime(self)))
}
}
impl fmt::Debug for Path {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "path({})", print::path_to_string(self))
- }
-}
-
-impl fmt::Display for Path {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", print::path_to_string(self))
+ write!(f, "path({})",
+ print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
}
}
// slightly different results.
pub items: BTreeMap<NodeId, Item>,
+ pub trait_items: BTreeMap<TraitItemId, TraitItem>,
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
- pub exprs: FnvHashMap<ExprId, Expr>,
+ pub bodies: FxHashMap<BodyId, Body>,
}
impl Crate {
&self.items[&id]
}
+ pub fn trait_item(&self, id: TraitItemId) -> &TraitItem {
+ &self.trait_items[&id]
+ }
+
pub fn impl_item(&self, id: ImplItemId) -> &ImplItem {
&self.impl_items[&id]
}
visitor.visit_item(item);
}
+ for (_, trait_item) in &self.trait_items {
+ visitor.visit_trait_item(trait_item);
+ }
+
for (_, impl_item) in &self.impl_items {
visitor.visit_impl_item(impl_item);
}
}
- pub fn expr(&self, id: ExprId) -> &Expr {
- &self.exprs[&id]
+ pub fn body(&self, id: BodyId) -> &Body {
+ &self.bodies[&id]
}
}
impl fmt::Debug for Pat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "pat({}: {})", self.id, print::pat_to_string(self))
+ write!(f, "pat({}: {})", self.id,
+ print::to_string(print::NO_ANN, |s| s.print_pat(self)))
}
}
write!(f,
"stmt({}: {})",
spanned.node.id(),
- print::stmt_to_string(&spanned))
+ print::to_string(print::NO_ANN, |s| s.print_stmt(&spanned)))
}
}
UserProvided,
}
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct ExprId(NodeId);
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct BodyId {
+ pub node_id: NodeId,
+}
-impl ExprId {
- pub fn node_id(self) -> NodeId {
- self.0
+/// The body of a function or constant value.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Body {
+ pub arguments: HirVec<Arg>,
+ pub value: Expr
+}
+
+impl Body {
+ pub fn id(&self) -> BodyId {
+ BodyId {
+ node_id: self.value.id
+ }
}
}
pub attrs: ThinVec<Attribute>,
}
-impl Expr {
- pub fn expr_id(&self) -> ExprId {
- ExprId(self.id)
- }
-}
-
impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "expr({}: {})", self.id, print::expr_to_string(self))
+ write!(f, "expr({}: {})", self.id,
+ print::to_string(print::NO_ANN, |s| s.print_expr(self)))
}
}
/// A closure (for example, `move |a, b, c| {a + b + c}`).
///
/// The final span is the span of the argument block `|...|`
- ExprClosure(CaptureClause, P<FnDecl>, ExprId, Span),
+ ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span),
/// A block (`{ ... }`)
ExprBlock(P<Block>),
///
/// For example, `[1; 5]`. The first expression is the element
/// to be repeated; the second is the number of times to repeat it.
- ExprRepeat(P<Expr>, P<Expr>),
+ ExprRepeat(P<Expr>, BodyId),
}
/// Optionally `Self`-qualified value/type path or associated extension.
TypeRelative(P<Ty>, P<PathSegment>)
}
-impl fmt::Display for QPath {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", print::qpath_to_string(self))
- }
-}
-
/// Hints at the original code for a `match _ { .. }`
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum MatchSource {
pub generics: Generics,
}
+// The bodies for items are stored "out of line", in a separate
+// hashmap in the `Crate`. Here we just record the node-id of the item
+// so it can fetched later.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct TraitItemId {
+ pub node_id: NodeId,
+}
+
/// Represents an item declaration within a trait declaration,
/// possibly including a default implementation. A trait item is
/// either required (meaning it doesn't have an implementation, just a
pub id: NodeId,
pub name: Name,
pub attrs: HirVec<Attribute>,
- pub node: TraitItem_,
+ pub node: TraitItemKind,
pub span: Span,
}
+/// A trait method's body (or just argument names).
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitMethod {
+ /// No default body in the trait, just a signature.
+ Required(HirVec<Spanned<Name>>),
+
+ /// Both signature and body are provided in the trait.
+ Provided(BodyId),
+}
+
/// Represents a trait method or associated constant or type
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum TraitItem_ {
+pub enum TraitItemKind {
/// An associated constant with an optional value (otherwise `impl`s
/// must contain a value)
- ConstTraitItem(P<Ty>, Option<P<Expr>>),
+ Const(P<Ty>, Option<BodyId>),
/// A method with an optional body
- MethodTraitItem(MethodSig, Option<ExprId>),
+ Method(MethodSig, TraitMethod),
/// An associated type with (possibly empty) bounds and optional concrete
/// type
- TypeTraitItem(TyParamBounds, Option<P<Ty>>),
+ Type(TyParamBounds, Option<P<Ty>>),
}
// The bodies for items are stored "out of line", in a separate
pub enum ImplItemKind {
/// An associated constant of the given type, set to the constant result
/// of the expression
- Const(P<Ty>, P<Expr>),
+ Const(P<Ty>, BodyId),
/// A method implementation with the given signature and body
- Method(MethodSig, ExprId),
+ Method(MethodSig, BodyId),
/// An associated type
Type(P<Ty>),
}
impl fmt::Debug for Ty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "type({})", print::ty_to_string(self))
+ write!(f, "type({})",
+ print::to_string(print::NO_ANN, |s| s.print_type(self)))
}
}
/// A variable length slice (`[T]`)
TySlice(P<Ty>),
/// A fixed length array (`[T; n]`)
- TyArray(P<Ty>, P<Expr>),
+ TyArray(P<Ty>, BodyId),
/// A raw pointer (`*const T` or `*mut T`)
TyPtr(MutTy),
/// A reference (`&'a T` or `&'a mut T`)
/// An `impl TraitA+TraitB` type.
TyImplTrait(TyParamBounds),
/// Unused for now
- TyTypeof(P<Expr>),
+ TyTypeof(BodyId),
/// TyInfer means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
TyInfer,
/// represents an argument in a function header
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Arg {
- pub ty: P<Ty>,
pub pat: P<Pat>,
pub id: NodeId,
}
-/// Alternative representation for `Arg`s describing `self` parameter of methods.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum SelfKind {
- /// `self`, `mut self`
- Value(Mutability),
- /// `&'lt self`, `&'lt mut self`
- Region(Option<Lifetime>, Mutability),
- /// `self: TYPE`, `mut self: TYPE`
- Explicit(P<Ty>, Mutability),
-}
-
-pub type ExplicitSelf = Spanned<SelfKind>;
-
-impl Arg {
- pub fn to_self(&self) -> Option<ExplicitSelf> {
- if let PatKind::Binding(BindByValue(mutbl), _, name, _) = self.pat.node {
- if name.node == keywords::SelfValue.name() {
- return match self.ty.node {
- TyInfer => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
- TyRptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyInfer => {
- Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
- }
- _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi),
- SelfKind::Explicit(self.ty.clone(), mutbl)))
- }
- }
- }
- None
- }
-
- pub fn is_self(&self) -> bool {
- if let PatKind::Binding(_, _, name, _) = self.pat.node {
- name.node == keywords::SelfValue.name()
- } else {
- false
- }
- }
-}
-
/// Represents the header (not the body) of a function declaration
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct FnDecl {
- pub inputs: HirVec<Arg>,
+ pub inputs: HirVec<P<Ty>>,
pub output: FunctionRetTy,
pub variadic: bool,
}
-impl FnDecl {
- pub fn get_self(&self) -> Option<ExplicitSelf> {
- self.inputs.get(0).and_then(Arg::to_self)
- }
- pub fn has_self(&self) -> bool {
- self.inputs.get(0).map(Arg::is_self).unwrap_or(false)
- }
-}
-
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Unsafety {
Unsafe,
pub attrs: HirVec<Attribute>,
pub data: VariantData,
/// Explicit discriminant, eg `Foo = 1`
- pub disr_expr: Option<P<Expr>>,
+ pub disr_expr: Option<BodyId>,
}
pub type Variant = Spanned<Variant_>;
ItemUse(P<Path>, UseKind),
/// A `static` item
- ItemStatic(P<Ty>, Mutability, P<Expr>),
+ ItemStatic(P<Ty>, Mutability, BodyId),
/// A `const` item
- ItemConst(P<Ty>, P<Expr>),
+ ItemConst(P<Ty>, BodyId),
/// A function declaration
- ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, ExprId),
+ ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, BodyId),
/// A module
ItemMod(Mod),
/// An external module
/// A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
ItemUnion(VariantData, Generics),
/// Represents a Trait Declaration
- ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItem>),
+ ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
// Default trait implementations
///
}
}
+/// A reference from an trait to one of its associated items. This
+/// contains the item's id, naturally, but also the item's name and
+/// some other high-level details (like whether it is an associated
+/// type or method, and whether it is public). This allows other
+/// passes to find the impl they want without loading the id (which
+/// means fewer edges in the incremental compilation graph).
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct TraitItemRef {
+ pub id: TraitItemId,
+ pub name: Name,
+ pub kind: AssociatedItemKind,
+ pub span: Span,
+ pub defaultness: Defaultness,
+}
+
/// A reference from an impl to one of its associated items. This
/// contains the item's id, naturally, but also the item's name and
/// some other high-level details (like whether it is an associated
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum ForeignItem_ {
/// A foreign function
- ForeignItemFn(P<FnDecl>, Generics),
+ ForeignItemFn(P<FnDecl>, HirVec<Spanned<Name>>, Generics),
/// A foreign static item (`static ext: u8`), with optional mutability
/// (the boolean is true when mutable)
ForeignItemStatic(P<Ty>, bool),
use syntax::abi::Abi;
use syntax::ast;
use syntax::codemap::{CodeMap, Spanned};
-use syntax::parse::token::{self, BinOpToken};
use syntax::parse::lexer::comments;
use syntax::print::pp::{self, break_offset, word, space, hardbreak};
use syntax::print::pp::{Breaks, eof};
use errors;
use hir;
-use hir::{Crate, PatKind, RegionTyParamBound, SelfKind, TraitTyParamBound, TraitBoundModifier};
+use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
use std::io::{self, Write, Read};
NodePat(&'a hir::Pat),
}
+pub enum Nested {
+ Item(hir::ItemId),
+ TraitItem(hir::TraitItemId),
+ ImplItem(hir::ImplItemId),
+ Body(hir::BodyId),
+ BodyArgPat(hir::BodyId, usize)
+}
+
pub trait PpAnn {
+ fn nested(&self, _state: &mut State, _nested: Nested) -> io::Result<()> {
+ Ok(())
+ }
fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
Ok(())
}
}
}
-#[derive(Copy, Clone)]
pub struct NoAnn;
-
impl PpAnn for NoAnn {}
+pub const NO_ANN: &'static PpAnn = &NoAnn;
+impl PpAnn for hir::Crate {
+ fn nested(&self, state: &mut State, nested: Nested) -> io::Result<()> {
+ match nested {
+ Nested::Item(id) => state.print_item(self.item(id.id)),
+ Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
+ Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
+ Nested::Body(id) => state.print_expr(&self.body(id).value),
+ Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat)
+ }
+ }
+}
pub struct State<'a> {
- krate: Option<&'a Crate>,
pub s: pp::Printer<'a>,
cm: Option<&'a CodeMap>,
comments: Option<Vec<comments::Comment>>,
}
}
-pub fn rust_printer<'a>(writer: Box<Write + 'a>, krate: Option<&'a Crate>) -> State<'a> {
- static NO_ANN: NoAnn = NoAnn;
- rust_printer_annotated(writer, &NO_ANN, krate)
-}
-
-pub fn rust_printer_annotated<'a>(writer: Box<Write + 'a>,
- ann: &'a PpAnn,
- krate: Option<&'a Crate>)
- -> State<'a> {
- State {
- krate: krate,
- s: pp::mk_printer(writer, default_columns),
- cm: None,
- comments: None,
- literals: None,
- cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
- cur_cmnt: 0,
- cur_lit: 0,
- },
- boxes: Vec::new(),
- ann: ann,
- }
-}
-
#[allow(non_upper_case_globals)]
pub const indent_unit: usize = 4;
is_expanded: bool)
-> io::Result<()> {
let mut s = State::new_from_input(cm, span_diagnostic, filename, input,
- out, ann, is_expanded, Some(krate));
+ out, ann, is_expanded);
// When printing the AST, we sometimes need to inject `#[no_std]` here.
// Since you can't compile the HIR, it's not necessary.
input: &mut Read,
out: Box<Write + 'a>,
ann: &'a PpAnn,
- is_expanded: bool,
- krate: Option<&'a Crate>)
+ is_expanded: bool)
-> State<'a> {
let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic,
filename,
None
} else {
Some(lits)
- },
- krate)
+ })
}
pub fn new(cm: &'a CodeMap,
out: Box<Write + 'a>,
ann: &'a PpAnn,
comments: Option<Vec<comments::Comment>>,
- literals: Option<Vec<comments::Literal>>,
- krate: Option<&'a Crate>)
+ literals: Option<Vec<comments::Literal>>)
-> State<'a> {
State {
- krate: krate,
s: pp::mk_printer(out, default_columns),
cm: Some(cm),
comments: comments.clone(),
}
}
-pub fn to_string<F>(f: F) -> String
+pub fn to_string<F>(ann: &PpAnn, f: F) -> String
where F: FnOnce(&mut State) -> io::Result<()>
{
let mut wr = Vec::new();
{
- let mut printer = rust_printer(Box::new(&mut wr), None);
+ let mut printer = State {
+ s: pp::mk_printer(Box::new(&mut wr), default_columns),
+ cm: None,
+ comments: None,
+ literals: None,
+ cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
+ cur_cmnt: 0,
+ cur_lit: 0,
+ },
+ boxes: Vec::new(),
+ ann: ann,
+ };
f(&mut printer).unwrap();
eof(&mut printer.s).unwrap();
}
String::from_utf8(wr).unwrap()
}
-pub fn binop_to_string(op: BinOpToken) -> &'static str {
- match op {
- token::Plus => "+",
- token::Minus => "-",
- token::Star => "*",
- token::Slash => "/",
- token::Percent => "%",
- token::Caret => "^",
- token::And => "&",
- token::Or => "|",
- token::Shl => "<<",
- token::Shr => ">>",
- }
-}
-
-pub fn ty_to_string(ty: &hir::Ty) -> String {
- to_string(|s| s.print_type(ty))
-}
-
-pub fn bounds_to_string(bounds: &[hir::TyParamBound]) -> String {
- to_string(|s| s.print_bounds("", bounds))
-}
-
-pub fn pat_to_string(pat: &hir::Pat) -> String {
- to_string(|s| s.print_pat(pat))
-}
-
-pub fn arm_to_string(arm: &hir::Arm) -> String {
- to_string(|s| s.print_arm(arm))
-}
-
-pub fn expr_to_string(e: &hir::Expr) -> String {
- to_string(|s| s.print_expr(e))
-}
-
-pub fn lifetime_to_string(e: &hir::Lifetime) -> String {
- to_string(|s| s.print_lifetime(e))
-}
-
-pub fn stmt_to_string(stmt: &hir::Stmt) -> String {
- to_string(|s| s.print_stmt(stmt))
-}
-
-pub fn item_to_string(i: &hir::Item) -> String {
- to_string(|s| s.print_item(i))
-}
-
-pub fn impl_item_to_string(i: &hir::ImplItem) -> String {
- to_string(|s| s.print_impl_item(i))
-}
-
-pub fn trait_item_to_string(i: &hir::TraitItem) -> String {
- to_string(|s| s.print_trait_item(i))
-}
-
-pub fn generics_to_string(generics: &hir::Generics) -> String {
- to_string(|s| s.print_generics(generics))
-}
-
-pub fn where_clause_to_string(i: &hir::WhereClause) -> String {
- to_string(|s| s.print_where_clause(i))
-}
-
-pub fn fn_block_to_string(p: &hir::FnDecl) -> String {
- to_string(|s| s.print_fn_block_args(p))
-}
-
-pub fn path_to_string(p: &hir::Path) -> String {
- to_string(|s| s.print_path(p, false))
-}
-
-pub fn qpath_to_string(p: &hir::QPath) -> String {
- to_string(|s| s.print_qpath(p, false))
-}
-
-pub fn name_to_string(name: ast::Name) -> String {
- to_string(|s| s.print_name(name))
-}
-
-pub fn fun_to_string(decl: &hir::FnDecl,
- unsafety: hir::Unsafety,
- constness: hir::Constness,
- name: ast::Name,
- generics: &hir::Generics)
- -> String {
- to_string(|s| {
- s.head("")?;
- s.print_fn(decl,
- unsafety,
- constness,
- Abi::Rust,
- Some(name),
- generics,
- &hir::Inherited)?;
- s.end()?; // Close the head box
- s.end() // Close the outer box
+pub fn visibility_qualified(vis: &hir::Visibility, w: &str) -> String {
+ to_string(NO_ANN, |s| {
+ s.print_visibility(vis)?;
+ word(&mut s.s, w)
})
}
-pub fn block_to_string(blk: &hir::Block) -> String {
- to_string(|s| {
- // containing cbox, will be closed by print-block at }
- s.cbox(indent_unit)?;
- // head-ibox, will be closed by print-block after {
- s.ibox(0)?;
- s.print_block(blk)
- })
-}
-
-pub fn variant_to_string(var: &hir::Variant) -> String {
- to_string(|s| s.print_variant(var))
-}
-
-pub fn arg_to_string(arg: &hir::Arg) -> String {
- to_string(|s| s.print_arg(arg, false))
-}
-
-pub fn visibility_qualified(vis: &hir::Visibility, s: &str) -> String {
- match *vis {
- hir::Public => format!("pub {}", s),
- hir::Visibility::Crate => format!("pub(crate) {}", s),
- hir::Visibility::Restricted { ref path, .. } => format!("pub({}) {}", path, s),
- hir::Inherited => s.to_string(),
- }
-}
-
fn needs_parentheses(expr: &hir::Expr) -> bool {
match expr.node {
hir::ExprAssign(..) |
pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> {
self.print_inner_attributes(attrs)?;
- for item_id in &_mod.item_ids {
- self.print_item_id(item_id)?;
+ for &item_id in &_mod.item_ids {
+ self.ann.nested(self, Nested::Item(item_id))?;
}
Ok(())
}
hir::TyImplTrait(ref bounds) => {
self.print_bounds("impl ", &bounds[..])?;
}
- hir::TyArray(ref ty, ref v) => {
+ hir::TyArray(ref ty, v) => {
word(&mut self.s, "[")?;
self.print_type(&ty)?;
word(&mut self.s, "; ")?;
- self.print_expr(&v)?;
+ self.ann.nested(self, Nested::Body(v))?;
word(&mut self.s, "]")?;
}
- hir::TyTypeof(ref e) => {
+ hir::TyTypeof(e) => {
word(&mut self.s, "typeof(")?;
- self.print_expr(&e)?;
+ self.ann.nested(self, Nested::Body(e))?;
word(&mut self.s, ")")?;
}
hir::TyInfer => {
self.maybe_print_comment(item.span.lo)?;
self.print_outer_attributes(&item.attrs)?;
match item.node {
- hir::ForeignItemFn(ref decl, ref generics) => {
+ hir::ForeignItemFn(ref decl, ref arg_names, ref generics) => {
self.head("")?;
self.print_fn(decl,
hir::Unsafety::Normal,
Abi::Rust,
Some(item.name),
generics,
- &item.vis)?;
+ &item.vis,
+ arg_names,
+ None)?;
self.end()?; // end head-ibox
word(&mut self.s, ";")?;
self.end() // end the outer fn box
fn print_associated_const(&mut self,
name: ast::Name,
ty: &hir::Ty,
- default: Option<&hir::Expr>,
+ default: Option<hir::BodyId>,
vis: &hir::Visibility)
-> io::Result<()> {
word(&mut self.s, &visibility_qualified(vis, ""))?;
if let Some(expr) = default {
space(&mut self.s)?;
self.word_space("=")?;
- self.print_expr(expr)?;
+ self.ann.nested(self, Nested::Body(expr))?;
}
word(&mut self.s, ";")
}
word(&mut self.s, ";")
}
- pub fn print_item_id(&mut self, item_id: &hir::ItemId) -> io::Result<()> {
- if let Some(krate) = self.krate {
- // skip nested items if krate context was not provided
- let item = &krate.items[&item_id.id];
- self.print_item(item)
- } else {
- Ok(())
- }
- }
-
- pub fn print_expr_id(&mut self, expr_id: &hir::ExprId) -> io::Result<()> {
- if let Some(krate) = self.krate {
- let expr = &krate.exprs[expr_id];
- self.print_expr(expr)
- } else {
- Ok(())
- }
- }
-
/// Pretty-print an item
pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> {
self.hardbreak_if_not_bol()?;
self.end()?; // end inner head-block
self.end()?; // end outer head-block
}
- hir::ItemStatic(ref ty, m, ref expr) => {
+ hir::ItemStatic(ref ty, m, expr) => {
self.head(&visibility_qualified(&item.vis, "static"))?;
if m == hir::MutMutable {
self.word_space("mut")?;
self.end()?; // end the head-ibox
self.word_space("=")?;
- self.print_expr(&expr)?;
+ self.ann.nested(self, Nested::Body(expr))?;
word(&mut self.s, ";")?;
self.end()?; // end the outer cbox
}
- hir::ItemConst(ref ty, ref expr) => {
+ hir::ItemConst(ref ty, expr) => {
self.head(&visibility_qualified(&item.vis, "const"))?;
self.print_name(item.name)?;
self.word_space(":")?;
self.end()?; // end the head-ibox
self.word_space("=")?;
- self.print_expr(&expr)?;
+ self.ann.nested(self, Nested::Body(expr))?;
word(&mut self.s, ";")?;
self.end()?; // end the outer cbox
}
- hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
+ hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, body) => {
self.head("")?;
self.print_fn(decl,
unsafety,
abi,
Some(item.name),
typarams,
- &item.vis)?;
+ &item.vis,
+ &[],
+ Some(body))?;
word(&mut self.s, " ")?;
self.end()?; // need to close a box
self.end()?; // need to close a box
- self.print_expr_id(body)?;
+ self.ann.nested(self, Nested::Body(body))?;
}
hir::ItemMod(ref _mod) => {
self.head(&visibility_qualified(&item.vis, "mod"))?;
self.bopen()?;
self.print_inner_attributes(&item.attrs)?;
for impl_item in impl_items {
- self.print_impl_item_ref(impl_item)?;
+ self.ann.nested(self, Nested::ImplItem(impl_item.id))?;
}
self.bclose(item.span)?;
}
word(&mut self.s, " ")?;
self.bopen()?;
for trait_item in trait_items {
- self.print_trait_item(trait_item)?;
+ self.ann.nested(self, Nested::TraitItem(trait_item.id))?;
}
self.bclose(item.span)?;
}
match *vis {
hir::Public => self.word_nbsp("pub"),
hir::Visibility::Crate => self.word_nbsp("pub(crate)"),
- hir::Visibility::Restricted { ref path, .. } =>
- self.word_nbsp(&format!("pub({})", path)),
+ hir::Visibility::Restricted { ref path, .. } => {
+ word(&mut self.s, "pub(")?;
+ self.print_path(path, false)?;
+ self.word_nbsp(")")
+ }
hir::Inherited => Ok(()),
}
}
self.head("")?;
let generics = hir::Generics::empty();
self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?;
- match v.node.disr_expr {
- Some(ref d) => {
- space(&mut self.s)?;
- self.word_space("=")?;
- self.print_expr(&d)
- }
- _ => Ok(()),
+ if let Some(d) = v.node.disr_expr {
+ space(&mut self.s)?;
+ self.word_space("=")?;
+ self.ann.nested(self, Nested::Body(d))?;
}
+ Ok(())
}
pub fn print_method_sig(&mut self,
name: ast::Name,
m: &hir::MethodSig,
- vis: &hir::Visibility)
+ vis: &hir::Visibility,
+ arg_names: &[Spanned<ast::Name>],
+ body_id: Option<hir::BodyId>)
-> io::Result<()> {
self.print_fn(&m.decl,
m.unsafety,
m.abi,
Some(name),
&m.generics,
- vis)
+ vis,
+ arg_names,
+ body_id)
}
pub fn print_trait_item(&mut self, ti: &hir::TraitItem) -> io::Result<()> {
self.maybe_print_comment(ti.span.lo)?;
self.print_outer_attributes(&ti.attrs)?;
match ti.node {
- hir::ConstTraitItem(ref ty, ref default) => {
- self.print_associated_const(ti.name,
- &ty,
- default.as_ref().map(|expr| &**expr),
- &hir::Inherited)?;
- }
- hir::MethodTraitItem(ref sig, ref body) => {
- if body.is_some() {
- self.head("")?;
- }
- self.print_method_sig(ti.name, sig, &hir::Inherited)?;
- if let Some(ref body) = *body {
- self.nbsp()?;
- self.end()?; // need to close a box
- self.end()?; // need to close a box
- self.print_expr_id(body)?;
- } else {
- word(&mut self.s, ";")?;
- }
+ hir::TraitItemKind::Const(ref ty, default) => {
+ self.print_associated_const(ti.name, &ty, default, &hir::Inherited)?;
}
- hir::TypeTraitItem(ref bounds, ref default) => {
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref arg_names)) => {
+ self.print_method_sig(ti.name, sig, &hir::Inherited, arg_names, None)?;
+ word(&mut self.s, ";")?;
+ }
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
+ self.head("")?;
+ self.print_method_sig(ti.name, sig, &hir::Inherited, &[], Some(body))?;
+ self.nbsp()?;
+ self.end()?; // need to close a box
+ self.end()?; // need to close a box
+ self.ann.nested(self, Nested::Body(body))?;
+ }
+ hir::TraitItemKind::Type(ref bounds, ref default) => {
self.print_associated_type(ti.name,
Some(bounds),
default.as_ref().map(|ty| &**ty))?;
self.ann.post(self, NodeSubItem(ti.id))
}
- pub fn print_impl_item_ref(&mut self, item_ref: &hir::ImplItemRef) -> io::Result<()> {
- if let Some(krate) = self.krate {
- // skip nested items if krate context was not provided
- let item = &krate.impl_item(item_ref.id);
- self.print_impl_item(item)
- } else {
- Ok(())
- }
- }
-
pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> {
self.ann.pre(self, NodeSubItem(ii.id))?;
self.hardbreak_if_not_bol()?;
}
match ii.node {
- hir::ImplItemKind::Const(ref ty, ref expr) => {
- self.print_associated_const(ii.name, &ty, Some(&expr), &ii.vis)?;
+ hir::ImplItemKind::Const(ref ty, expr) => {
+ self.print_associated_const(ii.name, &ty, Some(expr), &ii.vis)?;
}
- hir::ImplItemKind::Method(ref sig, ref body) => {
+ hir::ImplItemKind::Method(ref sig, body) => {
self.head("")?;
- self.print_method_sig(ii.name, sig, &ii.vis)?;
+ self.print_method_sig(ii.name, sig, &ii.vis, &[], Some(body))?;
self.nbsp()?;
self.end()?; // need to close a box
self.end()?; // need to close a box
- self.print_expr_id(body)?;
+ self.ann.nested(self, Nested::Body(body))?;
}
hir::ImplItemKind::Type(ref ty) => {
self.print_associated_type(ii.name, None, Some(ty))?;
self.end()
}
- fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::Expr) -> io::Result<()> {
+ fn print_expr_repeat(&mut self, element: &hir::Expr, count: hir::BodyId) -> io::Result<()> {
self.ibox(indent_unit)?;
word(&mut self.s, "[")?;
self.print_expr(element)?;
self.word_space(";")?;
- self.print_expr(count)?;
+ self.ann.nested(self, Nested::Body(count))?;
word(&mut self.s, "]")?;
self.end()
}
hir::ExprArray(ref exprs) => {
self.print_expr_vec(exprs)?;
}
- hir::ExprRepeat(ref element, ref count) => {
- self.print_expr_repeat(&element, &count)?;
+ hir::ExprRepeat(ref element, count) => {
+ self.print_expr_repeat(&element, count)?;
}
hir::ExprStruct(ref qpath, ref fields, ref wth) => {
self.print_expr_struct(qpath, &fields[..], wth)?;
}
self.bclose_(expr.span, indent_unit)?;
}
- hir::ExprClosure(capture_clause, ref decl, ref body, _fn_decl_span) => {
+ hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span) => {
self.print_capture_clause(capture_clause)?;
- self.print_fn_block_args(&decl)?;
+ self.print_closure_args(&decl, body)?;
space(&mut self.s)?;
// this is a bare expression
- self.print_expr_id(body)?;
+ self.ann.nested(self, Nested::Body(body))?;
self.end()?; // need to close a box
// a box will be closed by print_expr, but we didn't want an overall
}
self.end()
}
- hir::DeclItem(ref item) => {
- self.print_item_id(item)
+ hir::DeclItem(item) => {
+ self.ann.nested(self, Nested::Item(item))
}
}
}
self.print_expr(coll)
}
- fn print_path(&mut self,
- path: &hir::Path,
- colons_before_params: bool)
- -> io::Result<()> {
+ pub fn print_path(&mut self,
+ path: &hir::Path,
+ colons_before_params: bool)
+ -> io::Result<()> {
self.maybe_print_comment(path.span.lo)?;
for (i, segment) in path.segments.iter().enumerate() {
Ok(())
}
- fn print_qpath(&mut self,
- qpath: &hir::QPath,
- colons_before_params: bool)
- -> io::Result<()> {
+ pub fn print_qpath(&mut self,
+ qpath: &hir::QPath,
+ colons_before_params: bool)
+ -> io::Result<()> {
match *qpath {
hir::QPath::Resolved(None, ref path) => {
self.print_path(path, colons_before_params)
self.end() // close enclosing cbox
}
- fn print_explicit_self(&mut self, explicit_self: &hir::ExplicitSelf) -> io::Result<()> {
- match explicit_self.node {
- SelfKind::Value(m) => {
- self.print_mutability(m)?;
- word(&mut self.s, "self")
- }
- SelfKind::Region(ref lt, m) => {
- word(&mut self.s, "&")?;
- self.print_opt_lifetime(lt)?;
- self.print_mutability(m)?;
- word(&mut self.s, "self")
- }
- SelfKind::Explicit(ref typ, m) => {
- self.print_mutability(m)?;
- word(&mut self.s, "self")?;
- self.word_space(":")?;
- self.print_type(&typ)
- }
- }
- }
-
pub fn print_fn(&mut self,
decl: &hir::FnDecl,
unsafety: hir::Unsafety,
abi: Abi,
name: Option<ast::Name>,
generics: &hir::Generics,
- vis: &hir::Visibility)
+ vis: &hir::Visibility,
+ arg_names: &[Spanned<ast::Name>],
+ body_id: Option<hir::BodyId>)
-> io::Result<()> {
self.print_fn_header_info(unsafety, constness, abi, vis)?;
self.print_name(name)?;
}
self.print_generics(generics)?;
- self.print_fn_args_and_ret(decl)?;
- self.print_where_clause(&generics.where_clause)
- }
- pub fn print_fn_args_and_ret(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
self.popen()?;
- self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?;
+ let mut i = 0;
+ // Make sure we aren't supplied *both* `arg_names` and `body_id`.
+ assert!(arg_names.is_empty() || body_id.is_none());
+ self.commasep(Inconsistent, &decl.inputs, |s, ty| {
+ s.ibox(indent_unit)?;
+ if let Some(name) = arg_names.get(i) {
+ word(&mut s.s, &name.node.as_str())?;
+ word(&mut s.s, ":")?;
+ space(&mut s.s)?;
+ } else if let Some(body_id) = body_id {
+ s.ann.nested(s, Nested::BodyArgPat(body_id, i))?;
+ word(&mut s.s, ":")?;
+ space(&mut s.s)?;
+ }
+ i += 1;
+ s.print_type(ty)?;
+ s.end()
+ })?;
if decl.variadic {
word(&mut self.s, ", ...")?;
}
self.pclose()?;
- self.print_fn_output(decl)
+ self.print_fn_output(decl)?;
+ self.print_where_clause(&generics.where_clause)
}
- pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
+ fn print_closure_args(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) -> io::Result<()> {
word(&mut self.s, "|")?;
- self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true))?;
+ let mut i = 0;
+ self.commasep(Inconsistent, &decl.inputs, |s, ty| {
+ s.ibox(indent_unit)?;
+
+ s.ann.nested(s, Nested::BodyArgPat(body_id, i))?;
+ i += 1;
+
+ if ty.node != hir::TyInfer {
+ word(&mut s.s, ":")?;
+ space(&mut s.s)?;
+ s.print_type(ty)?;
+ }
+ s.end()
+ })?;
word(&mut self.s, "|")?;
if let hir::DefaultReturn(..) = decl.output {
self.print_type(&mt.ty)
}
- pub fn print_arg(&mut self, input: &hir::Arg, is_closure: bool) -> io::Result<()> {
- self.ibox(indent_unit)?;
- match input.ty.node {
- hir::TyInfer if is_closure => self.print_pat(&input.pat)?,
- _ => {
- if let Some(eself) = input.to_self() {
- self.print_explicit_self(&eself)?;
- } else {
- let invalid = if let PatKind::Binding(_, _, name, _) = input.pat.node {
- name.node == keywords::Invalid.name()
- } else {
- false
- };
- if !invalid {
- self.print_pat(&input.pat)?;
- word(&mut self.s, ":")?;
- space(&mut self.s)?;
- }
- self.print_type(&input.ty)?;
- }
- }
- }
- self.end()
- }
-
pub fn print_fn_output(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
if let hir::DefaultReturn(..) = decl.output {
return Ok(());
abi,
name,
&generics,
- &hir::Inherited)?;
+ &hir::Inherited,
+ &[],
+ None)?;
self.end()
}
use hir::map as ast_map;
use hir;
-use hir::print as pprust;
use lint;
use hir::def::Def;
Some(ref node) => match *node {
ast_map::NodeItem(ref item) => {
match item.node {
- hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => {
- Some((fn_decl, gen, unsafety, constness, item.name, item.span))
+ hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, body) => {
+ Some((fn_decl, gen, unsafety, constness, item.name, item.span, body))
}
_ => None,
}
return;
}
}
- if let hir::ImplItemKind::Method(ref sig, _) = item.node {
+ if let hir::ImplItemKind::Method(ref sig, body) = item.node {
Some((&sig.decl,
&sig.generics,
sig.unsafety,
sig.constness,
item.name,
- item.span))
+ item.span,
+ body))
} else {
None
}
},
ast_map::NodeTraitItem(item) => {
match item.node {
- hir::MethodTraitItem(ref sig, Some(_)) => {
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
Some((&sig.decl,
&sig.generics,
sig.unsafety,
sig.constness,
item.name,
- item.span))
+ item.span,
+ body))
}
_ => None,
}
},
None => None,
};
- let (fn_decl, generics, unsafety, constness, name, span)
+ let (fn_decl, generics, unsafety, constness, name, span, body)
= node_inner.expect("expect item fn");
let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver);
let (fn_decl, generics) = rebuilder.rebuild();
self.give_expl_lifetime_param(
- err, &fn_decl, unsafety, constness, name, &generics, span);
+ err, &fn_decl, unsafety, constness, name, &generics, span, body);
}
pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
}
fn rebuild_args_ty(&self,
- inputs: &[hir::Arg],
+ inputs: &[P<hir::Ty>],
lifetime: hir::Lifetime,
anon_nums: &HashSet<u32>,
region_names: &HashSet<ast::Name>)
- -> hir::HirVec<hir::Arg> {
- let mut new_inputs = Vec::new();
- for arg in inputs {
- let new_ty = self.rebuild_arg_ty_or_output(&arg.ty, lifetime,
- anon_nums, region_names);
- let possibly_new_arg = hir::Arg {
- ty: new_ty,
- pat: arg.pat.clone(),
- id: arg.id
- };
- new_inputs.push(possibly_new_arg);
- }
- new_inputs.into()
+ -> hir::HirVec<P<hir::Ty>> {
+ inputs.iter().map(|arg_ty| {
+ self.rebuild_arg_ty_or_output(arg_ty, lifetime, anon_nums, region_names)
+ }).collect()
}
fn rebuild_output(&self, ty: &hir::FunctionRetTy,
constness: hir::Constness,
name: ast::Name,
generics: &hir::Generics,
- span: Span) {
- let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, name, generics);
- let msg = format!("consider using an explicit lifetime \
- parameter as shown: {}", suggested_fn);
+ span: Span,
+ body: hir::BodyId) {
+ let s = hir::print::to_string(&self.tcx.map, |s| {
+ use syntax::abi::Abi;
+ use syntax::print::pprust::PrintState;
+
+ s.head("")?;
+ s.print_fn(decl,
+ unsafety,
+ constness,
+ Abi::Rust,
+ Some(name),
+ generics,
+ &hir::Inherited,
+ &[],
+ Some(body))?;
+ s.end()?; // Close the head box
+ s.end() // Close the outer box
+ });
+ let msg = format!("consider using an explicit lifetime parameter as shown: {}", s);
err.span_help(span, &msg[..]);
}
#![feature(conservative_impl_trait)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
-#![cfg_attr(stage0, feature(item_like_imports))]
#![feature(libc)]
#![feature(nonzero)]
+#![feature(pub_restricted)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
pub mod middle {
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_qualif;
pub mod cstore;
pub mod dataflow;
pub mod dead;
self.with_lint_attrs(&e.attrs, |cx| {
run_lints!(cx, check_expr, late_passes, e);
hir_visit::walk_expr(cx, e);
+ run_lints!(cx, check_expr_post, late_passes, e);
})
}
}
fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId, span: Span, id: ast::NodeId) {
- let body = self.tcx.map.expr(body_id);
+ body_id: hir::BodyId, span: Span, id: ast::NodeId) {
+ let body = self.tcx.map.body(body_id);
run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
hir_visit::walk_fn(self, fk, decl, body_id, span, id);
run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
hir_visit::walk_decl(self, d);
}
- fn visit_expr_post(&mut self, e: &'tcx hir::Expr) {
- run_lints!(self, check_expr_post, late_passes, e);
- }
-
fn visit_generics(&mut self, g: &'tcx hir::Generics) {
run_lints!(self, check_generics, late_passes, g);
hir_visit::walk_generics(self, g);
_: &LateContext<'a, 'tcx>,
_: FnKind<'tcx>,
_: &'tcx hir::FnDecl,
- _: &'tcx hir::Expr,
+ _: &'tcx hir::Body,
_: Span,
_: ast::NodeId) { }
fn check_fn_post(&mut self,
_: &LateContext<'a, 'tcx>,
_: FnKind<'tcx>,
_: &'tcx hir::FnDecl,
- _: &'tcx hir::Expr,
+ _: &'tcx hir::Body,
_: Span,
_: ast::NodeId) { }
fn check_trait_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { }
+++ /dev/null
-// 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
- }
-}
use session::Session;
use session::search_paths::PathKind;
use util::nodemap::{NodeSet, DefIdMap};
+
+use std::collections::BTreeMap;
use std::path::PathBuf;
use std::rc::Rc;
use syntax::ast;
use syntax::attr;
use syntax::ext::base::SyntaxExtension;
-use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;
use rustc_back::target::Target;
use hir;
-use hir::intravisit::Visitor;
use rustc_back::PanicStrategy;
pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
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: P<hir::Expr>,
- pub const_fn_args: Vec<Option<DefId>>,
-}
-
-/// 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::Expr,
- pub const_fn_args: Vec<Option<DefId>>,
-}
-
-fn get_fn_args(decl: &hir::FnDecl) -> Vec<Option<DefId>> {
- decl.inputs.iter().map(|arg| match arg.pat.node {
- hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
- _ => None
- }).collect()
-}
-
-impl<'a> InlinedItemRef<'a> {
- pub fn from_item<'b, 'tcx>(def_id: DefId,
- item: &'a hir::Item,
- tcx: TyCtxt<'b, 'a, 'tcx>)
- -> InlinedItemRef<'a> {
- let (body, args) = match item.node {
- hir::ItemFn(ref decl, _, _, _, _, body_id) =>
- (tcx.map.expr(body_id), get_fn_args(decl)),
- hir::ItemConst(_, ref body) => (&**body, Vec::new()),
- _ => bug!("InlinedItemRef::from_item wrong kind")
- };
- InlinedItemRef {
- def_id: def_id,
- body: body,
- const_fn_args: args
- }
- }
-
- pub fn from_trait_item(def_id: DefId,
- item: &'a hir::TraitItem,
- _tcx: TyCtxt)
- -> InlinedItemRef<'a> {
- let (body, args) = match item.node {
- hir::ConstTraitItem(_, Some(ref body)) =>
- (&**body, Vec::new()),
- hir::ConstTraitItem(_, None) => {
- bug!("InlinedItemRef::from_trait_item called for const without body")
- },
- _ => bug!("InlinedItemRef::from_trait_item wrong kind")
- };
- InlinedItemRef {
- def_id: def_id,
- body: body,
- const_fn_args: args
- }
- }
-
- pub fn from_impl_item<'b, 'tcx>(def_id: DefId,
- item: &'a hir::ImplItem,
- tcx: TyCtxt<'b, 'a, 'tcx>)
- -> InlinedItemRef<'a> {
- let (body, args) = match item.node {
- hir::ImplItemKind::Method(ref sig, body_id) =>
- (tcx.map.expr(body_id), get_fn_args(&sig.decl)),
- hir::ImplItemKind::Const(_, ref body) =>
- (&**body, Vec::new()),
- _ => bug!("InlinedItemRef::from_impl_item wrong kind")
- };
- InlinedItemRef {
- def_id: def_id,
- body: body,
- const_fn_args: args
- }
- }
-
- pub fn visit<V>(&self, visitor: &mut V)
- where V: Visitor<'a>
- {
- visitor.visit_expr(&self.body);
- }
-}
-
-impl InlinedItem {
- pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
- where V: Visitor<'ast>
- {
- visitor.visit_expr(&self.body);
- }
-}
-
pub enum LoadedMacro {
MacroRules(ast::MacroDef),
ProcMacro(Rc<SyntaxExtension>),
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
// misc. metadata
- fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<(&'tcx InlinedItem, ast::NodeId)>;
- fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId>;
- fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId>;
+ fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+ -> Option<&'tcx hir::Body>;
+ fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body>;
+ fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool;
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 load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
// misc. metadata
- fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<(&'tcx InlinedItem, ast::NodeId)> {
- bug!("maybe_get_item_ast")
+ fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+ -> Option<&'tcx hir::Body> {
+ bug!("maybe_get_item_body")
}
- fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
- bug!("local_node_for_inlined_defid")
+ fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
+ bug!("item_body_nested_bodies")
}
- fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
- bug!("defid_for_inlined_node")
+ fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
+ bug!("const_is_rvalue_promotable_to_static")
}
fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
}
impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> {
+ fn nested(&self, state: &mut pprust::State, nested: pprust::Nested) -> io::Result<()> {
+ pprust::PpAnn::nested(&self.tcx.map, state, nested)
+ }
fn pre(&self,
ps: &mut pprust::State,
node: pprust::AnnNode) -> io::Result<()> {
}
}
-fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
+fn build_nodeid_to_index(body: Option<&hir::Body>,
cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> {
let mut index = NodeMap();
// into cfg itself? i.e. introduce a fn-based flow-graph in
// addition to the current block-based flow-graph, rather than
// have to put traversals like this here?
- if let Some(decl) = decl {
- add_entries_from_fn_decl(&mut index, decl, cfg.entry);
+ if let Some(body) = body {
+ add_entries_from_fn_body(&mut index, body, cfg.entry);
}
cfg.graph.each_node(|node_idx, node| {
return index;
- fn add_entries_from_fn_decl(index: &mut NodeMap<Vec<CFGIndex>>,
- decl: &hir::FnDecl,
+ /// Add mappings from the ast nodes for the formal bindings to
+ /// the entry-node in the graph.
+ fn add_entries_from_fn_body(index: &mut NodeMap<Vec<CFGIndex>>,
+ body: &hir::Body,
entry: CFGIndex) {
- //! add mappings from the ast nodes for the formal bindings to
- //! the entry-node in the graph.
+ use hir::intravisit::Visitor;
+
struct Formals<'a> {
entry: CFGIndex,
index: &'a mut NodeMap<Vec<CFGIndex>>,
}
let mut formals = Formals { entry: entry, index: index };
- intravisit::walk_fn_decl(&mut formals, decl);
- impl<'a, 'v> intravisit::Visitor<'v> for Formals<'a> {
+ for arg in &body.arguments {
+ formals.visit_pat(&arg.pat);
+ }
+ impl<'a, 'v> Visitor<'v> for Formals<'a> {
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
- panic!("should not encounter fn bodies or items")
+ intravisit::NestedVisitorMap::None
}
fn visit_pat(&mut self, p: &hir::Pat) {
impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
analysis_name: &'static str,
- decl: Option<&hir::FnDecl>,
+ body: Option<&hir::Body>,
cfg: &cfg::CFG,
oper: O,
id_range: IdRange,
let kills2 = zeroes;
let on_entry = vec![entry; num_nodes * words_per_id];
- let nodeid_to_index = build_nodeid_to_index(decl, cfg);
+ let nodeid_to_index = build_nodeid_to_index(body, cfg);
DataFlowContext {
tcx: tcx,
impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
// ^^^^^^^^^^^^^ only needed for pretty printing
- pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Expr) {
+ pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) {
//! Performs the data flow analysis.
if self.bits_per_id == 0 {
}
debug!("Dataflow result for {}:", self.analysis_name);
- debug!("{}", {
- let mut v = Vec::new();
- self.pretty_print_to(box &mut v, body).unwrap();
- String::from_utf8(v).unwrap()
- });
- }
-
- fn pretty_print_to<'b>(&self, wr: Box<io::Write + 'b>,
- body: &hir::Expr) -> io::Result<()> {
- let mut ps = pprust::rust_printer_annotated(wr, self, None);
- ps.cbox(pprust::indent_unit)?;
- ps.ibox(0)?;
- ps.print_expr(body)?;
- pp::eof(&mut ps.s)
+ debug!("{}", pprust::to_string(self, |s| {
+ s.cbox(pprust::indent_unit)?;
+ s.ibox(0)?;
+ s.print_expr(&body.value)
+ }));
}
}
self.worklist.extend(enum_def.variants.iter()
.map(|variant| variant.node.data.id()));
}
- hir::ItemTrait(.., ref trait_items) => {
- for trait_item in trait_items {
+ hir::ItemTrait(.., ref trait_item_refs) => {
+ for trait_item_ref in trait_item_refs {
+ let trait_item = self.krate.trait_item(trait_item_ref.id);
match trait_item.node {
- hir::ConstTraitItem(_, Some(_)) |
- hir::MethodTraitItem(_, Some(_)) => {
+ hir::TraitItemKind::Const(_, Some(_)) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
if has_allow_dead_code_or_lang_attr(&trait_item.attrs) {
self.worklist.push(trait_item.id);
}
}
}
+ fn visit_trait_item(&mut self, _item: &hir::TraitItem) {
+ // ignore: we are handling this in `visit_item` above
+ }
+
fn visit_impl_item(&mut self, _item: &hir::ImplItem) {
// ignore: we are handling this in `visit_item` above
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
match impl_item.node {
- hir::ImplItemKind::Const(_, ref expr) => {
+ hir::ImplItemKind::Const(_, body_id) => {
if !self.symbol_is_live(impl_item.id, None) {
self.warn_dead_code(impl_item.id, impl_item.span,
impl_item.name, "associated const");
}
- intravisit::walk_expr(self, expr)
+ self.visit_nested_body(body_id)
}
hir::ImplItemKind::Method(_, body_id) => {
if !self.symbol_is_live(impl_item.id, None) {
self.warn_dead_code(impl_item.id, impl_item.span,
impl_item.name, "method");
}
- self.visit_body(body_id)
+ self.visit_nested_body(body_id)
}
hir::ImplItemKind::Type(..) => {}
}
// Overwrite so that we don't warn the trait item itself.
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
match trait_item.node {
- hir::ConstTraitItem(_, Some(ref body)) => {
- intravisit::walk_expr(self, body)
- }
- hir::MethodTraitItem(_, Some(body_id)) => {
- self.visit_body(body_id)
+ hir::TraitItemKind::Const(_, Some(body_id)) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
+ self.visit_nested_body(body_id)
}
- hir::ConstTraitItem(_, None) |
- hir::MethodTraitItem(_, None) |
- hir::TypeTraitItem(..) => {}
+ hir::TraitItemKind::Const(_, None) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
+ hir::TraitItemKind::Type(..) => {}
}
}
}
fn calculate_type(sess: &session::Session,
ty: config::CrateType) -> DependencyList {
+ if !sess.opts.output_types.should_trans() {
+ return Vec::new();
+ }
+
match ty {
// If the global prefer_dynamic switch is turned off, first attempt
// static linkage (this can fail).
// No linkage happens with rlibs, we just needed the metadata (which we
// got long ago), so don't bother with anything.
- config::CrateTypeRlib | config::CrateTypeMetadata => return Vec::new(),
+ config::CrateTypeRlib => return Vec::new(),
// Staticlibs and cdylibs must have all static dependencies. If any fail
// to be found, we generate some nice pretty errors.
}
fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, fn_decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId, span: Span, id: ast::NodeId) {
+ body_id: hir::BodyId, span: Span, id: ast::NodeId) {
let (is_item_fn, is_unsafe_fn) = match fn_kind {
FnKind::ItemFn(_, _, unsafety, ..) =>
use syntax::attr;
use syntax::entry::EntryPointType;
use syntax_pos::Span;
-use hir::{Item, ItemFn, ImplItem};
+use hir::{Item, ItemFn, ImplItem, TraitItem};
use hir::itemlikevisit::ItemLikeVisitor;
struct EntryContext<'a, 'tcx: 'a> {
find_item(item, self, at_root);
}
+ fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem) {
+ // entry fn is never a trait item
+ }
fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) {
// entry fn is never an impl item
}
}
- pub fn walk_fn(&mut self,
- decl: &hir::FnDecl,
- body: &hir::Expr) {
- self.walk_arg_patterns(decl, body);
- self.consume_expr(body);
- }
-
- fn walk_arg_patterns(&mut self,
- decl: &hir::FnDecl,
- body: &hir::Expr) {
- for arg in &decl.inputs {
+ pub fn consume_body(&mut self, body: &hir::Body) {
+ for arg in &body.arguments {
let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));
- let fn_body_scope_r = self.tcx().node_scope_region(body.id);
+ let fn_body_scope_r = self.tcx().node_scope_region(body.value.id);
let arg_cmt = self.mc.cat_rvalue(
arg.id,
arg.pat.span,
self.walk_irrefutable_pat(arg_cmt, &arg.pat);
}
+
+ self.consume_expr(&body.value);
}
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
}
}
- hir::ExprRepeat(ref base, ref count) => {
+ hir::ExprRepeat(ref base, _) => {
self.consume_expr(&base);
- self.consume_expr(&count);
}
hir::ExprClosure(.., fn_decl_span) => {
}
impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
- fn visit_const(&mut self, item_id: ast::NodeId, expr: &'tcx hir::Expr) {
+ fn visit_const(&mut self, item_id: ast::NodeId, body: hir::BodyId) {
let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
- visitor.visit_expr(expr);
+ visitor.visit_nested_body(body);
});
}
}
}
// const, static and N in [T; N].
- fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+ fn visit_body(&mut self, body: &'tcx hir::Body) {
self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
- visitor.visit_expr(expr);
+ visitor.visit_body(body);
});
}
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
- if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
- self.visit_const(item.id, expr);
+ if let hir::TraitItemKind::Const(_, Some(body)) = item.node {
+ self.visit_const(item.id, body);
} else {
intravisit::walk_trait_item(self, item);
}
}
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
- if let hir::ImplItemKind::Const(_, ref expr) = item.node {
- self.visit_const(item.id, expr);
+ if let hir::ImplItemKind::Const(_, body) = item.node {
+ self.visit_const(item.id, body);
} else {
intravisit::walk_impl_item(self, item);
}
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, id: ast::NodeId) {
+ b: hir::BodyId, s: Span, id: ast::NodeId) {
if let FnKind::Closure(..) = fk {
span_bug!(s, "intrinsicck: closure outside of function")
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ // at present, lang items are always items, not trait items
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
// at present, lang items are always items, not impl items
}
PanicFmtLangItem, "panic_fmt", panic_fmt;
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
- ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn;
BoxFreeFnLangItem, "box_free", box_free_fn;
StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn;
use hir::Expr;
use hir;
-use hir::print::{expr_to_string, block_to_string};
use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
/// For use with `propagate_through_loop`.
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, id: NodeId) {
+ b: hir::BodyId, s: Span, id: NodeId) {
visit_fn(self, fk, fd, b, s, id);
}
fn visit_local(&mut self, l: &'tcx hir::Local) { visit_local(self, l); }
impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::OnlyBodies(&self.ir.tcx.map)
+ NestedVisitorMap::None
}
- fn visit_fn(&mut self, _: FnKind<'tcx>, _: &'tcx hir::FnDecl,
- _: hir::ExprId, _: Span, _: NodeId) {
- // do not check contents of nested fns
- }
fn visit_local(&mut self, l: &'tcx hir::Local) {
check_local(self, l);
}
fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
sp: Span,
id: ast::NodeId) {
debug!("visit_fn");
debug!("creating fn_maps: {:?}", &fn_maps as *const IrMaps);
- for arg in &decl.inputs {
+ let body = ir.tcx.map.body(body_id);
+
+ for arg in &body.arguments {
arg.pat.each_binding(|_bm, arg_id, _x, path1| {
debug!("adding argument {}", arg_id);
let name = path1.node;
clean_exit_var: fn_maps.add_variable(CleanExit)
};
- let body = ir.tcx.map.expr(body_id);
-
// compute liveness
let mut lsets = Liveness::new(&mut fn_maps, specials);
- let entry_ln = lsets.compute(body);
+ let entry_ln = lsets.compute(&body.value);
// check for various error conditions
- lsets.visit_expr(body);
+ lsets.visit_body(body);
lsets.check_ret(id, sp, fk, entry_ln, body);
- lsets.warn_about_unused_args(decl, entry_ln);
+ lsets.warn_about_unused_args(body, entry_ln);
}
fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
// effectively a return---this only occurs in `for` loops,
// where the body is really a closure.
- debug!("compute: using id for body, {}", expr_to_string(body));
+ debug!("compute: using id for body, {}", self.ir.tcx.map.node_to_pretty_string(body.id));
let exit_ln = self.s.exit_ln;
let entry_ln: LiveNode = self.with_loop_nodes(body.id, exit_ln, exit_ln, |this| {
fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
-> LiveNode {
- debug!("propagate_through_expr: {}", expr_to_string(expr));
+ debug!("propagate_through_expr: {}", self.ir.tcx.map.node_to_pretty_string(expr.id));
match expr.node {
// Interesting cases with control flow or which gen/kill
hir::ExprClosure(.., blk_id, _) => {
debug!("{} is an ExprClosure",
- expr_to_string(expr));
+ self.ir.tcx.map.node_to_pretty_string(expr.id));
/*
The next-node for a break is the successor of the entire
loop. The next-node for a continue is the top of this loop.
*/
let node = self.live_node(expr.id, expr.span);
- self.with_loop_nodes(blk_id.node_id(), succ, node, |this| {
+ self.with_loop_nodes(blk_id.node_id, succ, node, |this| {
// the construction of a closure itself is not important,
// but we have to consider the closed over variables.
self.propagate_through_exprs(exprs, succ)
}
- hir::ExprRepeat(ref element, ref count) => {
- let succ = self.propagate_through_expr(&count, succ);
- self.propagate_through_expr(&element, succ)
- }
-
hir::ExprStruct(_, ref fields, ref with_expr) => {
let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ);
fields.iter().rev().fold(succ, |succ, field| {
hir::ExprAddrOf(_, ref e) |
hir::ExprCast(ref e, _) |
hir::ExprType(ref e, _) |
- hir::ExprUnary(_, ref e) => {
+ hir::ExprUnary(_, ref e) |
+ hir::ExprRepeat(ref e, _) => {
self.propagate_through_expr(&e, succ)
}
}
}
debug!("propagate_through_loop: using id for loop body {} {}",
- expr.id, block_to_string(body));
+ expr.id, self.ir.tcx.map.node_to_pretty_string(body.id));
let cond_ln = match kind {
LoopLoop => ln,
sp: Span,
fk: FnKind,
entry_ln: LiveNode,
- body: &hir::Expr)
+ body: &hir::Body)
{
let fn_ty = if let FnKind::Closure(_) = fk {
self.ir.tcx.tables().node_id_to_type(id)
// and must outlive the *call-site* of the function.
let fn_ret =
self.ir.tcx.liberate_late_bound_regions(
- self.ir.tcx.region_maps.call_site_extent(id, body.id),
+ self.ir.tcx.region_maps.call_site_extent(id, body.value.id),
&fn_ret);
if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
}
}
- fn warn_about_unused_args(&self, decl: &hir::FnDecl, entry_ln: LiveNode) {
- for arg in &decl.inputs {
+ fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
+ for arg in &body.arguments {
arg.pat.each_binding(|_bm, p_id, sp, path1| {
let var = self.variable(p_id, sp);
// Ignore unused self.
use hir::def_id::DefId;
use hir::map as ast_map;
use infer::InferCtxt;
-use middle::const_qualif::ConstQualif;
use hir::def::{Def, CtorKind};
use ty::adjustment;
use ty::{self, Ty, TyCtxt};
};
match fn_expr.node {
- hir::ExprClosure(.., body_id, _) => body_id.node_id(),
+ hir::ExprClosure(.., body_id, _) => body_id.node_id,
_ => bug!()
}
};
span: Span,
expr_ty: Ty<'tcx>)
-> cmt<'tcx> {
- let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned()
- .unwrap_or(ConstQualif::NOT_CONST);
+ let promotable = self.tcx().rvalue_promotable_to_static.borrow().get(&id).cloned()
+ .unwrap_or(false);
// Only promote `[T; 0]` before an RFC for rvalue promotions
// is accepted.
- let qualif = match expr_ty.sty {
- ty::TyArray(_, 0) => qualif,
- _ => ConstQualif::NOT_CONST
+ let promotable = match expr_ty.sty {
+ ty::TyArray(_, 0) => true,
+ _ => promotable & false
};
// Compute maximum lifetime of this rvalue. This is 'static if
// we can promote to a constant, otherwise equal to enclosing temp
// lifetime.
- let re = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
- self.temporary_scope(id)
- } else {
+ let re = if promotable {
self.tcx().mk_region(ty::ReStatic)
+ } else {
+ self.temporary_scope(id)
};
let ret = self.cat_rvalue(id, span, re, expr_ty);
debug!("cat_rvalue_node ret {:?}", ret);
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> {
let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
*ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib ||
- *ty == config::CrateTypeProcMacro || *ty == config::CrateTypeMetadata
+ *ty == config::CrateTypeProcMacro
});
ReachableContext {
tcx: tcx,
}
Some(ast_map::NodeTraitItem(trait_method)) => {
match trait_method.node {
- hir::ConstTraitItem(_, ref default) => default.is_some(),
- hir::MethodTraitItem(_, ref body) => body.is_some(),
- hir::TypeTraitItem(..) => false,
+ hir::TraitItemKind::Const(_, ref default) => default.is_some(),
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true,
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
+ hir::TraitItemKind::Type(..) => false,
}
}
Some(ast_map::NodeImplItem(impl_item)) => {
match item.node {
hir::ItemFn(.., body) => {
if item_might_be_inlined(&item) {
- self.visit_body(body);
+ self.visit_nested_body(body);
}
}
// Reachable constants will be inlined into other crates
// unconditionally, so we need to make sure that their
// contents are also reachable.
- hir::ItemConst(_, ref init) => {
- self.visit_expr(&init);
+ hir::ItemConst(_, init) => {
+ self.visit_nested_body(init);
}
// These are normal, nothing reachable about these
}
ast_map::NodeTraitItem(trait_method) => {
match trait_method.node {
- hir::ConstTraitItem(_, None) |
- hir::MethodTraitItem(_, None) => {
+ hir::TraitItemKind::Const(_, None) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => {
// Keep going, nothing to get exported
}
- hir::ConstTraitItem(_, Some(ref body)) => {
- self.visit_expr(body);
+ hir::TraitItemKind::Const(_, Some(body_id)) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
+ self.visit_nested_body(body_id);
}
- hir::MethodTraitItem(_, Some(body_id)) => {
- self.visit_body(body_id);
- }
- hir::TypeTraitItem(..) => {}
+ hir::TraitItemKind::Type(..) => {}
}
}
ast_map::NodeImplItem(impl_item) => {
match impl_item.node {
- hir::ImplItemKind::Const(_, ref expr) => {
- self.visit_expr(&expr);
+ hir::ImplItemKind::Const(_, body) => {
+ self.visit_nested_body(body);
}
hir::ImplItemKind::Method(ref sig, body) => {
let did = self.tcx.map.get_parent_did(search_item);
if method_might_be_inlined(self.tcx, sig, impl_item, did) {
- self.visit_body(body)
+ self.visit_nested_body(body)
}
}
hir::ImplItemKind::Type(_) => {}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {}
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
// processed in visit_item above
}
fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
kind: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
sp: Span,
id: ast::NodeId) {
debug!("region::resolve_fn(id={:?}, \
visitor.cx.parent);
visitor.cx.parent = visitor.new_code_extent(
- CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id() });
+ CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
let fn_decl_scope = visitor.new_code_extent(
- CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id() });
+ CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id });
if let Some(root_id) = visitor.cx.root_id {
- visitor.region_maps.record_fn_parent(body_id.node_id(), root_id);
+ visitor.region_maps.record_fn_parent(body_id.node_id, root_id);
}
let outer_cx = visitor.cx;
let outer_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
- visitor.terminating_scopes.insert(body_id.node_id());
+ visitor.terminating_scopes.insert(body_id.node_id);
// The arguments and `self` are parented to the fn.
visitor.cx = Context {
- root_id: Some(body_id.node_id()),
+ root_id: Some(body_id.node_id),
parent: ROOT_CODE_EXTENT,
var_parent: fn_decl_scope,
};
// The body of the every fn is a root scope.
visitor.cx = Context {
- root_id: Some(body_id.node_id()),
+ root_id: Some(body_id.node_id),
parent: fn_decl_scope,
var_parent: fn_decl_scope
};
- visitor.visit_body(body_id);
+ visitor.visit_nested_body(body_id);
// Restore context we had at the start.
visitor.cx = outer_cx;
}
fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl,
- b: hir::ExprId, s: Span, n: NodeId) {
+ b: hir::BodyId, s: Span, n: NodeId) {
resolve_fn(self, fk, fd, b, s, n);
}
fn visit_arm(&mut self, a: &'ast Arm) {
use rustc_data_structures::fx::FxHashSet;
use hir;
-use hir::print::lifetime_to_string;
use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
// Items always introduce a new root scope
self.with(RootScope, |_, this| {
match item.node {
- hir::ForeignItemFn(ref decl, ref generics) => {
+ hir::ForeignItemFn(ref decl, _, ref generics) => {
this.visit_early_late(item.id, decl, generics, |this| {
intravisit::walk_foreign_item(this, item);
})
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, fn_id: ast::NodeId) {
+ b: hir::BodyId, s: Span, fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, ..) => {
self.visit_early_late(fn_id,decl, generics, |this| {
// methods in an impl can reuse label names.
let saved = replace(&mut self.labels_in_fn, vec![]);
- if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
+ if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) =
+ trait_item.node {
self.visit_early_late(
trait_item.id,
&sig.decl, &sig.generics,
// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
// if one of the label shadows a lifetime or another label.
-fn extract_labels(ctxt: &mut LifetimeContext, b: hir::ExprId) {
+fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) {
struct GatherLabels<'a> {
sess: &'a Session,
scope: Scope<'a>,
scope: ctxt.scope,
labels_in_fn: &mut ctxt.labels_in_fn,
};
- gather.visit_expr(ctxt.hir_map.expr(b));
+ gather.visit_body(ctxt.hir_map.body(b));
return;
impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
fn add_scope_and_walk_fn(&mut self,
fk: FnKind<'tcx>,
fd: &'tcx hir::FnDecl,
- fb: hir::ExprId,
+ fb: hir::BodyId,
_span: Span,
fn_id: ast::NodeId) {
match fk {
// `self.labels_in_fn`.
extract_labels(self, fb);
- self.with(FnScope { fn_id: fn_id, body_id: fb.node_id(), s: self.scope },
- |_old_scope, this| this.visit_body(fb))
+ self.with(FnScope { fn_id: fn_id, body_id: fb.node_id, s: self.scope },
+ |_old_scope, this| this.visit_nested_body(fb))
}
// FIXME(#37666) this works around a limitation in the region inferencer
probably a bug in syntax::fold");
}
- debug!("lifetime_ref={:?} id={:?} resolved to {:?} span={:?}",
- lifetime_to_string(lifetime_ref),
- lifetime_ref.id,
+ debug!("{} resolved to {:?} span={:?}",
+ self.hir_map.node_to_string(lifetime_ref.id),
def,
self.sess.codemap().span_to_string(lifetime_ref.span));
self.map.defs.insert(lifetime_ref.id, def);
debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics);
let mut constrained_by_input = ConstrainedCollector { regions: FxHashSet() };
- for arg in &decl.inputs {
- constrained_by_input.visit_ty(&arg.ty);
+ for arg_ty in &decl.inputs {
+ constrained_by_input.visit_ty(arg_ty);
}
let mut appears_in_output = AllCollector {
config::CrateTypeCdylib |
config::CrateTypeExecutable |
config::CrateTypeStaticlib => true,
- config::CrateTypeRlib |
- config::CrateTypeMetadata => false,
+ config::CrateTypeRlib => false,
}
});
if !needs_check {
match tcx.map.get(id) {
map::NodeItem(&Item { node: ItemConst(..), .. }) |
- map::NodeTraitItem(&TraitItem { node: ConstTraitItem(..), .. }) |
+ map::NodeTraitItem(&TraitItem { node: TraitItemKind::Const(..), .. }) |
map::NodeImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) => {
MirSource::Const(id)
}
Bitcode,
Assembly,
LlvmAssembly,
+ Metadata,
Object,
Exe,
DepInfo,
OutputType::Bitcode |
OutputType::Assembly |
OutputType::LlvmAssembly |
- OutputType::Object => false,
+ OutputType::Object |
+ OutputType::Metadata => false,
}
}
OutputType::Assembly => "asm",
OutputType::LlvmAssembly => "llvm-ir",
OutputType::Object => "obj",
+ OutputType::Metadata => "metadata",
OutputType::Exe => "link",
OutputType::DepInfo => "dep-info",
}
OutputType::Assembly => "s",
OutputType::LlvmAssembly => "ll",
OutputType::Object => "o",
+ OutputType::Metadata => "rmeta",
OutputType::DepInfo => "d",
OutputType::Exe => "",
}
pub fn values<'a>(&'a self) -> BTreeMapValuesIter<'a, OutputType, Option<PathBuf>> {
self.0.values()
}
+
+ // True if any of the output types require codegen or linking.
+ pub fn should_trans(&self) -> bool {
+ self.0.keys().any(|k| match *k {
+ OutputType::Bitcode |
+ OutputType::Assembly |
+ OutputType::LlvmAssembly |
+ OutputType::Object |
+ OutputType::Exe => true,
+ OutputType::Metadata |
+ OutputType::DepInfo => false,
+ })
+ }
}
CrateTypeStaticlib,
CrateTypeCdylib,
CrateTypeProcMacro,
- CrateTypeMetadata,
}
#[derive(Clone, Hash)]
let os = &sess.target.target.target_os;
let env = &sess.target.target.target_env;
let vendor = &sess.target.target.target_vendor;
+ let min_atomic_width = sess.target.target.min_atomic_width();
let max_atomic_width = sess.target.target.max_atomic_width();
let mut ret = HashSet::new();
ret.insert((Symbol::intern("target_thread_local"), None));
}
for &i in &[8, 16, 32, 64, 128] {
- if i <= max_atomic_width {
+ if i >= min_atomic_width && i <= max_atomic_width {
let s = i.to_string();
ret.insert((Symbol::intern("target_has_atomic"), Some(Symbol::intern(&s))));
if &s == wordsz {
assumed.", "[KIND=]NAME"),
opt::multi_s("", "crate-type", "Comma separated list of types of crates
for the compiler to emit",
- "[bin|lib|rlib|dylib|cdylib|staticlib|metadata]"),
+ "[bin|lib|rlib|dylib|cdylib|staticlib]"),
opt::opt_s("", "crate-name", "Specify the name of the crate being built",
"NAME"),
opt::multi_s("", "emit", "Comma separated list of types of output for \
the compiler to emit",
- "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"),
+ "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info]"),
opt::multi_s("", "print", "Comma separated list of compiler information to \
print on stdout", &print_opts.join("|")),
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
};
let unparsed_crate_types = matches.opt_strs("crate-type");
- let crate_types = parse_crate_types_from_list(unparsed_crate_types)
+ let (crate_types, emit_metadata) = parse_crate_types_from_list(unparsed_crate_types)
.unwrap_or_else(|e| early_error(error_format, &e[..]));
let mut lint_opts = vec![];
"llvm-ir" => OutputType::LlvmAssembly,
"llvm-bc" => OutputType::Bitcode,
"obj" => OutputType::Object,
+ "metadata" => OutputType::Metadata,
"link" => OutputType::Exe,
"dep-info" => OutputType::DepInfo,
part => {
}
}
};
- if output_types.is_empty() {
+ if emit_metadata {
+ output_types.insert(OutputType::Metadata, None);
+ } else if output_types.is_empty() {
output_types.insert(OutputType::Exe, None);
}
cfg)
}
-pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
+pub fn parse_crate_types_from_list(list_list: Vec<String>)
+ -> Result<(Vec<CrateType>, bool), String> {
let mut crate_types: Vec<CrateType> = Vec::new();
+ let mut emit_metadata = false;
for unparsed_crate_type in &list_list {
for part in unparsed_crate_type.split(',') {
let new_part = match part {
"cdylib" => CrateTypeCdylib,
"bin" => CrateTypeExecutable,
"proc-macro" => CrateTypeProcMacro,
- "metadata" => CrateTypeMetadata,
+ // FIXME(#38640) remove this when Cargo is fixed.
+ "metadata" => {
+ early_warn(ErrorOutputType::default(), "--crate-type=metadata is deprecated, \
+ prefer --emit=metadata");
+ emit_metadata = true;
+ CrateTypeRlib
+ }
_ => {
return Err(format!("unknown crate type: `{}`",
part));
}
}
- return Ok(crate_types);
+ return Ok((crate_types, emit_metadata));
}
pub mod nightly_options {
CrateTypeStaticlib => "staticlib".fmt(f),
CrateTypeCdylib => "cdylib".fmt(f),
CrateTypeProcMacro => "proc-macro".fmt(f),
- CrateTypeMetadata => "metadata".fmt(f),
}
}
}
/// FIXME(arielb1): why is this separate from populated_external_types?
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.
pub stability: RefCell<stability::Index<'tcx>>,
/// Caches the representation hints for struct definitions.
repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>,
- /// Maps Expr NodeId's to their constant qualification.
- pub const_qualif_map: RefCell<NodeMap<middle::const_qualif::ConstQualif>>,
+ /// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
+ pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
/// Caches CoerceUnsized kinds for impls on custom types.
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
used_trait_imports: RefCell::new(NodeSet()),
populated_external_types: 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),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
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()),
cast_kinds: RefCell::new(NodeMap()),
fragment_infos: RefCell::new(DefIdMap()),
tcx.construct_parameter_environment(
impl_item.span,
tcx.map.local_def_id(id),
- tcx.region_maps.call_site_extent(id, body.node_id()))
+ tcx.region_maps.call_site_extent(id, body.node_id))
}
}
}
Some(ast_map::NodeTraitItem(trait_item)) => {
match trait_item.node {
- hir::TypeTraitItem(..) | hir::ConstTraitItem(..) => {
+ hir::TraitItemKind::Type(..) | hir::TraitItemKind::Const(..) => {
// associated types don't have their own entry (for some reason),
// so for now just grab environment for the trait
let trait_id = tcx.map.get_parent(id);
trait_def_id,
tcx.region_maps.item_extent(id))
}
- hir::MethodTraitItem(_, ref body) => {
+ hir::TraitItemKind::Method(_, ref body) => {
// Use call-site for extent (unless this is a
// trait method with no default; then fallback
// to the method id).
- let extent = if let Some(body_id) = *body {
+ let extent = if let hir::TraitMethod::Provided(body_id) = *body {
// default impl: use call_site extent as free_id_outlive bound.
- tcx.region_maps.call_site_extent(id, body_id.node_id())
+ tcx.region_maps.call_site_extent(id, body_id.node_id)
} else {
// no default impl: use item extent as free_id_outlive bound.
tcx.region_maps.item_extent(id)
tcx.construct_parameter_environment(
item.span,
fn_def_id,
- tcx.region_maps.call_site_extent(id, body_id.node_id()))
+ tcx.region_maps.call_site_extent(id, body_id.node_id))
}
hir::ItemEnum(..) |
hir::ItemStruct(..) |
tcx.construct_parameter_environment(
expr.span,
base_def_id,
- tcx.region_maps.call_site_extent(id, body.node_id()))
+ tcx.region_maps.call_site_extent(id, body.node_id))
} else {
tcx.empty_parameter_environment()
}
}
}
- hir::ItemTrait(.., ref trait_items) => {
- for trait_item in trait_items {
+ hir::ItemTrait(.., ref trait_item_refs) => {
+ for trait_item_ref in trait_item_refs {
let assoc_item =
- self.associated_item_from_trait_item_ref(parent_def_id, trait_item);
+ self.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref);
self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
}
}
fn associated_item_from_trait_item_ref(self,
parent_def_id: DefId,
- trait_item: &hir::TraitItem)
+ trait_item_ref: &hir::TraitItemRef)
-> AssociatedItem {
- let def_id = self.map.local_def_id(trait_item.id);
-
- let (kind, has_self, has_value) = match trait_item.node {
- hir::MethodTraitItem(ref sig, ref body) => {
- (AssociatedKind::Method, sig.decl.get_self().is_some(),
- body.is_some())
- }
- hir::ConstTraitItem(_, ref value) => {
- (AssociatedKind::Const, false, value.is_some())
- }
- hir::TypeTraitItem(_, ref ty) => {
- (AssociatedKind::Type, false, ty.is_some())
+ let def_id = self.map.local_def_id(trait_item_ref.id.node_id);
+ let (kind, has_self) = match trait_item_ref.kind {
+ hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false),
+ hir::AssociatedItemKind::Method { has_self } => {
+ (ty::AssociatedKind::Method, has_self)
}
+ hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
};
AssociatedItem {
- name: trait_item.name,
+ name: trait_item_ref.name,
kind: kind,
- vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self),
- defaultness: hir::Defaultness::Default { has_value: has_value },
+ vis: Visibility::from_hir(&hir::Inherited, trait_item_ref.id.node_id, self),
+ defaultness: trait_item_ref.defaultness,
def_id: def_id,
container: TraitContainer(parent_def_id),
method_has_self_argument: has_self
let id = self.map.as_local_node_id(def_id).unwrap();
let item = self.map.expect_item(id);
let vec: Vec<_> = match item.node {
- hir::ItemTrait(.., ref trait_items) => {
- trait_items.iter()
- .map(|trait_item| trait_item.id)
- .map(|id| self.map.local_def_id(id))
- .collect()
+ hir::ItemTrait(.., ref trait_item_refs) => {
+ trait_item_refs.iter()
+ .map(|trait_item_ref| trait_item_ref.id)
+ .map(|id| self.map.local_def_id(id.node_id))
+ .collect()
}
hir::ItemImpl(.., ref impl_item_refs) => {
impl_item_refs.iter()
#[derive(Clone, Copy, Debug)]
pub struct ErrorReported;
+thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
+
+/// Read the current depth of `time()` calls. This is used to
+/// encourage indentation across threads.
+pub fn time_depth() -> usize {
+ TIME_DEPTH.with(|slot| slot.get())
+}
+
+/// Set the current depth of `time()` calls. The idea is to call
+/// `set_time_depth()` with the result from `time_depth()` in the
+/// parent thread.
+pub fn set_time_depth(depth: usize) {
+ TIME_DEPTH.with(|slot| slot.set(depth));
+}
+
pub fn time<T, F>(do_it: bool, what: &str, f: F) -> T where
F: FnOnce() -> T,
{
- thread_local!(static DEPTH: Cell<usize> = Cell::new(0));
if !do_it { return f(); }
- let old = DEPTH.with(|slot| {
+ let old = TIME_DEPTH.with(|slot| {
let r = slot.get();
slot.set(r + 1);
r
mem_string,
what);
- DEPTH.with(|slot| slot.set(old));
+ TIME_DEPTH.with(|slot| slot.set(old));
rv
}
// file
pub no_integrated_as: bool,
+ /// Don't use this field; instead use the `.min_atomic_width()` method.
+ pub min_atomic_width: Option<u64>,
+
/// Don't use this field; instead use the `.max_atomic_width()` method.
pub max_atomic_width: Option<u64>,
has_elf_tls: false,
obj_is_bitcode: false,
no_integrated_as: false,
+ min_atomic_width: None,
max_atomic_width: None,
panic_strategy: PanicStrategy::Unwind,
abi_blacklist: vec![],
}
}
+ /// Minimum integer size in bits that this target can perform atomic
+ /// operations on.
+ pub fn min_atomic_width(&self) -> u64 {
+ self.options.min_atomic_width.unwrap_or(8)
+ }
+
/// Maximum integer size in bits that this target can perform atomic
/// operations on.
pub fn max_atomic_width(&self) -> u64 {
key!(obj_is_bitcode, bool);
key!(no_integrated_as, bool);
key!(max_atomic_width, Option<u64>);
+ key!(min_atomic_width, Option<u64>);
try!(key!(panic_strategy, PanicStrategy));
key!(crt_static_default, bool);
target_option_val!(has_elf_tls);
target_option_val!(obj_is_bitcode);
target_option_val!(no_integrated_as);
+ target_option_val!(min_atomic_width);
target_option_val!(max_atomic_width);
target_option_val!(panic_strategy);
target_option_val!(crt_static_default);
move_data: &move_data::FlowedMoveData<'c, 'tcx>,
all_loans: &[Loan<'tcx>],
fn_id: ast::NodeId,
- decl: &hir::FnDecl,
- body: &hir::Expr) {
- debug!("check_loans(body id={})", body.id);
+ body: &hir::Body) {
+ debug!("check_loans(body id={})", body.value.id);
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
all_loans: all_loans,
param_env: &infcx.parameter_environment
};
- euv::ExprUseVisitor::new(&mut clcx, &infcx).walk_fn(decl, body);
+ euv::ExprUseVisitor::new(&mut clcx, &infcx).consume_body(body);
}
#[derive(PartialEq)]
pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
fn_id: NodeId,
- decl: &hir::FnDecl,
- body: &hir::Expr)
+ body: &hir::Body)
-> (Vec<Loan<'tcx>>,
move_data::MoveData<'tcx>) {
let mut glcx = GatherLoanCtxt {
bccx: bccx,
all_loans: Vec::new(),
- item_ub: bccx.tcx.region_maps.node_extent(body.id),
+ item_ub: bccx.tcx.region_maps.node_extent(body.value.id),
move_data: MoveData::new(),
move_error_collector: move_error::MoveErrorCollector::new(),
};
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
- euv::ExprUseVisitor::new(&mut glcx, &infcx).walk_fn(decl, body);
+ euv::ExprUseVisitor::new(&mut glcx, &infcx).consume_body(body);
glcx.report_potential_errors();
let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
pub fn gather_loans_in_static_initializer<'a, 'tcx>(bccx: &mut BorrowckCtxt<'a, 'tcx>,
item_id: ast::NodeId,
- expr: &'tcx hir::Expr) {
+ body: hir::BodyId) {
- debug!("gather_loans_in_static_initializer(expr={:?})", expr);
+ debug!("gather_loans_in_static_initializer(expr={:?})", body);
let mut sicx = StaticInitializerCtxt {
bccx: bccx,
item_id: item_id
};
- sicx.visit_expr(expr);
+ sicx.visit_nested_body(body);
}
use std::mem;
use std::path::Path;
-use super::super::MoveDataParamEnv;
use super::super::MirBorrowckCtxtPreDataflow;
use super::{BitDenotation, DataflowState};
impl<O: BitDenotation> DataflowState<O> {
- fn each_bit<F>(&self, ctxt: &O::Ctxt, words: &IdxSet<O::Idx>, mut f: F)
+ fn each_bit<F>(&self, words: &IdxSet<O::Idx>, mut f: F)
where F: FnMut(O::Idx) {
//! Helper for iterating over the bits in a bitvector.
- let bits_per_block = self.operator.bits_per_block(ctxt);
+ let bits_per_block = self.operator.bits_per_block();
let usize_bits: usize = mem::size_of::<usize>() * 8;
for (word_index, &word) in words.words().iter().enumerate() {
}
pub fn interpret_set<'c, P>(&self,
- ctxt: &'c O::Ctxt,
+ o: &'c O,
words: &IdxSet<O::Idx>,
render_idx: &P)
-> Vec<&'c Debug>
- where P: for <'b> Fn(&'b O::Ctxt, O::Idx) -> &'b Debug
+ where P: Fn(&O, O::Idx) -> &Debug
{
let mut v = Vec::new();
- self.each_bit(ctxt, words, |i| {
- v.push(render_idx(ctxt, i));
+ self.each_bit(words, |i| {
+ v.push(render_idx(o, i));
});
v
}
}
pub trait MirWithFlowState<'tcx> {
- type BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>;
+ type BD: BitDenotation;
fn node_id(&self) -> NodeId;
fn mir(&self) -> &Mir<'tcx>;
- fn analysis_ctxt(&self) -> &<Self::BD as BitDenotation>::Ctxt;
fn flow_state(&self) -> &DataflowState<Self::BD>;
}
impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
- where 'tcx: 'a, BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>
+ where 'tcx: 'a, BD: BitDenotation
{
type BD = BD;
fn node_id(&self) -> NodeId { self.node_id }
fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() }
- fn analysis_ctxt(&self) -> &BD::Ctxt { &self.flow_state.ctxt }
fn flow_state(&self) -> &DataflowState<Self::BD> { &self.flow_state.flow_state }
}
path: &Path,
render_idx: P)
-> io::Result<()>
- where BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>,
- P: for <'b> Fn(&'b BD::Ctxt, BD::Idx) -> &'b Debug
+ where BD: BitDenotation,
+ P: Fn(&BD, BD::Idx) -> &Debug
{
let g = Graph { mbcx: mbcx, phantom: PhantomData, render_idx: render_idx };
let mut v = Vec::new();
impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
where MWF: MirWithFlowState<'tcx>,
- P: for <'b> Fn(&'b <MWF::BD as BitDenotation>::Ctxt,
- <MWF::BD as BitDenotation>::Idx)
- -> &'b Debug,
+ P: for <'b> Fn(&'b MWF::BD, <MWF::BD as BitDenotation>::Idx) -> &'b Debug,
{
type Node = Node;
type Edge = Edge;
::rustc_mir::graphviz::write_node_label(
*n, self.mbcx.mir(), &mut v, 4,
|w| {
- let ctxt = self.mbcx.analysis_ctxt();
let flow = self.mbcx.flow_state();
- let entry_interp = flow.interpret_set(ctxt,
+ let entry_interp = flow.interpret_set(&flow.operator,
flow.sets.on_entry_set_for(i),
&self.render_idx);
chunked_present_left(w, &entry_interp[..], chunk_size)?;
entrybits=bits_to_string(entry.words(), bits_per_block))
},
|w| {
- let ctxt = self.mbcx.analysis_ctxt();
let flow = self.mbcx.flow_state();
let gen_interp =
- flow.interpret_set(ctxt, flow.sets.gen_set_for(i), &self.render_idx);
+ flow.interpret_set(&flow.operator, flow.sets.gen_set_for(i), &self.render_idx);
let kill_interp =
- flow.interpret_set(ctxt, flow.sets.kill_set_for(i), &self.render_idx);
+ flow.interpret_set(&flow.operator, flow.sets.kill_set_for(i), &self.render_idx);
chunked_present_left(w, &gen_interp[..], chunk_size)?;
let bits_per_block = flow.sets.bits_per_block();
{
use rustc_data_structures::indexed_set::{IdxSet};
use rustc_data_structures::indexed_vec::Idx;
-use super::super::gather_moves::{MoveOutIndex, MovePathIndex};
+use super::super::gather_moves::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex};
use super::super::MoveDataParamEnv;
use super::super::DropFlagState;
use super::super::drop_flag_effects_for_function_entry;
pub struct MaybeInitializedLvals<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>,
}
impl<'a, 'tcx: 'a> MaybeInitializedLvals<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
- MaybeInitializedLvals { tcx: tcx, mir: mir }
+ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>)
+ -> Self
+ {
+ MaybeInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
}
}
+impl<'a, 'tcx: 'a> HasMoveData<'tcx> for MaybeInitializedLvals<'a, 'tcx> {
+ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
+}
+
/// `MaybeUninitializedLvals` tracks all l-values that might be
/// uninitialized upon reaching a particular point in the control flow
/// for a function.
pub struct MaybeUninitializedLvals<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>,
}
impl<'a, 'tcx: 'a> MaybeUninitializedLvals<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
- MaybeUninitializedLvals { tcx: tcx, mir: mir }
+ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>)
+ -> Self
+ {
+ MaybeUninitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
}
}
+impl<'a, 'tcx: 'a> HasMoveData<'tcx> for MaybeUninitializedLvals<'a, 'tcx> {
+ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
+}
+
/// `DefinitelyInitializedLvals` tracks all l-values that are definitely
/// initialized upon reaching a particular point in the control flow
/// for a function.
pub struct DefinitelyInitializedLvals<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>,
}
impl<'a, 'tcx: 'a> DefinitelyInitializedLvals<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
- DefinitelyInitializedLvals { tcx: tcx, mir: mir }
+ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>)
+ -> Self
+ {
+ DefinitelyInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
}
}
+impl<'a, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedLvals<'a, 'tcx> {
+ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
+}
+
/// `MovingOutStatements` tracks the statements that perform moves out
/// of particular l-values. More precisely, it tracks whether the
/// *effect* of such moves (namely, the uninitialization of the
pub struct MovingOutStatements<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>,
+}
+
+impl<'a, 'tcx> HasMoveData<'tcx> for MovingOutStatements<'a, 'tcx> {
+ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
}
impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> {
impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> {
type Idx = MovePathIndex;
- type Ctxt = MoveDataParamEnv<'tcx>;
fn name() -> &'static str { "maybe_init" }
- fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize {
- ctxt.move_data.move_paths.len()
+ fn bits_per_block(&self) -> usize {
+ self.move_data().move_paths.len()
}
- fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<MovePathIndex>)
+ fn start_block_effect(&self, sets: &mut BlockSets<MovePathIndex>)
{
drop_flag_effects_for_function_entry(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
|path, s| {
assert!(s == DropFlagState::Present);
sets.on_entry.add(&path);
}
fn statement_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
idx: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: idx },
|path, s| Self::update_bits(sets, path, s)
)
}
fn terminator_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
statements_len: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: statements_len },
|path, s| Self::update_bits(sets, path, s)
)
}
fn propagate_call_return(&self,
- ctxt: &Self::Ctxt,
in_out: &mut IdxSet<MovePathIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_lval: &mir::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 1 (initialized).
- on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
- ctxt.move_data.rev_lookup.find(dest_lval),
+ on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
+ self.move_data().rev_lookup.find(dest_lval),
|mpi| { in_out.add(&mpi); });
}
}
impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> {
type Idx = MovePathIndex;
- type Ctxt = MoveDataParamEnv<'tcx>;
fn name() -> &'static str { "maybe_uninit" }
- fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize {
- ctxt.move_data.move_paths.len()
+ fn bits_per_block(&self) -> usize {
+ self.move_data().move_paths.len()
}
// sets on_entry bits for Arg lvalues
- fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<MovePathIndex>) {
+ fn start_block_effect(&self, sets: &mut BlockSets<MovePathIndex>) {
// set all bits to 1 (uninit) before gathering counterevidence
for e in sets.on_entry.words_mut() { *e = !0; }
drop_flag_effects_for_function_entry(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
|path, s| {
assert!(s == DropFlagState::Present);
sets.on_entry.remove(&path);
}
fn statement_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
idx: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: idx },
|path, s| Self::update_bits(sets, path, s)
)
}
fn terminator_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
statements_len: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: statements_len },
|path, s| Self::update_bits(sets, path, s)
)
}
fn propagate_call_return(&self,
- ctxt: &Self::Ctxt,
in_out: &mut IdxSet<MovePathIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_lval: &mir::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 0 (initialized).
- on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
- ctxt.move_data.rev_lookup.find(dest_lval),
+ on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
+ self.move_data().rev_lookup.find(dest_lval),
|mpi| { in_out.remove(&mpi); });
}
}
impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> {
type Idx = MovePathIndex;
- type Ctxt = MoveDataParamEnv<'tcx>;
fn name() -> &'static str { "definite_init" }
- fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize {
- ctxt.move_data.move_paths.len()
+ fn bits_per_block(&self) -> usize {
+ self.move_data().move_paths.len()
}
// sets on_entry bits for Arg lvalues
- fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<MovePathIndex>) {
+ fn start_block_effect(&self, sets: &mut BlockSets<MovePathIndex>) {
for e in sets.on_entry.words_mut() { *e = 0; }
drop_flag_effects_for_function_entry(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
|path, s| {
assert!(s == DropFlagState::Present);
sets.on_entry.add(&path);
}
fn statement_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
idx: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: idx },
|path, s| Self::update_bits(sets, path, s)
)
}
fn terminator_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
statements_len: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: statements_len },
|path, s| Self::update_bits(sets, path, s)
)
}
fn propagate_call_return(&self,
- ctxt: &Self::Ctxt,
in_out: &mut IdxSet<MovePathIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_lval: &mir::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 1 (initialized).
- on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
- ctxt.move_data.rev_lookup.find(dest_lval),
+ on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
+ self.move_data().rev_lookup.find(dest_lval),
|mpi| { in_out.add(&mpi); });
}
}
impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
type Idx = MoveOutIndex;
- type Ctxt = MoveDataParamEnv<'tcx>;
fn name() -> &'static str { "moving_out" }
- fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize {
- ctxt.move_data.moves.len()
+ fn bits_per_block(&self) -> usize {
+ self.move_data().moves.len()
}
- fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets<MoveOutIndex>) {
+ fn start_block_effect(&self, _sets: &mut BlockSets<MoveOutIndex>) {
// no move-statements have been executed prior to function
// execution, so this method has no effect on `_sets`.
}
fn statement_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MoveOutIndex>,
bb: mir::BasicBlock,
idx: usize) {
- let (tcx, mir, move_data) = (self.tcx, self.mir, &ctxt.move_data);
+ let (tcx, mir, move_data) = (self.tcx, self.mir, self.move_data());
let stmt = &mir[bb].statements[idx];
let loc_map = &move_data.loc_map;
let path_map = &move_data.path_map;
// here, in dataflow vector
zero_to_one(sets.gen_set.words_mut(), *move_index);
}
- let bits_per_block = self.bits_per_block(ctxt);
+ let bits_per_block = self.bits_per_block();
match stmt.kind {
mir::StatementKind::SetDiscriminant { .. } => {
span_bug!(stmt.source_info.span, "SetDiscriminant should not exist in borrowck");
}
fn terminator_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MoveOutIndex>,
bb: mir::BasicBlock,
statements_len: usize)
{
- let (mir, move_data) = (self.mir, &ctxt.move_data);
+ let (mir, move_data) = (self.mir, self.move_data());
let term = mir[bb].terminator();
let loc_map = &move_data.loc_map;
let loc = Location { block: bb, statement_index: statements_len };
debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}",
term, loc, &loc_map[loc]);
- let bits_per_block = self.bits_per_block(ctxt);
+ let bits_per_block = self.bits_per_block();
for move_index in &loc_map[loc] {
assert!(move_index.index() < bits_per_block);
zero_to_one(sets.gen_set.words_mut(), *move_index);
}
fn propagate_call_return(&self,
- ctxt: &Self::Ctxt,
in_out: &mut IdxSet<MoveOutIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_lval: &mir::Lvalue) {
- let move_data = &ctxt.move_data;
- let bits_per_block = self.bits_per_block(ctxt);
+ let move_data = self.move_data();
+ let bits_per_block = self.bits_per_block();
let path_map = &move_data.path_map;
on_lookup_result_bits(self.tcx,
use std::usize;
use super::MirBorrowckCtxtPreDataflow;
-use super::MoveDataParamEnv;
pub use self::sanity_check::sanity_check_via_rustc_peek;
pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
mod impls;
pub trait Dataflow<BD: BitDenotation> {
- fn dataflow<P>(&mut self, p: P) where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug;
+ fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug;
}
impl<'a, 'tcx: 'a, BD> Dataflow<BD> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
- where BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>> + DataflowOperator
+ where BD: BitDenotation + DataflowOperator
{
- fn dataflow<P>(&mut self, p: P) where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug {
+ fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug {
self.flow_state.build_sets();
self.pre_dataflow_instrumentation(|c,i| p(c,i)).unwrap();
self.flow_state.propagate();
}
struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O>
- where O: 'b + BitDenotation, O::Ctxt: 'a
+ where O: 'b + BitDenotation
{
builder: &'b mut DataflowAnalysis<'a, 'tcx, O>,
changed: bool,
{
let sets = &mut self.flow_state.sets.for_block(mir::START_BLOCK.index());
- self.flow_state.operator.start_block_effect(&self.ctxt, sets);
+ self.flow_state.operator.start_block_effect(sets);
}
for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
let sets = &mut self.flow_state.sets.for_block(bb.index());
for j_stmt in 0..statements.len() {
- self.flow_state.operator.statement_effect(&self.ctxt, sets, bb, j_stmt);
+ self.flow_state.operator.statement_effect(sets, bb, j_stmt);
}
if terminator.is_some() {
let stmts_len = statements.len();
- self.flow_state.operator.terminator_effect(&self.ctxt, sets, bb, stmts_len);
+ self.flow_state.operator.terminator_effect(sets, bb, stmts_len);
}
}
}
}
impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
- where BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>
+ where BD: BitDenotation
{
fn pre_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
- where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug
+ where P: Fn(&BD, BD::Idx) -> &Debug
{
if let Some(ref path_str) = self.print_preflow_to {
let path = dataflow_path(BD::name(), "preflow", path_str);
}
fn post_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
- where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug
+ where P: Fn(&BD, BD::Idx) -> &Debug
{
if let Some(ref path_str) = self.print_postflow_to {
let path = dataflow_path(BD::name(), "postflow", path_str);
}
pub struct DataflowAnalysis<'a, 'tcx: 'a, O>
- where O: BitDenotation, O::Ctxt: 'a
+ where O: BitDenotation
{
flow_state: DataflowState<O>,
mir: &'a Mir<'tcx>,
- ctxt: &'a O::Ctxt,
}
impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O>
/// Specifies what index type is used to access the bitvector.
type Idx: Idx;
- /// Specifies what, if any, separate context needs to be supplied for methods below.
- type Ctxt;
-
/// A name describing the dataflow analysis that this
/// BitDenotation is supporting. The name should be something
/// suitable for plugging in as part of a filename e.g. avoid
fn name() -> &'static str;
/// Size of each bitvector allocated for each block in the analysis.
- fn bits_per_block(&self, &Self::Ctxt) -> usize;
+ fn bits_per_block(&self) -> usize;
/// Mutates the block-sets (the flow sets for the given
/// basic block) according to the effects that have been
/// (Typically this should only modify `sets.on_entry`, since the
/// gen and kill sets should reflect the effects of *executing*
/// the start block itself.)
- fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<Self::Idx>);
+ fn start_block_effect(&self, sets: &mut BlockSets<Self::Idx>);
/// Mutates the block-sets (the flow sets for the given
/// basic block) according to the effects of evaluating statement.
/// `bb_data` is the sequence of statements identifed by `bb` in
/// the MIR.
fn statement_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<Self::Idx>,
bb: mir::BasicBlock,
idx_stmt: usize);
/// The effects applied here cannot depend on which branch the
/// terminator took.
fn terminator_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<Self::Idx>,
bb: mir::BasicBlock,
idx_term: usize);
/// kill-sets associated with each edge coming out of the basic
/// block.
fn propagate_call_return(&self,
- ctxt: &Self::Ctxt,
in_out: &mut IdxSet<Self::Idx>,
call_bb: mir::BasicBlock,
dest_bb: mir::BasicBlock,
{
pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
- ctxt: &'a D::Ctxt,
denotation: D) -> Self {
- let bits_per_block = denotation.bits_per_block(&ctxt);
+ let bits_per_block = denotation.bits_per_block();
let usize_bits = mem::size_of::<usize>() * 8;
let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits;
});
DataflowAnalysis {
- ctxt: ctxt,
mir: mir,
flow_state: DataflowState {
sets: AllSets {
// N.B.: This must be done *last*, after all other
// propagation, as documented in comment above.
self.flow_state.operator.propagate_call_return(
- &self.ctxt, in_out, bb, *dest_bb, dest_lval);
+ in_out, bb, *dest_bb, dest_lval);
self.propagate_bits_into_entry_set_for(in_out, changed, dest_bb);
}
}
use rustc_data_structures::indexed_vec::Idx;
use super::super::gather_moves::{MovePathIndex, LookupResult};
-use super::super::MoveDataParamEnv;
use super::BitDenotation;
use super::DataflowResults;
+use super::super::gather_moves::HasMoveData;
/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
mir: &Mir<'tcx>,
id: ast::NodeId,
_attributes: &[ast::Attribute],
- flow_ctxt: &O::Ctxt,
results: &DataflowResults<O>)
- where O: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>, Idx=MovePathIndex>
+ where O: BitDenotation<Idx=MovePathIndex> + HasMoveData<'tcx>
{
debug!("sanity_check_via_rustc_peek id: {:?}", id);
// FIXME: this is not DRY. Figure out way to abstract this and
// stuff, so such generalization may not be realistic.)
for bb in mir.basic_blocks().indices() {
- each_block(tcx, mir, flow_ctxt, results, bb);
+ each_block(tcx, mir, results, bb);
}
}
fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
- ctxt: &O::Ctxt,
results: &DataflowResults<O>,
bb: mir::BasicBlock) where
- O: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>, Idx=MovePathIndex>
+ O: BitDenotation<Idx=MovePathIndex> + HasMoveData<'tcx>
{
- let move_data = &ctxt.move_data;
+ let move_data = results.0.operator.move_data();
let mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = mir[bb];
let (args, span) = match is_rustc_peek(tcx, terminator) {
// reset GEN and KILL sets before emulating their effect.
for e in sets.gen_set.words_mut() { *e = 0; }
for e in sets.kill_set.words_mut() { *e = 0; }
- results.0.operator.statement_effect(ctxt, &mut sets, bb, j);
+ results.0.operator.statement_effect(&mut sets, bb, j);
sets.on_entry.union(sets.gen_set);
sets.on_entry.subtract(sets.kill_set);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::gather_moves::{MoveData, MovePathIndex, LookupResult};
+use super::gather_moves::{HasMoveData, MoveData, MovePathIndex, LookupResult};
use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use super::dataflow::{DataflowResults};
use super::{drop_flag_effects_for_location, on_all_children_bits};
param_env: param_env
};
let flow_inits =
- super::do_dataflow(tcx, mir, id, &[], &env,
- MaybeInitializedLvals::new(tcx, mir));
+ super::do_dataflow(tcx, mir, id, &[],
+ MaybeInitializedLvals::new(tcx, mir, &env),
+ |bd, p| &bd.move_data().move_paths[p]);
let flow_uninits =
- super::do_dataflow(tcx, mir, id, &[], &env,
- MaybeUninitializedLvals::new(tcx, mir));
+ super::do_dataflow(tcx, mir, id, &[],
+ MaybeUninitializedLvals::new(tcx, mir, &env),
+ |bd, p| &bd.move_data().move_paths[p]);
ElaborateDropsCtxt {
tcx: tcx,
is_cleanup: bool)
-> Vec<BasicBlock>
{
- let mut succ = succ;
let mut unwind_succ = if is_cleanup {
None
} else {
c.unwind
};
- let mut update_drop_flag = true;
+
+ let mut succ = self.new_block(
+ c, c.is_cleanup, TerminatorKind::Goto { target: succ }
+ );
+
+ // Always clear the "master" drop flag at the bottom of the
+ // ladder. This is needed because the "master" drop flag
+ // protects the ADT's discriminant, which is invalidated
+ // after the ADT is dropped.
+ self.set_drop_flag(
+ Location { block: succ, statement_index: 0 },
+ c.path,
+ DropFlagState::Absent
+ );
fields.iter().rev().enumerate().map(|(i, &(ref lv, path))| {
- let drop_block = match path {
- Some(path) => {
- debug!("drop_ladder: for std field {} ({:?})", i, lv);
-
- self.elaborated_drop_block(&DropCtxt {
- source_info: c.source_info,
- is_cleanup: is_cleanup,
- init_data: c.init_data,
- lvalue: lv,
- path: path,
- succ: succ,
- unwind: unwind_succ,
- })
- }
- None => {
- debug!("drop_ladder: for rest field {} ({:?})", i, lv);
-
- let blk = self.complete_drop(&DropCtxt {
- source_info: c.source_info,
- is_cleanup: is_cleanup,
- init_data: c.init_data,
- lvalue: lv,
- path: c.path,
- succ: succ,
- unwind: unwind_succ,
- }, update_drop_flag);
-
- // the drop flag has been updated - updating
- // it again would clobber it.
- update_drop_flag = false;
-
- blk
- }
+ succ = if let Some(path) = path {
+ debug!("drop_ladder: for std field {} ({:?})", i, lv);
+
+ self.elaborated_drop_block(&DropCtxt {
+ source_info: c.source_info,
+ is_cleanup: is_cleanup,
+ init_data: c.init_data,
+ lvalue: lv,
+ path: path,
+ succ: succ,
+ unwind: unwind_succ,
+ })
+ } else {
+ debug!("drop_ladder: for rest field {} ({:?})", i, lv);
+
+ self.complete_drop(&DropCtxt {
+ source_info: c.source_info,
+ is_cleanup: is_cleanup,
+ init_data: c.init_data,
+ lvalue: lv,
+ path: c.path,
+ succ: succ,
+ unwind: unwind_succ,
+ }, false)
};
- succ = drop_block;
unwind_succ = unwind_ladder.as_ref().map(|p| p[i]);
-
- drop_block
+ succ
}).collect()
}
pub rev_lookup: MovePathLookup<'tcx>,
}
+pub trait HasMoveData<'tcx> {
+ fn move_data(&self) -> &MoveData<'tcx>;
+}
+
#[derive(Debug)]
pub struct LocationMap<T> {
/// Location-indexed (BasicBlock for outer index, index within BB
use borrowck::BorrowckCtxt;
use syntax::ast::{self, MetaItem};
-use syntax_pos::{Span, DUMMY_SP};
-
-use rustc::hir;
-use rustc::hir::intravisit::{FnKind};
+use syntax_pos::DUMMY_SP;
use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location};
use rustc::session::Session;
use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults};
use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use self::dataflow::{DefinitelyInitializedLvals};
-use self::gather_moves::{MoveData, MovePathIndex, LookupResult};
+use self::gather_moves::{HasMoveData, MoveData, MovePathIndex, LookupResult};
+
+use std::fmt;
fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<MetaItem> {
for attr in attrs {
}
pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
- fk: FnKind,
- _decl: &hir::FnDecl,
- body: &hir::Expr,
- _sp: Span,
id: ast::NodeId,
attributes: &[ast::Attribute]) {
- match fk {
- FnKind::ItemFn(name, ..) |
- FnKind::Method(name, ..) => {
- debug!("borrowck_mir({}) UNIMPLEMENTED", name);
- }
- FnKind::Closure(_) => {
- debug!("borrowck_mir closure (body.id={}) UNIMPLEMENTED", body.id);
- }
- }
-
let tcx = bcx.tcx;
- let param_env = ty::ParameterEnvironment::for_item(tcx, id);
-
- let mir = &tcx.item_mir(tcx.map.local_def_id(id));
+ let def_id = tcx.map.local_def_id(id);
+ debug!("borrowck_mir({}) UNIMPLEMENTED", tcx.item_path_str(def_id));
+ let mir = &tcx.item_mir(def_id);
+ let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let move_data = MoveData::gather_moves(mir, tcx, ¶m_env);
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
let flow_inits =
- do_dataflow(tcx, mir, id, attributes, &mdpe, MaybeInitializedLvals::new(tcx, mir));
+ do_dataflow(tcx, mir, id, attributes, MaybeInitializedLvals::new(tcx, mir, &mdpe),
+ |bd, i| &bd.move_data().move_paths[i]);
let flow_uninits =
- do_dataflow(tcx, mir, id, attributes, &mdpe, MaybeUninitializedLvals::new(tcx, mir));
+ do_dataflow(tcx, mir, id, attributes, MaybeUninitializedLvals::new(tcx, mir, &mdpe),
+ |bd, i| &bd.move_data().move_paths[i]);
let flow_def_inits =
- do_dataflow(tcx, mir, id, attributes, &mdpe, DefinitelyInitializedLvals::new(tcx, mir));
+ do_dataflow(tcx, mir, id, attributes, DefinitelyInitializedLvals::new(tcx, mir, &mdpe),
+ |bd, i| &bd.move_data().move_paths[i]);
if has_rustc_mir_with(attributes, "rustc_peek_maybe_init").is_some() {
- dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &mdpe, &flow_inits);
+ dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &flow_inits);
}
if has_rustc_mir_with(attributes, "rustc_peek_maybe_uninit").is_some() {
- dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &mdpe, &flow_uninits);
+ dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &flow_uninits);
}
if has_rustc_mir_with(attributes, "rustc_peek_definite_init").is_some() {
- dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &mdpe, &flow_def_inits);
+ dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &flow_def_inits);
}
if has_rustc_mir_with(attributes, "stop_after_dataflow").is_some() {
bcx: bcx,
mir: mir,
node_id: id,
- move_data: mdpe.move_data,
+ move_data: &mdpe.move_data,
flow_inits: flow_inits,
flow_uninits: flow_uninits,
};
debug!("borrowck_mir done");
}
-fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mir: &Mir<'tcx>,
- node_id: ast::NodeId,
- attributes: &[ast::Attribute],
- ctxt: &BD::Ctxt,
- bd: BD) -> DataflowResults<BD>
- where BD: BitDenotation<Idx=MovePathIndex, Ctxt=MoveDataParamEnv<'tcx>> + DataflowOperator
+fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &Mir<'tcx>,
+ node_id: ast::NodeId,
+ attributes: &[ast::Attribute],
+ bd: BD,
+ p: P)
+ -> DataflowResults<BD>
+ where BD: BitDenotation<Idx=MovePathIndex> + DataflowOperator,
+ P: Fn(&BD, BD::Idx) -> &fmt::Debug
{
let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option<String> {
if let Some(item) = has_rustc_mir_with(attrs, name) {
node_id: node_id,
print_preflow_to: print_preflow_to,
print_postflow_to: print_postflow_to,
- flow_state: DataflowAnalysis::new(tcx, mir, ctxt, bd),
+ flow_state: DataflowAnalysis::new(tcx, mir, bd),
};
- mbcx.dataflow(|ctxt, i| &ctxt.move_data.move_paths[i]);
+ mbcx.dataflow(p);
mbcx.flow_state.results()
}
-pub struct MirBorrowckCtxtPreDataflow<'a, 'tcx: 'a, BD>
- where BD: BitDenotation, BD::Ctxt: 'a
+pub struct MirBorrowckCtxtPreDataflow<'a, 'tcx: 'a, BD> where BD: BitDenotation
{
node_id: ast::NodeId,
flow_state: DataflowAnalysis<'a, 'tcx, BD>,
bcx: &'b mut BorrowckCtxt<'a, 'tcx>,
mir: &'b Mir<'tcx>,
node_id: ast::NodeId,
- move_data: MoveData<'tcx>,
+ move_data: &'b MoveData<'tcx>,
flow_inits: DataflowResults<MaybeInitializedLvals<'b, 'tcx>>,
flow_uninits: DataflowResults<MaybeUninitializedLvals<'b, 'tcx>>
}
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, id: ast::NodeId) {
+ b: hir::BodyId, s: Span, id: ast::NodeId) {
match fk {
FnKind::ItemFn(..) |
FnKind::Method(..) => {
}
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
- if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
- gather_loans::gather_loans_in_static_initializer(self, ti.id, &expr);
+ if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node {
+ gather_loans::gather_loans_in_static_initializer(self, ti.id, expr);
}
intravisit::walk_trait_item(self, ti);
}
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
- if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
- gather_loans::gather_loans_in_static_initializer(self, ii.id, &expr);
+ if let hir::ImplItemKind::Const(_, expr) = ii.node {
+ gather_loans::gather_loans_in_static_initializer(self, ii.id, expr);
}
intravisit::walk_impl_item(self, ii);
}
// loan step is intended for things that have a data
// flow dependent conditions.
match item.node {
- hir::ItemStatic(.., ref ex) |
- hir::ItemConst(_, ref ex) => {
- gather_loans::gather_loans_in_static_initializer(this, item.id, &ex);
+ hir::ItemStatic(.., ex) |
+ hir::ItemConst(_, ex) => {
+ gather_loans::gather_loans_in_static_initializer(this, item.id, ex);
}
_ => { }
}
fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
sp: Span,
id: ast::NodeId,
attributes: &[ast::Attribute]) {
debug!("borrowck_fn(id={})", id);
- let body = this.tcx.map.expr(body_id);
+ let body = this.tcx.map.body(body_id);
if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) {
this.with_temp_region_map(id, |this| {
- mir::borrowck_mir(this, fk, decl, body, sp, id, attributes)
+ mir::borrowck_mir(this, id, attributes)
});
}
- let cfg = cfg::CFG::new(this.tcx, body);
+ let cfg = cfg::CFG::new(this.tcx, &body.value);
let AnalysisData { all_loans,
loans: loan_dfcx,
move_data: flowed_moves } =
- build_borrowck_dataflow_data(this, fk, decl, &cfg, body, sp, id);
+ build_borrowck_dataflow_data(this, &cfg, body, id);
move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
this.tcx,
&flowed_moves,
&all_loans[..],
id,
- decl,
body);
intravisit::walk_fn(this, fk, decl, body_id, sp, id);
}
fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
- fk: FnKind<'tcx>,
- decl: &'tcx hir::FnDecl,
cfg: &cfg::CFG,
- body: &'tcx hir::Expr,
- sp: Span,
+ body: &'tcx hir::Body,
id: ast::NodeId)
-> AnalysisData<'a, 'tcx>
{
// Check the body of fn items.
let tcx = this.tcx;
- let id_range = intravisit::compute_id_range_for_fn_body(fk, decl, body, sp, id, &tcx.map);
+ let id_range = {
+ let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.map);
+ visitor.visit_body(body);
+ visitor.result()
+ };
let (all_loans, move_data) =
- gather_loans::gather_loans_in_fn(this, id, decl, body);
+ gather_loans::gather_loans_in_fn(this, id, body);
let mut loan_dfcx =
DataFlowContext::new(this.tcx,
"borrowck",
- Some(decl),
+ Some(body),
cfg,
LoanDataFlowOperator,
id_range,
this.tcx,
cfg,
id_range,
- decl,
body);
AnalysisData { all_loans: all_loans,
}
};
- let body = tcx.map.expr(fn_parts.body);
+ let body = tcx.map.body(fn_parts.body);
let dataflow_data = build_borrowck_dataflow_data(&mut bccx,
- fn_parts.kind,
- &fn_parts.decl,
cfg,
body,
- fn_parts.span,
fn_parts.id);
(bccx, dataflow_data)
match tcx.map.get(closure_id) {
hir_map::NodeExpr(expr) => match expr.node {
hir::ExprClosure(.., body_id, _) => {
- body_id.node_id()
+ body_id.node_id
}
_ => {
bug!("encountered non-closure id: {}", closure_id)
if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
if let Categorization::Local(local_id) = inner_cmt.cat {
let parent = self.tcx.map.get_parent_node(local_id);
- let opt_fn_decl = FnLikeNode::from_node(self.tcx.map.get(parent))
- .map(|fn_like| fn_like.decl());
- if let Some(fn_decl) = opt_fn_decl {
- if let Some(ref arg) = fn_decl.inputs.iter()
- .find(|ref arg| arg.pat.id == local_id) {
+ if let Some(fn_like) = FnLikeNode::from_node(self.tcx.map.get(parent)) {
+ if let Some(i) = self.tcx.map.body(fn_like.body()).arguments.iter()
+ .position(|arg| arg.pat.id == local_id) {
+ let arg_ty = &fn_like.decl().inputs[i];
if let hir::TyRptr(
opt_lifetime,
hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) =
- arg.ty.node {
+ arg_ty.node {
if let Some(lifetime) = opt_lifetime {
if let Ok(snippet) = self.tcx.sess.codemap()
.span_to_snippet(ty.span) {
if let Ok(lifetime_snippet) = self.tcx.sess.codemap()
.span_to_snippet(lifetime.span) {
- db.span_label(arg.ty.span,
+ db.span_label(arg_ty.span,
&format!("use `&{} mut {}` \
here to make mutable",
lifetime_snippet,
}
}
else if let Ok(snippet) = self.tcx.sess.codemap()
- .span_to_snippet(arg.ty.span) {
+ .span_to_snippet(arg_ty.span) {
if snippet.starts_with("&") {
- db.span_label(arg.ty.span,
+ db.span_label(arg_ty.span,
&format!("use `{}` here to make mutable",
snippet.replace("&", "&mut ")));
}
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cfg: &cfg::CFG,
id_range: IdRange,
- decl: &hir::FnDecl,
- body: &hir::Expr)
+ body: &hir::Body)
-> FlowedMoveData<'a, 'tcx> {
let mut dfcx_moves =
DataFlowContext::new(tcx,
"flowed_move_data_moves",
- Some(decl),
+ Some(body),
cfg,
MoveDataFlowOperator,
id_range,
let mut dfcx_assign =
DataFlowContext::new(tcx,
"flowed_move_data_assigns",
- Some(decl),
+ Some(body),
cfg,
AssignDataFlowOperator,
id_range,
use rustc::hir::def::*;
use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
-use rustc::hir::print::pat_to_string;
use rustc::hir::{self, Pat, PatKind};
use rustc_back::slice;
impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::None
- }
-
- fn visit_expr(&mut self, _expr: &'tcx hir::Expr) {
- return // const, static and N in [T; N] - shouldn't contain anything
- }
-
- fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
- if let hir::ConstTraitItem(..) = item.node {
- return // nothing worth match checking in a constant
- } else {
- intravisit::walk_trait_item(self, item);
- }
- }
-
- fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
- if let hir::ImplItemKind::Const(..) = item.node {
- return // nothing worth match checking in a constant
- } else {
- intravisit::walk_impl_item(self, item);
- }
+ NestedVisitorMap::OnlyBodies(&self.tcx.map)
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, id: ast::NodeId) {
- if let FnKind::Closure(..) = fk {
- span_bug!(s, "check_match: closure outside of function")
- }
+ b: hir::BodyId, s: Span, id: ast::NodeId) {
+ intravisit::walk_fn(self, fk, fd, b, s, id);
MatchVisitor {
tcx: self.tcx,
param_env: &ty::ParameterEnvironment::for_item(self.tcx, id)
- }.visit_fn(fk, fd, b, s, id);
+ }.visit_body(self.tcx.map.body(b));
}
}
impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::OnlyBodies(&self.tcx.map)
+ NestedVisitorMap::None
}
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
self.check_patterns(false, slice::ref_slice(&loc.pat));
}
- fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, n: ast::NodeId) {
- intravisit::walk_fn(self, fk, fd, b, s, n);
+ fn visit_body(&mut self, body: &'tcx hir::Body) {
+ intravisit::walk_body(self, body);
- for input in &fd.inputs {
- self.check_irrefutable(&input.pat, true);
- self.check_patterns(false, slice::ref_slice(&input.pat));
+ for arg in &body.arguments {
+ self.check_irrefutable(&arg.pat, true);
+ self.check_patterns(false, slice::ref_slice(&arg.pat));
}
}
}
Useful => bug!()
};
- let pattern_string = pat_to_string(witness[0].single_pattern());
+ let pattern_string = hir::print::to_string(&self.tcx.map, |s| {
+ s.print_pat(witness[0].single_pattern())
+ });
let mut diag = struct_span_err!(
self.tcx.sess, pat.span, E0005,
"refutable pattern in {}: `{}` not covered",
},
_ => bug!(),
};
- let pattern_string = pat_to_string(witness);
+ let pattern_string = hir::print::to_string(&cx.tcx.map, |s| {
+ s.print_pat(witness)
+ });
struct_span_err!(cx.tcx.sess, sp, E0297,
"refutable pattern in `for` loop binding: \
`{}` not covered",
},
_ => {
let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
- pat_to_string(w)
+ hir::print::to_string(&cx.tcx.map, |s| s.print_pat(w))
}).collect();
const LIMIT: usize = 3;
let joined_patterns = match pattern_strings.len() {
E0306: r##"
-In an array literal `[x; N]`, `N` is the number of elements in the array. This
+In an array type `[T; N]`, `N` is the number of elements in the array. This
must be an unsigned integer. Erroneous code example:
```compile_fail,E0306
-let x = [0i32; true]; // error: expected positive integer for repeat count,
- // found boolean
+const X: [i32; true] = [0]; // error: expected `usize` for array length,
+ // found boolean
```
Working example:
```
-let x = [0i32; 2];
+const X: [i32; 1] = [0];
```
"##,
}
use rustc::hir::map as ast_map;
use rustc::hir::map::blocks::FnLikeNode;
-use rustc::middle::cstore::InlinedItem;
use rustc::traits;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
variant_def: DefId)
-> Option<&'tcx Expr> {
- fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
- -> Option<&'a Expr> {
+ let variant_expr = |variants: &'tcx [hir::Variant], id: ast::NodeId |
+ -> Option<&'tcx Expr> {
for variant in variants {
if variant.node.data.id() == id {
- return variant.node.disr_expr.as_ref().map(|e| &**e);
+ return variant.node.disr_expr.map(|e| {
+ &tcx.map.body(e).value
+ });
}
}
None
- }
+ };
if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
let enum_node_id = tcx.map.get_parent(variant_node_id);
match tcx.map.find(node_id) {
None => None,
Some(ast_map::NodeItem(it)) => match it.node {
- hir::ItemConst(ref ty, ref const_expr) => {
- Some((&const_expr, tcx.ast_ty_to_prim_ty(ty)))
+ hir::ItemConst(ref ty, body) => {
+ Some((&tcx.map.body(body).value,
+ tcx.ast_ty_to_prim_ty(ty)))
}
_ => None
},
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
- hir::ConstTraitItem(ref ty, ref expr_option) => {
+ hir::TraitItemKind::Const(ref ty, default) => {
if let Some(substs) = substs {
// If we have a trait item and the substitutions for it,
// `resolve_trait_associated_const` will select an impl
// or the default.
let trait_id = tcx.map.get_parent(node_id);
let trait_id = tcx.map.local_def_id(trait_id);
- let default_value = expr_option.as_ref()
- .map(|expr| (&**expr, tcx.ast_ty_to_prim_ty(ty)));
+ let default_value = default.map(|body| {
+ (&tcx.map.body(body).value,
+ tcx.ast_ty_to_prim_ty(ty))
+ });
resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
} else {
// Technically, without knowing anything about the
_ => None
},
Some(ast_map::NodeImplItem(ii)) => match ii.node {
- hir::ImplItemKind::Const(ref ty, ref expr) => {
- Some((&expr, tcx.ast_ty_to_prim_ty(ty)))
+ hir::ImplItemKind::Const(ref ty, body) => {
+ Some((&tcx.map.body(body).value,
+ tcx.ast_ty_to_prim_ty(ty)))
}
_ => None
},
Some(_) => None
}
} else {
- match tcx.extern_const_statics.borrow().get(&def_id) {
- Some(&None) => return None,
- Some(&Some((expr_id, ty))) => {
- return Some((tcx.map.expect_expr(expr_id), ty));
- }
- None => {}
- }
- let mut used_substs = false;
- let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
- Some((&InlinedItem { body: ref const_expr, .. }, _)) => {
- Some((&**const_expr, Some(tcx.sess.cstore.item_type(tcx, def_id))))
- }
- _ => None
- };
- let expr_ty = match tcx.sess.cstore.describe_def(def_id) {
+ let expr_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
+ (&body.value, Some(tcx.sess.cstore.item_type(tcx, def_id)))
+ });
+ match tcx.sess.cstore.describe_def(def_id) {
Some(Def::AssociatedConst(_)) => {
let trait_id = tcx.sess.cstore.trait_of_item(def_id);
// As mentioned in the comments above for in-crate
// trait-associated const if the caller gives us the
// substitutions for the reference to it.
if let Some(trait_id) = trait_id {
- used_substs = true;
-
if let Some(substs) = substs {
resolve_trait_associated_const(tcx, def_id, expr_ty, trait_id, substs)
} else {
},
Some(Def::Const(..)) => expr_ty,
_ => 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>,
- def_id: DefId)
- -> 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>>
+fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+ -> Option<&'tcx hir::Body>
{
- let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
- node_id
- } else {
- if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
- if let ast_map::NodeInlinedItem(ii) = tcx.map.get(fn_id) {
- return Some(ConstFnNode::Inlined(ii));
+ if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+ FnLikeNode::from_node(tcx.map.get(node_id)).and_then(|fn_like| {
+ if fn_like.constness() == hir::Constness::Const {
+ Some(tcx.map.body(fn_like.body()))
} else {
- bug!("Got const fn from external crate, but it's not inlined")
+ None
}
+ })
+ } else {
+ if tcx.sess.cstore.is_const_fn(def_id) {
+ tcx.sess.cstore.maybe_get_item_body(tcx, def_id)
} else {
- return None;
+ 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 {
- None
}
}
Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
callee => signal!(e, CallOn(callee)),
};
- let (arg_defs, body_id) = match lookup_const_fn_by_id(tcx, did) {
- Some(ConstFnNode::Inlined(ii)) => (ii.const_fn_args.clone(), ii.body.expr_id()),
- Some(ConstFnNode::Local(fn_like)) =>
- (fn_like.decl().inputs.iter()
- .map(|arg| match arg.pat.node {
- hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
- _ => None
- }).collect(),
- fn_like.body()),
+ let body = match lookup_const_fn_by_id(tcx, did) {
+ Some(body) => body,
None => signal!(e, NonConstPath),
};
- let result = tcx.map.expr(body_id);
+
+ let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
+ hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
+ _ => None
+ }).collect::<Vec<_>>();
assert_eq!(arg_defs.len(), args.len());
let mut call_args = DefIdMap();
}
}
debug!("const call({:?})", call_args);
- eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
+ eval_const_expr_partial(tcx, &body.value, ty_hint, Some(&call_args))?
},
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
Ok(val) => val,
}
}
hir::ExprArray(ref v) => Array(e.id, v.len() as u64),
- hir::ExprRepeat(_, ref n) => {
+ hir::ExprRepeat(_, n) => {
let len_hint = ty_hint.checked_or(tcx.types.usize);
+ let n = &tcx.map.body(n).value;
Repeat(
e.id,
- match eval_const_expr_partial(tcx, &n, len_hint, fn_args)? {
+ match eval_const_expr_partial(tcx, n, len_hint, fn_args)? {
Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
Integral(_) => signal!(e, RepeatCountNotNatural),
_ => signal!(e, RepeatCountNotInt),
if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
if let Def::Local(..) = path.def {
- diag.note(&format!("`{}` is a variable", path));
+ diag.note(&format!("`{}` is a variable",
+ tcx.map.node_to_pretty_string(count_expr.id)));
}
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
Some(ref n) if *n == "rlib" => {
Some(config::CrateTypeRlib)
}
- Some(ref n) if *n == "metadata" => {
- Some(config::CrateTypeMetadata)
- }
Some(ref n) if *n == "dylib" => {
Some(config::CrateTypeDylib)
}
control.after_hir_lowering.stop = Compilation::Stop;
}
- if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) {
+ if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
+ i == OutputType::Metadata) {
control.after_llvm.stop = Compilation::Stop;
}
use std::str::FromStr;
use rustc::hir::map as hir_map;
-use rustc::hir::map::{blocks, NodePrinter};
+use rustc::hir::map::blocks;
use rustc::hir;
use rustc::hir::print as pprust_hir;
}
impl<'ast> pprust::PpAnn for NoAnn<'ast> {}
-impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {}
+impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {
+ fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+ -> io::Result<()> {
+ if let Some(ref map) = self.ast_map {
+ pprust_hir::PpAnn::nested(map, state, nested)
+ } else {
+ Ok(())
+ }
+ }
+}
struct IdentifiedAnnotation<'ast> {
sess: &'ast Session,
}
impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> {
+ fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+ -> io::Result<()> {
+ if let Some(ref map) = self.ast_map {
+ pprust_hir::PpAnn::nested(map, state, nested)
+ } else {
+ Ok(())
+ }
+ }
fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
match node {
pprust_hir::NodeExpr(_) => s.popen(),
}
impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
+ fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+ -> io::Result<()> {
+ pprust_hir::PpAnn::nested(&self.tcx.map, state, nested)
+ }
fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
match node {
pprust_hir::NodeExpr(_) => s.popen(),
let cfg = match code {
blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr),
blocks::Code::FnLike(fn_like) => {
- let body = tcx.map.expr(fn_like.body());
- cfg::CFG::new(tcx, body)
+ let body = tcx.map.body(fn_like.body());
+ cfg::CFG::new(tcx, &body.value)
},
};
let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
&mut rdr,
box out,
annotation.pp_ann(),
- true,
- Some(ast_map.krate()));
+ true);
for node_id in uii.all_matching_node_ids(ast_map) {
let node = ast_map.get(node_id);
- pp_state.print_node(&node)?;
+ pp_state.print_node(node)?;
pp::space(&mut pp_state.s)?;
let path = annotation.node_path(node_id)
.expect("--unpretty missing node paths");
self.process_attrs(item.id, &item.attrs);
}
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+ self.process_attrs(trait_item.id, &trait_item.attrs);
+ }
+
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.process_attrs(impl_item.id, &impl_item.attrs);
}
visit::walk_item(self, item);
}
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+ self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item));
+ visit::walk_trait_item(self, trait_item);
+ }
+
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
visit::walk_impl_item(self, impl_item);
}
-
- fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
- self.calculate_node_id(item.id, |v| v.visit_foreign_item(item));
- visit::walk_foreign_item(self, item);
- }
}
SawLifetimeDef(usize),
SawMod,
- SawForeignItem,
+ SawForeignItem(SawForeignItemComponent),
SawItem(SawItemComponent),
SawTy(SawTyComponent),
+ SawFnDecl(bool),
SawGenerics,
SawTraitItem(SawTraitOrImplItemComponent),
SawImplItem(SawTraitOrImplItemComponent),
SawStructField,
- SawVariant,
+ SawVariant(bool),
SawQPath,
SawPathSegment,
SawPathParameters,
SawItemConst,
SawItemFn(Unsafety, Constness, Abi),
SawItemMod,
- SawItemForeignMod,
+ SawItemForeignMod(Abi),
SawItemTy,
SawItemEnum,
SawItemStruct,
ItemConst(..) =>SawItemConst,
ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi),
ItemMod(..) => SawItemMod,
- ItemForeignMod(..) => SawItemForeignMod,
+ ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi),
ItemTy(..) => SawItemTy,
ItemEnum(..) => SawItemEnum,
ItemStruct(..) => SawItemStruct,
}
}
+#[derive(Hash)]
+enum SawForeignItemComponent {
+ Static { mutable: bool },
+ Fn,
+}
+
#[derive(Hash)]
enum SawPatComponent {
SawPatWild,
SawTraitOrImplItemType
}
-fn saw_trait_item(ti: &TraitItem_) -> SawTraitOrImplItemComponent {
+fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent {
match *ti {
- ConstTraitItem(..) => SawTraitOrImplItemConst,
- MethodTraitItem(ref sig, ref body) =>
- SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, body.is_some()),
- TypeTraitItem(..) => SawTraitOrImplItemType
+ TraitItemKind::Const(..) => SawTraitOrImplItemConst,
+ TraitItemKind::Method(ref sig, TraitMethod::Required(_)) =>
+ SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false),
+ TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) =>
+ SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
+ TraitItemKind::Type(..) => SawTraitOrImplItemType
}
}
g: &'tcx Generics,
item_id: NodeId) {
debug!("visit_variant: st={:?}", self.st);
- SawVariant.hash(self.st);
+ SawVariant(v.node.disr_expr.is_some()).hash(self.st);
hash_attrs!(self, &v.node.attrs);
visit::walk_variant(self, v, g, item_id)
}
// implicitly hashing the discriminant of SawExprComponent.
hash_span!(self, ex.span, force_span);
hash_attrs!(self, &ex.attrs);
- visit::walk_expr(self, ex)
+
+ // Always hash nested constant bodies (e.g. n in `[x; n]`).
+ let hash_bodies = self.hash_bodies;
+ self.hash_bodies = true;
+ visit::walk_expr(self, ex);
+ self.hash_bodies = hash_bodies;
}
fn visit_stmt(&mut self, s: &'tcx Stmt) {
fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {
debug!("visit_foreign_item: st={:?}", self.st);
- SawForeignItem.hash(self.st);
+ match i.node {
+ ForeignItemFn(..) => {
+ SawForeignItem(SawForeignItemComponent::Fn)
+ }
+ ForeignItemStatic(_, mutable) => {
+ SawForeignItem(SawForeignItemComponent::Static {
+ mutable: mutable
+ })
+ }
+ }.hash(self.st);
+
hash_span!(self, i.span);
hash_attrs!(self, &i.attrs);
visit::walk_foreign_item(self, i)
debug!("visit_ty: st={:?}", self.st);
SawTy(saw_ty(&t.node)).hash(self.st);
hash_span!(self, t.span);
- visit::walk_ty(self, t)
+
+ // Always hash nested constant bodies (e.g. N in `[T; N]`).
+ let hash_bodies = self.hash_bodies;
+ self.hash_bodies = true;
+ visit::walk_ty(self, t);
+ self.hash_bodies = hash_bodies;
}
fn visit_generics(&mut self, g: &'tcx Generics) {
visit::walk_generics(self, g)
}
+ fn visit_fn_decl(&mut self, fd: &'tcx FnDecl) {
+ debug!("visit_fn_decl: st={:?}", self.st);
+ SawFnDecl(fd.variadic).hash(self.st);
+ visit::walk_fn_decl(self, fd)
+ }
+
fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
debug!("visit_trait_item: st={:?}", self.st);
// These fields are handled separately:
exported_macros: _,
items: _,
+ trait_items: _,
impl_items: _,
- exprs: _,
+ bodies: _,
} = *krate;
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
cx: &LateContext,
fk: FnKind,
_: &hir::FnDecl,
- _: &hir::Expr,
+ _: &hir::Body,
span: Span,
id: ast::NodeId) {
match fk {
}
}
- fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
- if let hir::MethodTraitItem(_, None) = trait_item.node {
+ fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
+ if let hir::TraitItemKind::Method(_, hir::TraitMethod::Required(ref names)) = item.node {
self.check_snake_case(cx,
"trait method",
- &trait_item.name.as_str(),
- Some(trait_item.span));
+ &item.name.as_str(),
+ Some(item.span));
+ for name in names {
+ self.check_snake_case(cx, "variable", &name.node.as_str(), Some(name.span));
+ }
}
}
}
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
- // Exclude parameter names from foreign functions
- let parent_node = cx.tcx.map.get_parent_node(p.id);
- if let hir::map::NodeForeignItem(item) = cx.tcx.map.get(parent_node) {
- if let hir::ForeignItemFn(..) = item.node {
- return;
- }
- }
-
if let &PatKind::Binding(_, _, ref path1, _) = &p.node {
self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span));
}
fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
match ti.node {
- hir::ConstTraitItem(..) => {
+ hir::TraitItemKind::Const(..) => {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span);
}
_ => {}
cx: &LateContext,
fk: FnKind<'tcx>,
_: &hir::FnDecl,
- _: &hir::Expr,
+ _: &hir::Body,
span: Span,
_: ast::NodeId) {
match fk {
}
}
- fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
- if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
+ fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
+ if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node {
if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE,
- trait_item.span,
+ item.span,
"declaration of an `unsafe` method")
}
}
hir::ItemEnum(..) => "an enum",
hir::ItemStruct(..) => "a struct",
hir::ItemUnion(..) => "a union",
- hir::ItemTrait(.., ref items) => {
+ hir::ItemTrait(.., ref trait_item_refs) => {
// Issue #11592, traits are always considered exported, even when private.
if it.vis == hir::Visibility::Inherited {
self.private_traits.insert(it.id);
- for itm in items {
- self.private_traits.insert(itm.id);
+ for trait_item_ref in trait_item_refs {
+ self.private_traits.insert(trait_item_ref.id.node_id);
}
return;
}
}
let desc = match trait_item.node {
- hir::ConstTraitItem(..) => "an associated constant",
- hir::MethodTraitItem(..) => "a trait method",
- hir::TypeTraitItem(..) => "an associated type",
+ hir::TraitItemKind::Const(..) => "an associated constant",
+ hir::TraitItemKind::Method(..) => "a trait method",
+ hir::TraitItemKind::Type(..) => "an associated type",
};
self.check_missing_docs_attrs(cx,
cx: &LateContext,
fn_kind: FnKind,
_: &hir::FnDecl,
- blk: &hir::Expr,
+ body: &hir::Body,
sp: Span,
id: ast::NodeId) {
let method = match fn_kind {
// to have behaviour like the above, rather than
// e.g. accidentally recurring after an assert.
- let cfg = cfg::CFG::new(cx.tcx, blk);
+ let cfg = cfg::CFG::new(cx.tcx, &body.value);
let mut work_queue = vec![cfg.entry];
let mut reached_exit_without_self_call = false;
let sig = self.cx.tcx.erase_late_bound_regions(&sig);
for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
- self.check_type_for_ffi_and_report_errors(input_hir.ty.span, input_ty);
+ self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
}
if let hir::Return(ref ret_hir) = decl.output {
if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic {
for ni in &nmod.items {
match ni.node {
- hir::ForeignItemFn(ref decl, _) => {
+ hir::ForeignItemFn(ref decl, _, _) => {
vis.check_foreign_fn(ni.id, decl);
}
hir::ForeignItemStatic(ref ty, _) => {
fn check_fn(&mut self,
cx: &LateContext,
_: FnKind,
- decl: &hir::FnDecl,
- _: &hir::Expr,
+ _: &hir::FnDecl,
+ body: &hir::Body,
_: Span,
_: ast::NodeId) {
- for a in &decl.inputs {
+ for a in &body.arguments {
self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
}
}
// generates an llvmdeps.rs file next to this one which will be
// automatically updated whenever LLVM is updated to include an up-to-date
// set of the libraries we need to link to LLVM for.
-#[cfg_attr(not(all(stage0,cargobuild)),
- link(name = "rustllvm", kind = "static"))] // not quite true but good enough
-#[cfg_attr(stage0, linked_from = "rustllvm")]
+#[link(name = "rustllvm", kind = "static")] // not quite true but good enough
extern "C" {
// Create and destroy contexts.
pub fn LLVMContextCreate() -> ContextRef;
#![feature(concat_idents)]
#![feature(libc)]
#![feature(link_args)]
-#![cfg_attr(stage0, feature(linked_from))]
#![feature(staged_api)]
-#![cfg_attr(not(stage0), feature(rustc_private))]
+#![feature(rustc_private)]
extern crate libc;
#[macro_use]
use encoder::EncodeContext;
use schema::*;
-use rustc::middle::cstore::{InlinedItem, InlinedItemRef};
-use rustc::middle::const_qualif::ConstQualif;
+use rustc::hir;
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TyCtxt, Ty};
#[derive(RustcEncodable, RustcDecodable)]
pub struct Ast<'tcx> {
id_range: IdRange,
- item: Lazy<InlinedItem>,
+ body: Lazy<hir::Body>,
side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)>,
+ pub nested_bodies: LazySeq<hir::Body>,
+ pub rvalue_promotable_to_static: bool,
}
#[derive(RustcEncodable, RustcDecodable)]
NodeType(Ty<'tcx>),
ItemSubsts(ty::ItemSubsts<'tcx>),
Adjustment(ty::adjustment::Adjustment<'tcx>),
- ConstQualif(ConstQualif),
}
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 body = self.tcx.map.body(body);
+
let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
- ii.visit(&mut id_visitor);
+ id_visitor.visit_body(body);
- let ii_pos = self.position();
- ii.encode(self).unwrap();
+ let body_pos = self.position();
+ body.encode(self).unwrap();
let tables_pos = self.position();
let tables_count = {
ecx: self,
count: 0,
};
- ii.visit(&mut visitor);
+ visitor.visit_body(body);
visitor.count
};
+ let nested_pos = self.position();
+ let nested_count = {
+ let mut visitor = NestedBodyEncodingVisitor {
+ ecx: self,
+ count: 0,
+ };
+ visitor.visit_body(body);
+ visitor.count
+ };
+
+ let rvalue_promotable_to_static =
+ self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id];
+
self.lazy(&Ast {
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),
+ nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count),
+ rvalue_promotable_to_static: rvalue_promotable_to_static
})
}
}
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().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
+struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> {
+ ecx: &'a mut EncodeContext<'b, 'tcx>,
+ count: usize,
+}
+
+impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedBodyEncodingVisitor<'a, 'b, 'tcx> {
+ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_nested_body(&mut self, body: hir::BodyId) {
+ let body = self.ecx.tcx.map.body(body);
+ body.encode(self.ecx).unwrap();
+ self.count += 1;
+
+ self.visit_body(body);
+ }
+}
+
+/// Decodes an item's body from its AST in the cdata's metadata and adds it to the
/// ast-map.
-pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ast: Ast<'tcx>,
- orig_did: DefId)
- -> &'tcx InlinedItem {
- debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did));
+pub fn decode_body<'a, 'tcx>(cdata: &CrateMetadata,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId,
+ ast: Ast<'tcx>)
+ -> &'tcx hir::Body {
+ 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 start = tcx.sess.reserve_node_ids(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)) {
match entry {
TableEntry::TypeRelativeDef(def) => {
TableEntry::Adjustment(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())
}
config::CrateTypeProcMacro |
config::CrateTypeCdylib |
config::CrateTypeStaticlib => need_lib_alloc = true,
- config::CrateTypeRlib |
- config::CrateTypeMetadata => {}
+ config::CrateTypeRlib => {}
}
}
if !need_lib_alloc && !need_exe_alloc { return }
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 dep_graph: DepGraph,
metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
used_link_args: RefCell<Vec<String>>,
statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
- pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
- pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
+ pub inlined_item_cache: RefCell<DefIdMap<Option<ast::NodeId>>>,
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
}
dllimport_foreign_items: RefCell::new(FxHashSet()),
visible_parent_map: RefCell::new(FxHashMap()),
inlined_item_cache: RefCell::new(FxHashMap()),
- defid_for_inlined_node: RefCell::new(FxHashMap()),
}
}
use locator;
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::hir::def::{self, Def};
use rustc::middle::lang_items;
use rustc_back::target::Target;
use rustc::hir;
+use std::collections::BTreeMap;
+
impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn describe_def(&self, def: DefId) -> Option<Def> {
self.dep_graph.read(DepNode::MetaData(def));
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>
{
- self.dep_graph.read(DepNode::MetaData(did));
+ // FIXME(#38501) We've skipped a `read` on the `HirBody` of
+ // a `fn` when encoding, so the dep-tracking wouldn't work.
+ // This is only used by rustdoc anyway, which shouldn't have
+ // incremental recompilation ever enabled.
+ assert!(!self.dep_graph.is_fully_enabled());
self.get_crate_data(did.krate).get_fn_arg_names(did.index)
}
})
}
- fn maybe_get_item_ast<'a>(&'tcx self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId)
- -> Option<(&'tcx InlinedItem, ast::NodeId)>
+ fn maybe_get_item_body<'a>(&'tcx self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> Option<&'tcx hir::Body>
{
self.dep_graph.read(DepNode::MetaData(def_id));
- match self.inlined_item_cache.borrow().get(&def_id) {
- Some(&None) => {
- return None; // Not inlinable
- }
- Some(&Some(ref cached_inlined_item)) => {
+ if let Some(&cached) = self.inlined_item_cache.borrow().get(&def_id) {
+ return cached.map(|root_id| {
// Already inline
- debug!("maybe_get_item_ast({}): already inline as node id {}",
- tcx.item_path_str(def_id), cached_inlined_item.item_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_body({}): already inline", tcx.item_path_str(def_id));
+ tcx.map.expect_inlined_body(root_id)
+ });
}
- 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 cache_inlined_item = |original_def_id, inlined_item_id, inlined_root_node_id| {
- let cache_entry = cstore::CachedInlinedItem {
- inlined_root: inlined_root_node_id,
- item_id: inlined_item_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| {
- 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")
- };
+ let inlined = self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index);
- 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.id);
- cache_inlined_item(def_id, inlined_root_node_id, inlined_root_node_id);
- }
- }
+ self.inlined_item_cache.borrow_mut().insert(def_id, inlined.map(|body| {
+ let root_id = tcx.map.get_parent_node(body.value.id);
+ assert_eq!(tcx.map.get_parent_node(root_id), root_id);
+ root_id
+ }));
- // We can be sure to hit the cache now
- return self.maybe_get_item_ast(tcx, def_id);
+ inlined
}
- fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
- assert!(!def_id.is_local());
- match self.inlined_item_cache.borrow().get(&def_id) {
- 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 item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
+ self.dep_graph.read(DepNode::MetaData(def));
+ self.get_crate_data(def.krate).item_body_nested_bodies(def.index)
}
- 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 const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
+ self.dep_graph.read(DepNode::MetaData(def));
+ self.get_crate_data(def.krate).const_is_rvalue_promotable_to_static(def.index)
}
fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx> {
// Decoding metadata from a single crate's metadata
-use astencode::decode_inlined_item;
+use astencode::decode_body;
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
use schema::*;
use rustc::hir;
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_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::middle::lang_items;
use std::borrow::Cow;
use std::cell::Ref;
+use std::collections::BTreeMap;
use std::io;
use std::mem;
use std::str;
}
}
- pub fn maybe_get_item_ast(&self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- id: DefIndex)
- -> Option<&'tcx InlinedItem> {
- debug!("Looking up item: {:?}", id);
+ pub fn maybe_get_item_body(&self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ id: DefIndex)
+ -> Option<&'tcx hir::Body> {
if self.is_proc_macro(id) { return None; }
- let item_doc = self.entry(id);
- let item_did = self.local_def_id(id);
- item_doc.ast.map(|ast| {
- let ast = ast.decode(self);
- decode_inlined_item(self, tcx, ast, item_did)
+ self.entry(id).ast.map(|ast| {
+ decode_body(self, tcx, self.local_def_id(id), ast.decode(self))
})
}
+ pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap<hir::BodyId, hir::Body> {
+ self.entry(id).ast.into_iter().flat_map(|ast| {
+ ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body))
+ }).collect()
+ }
+
+ 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 {
!self.is_proc_macro(id) &&
self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) {
Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)),
Some(None) => return,
+ None if self.proc_macros.is_some() => return,
None => None,
};
use index::Index;
use schema::*;
-use rustc::middle::cstore::{InlinedItemRef, LinkMeta};
-use rustc::middle::cstore::{LinkagePreference, NativeLibrary};
+use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary};
use rustc::hir::def;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
use rustc::hir::map::definitions::DefPathTable;
use std::rc::Rc;
use std::u32;
use syntax::ast::{self, CRATE_NODE_ID};
+use syntax::codemap::Spanned;
use syntax::attr;
use syntax::symbol::Symbol;
use syntax_pos;
let kind = match trait_item.kind {
ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
ty::AssociatedKind::Method => {
- let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node {
+ let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node {
+ let arg_names = match *m {
+ hir::TraitMethod::Required(ref names) => {
+ self.encode_fn_arg_names(names)
+ }
+ hir::TraitMethod::Provided(body) => {
+ self.encode_fn_arg_names_for_body(body)
+ }
+ };
FnData {
constness: hir::Constness::NotConst,
- arg_names: self.encode_fn_arg_names(&sig.decl),
+ arg_names: arg_names
}
} else {
bug!()
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: if let hir::ConstTraitItem(_, Some(_)) = ast_item.node {
- // We only save the HIR for associated consts with bodies
- // (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)
- ))
+ ast: if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node {
+ Some(self.encode_body(body))
} else {
None
},
}
fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
- let tcx = self.tcx;
-
let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
let ast_item = self.tcx.map.expect_impl_item(node_id);
let impl_item = self.tcx.associated_item(def_id);
- let impl_def_id = impl_item.container.id();
let container = match impl_item.defaultness {
hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault,
let kind = match impl_item.kind {
ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
ty::AssociatedKind::Method => {
- let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+ let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
FnData {
constness: sig.constness,
- arg_names: self.encode_fn_arg_names(&sig.decl),
+ arg_names: self.encode_fn_arg_names_for_body(body),
}
} else {
bug!()
ty::AssociatedKind::Type => EntryKind::AssociatedType(container)
};
- let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const {
- (true, true)
- } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+ let (ast, mir) = if let hir::ImplItemKind::Const(_, body) = ast_item.node {
+ (Some(body), true)
+ } else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
let generics = self.tcx.item_generics(def_id);
let types = generics.parent_types as usize + generics.types.len();
let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs);
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;
- (is_const_fn, needs_inline || is_const_fn || always_encode_mir)
+ (ast, needs_inline || is_const_fn || always_encode_mir)
} else {
- (false, false)
+ (None, false)
};
Entry {
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: if ast {
- Some(self.encode_inlined_item(
- InlinedItemRef::from_impl_item(impl_def_id, ast_item, tcx)
- ))
- } else {
- None
- },
+ ast: ast.map(|body| self.encode_body(body)),
mir: if mir { self.encode_mir(def_id) } else { None },
}
}
- fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) -> LazySeq<ast::Name> {
- self.lazy_seq(decl.inputs.iter().map(|arg| {
- if let PatKind::Binding(_, _, ref path1, _) = arg.pat.node {
- path1.node
- } else {
- Symbol::intern("")
+ fn encode_fn_arg_names_for_body(&mut self, body_id: hir::BodyId)
+ -> LazySeq<ast::Name> {
+ let _ignore = self.tcx.dep_graph.in_ignore();
+ let body = self.tcx.map.body(body_id);
+ self.lazy_seq(body.arguments.iter().map(|arg| {
+ match arg.pat.node {
+ PatKind::Binding(_, _, name, _) => name.node,
+ _ => Symbol::intern("")
}
}))
}
+ fn encode_fn_arg_names(&mut self, names: &[Spanned<ast::Name>])
+ -> LazySeq<ast::Name> {
+ self.lazy_seq(names.iter().map(|name| name.node))
+ }
+
fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Mir<'tcx>>> {
self.tcx.mir_map.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
}
hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
hir::ItemConst(..) => EntryKind::Const,
- hir::ItemFn(ref decl, _, constness, ..) => {
+ hir::ItemFn(_, _, constness, .., body) => {
let data = FnData {
constness: constness,
- arg_names: self.encode_fn_arg_names(&decl),
+ arg_names: self.encode_fn_arg_names_for_body(body),
};
EntryKind::Fn(self.lazy(&data))
},
ast: match item.node {
- hir::ItemConst(..) |
- hir::ItemFn(_, _, hir::Constness::Const, ..) => {
- Some(self.encode_inlined_item(
- InlinedItemRef::from_item(def_id, item, tcx)
- ))
+ hir::ItemConst(_, body) |
+ hir::ItemFn(_, _, hir::Constness::Const, _, _, body) => {
+ Some(self.encode_body(body))
}
_ => None,
},
mir: match item.node {
- hir::ItemStatic(..) |
+ hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => {
+ self.encode_mir(def_id)
+ }
hir::ItemConst(..) => self.encode_mir(def_id),
hir::ItemFn(_, _, constness, _, ref generics, _) => {
let tps_len = generics.ty_params.len();
debug!("writing foreign item {}", tcx.node_path_str(nitem.id));
let kind = match nitem.node {
- hir::ForeignItemFn(ref fndecl, _) => {
+ hir::ForeignItemFn(_, ref names, _) => {
let data = FnData {
constness: hir::Constness::NotConst,
- arg_names: self.encode_fn_arg_names(&fndecl),
+ arg_names: self.encode_fn_arg_names(names),
};
EntryKind::ForeignFn(self.lazy(&data))
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &'v hir::TraitItem) {}
+
fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) {
// handled in `visit_item` above
}
name: Some(name),
source_info: Some(source_info),
});
- let extent = self.extent_of_innermost_scope();
+ let extent = self.hir.tcx().region_maps.var_scope(var_id);
self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty);
self.var_indices.insert(var_id, var);
arguments: A,
abi: Abi,
return_ty: Ty<'gcx>,
- ast_body: &'gcx hir::Expr)
+ body: &'gcx hir::Body)
-> Mir<'tcx>
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
{
let span = tcx.map.span(fn_id);
let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
- let body_id = ast_body.id;
let call_site_extent =
tcx.region_maps.lookup_code_extent(
- CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
+ CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body.value.id });
let arg_extent =
tcx.region_maps.lookup_code_extent(
- CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
+ CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.value.id });
let mut block = START_BLOCK;
unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
unpack!(block = builder.in_scope(arg_extent, block, |builder| {
- builder.args_and_body(block, &arguments, arg_extent, ast_body)
+ builder.args_and_body(block, &arguments, arg_extent, &body.value)
}));
// Attribute epilogue to function's closing brace
let fn_end = Span { lo: span.hi, ..span };
pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
item_id: ast::NodeId,
- ast_expr: &'tcx hir::Expr)
+ body_id: hir::BodyId)
-> Mir<'tcx> {
let tcx = hir.tcx();
+ let ast_expr = &tcx.map.body(body_id).value;
let ty = tcx.tables().expr_ty_adjusted(ast_expr);
let span = tcx.map.span(item_id);
let mut builder = Builder::new(hir, span, 0, ty);
f: F)
where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>)
{
- let extent = self.extent_of_innermost_scope();
+ let extent = self.scopes.last().map(|scope| scope.extent).unwrap();
let loop_scope = LoopScope {
extent: extent.clone(),
continue_block: loop_block,
}
}
- pub fn extent_of_innermost_scope(&self) -> CodeExtent {
- self.scopes.last().map(|scope| scope.extent).unwrap()
- }
-
/// Returns the extent of the scope which should be exited by a
/// return.
pub fn extent_of_return_scope(&self) -> CodeExtent {
}
// Now comes the rote stuff:
- hir::ExprRepeat(ref v, ref c) => {
+ hir::ExprRepeat(ref v, c) => {
+ let c = &cx.tcx.map.body(c).value;
ExprKind::Repeat {
value: v.to_ref(),
count: TypedConstVal {
ConstVal::Integral(ConstInt::Usize(u)) => u,
other => bug!("constant evaluation of repeat count yielded {:?}", other),
},
- },
+ }
}
}
hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
let body_id = match cx.tcx.map.find(closure_expr_id) {
Some(map::NodeExpr(expr)) => {
match expr.node {
- hir::ExprClosure(.., body_id, _) => body_id.node_id(),
+ hir::ExprClosure(.., body, _) => body.node_id,
_ => {
span_bug!(expr.span, "closure expr is not a closure expr");
}
#![feature(associated_consts)]
#![feature(box_patterns)]
-#![cfg_attr(stage0, feature(item_like_imports))]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
}
impl<'a, 'gcx> BuildMir<'a, 'gcx> {
- fn build_const_integer(&mut self, expr: &'gcx hir::Expr) {
+ fn build_const_integer(&mut self, body: hir::BodyId) {
+ let body = self.tcx.map.body(body);
// FIXME(eddyb) Closures should have separate
// function definition IDs and expression IDs.
// Type-checking should not let closures get
// this far in an integer constant position.
- if let hir::ExprClosure(..) = expr.node {
+ if let hir::ExprClosure(..) = body.value.node {
return;
}
- self.cx(MirSource::Const(expr.id)).build(|cx| {
- build::construct_const(cx, expr.id, expr)
+ self.cx(MirSource::Const(body.value.id)).build(|cx| {
+ build::construct_const(cx, body.value.id, body.id())
});
}
}
// Const and static items.
fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node {
- hir::ItemConst(_, ref expr) => {
+ hir::ItemConst(_, expr) => {
self.cx(MirSource::Const(item.id)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
}
- hir::ItemStatic(_, m, ref expr) => {
+ hir::ItemStatic(_, m, expr) => {
self.cx(MirSource::Static(item.id, m)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
// Trait associated const defaults.
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
- if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
+ if let hir::TraitItemKind::Const(_, Some(expr)) = item.node {
self.cx(MirSource::Const(item.id)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
// Impl associated const.
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
- if let hir::ImplItemKind::Const(_, ref expr) = item.node {
+ if let hir::ImplItemKind::Const(_, expr) = item.node {
self.cx(MirSource::Const(item.id)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
// Repeat counts, i.e. [expr; constant].
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
- if let hir::ExprRepeat(_, ref count) = expr.node {
+ if let hir::ExprRepeat(_, count) = expr.node {
self.build_const_integer(count);
}
intravisit::walk_expr(self, expr);
// Array lengths, i.e. [T; constant].
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
- if let hir::TyArray(_, ref length) = ty.node {
+ if let hir::TyArray(_, length) = ty.node {
self.build_const_integer(length);
}
intravisit::walk_ty(self, ty);
// Enum variant discriminant values.
fn visit_variant(&mut self, v: &'tcx hir::Variant,
g: &'tcx hir::Generics, item_id: ast::NodeId) {
- if let Some(ref expr) = v.node.disr_expr {
+ if let Some(expr) = v.node.disr_expr {
self.build_const_integer(expr);
}
intravisit::walk_variant(self, v, g, item_id);
fn visit_fn(&mut self,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
span: Span,
id: ast::NodeId) {
// fetch the fully liberated fn signature (that is, all bound
};
let (abi, implicit_argument) = if let FnKind::Closure(..) = fk {
- (Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id()), None)))
+ (Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id), None)))
} else {
let def_id = self.tcx.map.local_def_id(id);
(self.tcx.item_type(def_id).fn_abi(), None)
};
+ let body = self.tcx.map.body(body_id);
let explicit_arguments =
- decl.inputs
+ body.arguments
.iter()
.enumerate()
.map(|(index, arg)| {
(fn_sig.inputs()[index], Some(&*arg.pat))
});
- let body = self.tcx.map.expr(body_id);
-
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
self.cx(MirSource::Fn(id)).build(|cx| {
build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
use rustc::dep_graph::DepNode;
use rustc::ty::cast::CastKind;
-use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs};
-use rustc_const_eval::{ConstFnNode, eval_const_expr_partial, lookup_const_by_id};
+use rustc_const_eval::{ConstEvalErr, compare_lit_exprs};
+use rustc_const_eval::{eval_const_expr_partial};
use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
use rustc_const_eval::ErrKind::UnresolvedPath;
use rustc_const_math::{ConstMathErr, Op};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
+use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
+use rustc::mir::transform::MirSource;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
-use rustc::util::nodemap::NodeMap;
-use rustc::middle::const_qualif::ConstQualif;
+use rustc::util::nodemap::NodeSet;
use rustc::lint::builtin::CONST_ERR;
use rustc::hir::{self, PatKind};
use syntax::ast;
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::cmp::Ordering;
-
-#[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,
-}
+use std::mem;
struct CheckCrateVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mode: Mode,
- qualif: ConstQualif,
- rvalue_borrows: NodeMap<hir::Mutability>,
+ in_fn: bool,
+ promotable: bool,
+ mut_rvalue_borrows: NodeSet,
+ param_env: ty::ParameterEnvironment<'tcx>,
}
impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
- fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R
- 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_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());
- }
- }
+ fn check_const_eval(&self, expr: &'gcx hir::Expr) {
if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) {
match err.kind {
UnimplementedConstVal(_) => {}
}
}
}
- 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,
- fk: FnKind<'gcx>,
- fd: &'gcx hir::FnDecl,
- b: hir::ExprId,
- 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());
- }
+ // Adds the worst effect out of all the values of one type.
+ fn add_type(&mut self, ty: Ty<'gcx>) {
+ if ty.type_contents(self.tcx).interior_unsafe() {
+ self.promotable = false;
}
- let mode = match fk {
- FnKind::ItemFn(_, _, _, hir::Constness::Const, ..)
- => Mode::ConstFn,
- FnKind::Method(_, m, ..) => {
- if m.constness == hir::Constness::Const {
- Mode::ConstFn
- } else {
- Mode::Var
- }
- }
- _ => Mode::Var,
- };
-
- let qualif = self.with_mode(mode, |this| {
- let body = this.tcx.map.expr(b);
- this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, 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.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
+ if self.tcx.type_needs_drop_given_env(ty, &self.param_env) {
+ self.promotable = 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);
- }
- }
+ fn handle_const_fn_call(&mut self, def_id: DefId, ret_ty: Ty<'gcx>) {
+ self.add_type(ret_ty);
+
+ 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| {
+ fn_like.constness() == hir::Constness::Const
+ })
+ } else {
+ self.tcx.sess.cstore.is_const_fn(def_id)
+ };
}
}
impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, '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) {
- debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
- assert_eq!(self.mode, Mode::Var);
- match i.node {
- hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
- self.global_expr(Mode::Static, &expr);
- }
- hir::ItemStatic(_, hir::MutMutable, ref expr) => {
- self.global_expr(Mode::StaticMut, &expr);
- }
- hir::ItemConst(_, ref expr) => {
- self.global_expr(Mode::Const, &expr);
- }
- hir::ItemEnum(ref enum_definition, _) => {
- for var in &enum_definition.variants {
- if let Some(ref ex) = var.node.disr_expr {
- self.global_expr(Mode::Const, &ex);
- }
- }
- }
- _ => {
- intravisit::walk_item(self, i);
+ fn visit_nested_body(&mut self, body: hir::BodyId) {
+ match self.tcx.rvalue_promotable_to_static.borrow_mut().entry(body.node_id) {
+ Entry::Occupied(_) => return,
+ Entry::Vacant(entry) => {
+ // Prevent infinite recursion on re-entry.
+ entry.insert(false);
}
}
- }
- fn visit_trait_item(&mut self, t: &'tcx hir::TraitItem) {
- match t.node {
- hir::ConstTraitItem(_, ref default) => {
- if let Some(ref expr) = *default {
- self.global_expr(Mode::Const, &expr);
- } else {
- intravisit::walk_trait_item(self, t);
- }
- }
- _ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
- }
- }
+ let item_id = self.tcx.map.body_owner(body);
- fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
- match i.node {
- hir::ImplItemKind::Const(_, ref expr) => {
- self.global_expr(Mode::Const, &expr);
- }
- _ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
+ let outer_in_fn = self.in_fn;
+ self.in_fn = match MirSource::from_node(self.tcx, item_id) {
+ MirSource::Fn(_) => true,
+ _ => false
+ };
+
+ let body = self.tcx.map.body(body);
+ if !self.in_fn {
+ self.check_const_eval(&body.value);
}
- }
- fn visit_fn(&mut self,
- fk: FnKind<'tcx>,
- fd: &'tcx hir::FnDecl,
- b: hir::ExprId,
- s: Span,
- fn_id: ast::NodeId) {
- self.fn_like(fk, fd, b, s, fn_id);
+ let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
+ let outer_param_env = mem::replace(&mut self.param_env, param_env);
+ self.tcx.infer_ctxt(None, Some(self.param_env.clone()), Reveal::NotSpecializable)
+ .enter(|infcx| euv::ExprUseVisitor::new(self, &infcx).consume_body(body));
+
+ self.visit_body(body);
+
+ self.param_env = outer_param_env;
+ self.in_fn = outer_in_fn;
}
fn visit_pat(&mut self, p: &'tcx hir::Pat) {
match p.node {
PatKind::Lit(ref lit) => {
- self.global_expr(Mode::Const, &lit);
+ self.check_const_eval(lit);
}
PatKind::Range(ref start, ref end) => {
- self.global_expr(Mode::Const, &start);
- self.global_expr(Mode::Const, &end);
+ self.check_const_eval(start);
+ self.check_const_eval(end);
match compare_lit_exprs(self.tcx, p.span, start, end) {
Ok(Ordering::Less) |
Err(ErrorReported) => {}
}
}
- _ => intravisit::walk_pat(self, p),
+ _ => {}
}
+ intravisit::walk_pat(self, p);
}
- fn visit_block(&mut self, block: &'tcx hir::Block) {
- // Check all statements in the block
- for stmt in &block.stmts {
- match stmt.node {
- hir::StmtDecl(ref decl, _) => {
- match decl.node {
- hir::DeclLocal(_) => {}
- // Item statements are allowed
- hir::DeclItem(_) => continue,
+ fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
+ match stmt.node {
+ hir::StmtDecl(ref decl, _) => {
+ match decl.node {
+ hir::DeclLocal(_) => {
+ self.promotable = false;
}
+ // 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) {
- let mut outer = self.qualif;
- self.qualif = ConstQualif::empty();
+ let outer = self.promotable;
+ self.promotable = true;
let node_ty = self.tcx.tables().node_id_to_type(ex.id);
check_expr(self, ex, node_ty);
check_adjustments(self, ex);
- // Special-case some expressions to avoid certain flags bubbling up.
- match ex.node {
- hir::ExprCall(ref callee, ref args) => {
- for arg in args {
- self.visit_expr(&arg)
+ if let hir::ExprMatch(ref discr, ref arms, _) = ex.node {
+ // Compute the most demanding borrow from all the arms'
+ // patterns and set that on the discriminator.
+ let mut mut_borrow = false;
+ 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);
- }
+ if mut_borrow {
+ self.mut_rvalue_borrows.insert(discr.id);
}
- hir::ExprMatch(ref discr, ref arms, _) => {
- // Compute the most demanding borrow from all the arms'
- // 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.
- match self.rvalue_borrows.remove(&ex.id) {
- Some(hir::MutImmutable) => {
- // 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.mut_rvalue_borrows.remove(&ex.id) {
+ self.promotable = false;
}
- 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) {
Ok(_) => {}
Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
}
}
- self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
- // Don't propagate certain flags.
- self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
+ self.tcx.rvalue_promotable_to_static.borrow_mut().insert(ex.id, self.promotable);
+ self.promotable &= outer;
}
}
fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
match node_ty.sty {
ty::TyAdt(def, _) if def.has_dtor() => {
- v.add_qualif(ConstQualif::NEEDS_DROP);
+ v.promotable = false;
}
_ => {}
}
hir::ExprUnary(..) |
hir::ExprBinary(..) |
hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
hir::ExprBox(_) => {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
hir::ExprUnary(op, ref inner) => {
match v.tcx.tables().node_id_to_type(inner.id).sty {
ty::TyRawPtr(_) => {
assert!(op == hir::UnDeref);
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
_ => {}
}
op.node == hir::BiLe || op.node == hir::BiLt ||
op.node == hir::BiGe || op.node == hir::BiGt);
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
_ => {}
}
match v.tcx.cast_kinds.borrow().get(&from.id) {
None => span_bug!(e.span, "no kind for cast"),
Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
_ => {}
}
hir::ExprPath(ref qpath) => {
let def = v.tcx.tables().qpath_def(qpath, e.id);
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::Fn(..) | Def::Method(..) => {}
- Def::Static(..) => {
- match v.mode {
- Mode::Static | Mode::StaticMut => {}
- Mode::Const | Mode::ConstFn => {}
- Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
- }
- }
- Def::Const(did) | Def::AssociatedConst(did) => {
- let substs = Some(v.tcx.tables().node_id_item_substs(e.id)
- .unwrap_or_else(|| v.tcx.intern_substs(&[])));
- if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) {
- let inner = v.global_expr(Mode::Const, expr);
- 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);
+ Def::AssociatedConst(_) => v.add_type(node_ty),
+ Def::Const(did) => {
+ v.promotable &= if let Some(node_id) = v.tcx.map.as_local_node_id(did) {
+ match v.tcx.map.expect_item(node_id).node {
+ hir::ItemConst(_, body) => {
+ v.visit_nested_body(body);
+ v.tcx.rvalue_promotable_to_static.borrow()[&body.node_id]
+ }
+ _ => false
+ }
+ } else {
+ v.tcx.sess.cstore.const_is_rvalue_promotable_to_static(did)
+ };
}
_ => {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
}
}
} else {
Def::Err
};
- let is_const = match def {
+ match def {
Def::StructCtor(_, 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::VariantCtor(_, CtorKind::Fn) => {}
Def::Fn(did) => {
- v.handle_const_fn_call(e, did, node_ty)
+ v.handle_const_fn_call(did, node_ty)
}
Def::Method(did) => {
match v.tcx.associated_item(did).container {
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
- };
- if !is_const {
- v.add_qualif(ConstQualif::NOT_CONST);
+ _ => v.promotable = false
}
}
hir::ExprMethodCall(..) => {
let method = v.tcx.tables().method_map[&method_call];
- let is_const = match v.tcx.associated_item(method.def_id).container {
- ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
- ty::TraitContainer(_) => false
- };
- if !is_const {
- v.add_qualif(ConstQualif::NOT_CONST);
+ match v.tcx.associated_item(method.def_id).container {
+ ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty),
+ ty::TraitContainer(_) => v.promotable = false
}
}
hir::ExprStruct(..) => {
if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty {
// unsafe_cell_type doesn't necessarily exist with no_core
if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
- v.add_qualif(ConstQualif::MUTABLE_MEM);
+ v.promotable = false;
}
}
}
hir::ExprLit(_) |
- hir::ExprAddrOf(..) => {
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
-
- hir::ExprRepeat(..) => {
- v.add_qualif(ConstQualif::PREFER_IN_PLACE);
- }
+ hir::ExprAddrOf(..) |
+ hir::ExprRepeat(..) => {}
hir::ExprClosure(..) => {
// Paths in constant contexts cannot refer to local variables,
// as there are none, and thus closures can't have upvars there.
if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
- assert!(v.mode == Mode::Var,
- "global closures can't capture anything");
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
}
hir::ExprAssign(..) |
hir::ExprAssignOp(..) |
hir::ExprInlineAsm(..) => {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
}
}
Some(Adjust::DerefRef { autoderefs, .. }) => {
if (0..autoderefs as u32)
.any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
}
}
tcx.visit_all_item_likes_in_krate(DepNode::CheckConst,
&mut CheckCrateVisitor {
tcx: tcx,
- mode: Mode::Var,
- qualif: ConstQualif::NOT_CONST,
- rvalue_borrows: NodeMap(),
+ in_fn: false,
+ promotable: false,
+ mut_rvalue_borrows: NodeSet(),
+ param_env: tcx.empty_parameter_environment(),
}.as_deep_visitor());
tcx.sess.abort_if_errors();
}
fn consume(&mut self,
_consume_id: ast::NodeId,
_consume_span: Span,
- cmt: mc::cmt,
- _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,
+ _cmt: mc::cmt,
+ _mode: euv::ConsumeMode) {}
- Categorization::Rvalue(..) |
- Categorization::Upvar(..) |
- Categorization::Local(..) => break,
- }
- }
- }
fn borrow(&mut self,
borrow_id: ast::NodeId,
_borrow_span: Span,
// Ignore the dummy immutable borrow created by EUV.
break;
}
- let mutbl = bk.to_mutbl_lossy();
- if mutbl == hir::MutMutable && self.mode == Mode::StaticMut {
- // 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,
- _ => {}
- }
+ if bk.to_mutbl_lossy() == hir::MutMutable {
+ self.mut_rvalue_borrows.insert(borrow_id);
}
- self.record_borrow(borrow_id, mutbl);
break;
}
Categorization::StaticItem => {
self.visit_item(nested_item)
}
+ fn visit_nested_trait_item(&mut self, trait_item_id: hir::TraitItemId) {
+ let nested_trait_item = self.krate.unwrap().trait_item(trait_item_id);
+ self.visit_trait_item(nested_trait_item)
+ }
+
fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id);
self.visit_impl_item(nested_impl_item)
fn visit_fn(&mut self,
fk: hir_visit::FnKind<'v>,
fd: &'v hir::FnDecl,
- b: hir::ExprId,
+ b: hir::BodyId,
s: Span,
id: NodeId) {
self.record("FnDecl", Id::None, fd);
self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
}
hir::ExprClosure(.., b, _) => {
- self.with_context(Closure, |v| v.visit_body(b));
+ self.with_context(Closure, |v| v.visit_nested_body(b));
}
hir::ExprBreak(label, ref opt_expr) => {
if opt_expr.is_some() {
fn visit_fn(&mut self,
fk: intravisit::FnKind<'tcx>,
fd: &'tcx hir::FnDecl,
- b: hir::ExprId,
+ b: hir::BodyId,
s: Span,
fn_id: ast::NodeId) {
// FIXME (@jroesch) change this to be an inference context
tcx: infcx.tcx,
param_env: ¶m_env
};
- let body = infcx.tcx.map.expr(b);
+ let body = infcx.tcx.map.body(b);
let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
- euv.walk_fn(fd, body);
+ euv.consume_body(body);
});
intravisit::walk_fn(self, fk, fd, b, s, fn_id)
}
// variant definitions with the discriminant expression that applies to
// each one. If the variant uses the default values (starting from `0`),
// then `None` is stored.
- discriminant_map: NodeMap<Option<&'ast hir::Expr>>,
+ discriminant_map: NodeMap<Option<hir::BodyId>>,
detected_recursive_ids: NodeSet,
}
fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
match ti.node {
- hir::ConstTraitItem(_, ref default) => {
+ hir::TraitItemKind::Const(_, ref default) => {
if let Some(_) = *default {
let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ti.span);
recursion_visitor.visit_trait_item(ti);
root_span: &'b Span,
sess: &'b Session,
ast_map: &'b ast_map::Map<'ast>,
- discriminant_map: &'a mut NodeMap<Option<&'ast hir::Expr>>,
+ discriminant_map: &'a mut NodeMap<Option<hir::BodyId>>,
idstack: Vec<ast::NodeId>,
detected_recursive_ids: &'a mut NodeSet,
}
variant_stack.push(variant.node.data.id());
// When we find an expression, every variant currently on the stack
// is affected by that expression.
- if let Some(ref expr) = variant.node.disr_expr {
+ if let Some(expr) = variant.node.disr_expr {
for id in &variant_stack {
self.discriminant_map.insert(*id, Some(expr));
}
_: &'ast hir::Generics,
_: ast::NodeId) {
let variant_id = variant.node.data.id();
- let maybe_expr;
- if let Some(get_expr) = self.discriminant_map.get(&variant_id) {
- // This is necessary because we need to let the `discriminant_map`
- // borrow fall out of scope, so that we can reborrow farther down.
- maybe_expr = (*get_expr).clone();
- } else {
+ let maybe_expr = *self.discriminant_map.get(&variant_id).unwrap_or_else(|| {
span_bug!(variant.span,
"`check_static_recursion` attempted to visit \
variant with unknown discriminant")
- }
+ });
// If `maybe_expr` is `None`, that's because no discriminant is
// specified that affects this variant. Thus, no risk of recursion.
if let Some(expr) = maybe_expr {
+ let expr = &self.ast_map.body(expr).value;
self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr), expr.span);
}
}
authors = ["The Rust Project Developers"]
name = "rustc_plugin"
version = "0.0.0"
+build = false
[lib]
name = "rustc_plugin"
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
hir::ItemImpl(.., None, _, ref impl_item_refs) => {
for impl_item_ref in impl_item_refs {
- let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
- if impl_item.vis == hir::Public {
- self.update(impl_item.id, item_level);
+ if impl_item_ref.vis == hir::Public {
+ self.update(impl_item_ref.id.node_id, item_level);
}
}
}
hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => {
for impl_item_ref in impl_item_refs {
- let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
- self.update(impl_item.id, item_level);
+ self.update(impl_item_ref.id.node_id, item_level);
}
}
- hir::ItemTrait(.., ref trait_items) => {
- for trait_item in trait_items {
- self.update(trait_item.id, item_level);
+ hir::ItemTrait(.., ref trait_item_refs) => {
+ for trait_item_ref in trait_item_refs {
+ self.update(trait_item_ref.id.node_id, item_level);
}
}
hir::ItemStruct(ref def, _) | hir::ItemUnion(ref def, _) => {
self.reach(item.id).generics().predicates().item_type();
}
}
- hir::ItemTrait(.., ref trait_items) => {
+ hir::ItemTrait(.., ref trait_item_refs) => {
if item_level.is_some() {
self.reach(item.id).generics().predicates();
- for trait_item in trait_items {
- let mut reach = self.reach(trait_item.id);
+ for trait_item_ref in trait_item_refs {
+ let mut reach = self.reach(trait_item_ref.id.node_id);
reach.generics().predicates();
- if let hir::TypeTraitItem(_, None) = trait_item.node {
+ if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
+ !trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
reach.item_type();
}
}
// Visit everything except for private impl items
- hir::ItemImpl(.., ref trait_ref, _, ref impl_items) => {
+ hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => {
if item_level.is_some() {
self.reach(item.id).generics().predicates().impl_trait_ref();
- for impl_item in impl_items {
- let id = impl_item.id.node_id;
+ for impl_item_ref in impl_item_refs {
+ let id = impl_item_ref.id.node_id;
if trait_ref.is_some() || self.get(id).is_some() {
self.reach(id).generics().predicates().item_type();
}
// methods will be visible as `Public::foo`.
let mut found_pub_static = false;
for impl_item_ref in impl_item_refs {
- let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
- match impl_item.node {
- hir::ImplItemKind::Const(..) => {
- if self.item_is_public(&impl_item.id, &impl_item.vis) {
+ if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) {
+ let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
+ match impl_item_ref.kind {
+ hir::AssociatedItemKind::Const => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
- }
- hir::ImplItemKind::Method(ref sig, _) => {
- if !sig.decl.has_self() &&
- self.item_is_public(&impl_item.id, &impl_item.vis) {
+ hir::AssociatedItemKind::Method { has_self: false } => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
+ _ => {}
}
- _ => {}
}
}
if found_pub_static {
self.inner_visibility = item_visibility;
intravisit::walk_item(self, item);
}
- hir::ItemTrait(.., ref trait_items) => {
+ hir::ItemTrait(.., ref trait_item_refs) => {
self.check(item.id, item_visibility).generics().predicates();
- for trait_item in trait_items {
- let mut check = self.check(trait_item.id, item_visibility);
+ for trait_item_ref in trait_item_refs {
+ let mut check = self.check(trait_item_ref.id.node_id, item_visibility);
check.generics().predicates();
- if let hir::TypeTraitItem(_, None) = trait_item.node {
+ if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
+ !trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
check.item_type();
fn visit_ty(&mut self, ty: &'tcx Ty) {
if let TyKind::Path(ref qself, ref path) = ty.node {
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
+ } else if let TyKind::ImplicitSelf = ty.node {
+ let self_ty = keywords::SelfType.ident();
+ let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.span))
+ .map_or(Def::Err, |d| d.def());
+ self.record_def(ty.id, PathResolution::new(def));
+ } else if let TyKind::Array(ref element, ref length) = ty.node {
+ self.visit_ty(element);
+ self.with_constant_rib(|this| {
+ this.visit_expr(length);
+ });
+ return;
}
visit::walk_ty(self, ty);
}
_ => None,
}
}
+
+ fn def(self) -> Def {
+ match self {
+ LexicalScopeBinding::Item(binding) => binding.def(),
+ LexicalScopeBinding::Def(def) => def,
+ }
+ }
}
#[derive(Clone)]
self.visit_ty(ty);
}
}
+
+ ExprKind::Repeat(ref element, ref count) => {
+ self.visit_expr(element);
+ self.with_constant_rib(|this| {
+ this.visit_expr(count);
+ });
+ }
ExprKind::Call(ref callee, ref arguments) => {
self.resolve_expr(callee, Some(&expr.node));
for argument in arguments {
match item.node {
hir::ItemImpl(.., ref ty, _) => {
let mut result = String::from("<");
- result.push_str(&rustc::hir::print::ty_to_string(&ty));
+ result.push_str(&self.tcx.map.node_to_pretty_string(ty.id));
let trait_id = self.tcx.trait_id_of_impl(impl_id);
let mut decl_id = None;
let mut out_filenames = Vec::new();
for &crate_type in sess.crate_types.borrow().iter() {
// Ignore executable crates if we have -Z no-trans, as they will error.
- if sess.opts.debugging_opts.no_trans &&
+ if (sess.opts.debugging_opts.no_trans ||
+ !sess.opts.output_types.should_trans()) &&
crate_type == config::CrateTypeExecutable {
continue;
}
bug!("invalid output type `{:?}` for target os `{}`",
crate_type, sess.opts.target_triple);
}
- let out_file = link_binary_output(sess, trans, crate_type, outputs,
- crate_name);
- out_filenames.push(out_file);
+ let mut out_files = link_binary_output(sess, trans, crate_type, outputs, crate_name);
+ out_filenames.append(&mut out_files);
}
// Remove the temporary object file and metadata if we aren't saving temps
if !sess.opts.cg.save_temps {
- for obj in object_filenames(trans, outputs) {
- remove(sess, &obj);
+ if sess.opts.output_types.should_trans() {
+ for obj in object_filenames(trans, outputs) {
+ remove(sess, &obj);
+ }
}
remove(sess, &outputs.with_extension("metadata.o"));
}
}
}
+fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf {
+ let out_filename = outputs.single_output_file.clone()
+ .unwrap_or(outputs
+ .out_directory
+ .join(&format!("lib{}{}.rmeta", crate_name, sess.opts.cg.extra_filename)));
+ check_file_is_writeable(&out_filename, sess);
+ out_filename
+}
+
pub fn filename_for_input(sess: &Session,
crate_type: config::CrateType,
crate_name: &str,
outputs: &OutputFilenames) -> PathBuf {
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
+
match crate_type {
config::CrateTypeRlib => {
outputs.out_directory.join(&format!("lib{}.rlib", libname))
}
- config::CrateTypeMetadata => {
- outputs.out_directory.join(&format!("lib{}.rmeta", libname))
- }
config::CrateTypeCdylib |
config::CrateTypeProcMacro |
config::CrateTypeDylib => {
}
}
+fn out_filename(sess: &Session,
+ crate_type: config::CrateType,
+ outputs: &OutputFilenames,
+ crate_name: &str)
+ -> PathBuf {
+ let default_filename = filename_for_input(sess, crate_type, crate_name, outputs);
+ let out_filename = outputs.outputs.get(&OutputType::Exe)
+ .and_then(|s| s.to_owned())
+ .or_else(|| outputs.single_output_file.clone())
+ .unwrap_or(default_filename);
+
+ check_file_is_writeable(&out_filename, sess);
+
+ out_filename
+}
+
+// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
+// check this already -- however, the Linux linker will happily overwrite a
+// read-only file. We should be consistent.
+fn check_file_is_writeable(file: &Path, sess: &Session) {
+ if !is_writeable(file) {
+ sess.fatal(&format!("output file {} is not writeable -- check its \
+ permissions", file.display()));
+ }
+}
+
fn link_binary_output(sess: &Session,
trans: &CrateTranslation,
crate_type: config::CrateType,
outputs: &OutputFilenames,
- crate_name: &str) -> PathBuf {
+ crate_name: &str) -> Vec<PathBuf> {
let objects = object_filenames(trans, outputs);
- let default_filename = filename_for_input(sess, crate_type, crate_name,
- outputs);
- let out_filename = outputs.outputs.get(&OutputType::Exe)
- .and_then(|s| s.to_owned())
- .or_else(|| outputs.single_output_file.clone())
- .unwrap_or(default_filename);
- // Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
- // check this already -- however, the Linux linker will happily overwrite a
- // read-only file. We should be consistent.
- for file in objects.iter().chain(Some(&out_filename)) {
- if !is_writeable(file) {
- sess.fatal(&format!("output file {} is not writeable -- check its \
- permissions", file.display()));
- }
+ for file in &objects {
+ check_file_is_writeable(file, sess);
}
let tmpdir = match TempDir::new("rustc") {
Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)),
};
- match crate_type {
- config::CrateTypeRlib => {
- link_rlib(sess, Some(trans), &objects, &out_filename,
- tmpdir.path()).build();
- }
- config::CrateTypeStaticlib => {
- link_staticlib(sess, &objects, &out_filename, tmpdir.path());
- }
- config::CrateTypeMetadata => {
- emit_metadata(sess, trans, &out_filename);
- }
- _ => {
- link_natively(sess, crate_type, &objects, &out_filename, trans,
- outputs, tmpdir.path());
+ let mut out_filenames = vec![];
+
+ if outputs.outputs.contains_key(&OutputType::Metadata) {
+ let out_filename = filename_for_metadata(sess, crate_name, outputs);
+ emit_metadata(sess, trans, &out_filename);
+ out_filenames.push(out_filename);
+ }
+
+ if outputs.outputs.should_trans() {
+ let out_filename = out_filename(sess, crate_type, outputs, crate_name);
+ match crate_type {
+ config::CrateTypeRlib => {
+ link_rlib(sess, Some(trans), &objects, &out_filename,
+ tmpdir.path()).build();
+ }
+ config::CrateTypeStaticlib => {
+ link_staticlib(sess, &objects, &out_filename, tmpdir.path());
+ }
+ _ => {
+ link_natively(sess, crate_type, &objects, &out_filename, trans,
+ outputs, tmpdir.path());
+ }
}
+ out_filenames.push(out_filename);
}
- out_filename
+ out_filenames
}
fn object_filenames(trans: &CrateTranslation,
config::CrateTypeDylib |
config::CrateTypeRlib |
- config::CrateTypeMetadata |
config::CrateTypeProcMacro => false,
}
}
config::CrateTypeProcMacro |
config::CrateTypeCdylib => SymbolExportLevel::C,
config::CrateTypeRlib |
- config::CrateTypeMetadata |
config::CrateTypeDylib => SymbolExportLevel::Rust,
}
}
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
use llvm::SMDiagnosticRef;
use {CrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation};
-use util::common::time;
+use util::common::{time, time_depth, set_time_depth};
use util::common::path2cstr;
use util::fs::link_or_copy;
use errors::{self, Handler, Level, DiagnosticBuilder};
for output_type in output_types.keys() {
match *output_type {
- OutputType::Bitcode => { modules_config.emit_bc = true; },
- OutputType::LlvmAssembly => { modules_config.emit_ir = true; },
+ OutputType::Bitcode => { modules_config.emit_bc = true; }
+ OutputType::LlvmAssembly => { modules_config.emit_ir = true; }
OutputType::Assembly => {
modules_config.emit_asm = true;
// If we're not using the LLVM assembler, this function
if !sess.opts.output_types.contains_key(&OutputType::Assembly) {
metadata_config.emit_obj = true;
}
- },
- OutputType::Object => { modules_config.emit_obj = true; },
+ }
+ OutputType::Object => { modules_config.emit_obj = true; }
+ OutputType::Metadata => { metadata_config.emit_obj = true; }
OutputType::Exe => {
modules_config.emit_obj = true;
metadata_config.emit_obj = true;
user_wants_objects = true;
copy_if_one_unit(OutputType::Object, true);
}
+ OutputType::Metadata |
OutputType::Exe |
OutputType::DepInfo => {}
}
let incr_comp_session_dir = sess.incr_comp_session_dir_opt().map(|r| r.clone());
+ let depth = time_depth();
thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || {
+ set_time_depth(depth);
+
let diag_handler = Handler::with_emitter(true, false, box diag_emitter);
// Must construct cgcx inside the proc because it has non-Send
config::CrateTypeStaticlib |
config::CrateTypeCdylib => MetadataKind::None,
- config::CrateTypeRlib |
- config::CrateTypeMetadata => MetadataKind::Uncompressed,
+ config::CrateTypeRlib => MetadataKind::Uncompressed,
config::CrateTypeDylib |
config::CrateTypeProcMacro => MetadataKind::Compressed,
// Skip crate items and just output metadata in -Z no-trans mode.
if tcx.sess.opts.debugging_opts.no_trans ||
- tcx.sess.crate_types.borrow().iter().all(|ct| ct == &config::CrateTypeMetadata) {
+ tcx.sess.opts.output_types.contains_key(&config::OutputType::Metadata) {
let linker_info = LinkerInfo::new(&shared_ccx, &ExportedSymbols::empty());
return CrateTranslation {
modules: modules,
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
-use rustc::middle::lang_items::{ExchangeFreeFnLangItem, ExchangeMallocFnLangItem};
+use rustc::middle::lang_items::{BoxFreeFnLangItem, ExchangeMallocFnLangItem};
use rustc::traits;
-use rustc::ty::subst::{Substs, Subst};
+use rustc::ty::subst::{Kind, Substs, Subst};
use rustc::ty::{self, TypeFoldable, TyCtxt};
use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::mir::{self, Location};
use rustc::mir::visit as mir_visit;
use rustc::mir::visit::Visitor as MirVisitor;
-use rustc_const_eval as const_eval;
-
use syntax::abi::Abi;
use syntax_pos::DUMMY_SP;
use base::custom_coerce_unsize_info;
use trans_item::{TransItem, DefPathBasedNames};
+use std::iter;
+
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum TransItemCollectionMode {
Eager,
recursion_depth_reset = None;
- // Scan the MIR in order to find function calls, closures, and
- // 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);
+ collect_neighbours(scx, Instance::mono(scx, def_id), &mut neighbors);
}
TransItem::Fn(instance) => {
// Keep track of the monomorphization recursion depth
recursion_depths));
check_type_length_limit(scx.tcx(), instance);
- // Scan the MIR in order to find function calls, closures, and
- // 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);
+ collect_neighbours(scx, instance, &mut neighbors);
}
}
// This is not a callee, but we still have to look for
// references to `const` items
if let mir::Literal::Item { def_id, substs } = constant.literal {
- let tcx = self.scx.tcx();
let substs = monomorphize::apply_param_substs(self.scx,
self.param_substs,
&substs);
- // If the constant referred to here is an associated
- // item of a trait, we need to resolve it to the actual
- // 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);
- }
+ let instance = Instance::new(def_id, substs).resolve_const(self.scx);
+ collect_neighbours(self.scx, instance, self.output);
}
None
debug!("find_drop_glue_neighbors: {}", type_to_string(scx.tcx(), ty));
- // Make sure the exchange_free_fn() lang-item gets translated if
- // there is a boxed value.
- if let ty::TyBox(_) = ty.sty {
- let exchange_free_fn_def_id = scx.tcx()
- .lang_items
- .require(ExchangeFreeFnLangItem)
- .unwrap_or_else(|e| scx.sess().fatal(&e));
-
- assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id));
- let fn_substs = scx.empty_substs_for_def_id(exchange_free_fn_def_id);
- let exchange_free_fn_trans_item =
+ // Make sure the BoxFreeFn lang-item gets translated if there is a boxed value.
+ if let ty::TyBox(content_type) = ty.sty {
+ let def_id = scx.tcx().require_lang_item(BoxFreeFnLangItem);
+ assert!(can_have_local_instance(scx.tcx(), def_id));
+ let box_free_fn_trans_item =
create_fn_trans_item(scx,
- exchange_free_fn_def_id,
- fn_substs,
+ def_id,
+ scx.tcx().mk_substs(iter::once(Kind::from(content_type))),
scx.tcx().intern_substs(&[]));
- output.push(exchange_free_fn_trans_item);
+ output.push(box_free_fn_trans_item);
}
// If the type implements Drop, also add a translation item for the
}
}
+ fn visit_trait_item(&mut self, _: &'v hir::TraitItem) {
+ // Even if there's a default body with no explicit generics,
+ // it's still generic over some `Self: Trait`, so not a root.
+ }
+
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
match ii.node {
hir::ImplItemKind::Method(hir::MethodSig {
}
}
-// There are no translation items for constants themselves but their
-// initializers might still contain something that produces translation items,
-// such as cast that introduce a new vtable.
-fn collect_const_item_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
- def_id: DefId,
- substs: &'tcx Substs<'tcx>,
- output: &mut Vec<TransItem<'tcx>>)
+/// Scan the MIR in order to find function calls, closures, and drop-glue
+fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+ instance: Instance<'tcx>,
+ output: &mut Vec<TransItem<'tcx>>)
{
- // Scan the MIR in order to find function calls, closures, and
- // drop-glue
- let mir = scx.tcx().item_mir(def_id);
+ let mir = scx.tcx().item_mir(instance.def);
- let visitor = MirNeighborCollector {
+ let mut visitor = MirNeighborCollector {
scx: scx,
mir: &mir,
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);
for promoted in &mir.promoted {
visitor.visit_mir(promoted);
&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>> {
&self.local().instances
}
// Code relating to drop glue.
use std;
+use std::iter;
use llvm;
use llvm::{ValueRef, get_param};
-use middle::lang_items::ExchangeFreeFnLangItem;
+use middle::lang_items::BoxFreeFnLangItem;
use rustc::ty::subst::{Substs};
use rustc::traits;
use rustc::ty::{self, AdtKind, Ty, TypeFoldable};
+use rustc::ty::subst::Kind;
use adt::{self, MaybeSizedValue};
use base::*;
use callee::Callee;
use syntax_pos::DUMMY_SP;
-pub fn trans_exchange_free_dyn<'a, 'tcx>(
+pub fn trans_exchange_free_ty<'a, 'tcx>(
bcx: &BlockAndBuilder<'a, 'tcx>,
- v: ValueRef,
- size: ValueRef,
- align: ValueRef
+ ptr: MaybeSizedValue,
+ content_ty: Ty<'tcx>
) {
- let def_id = langcall(bcx.tcx(), None, "", ExchangeFreeFnLangItem);
- let args = [bcx.pointercast(v, Type::i8p(bcx.ccx)), size, align];
- let callee = Callee::def(bcx.ccx, def_id, bcx.tcx().intern_substs(&[]));
+ let def_id = langcall(bcx.tcx(), None, "", BoxFreeFnLangItem);
+ let substs = bcx.tcx().mk_substs(iter::once(Kind::from(content_ty)));
+ let callee = Callee::def(bcx.ccx, def_id, substs);
- let ccx = bcx.ccx;
- let fn_ty = callee.direct_fn_type(ccx, &[]);
+ let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
- let llret = bcx.call(callee.reify(ccx), &args[..], None);
+ let llret = bcx.call(callee.reify(bcx.ccx),
+ &[ptr.value, ptr.meta][..1 + ptr.has_meta() as usize], None);
fn_ty.apply_attrs_callsite(llret);
}
-pub fn trans_exchange_free_ty<'a, 'tcx>(
- bcx: &BlockAndBuilder<'a, 'tcx>, ptr: ValueRef, content_ty: Ty<'tcx>
-) {
- assert!(bcx.ccx.shared().type_is_sized(content_ty));
- let sizing_type = sizing_type_of(bcx.ccx, content_ty);
- let content_size = llsize_of_alloc(bcx.ccx, sizing_type);
-
- // `Box<ZeroSizeType>` does not allocate.
- if content_size != 0 {
- let content_align = align_of(bcx.ccx, content_ty);
- let ccx = bcx.ccx;
- trans_exchange_free_dyn(bcx, ptr, C_uint(ccx, content_size), C_uint(ccx, content_align));
- }
-}
-
pub fn get_drop_glue_type<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> {
assert!(t.is_normalized_for_trans());
// special. It may move to library and have Drop impl. As
// a safe-guard, assert TyBox not used with TyContents.
assert!(!skip_dtor);
- if !bcx.ccx.shared().type_is_sized(content_ty) {
+ let ptr = if !bcx.ccx.shared().type_is_sized(content_ty) {
let llbox = bcx.load(get_dataptr(&bcx, ptr.value));
let info = bcx.load(get_meta(&bcx, ptr.value));
- drop_ty(&bcx, MaybeSizedValue::unsized_(llbox, info), content_ty);
- let (llsize, llalign) = size_and_align_of_dst(&bcx, content_ty, info);
-
- // `Box<ZeroSizeType>` does not allocate.
- let needs_free = bcx.icmp(llvm::IntNE, llsize, C_uint(bcx.ccx, 0u64));
- if const_to_opt_uint(needs_free) == Some(0) {
- bcx
- } else {
- let next_cx = bcx.fcx().build_new_block("next");
- let cond_cx = bcx.fcx().build_new_block("cond");
- bcx.cond_br(needs_free, cond_cx.llbb(), next_cx.llbb());
- trans_exchange_free_dyn(&cond_cx, llbox, llsize, llalign);
- cond_cx.br(next_cx.llbb());
- next_cx
- }
+ MaybeSizedValue::unsized_(llbox, info)
} else {
- let llbox = bcx.load(ptr.value);
- drop_ty(&bcx, MaybeSizedValue::sized(llbox), content_ty);
- trans_exchange_free_ty(&bcx, llbox, content_ty);
- bcx
- }
+ MaybeSizedValue::sized(bcx.load(ptr.value))
+ };
+ drop_ty(&bcx, ptr, content_ty);
+ trans_exchange_free_ty(&bcx, ptr, content_ty);
+ bcx
}
ty::TyDynamic(..) => {
// No support in vtable for distinguishing destroying with
use rustc::infer::TransNormalize;
use rustc::mir;
use rustc::mir::tcx::LvalueTy;
-use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::subst::Substs;
use value::Value;
use syntax::ast;
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::Span;
use std::fmt;
use std::ptr;
}
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
- mut instance: Instance<'tcx>,
+ instance: Instance<'tcx>,
args: IndexVec<mir::Local, Const<'tcx>>)
-> Result<Const<'tcx>, ConstEvalErr> {
- // Try to resolve associated constants.
- 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 instance = instance.resolve_const(ccx.shared());
let mir = ccx.tcx().item_mir(instance.def);
MirConstContext::new(ccx, &mir, instance.substs, args).trans()
}
use common::*;
use rustc::hir::def_id::DefId;
use rustc::infer::TransNormalize;
+use rustc::traits;
use rustc::ty::fold::{TypeFolder, TypeFoldable};
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::ppaux;
use rustc::util::common::MemoizationMap;
+
+use syntax::codemap::DUMMY_SP;
+
use std::fmt;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
}
}
-impl<'tcx> Instance<'tcx> {
+impl<'a, 'tcx> Instance<'tcx> {
pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
-> Instance<'tcx> {
assert!(substs.regions().all(|&r| r == ty::ReErased));
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))
}
+
+ /// 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
use rustc_const_eval::eval_length;
use rustc_data_structures::accumulate_vec::AccumulateVec;
-use hir::{self, SelfKind};
+use hir;
use hir::def::Def;
use hir::def_id::DefId;
-use hir::print as pprust;
use middle::resolve_lifetime as rl;
use rustc::lint;
use rustc::ty::subst::{Kind, Subst, Substs};
}
fn report_elision_failure(
+ tcx: TyCtxt,
db: &mut DiagnosticBuilder,
params: Vec<ElisionFailureInfo>)
{
for (i, info) in elided_params.into_iter().enumerate() {
let ElisionFailureInfo {
- name, lifetime_count: n, have_bound_regions
+ parent, index, lifetime_count: n, have_bound_regions
} = info;
- let help_name = if name.is_empty() {
- format!("argument {}", i + 1)
+ let help_name = if let Some(body) = parent {
+ let arg = &tcx.map.body(body).arguments[index];
+ format!("`{}`", tcx.map.node_to_pretty_string(arg.pat.id))
} else {
- format!("`{}`", name)
+ format!("argument {}", index + 1)
};
m.push_str(&(if n == 1 {
err.span_label(ampersand_span, &format!("expected lifetime parameter"));
if let Some(params) = params {
- report_elision_failure(&mut err, params);
+ report_elision_failure(self.tcx(), &mut err, params);
}
err.emit();
ty::ReStatic
/// corresponding to each input type/pattern.
fn find_implied_output_region<I>(&self,
input_tys: &[Ty<'tcx>],
- input_pats: I) -> ElidedLifetime
- where I: Iterator<Item=String>
+ parent: Option<hir::BodyId>,
+ input_indices: I) -> ElidedLifetime
+ where I: Iterator<Item=usize>
{
let tcx = self.tcx();
let mut lifetimes_for_params = Vec::with_capacity(input_tys.len());
let mut possible_implied_output_region = None;
let mut lifetimes = 0;
- for input_type in input_tys.iter() {
+ for (input_type, index) in input_tys.iter().zip(input_indices) {
let mut regions = FxHashSet();
let have_bound_regions = tcx.collect_regions(input_type, &mut regions);
possible_implied_output_region = regions.iter().cloned().next();
}
- // Use a placeholder for `name` because computing it can be
- // expensive and we don't want to do it until we know it's
- // necessary.
lifetimes_for_params.push(ElisionFailureInfo {
- name: String::new(),
+ parent: parent,
+ index: index,
lifetime_count: regions.len(),
have_bound_regions: have_bound_regions
});
if lifetimes == 1 {
Ok(*possible_implied_output_region.unwrap())
} else {
- // Fill in the expensive `name` fields now that we know they're
- // needed.
- for (info, input_pat) in lifetimes_for_params.iter_mut().zip(input_pats) {
- info.name = input_pat;
- }
Err(Some(lifetimes_for_params))
}
}
let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| {
self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t)
}));
- let input_params = iter::repeat(String::new()).take(inputs.len());
- let implied_output_region = self.find_implied_output_region(&inputs, input_params);
+ let input_params = 0..inputs.len();
+ let implied_output_region = self.find_implied_output_region(&inputs, None, input_params);
let (output, output_span) = match data.output {
Some(ref output_ty) => {
}
_ => {
span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait",
- path);
+ self.tcx().map.node_to_pretty_string(trait_ref.ref_id));
}
}
}
let mut err = struct_span_err!(tcx.sess, ty.span, E0178,
"expected a path on the left-hand side \
of `+`, not `{}`",
- pprust::ty_to_string(ty));
+ tcx.map.node_to_pretty_string(ty.id));
err.span_label(ty.span, &format!("expected a path"));
let hi = bounds.iter().map(|x| match *x {
hir::TraitTyParamBound(ref tr, _) => tr.span.hi,
expn_id: ty.span.expn_id,
});
match (&ty.node, full_span) {
- (&hir::TyRptr(None, ref mut_ty), Some(full_span)) => {
- let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
+ (&hir::TyRptr(ref lifetime, ref mut_ty), Some(full_span)) => {
+ let ty_str = hir::print::to_string(&tcx.map, |s| {
+ use syntax::print::pp::word;
+ use syntax::print::pprust::PrintState;
+
+ word(&mut s.s, "&")?;
+ s.print_opt_lifetime(lifetime)?;
+ s.print_mutability(mut_ty.mutbl)?;
+ s.popen()?;
+ s.print_type(&mut_ty.ty)?;
+ s.print_bounds(" +", bounds)?;
+ s.pclose()
+ });
err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
- format!("&{}({} +{})",
- mutbl_str,
- pprust::ty_to_string(&mut_ty.ty),
- pprust::bounds_to_string(bounds)));
- }
- (&hir::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
- let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
- err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
- format!("&{} {}({} +{})",
- pprust::lifetime_to_string(lt),
- mutbl_str,
- pprust::ty_to_string(&mut_ty.ty),
- pprust::bounds_to_string(bounds)));
+ ty_str);
}
_ => {
bf.abi,
None,
&bf.decl,
+ None,
anon_scope,
anon_scope);
};
self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
}
- hir::TyArray(ref ty, ref e) => {
- if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
+ hir::TyArray(ref ty, length) => {
+ let e = &tcx.map.body(length).value;
+ if let Ok(length) = eval_length(tcx.global_tcx(), e, "array length") {
tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
} else {
self.tcx().types.err
pub fn ty_of_arg(&self,
rscope: &RegionScope,
- a: &hir::Arg,
+ ty: &hir::Ty,
expected_ty: Option<Ty<'tcx>>)
-> Ty<'tcx>
{
- match a.ty.node {
+ match ty.node {
hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
- hir::TyInfer => self.ty_infer(a.ty.span),
- _ => self.ast_ty_to_ty(rscope, &a.ty),
+ hir::TyInfer => self.ty_infer(ty.span),
+ _ => self.ast_ty_to_ty(rscope, ty),
}
}
pub fn ty_of_method(&self,
sig: &hir::MethodSig,
- untransformed_self_ty: Ty<'tcx>,
+ opt_self_value_ty: Option<Ty<'tcx>>,
+ body: Option<hir::BodyId>,
anon_scope: Option<AnonTypeScope>)
-> &'tcx ty::BareFnTy<'tcx> {
self.ty_of_method_or_bare_fn(sig.unsafety,
sig.abi,
- Some(untransformed_self_ty),
+ opt_self_value_ty,
&sig.decl,
+ body,
None,
anon_scope)
}
unsafety: hir::Unsafety,
abi: abi::Abi,
decl: &hir::FnDecl,
+ body: hir::BodyId,
anon_scope: Option<AnonTypeScope>)
-> &'tcx ty::BareFnTy<'tcx> {
- self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope)
+ self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, Some(body), None, anon_scope)
}
fn ty_of_method_or_bare_fn(&self,
unsafety: hir::Unsafety,
abi: abi::Abi,
- opt_untransformed_self_ty: Option<Ty<'tcx>>,
+ opt_self_value_ty: Option<Ty<'tcx>>,
decl: &hir::FnDecl,
+ body: Option<hir::BodyId>,
arg_anon_scope: Option<AnonTypeScope>,
ret_anon_scope: Option<AnonTypeScope>)
-> &'tcx ty::BareFnTy<'tcx>
// declaration are bound to that function type.
let rb = MaybeWithAnonTypes::new(BindingRscope::new(), arg_anon_scope);
- // `implied_output_region` is the region that will be assumed for any
- // region parameters in the return type. In accordance with the rules for
- // lifetime elision, we can determine it in two ways. First (determined
- // here), if self is by-reference, then the implied output region is the
- // region of the self parameter.
- let (self_ty, explicit_self) = match (opt_untransformed_self_ty, decl.get_self()) {
- (Some(untransformed_self_ty), Some(explicit_self)) => {
- let self_type = self.determine_self_type(&rb, untransformed_self_ty,
- &explicit_self);
- (Some(self_type), Some(ExplicitSelf::determine(untransformed_self_ty, self_type)))
- }
- _ => (None, None),
- };
+ let input_tys: Vec<Ty> =
+ decl.inputs.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
- // HACK(eddyb) replace the fake self type in the AST with the actual type.
- let arg_params = if self_ty.is_some() {
- &decl.inputs[1..]
- } else {
- &decl.inputs[..]
- };
- let arg_tys: Vec<Ty> =
- arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
+ let has_self = opt_self_value_ty.is_some();
+ let explicit_self = opt_self_value_ty.map(|self_value_ty| {
+ ExplicitSelf::determine(self_value_ty, input_tys[0])
+ });
- // Second, if there was exactly one lifetime (either a substitution or a
- // reference) in the arguments, then any anonymous regions in the output
- // have that lifetime.
let implied_output_region = match explicit_self {
+ // `implied_output_region` is the region that will be assumed for any
+ // region parameters in the return type. In accordance with the rules for
+ // lifetime elision, we can determine it in two ways. First (determined
+ // here), if self is by-reference, then the implied output region is the
+ // region of the self parameter.
Some(ExplicitSelf::ByReference(region, _)) => Ok(*region),
+
+ // Second, if there was exactly one lifetime (either a substitution or a
+ // reference) in the arguments, then any anonymous regions in the output
+ // have that lifetime.
_ => {
- self.find_implied_output_region(&arg_tys,
- arg_params.iter()
- .map(|a| pprust::pat_to_string(&a.pat)))
+ let arg_tys = &input_tys[has_self as usize..];
+ let arg_params = has_self as usize..input_tys.len();
+ self.find_implied_output_region(arg_tys, body, arg_params)
}
};
unsafety: unsafety,
abi: abi,
sig: ty::Binder(self.tcx().mk_fn_sig(
- self_ty.into_iter().chain(arg_tys),
+ input_tys.into_iter(),
output_ty,
decl.variadic
)),
})
}
- fn determine_self_type<'a>(&self,
- rscope: &RegionScope,
- untransformed_self_ty: Ty<'tcx>,
- explicit_self: &hir::ExplicitSelf)
- -> Ty<'tcx>
- {
- match explicit_self.node {
- SelfKind::Value(..) => untransformed_self_ty,
- SelfKind::Region(ref lifetime, mutability) => {
- let region =
- self.opt_ast_region_to_region(
- rscope,
- explicit_self.span,
- lifetime);
- self.tcx().mk_ref(region,
- ty::TypeAndMut {
- ty: untransformed_self_ty,
- mutbl: mutability
- })
- }
- SelfKind::Explicit(ref ast_type, _) => self.ast_ty_to_ty(rscope, &ast_type)
- }
- }
-
pub fn ty_of_closure(&self,
unsafety: hir::Unsafety,
decl: &hir::FnDecl,
let report_unexpected_def = |def: Def| {
span_err!(tcx.sess, pat.span, E0533,
"expected unit struct/variant or constant, found {} `{}`",
- def.kind_name(), qpath);
+ def.kind_name(),
+ hir::print::to_string(&tcx.map, |s| s.print_qpath(qpath, false)));
};
// Resolve the path and check the definition for errors.
};
let report_unexpected_def = |def: Def| {
let msg = format!("expected tuple struct/variant, found {} `{}`",
- def.kind_name(), qpath);
+ def.kind_name(),
+ hir::print::to_string(&tcx.map, |s| s.print_qpath(qpath, false)));
struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg)
.span_label(pat.span, &format!("not a tuple variant or struct")).emit();
on_error();
use CrateCtxt;
use hir::def::Def;
use hir::def_id::{DefId, LOCAL_CRATE};
-use hir::print;
use rustc::{infer, traits};
use rustc::ty::{self, LvaluePreference, Ty};
use syntax::symbol::Symbol;
if let &ty::TyAdt(adt_def, ..) = t {
if adt_def.is_enum() {
if let hir::ExprCall(ref expr, _) = call_expr.node {
- unit_variant = Some(print::expr_to_string(expr))
+ unit_variant = Some(self.tcx.map.node_to_pretty_string(expr.id))
}
}
}
expr: &hir::Expr,
_capture: hir::CaptureClause,
decl: &'gcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
expected: Expectation<'tcx>)
-> Ty<'tcx> {
debug!("check_expr_closure(expr={:?},expected={:?})",
Some(ty) => self.deduce_expectations_from_expected_type(ty),
None => (None, None),
};
- let body = self.tcx.map.expr(body_id);
+ let body = self.tcx.map.body(body_id);
self.check_closure(expr, expected_kind, decl, body, expected_sig)
}
expr: &hir::Expr,
opt_kind: Option<ty::ClosureKind>,
decl: &'gcx hir::FnDecl,
- body: &'gcx hir::Expr,
+ body: &'gcx hir::Body,
expected_sig: Option<ty::FnSig<'tcx>>)
-> Ty<'tcx> {
debug!("check_closure opt_kind={:?} expected_sig={:?}",
debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
- let fn_sig = self.tcx
- .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id),
- &fn_ty.sig);
- let fn_sig = (**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
+ let extent = self.tcx.region_maps.call_site_extent(expr.id, body.value.id);
+ let fn_sig = self.tcx.liberate_late_bound_regions(extent, &fn_ty.sig);
+ let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
+ body.value.id, &fn_sig);
check_fn(self,
hir::Unsafety::Normal,
&fn_sig,
decl,
expr.id,
- &body);
+ body);
// Tuple up the arguments and insert the resulting function type into
// the `closures` table.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::hir;
+use rustc::hir::{self, ImplItemKind, TraitItemKind};
use rustc::infer::{self, InferOk};
use rustc::middle::free_region::FreeRegionMap;
use rustc::ty;
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::error::{ExpectedFound, TypeError};
use rustc::ty::subst::{Subst, Substs};
-use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
use rustc::util::common::ErrorReported;
use syntax::ast;
TypeError::Mutability => {
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
- TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+ TraitItemKind::Method(ref trait_m_sig, _) => {
trait_m_sig.decl.inputs.iter()
}
- _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+ _ => bug!("{:?} is not a TraitItemKind::Method", trait_m),
};
- impl_m_iter.zip(trait_m_iter)
- .find(|&(ref impl_arg, ref trait_arg)| {
- match (&impl_arg.ty.node, &trait_arg.ty.node) {
- (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
- (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
- impl_mt.mutbl != trait_mt.mutbl
- }
- _ => false,
- }
- })
- .map(|(ref impl_arg, ref trait_arg)| {
- match (impl_arg.to_self(), trait_arg.to_self()) {
- (Some(impl_self), Some(trait_self)) => {
- (impl_self.span, Some(trait_self.span))
- }
- (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
- _ => {
- bug!("impl and trait fns have different first args, impl: \
- {:?}, trait: {:?}",
- impl_arg,
- trait_arg)
- }
- }
- })
- .unwrap_or((cause.span, tcx.map.span_if_local(trait_m.def_id)))
+ impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
+ match (&impl_arg.node, &trait_arg.node) {
+ (&hir::TyRptr(_, ref impl_mt), &hir::TyRptr(_, ref trait_mt)) |
+ (&hir::TyPtr(ref impl_mt), &hir::TyPtr(ref trait_mt)) => {
+ impl_mt.mutbl != trait_mt.mutbl
+ }
+ _ => false,
+ }
+ }).map(|(ref impl_arg, ref trait_arg)| {
+ (impl_arg.span, Some(trait_arg.span))
+ })
+ .unwrap_or_else(|| (cause.span, tcx.map.span_if_local(trait_m.def_id)))
} else {
(cause.span, tcx.map.span_if_local(trait_m.def_id))
}
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
let (trait_m_output, trait_m_iter) =
match tcx.map.expect_trait_item(trait_m_node_id).node {
- TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+ TraitItemKind::Method(ref trait_m_sig, _) => {
(&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
}
- _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+ _ => bug!("{:?} is not a TraitItemKind::Method", trait_m),
};
let impl_iter = impl_sig.inputs().iter();
.filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) {
Ok(_) => None,
- Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
+ Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
}
})
.next()
let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
let trait_span = if let Some(trait_id) = trait_m_node_id {
match tcx.map.expect_trait_item(trait_id).node {
- TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+ TraitItemKind::Method(ref trait_m_sig, _) => {
if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 {
trait_number_args - 1
} else {
0
}) {
- Some(arg.pat.span)
+ Some(arg.span)
} else {
trait_item_span
}
} else {
0
}) {
- arg.pat.span
+ arg.span
} else {
impl_m_span
}
// Add a label to the Span containing just the type of the item
let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap();
let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node {
- TraitItem_::ConstTraitItem(ref ty, _) => ty.span,
+ TraitItemKind::Const(ref ty, _) => ty.span,
_ => bug!("{:?} is not a trait const", trait_c),
};
let i_n_tps = tcx.item_generics(def_id).types.len();
if i_n_tps != n_tps {
let span = match it.node {
- hir::ForeignItemFn(_, ref generics) => generics.span,
+ hir::ForeignItemFn(_, _, ref generics) => generics.span,
hir::ForeignItemStatic(..) => it.span
};
use errors::DiagnosticBuilder;
use syntax_pos::Span;
-use rustc::hir::print as pprust;
use rustc::hir;
use rustc::infer::type_variable::TypeVariableOrigin;
let msg = if let Some(callee) = rcvr_expr {
format!("{}; use overloaded call notation instead (e.g., `{}()`)",
msg,
- pprust::expr_to_string(callee))
+ self.tcx.map.node_to_pretty_string(callee.id))
} else {
msg
};
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::{self, PatKind};
-use rustc::hir::print as pprust;
use rustc::middle::lang_items;
use rustc_back::slice;
use rustc_const_eval::eval_length;
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
match t.node {
- hir::TyArray(_, ref expr) => {
- check_const_with_type(self.ccx, &expr, self.ccx.tcx.types.usize, expr.id);
+ hir::TyArray(_, length) => {
+ check_const_with_type(self.ccx, length, self.ccx.tcx.types.usize, length.node_id);
}
_ => {}
}
intravisit::walk_ty(self, t);
}
+
+ fn visit_expr(&mut self, e: &'tcx hir::Expr) {
+ match e.node {
+ hir::ExprRepeat(_, count) => {
+ check_const_with_type(self.ccx, count, self.ccx.tcx.types.usize, count.node_id);
+ }
+ _ => {}
+ }
+
+ intravisit::walk_expr(self, e);
+ }
}
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
check_item_body(self.ccx, i);
}
+ fn visit_trait_item(&mut self, _item: &'tcx hir::TraitItem) {
+ // done as part of `visit_item` above
+ }
+
fn visit_impl_item(&mut self, _item: &'tcx hir::ImplItem) {
// done as part of `visit_item` above
}
fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
fn_id: ast::NodeId,
span: Span) {
- let body = ccx.tcx.map.expr(body_id);
+ let body = ccx.tcx.map.body(body_id);
let raw_fty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(fn_id));
let fn_ty = match raw_fty.sty {
ty::TyFnDef(.., f) => f,
- _ => span_bug!(body.span, "check_bare_fn: function type expected")
+ _ => span_bug!(body.value.span, "check_bare_fn: function type expected")
};
check_abi(ccx, span, fn_ty.abi);
ccx.inherited(fn_id).enter(|inh| {
// Compute the fty from point of view of inside fn.
- let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id());
+ let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id);
let fn_sig =
fn_ty.sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
let fn_sig =
inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
let fn_sig =
- inh.normalize_associated_types_in(body.span, body_id.node_id(), &fn_sig);
+ inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
fcx.check_casts();
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
- fcx.regionck_fn(fn_id, decl, body_id);
- fcx.resolve_type_vars_in_fn(decl, body, fn_id);
+ fcx.regionck_fn(fn_id, body);
+ fcx.resolve_type_vars_in_body(body, fn_id);
});
}
intravisit::walk_pat(self, p);
}
- fn visit_block(&mut self, b: &'gcx hir::Block) {
- // non-obvious: the `blk` variable maps to region lb, so
- // we have to keep this up-to-date. This
- // is... unfortunate. It'd be nice to not need this.
- intravisit::walk_block(self, b);
- }
-
- // Since an expr occurs as part of the type fixed size arrays we
- // need to record the type for that node
- fn visit_ty(&mut self, t: &'gcx hir::Ty) {
- match t.node {
- hir::TyArray(ref ty, ref count_expr) => {
- self.visit_ty(&ty);
- self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx.types.usize);
- }
- hir::TyBareFn(ref function_declaration) => {
- intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
- walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
- }
- _ => intravisit::walk_ty(self, t)
- }
- }
-
// Don't descend into the bodies of nested closures
fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
- _: hir::ExprId, _: Span, _: ast::NodeId) { }
+ _: hir::BodyId, _: Span, _: ast::NodeId) { }
}
/// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
fn_sig: &ty::FnSig<'tcx>,
decl: &'gcx hir::FnDecl,
fn_id: ast::NodeId,
- body: &'gcx hir::Expr)
+ body: &'gcx hir::Body)
-> FnCtxt<'a, 'gcx, 'tcx>
{
let mut fn_sig = fn_sig.clone();
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
- let mut fcx = FnCtxt::new(inherited, None, body.id);
+ let mut fcx = FnCtxt::new(inherited, None, body.value.id);
let ret_ty = fn_sig.output();
*fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty.unwrap(),
fn_sig.variadic);
- {
- let mut visit = GatherLocalsVisitor { fcx: &fcx, };
-
- // Add formal parameters.
- for (arg_ty, input) in fn_sig.inputs().iter().zip(&decl.inputs) {
- // The type of the argument must be well-formed.
- //
- // NB -- this is now checked in wfcheck, but that
- // currently only results in warnings, so we issue an
- // old-style WF obligation here so that we still get the
- // errors that we used to get.
- fcx.register_old_wf_obligation(arg_ty, input.ty.span, traits::MiscObligation);
-
- // Create type variables for each argument.
- input.pat.each_binding(|_bm, pat_id, sp, _path| {
- let var_ty = visit.assign(sp, pat_id, None);
- fcx.require_type_is_sized(var_ty, sp, traits::VariableType(pat_id));
- });
+ GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
- // Check the pattern.
- fcx.check_pat(&input.pat, arg_ty);
- fcx.write_ty(input.id, arg_ty);
- }
+ // Add formal parameters.
+ for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
+ // The type of the argument must be well-formed.
+ //
+ // NB -- this is now checked in wfcheck, but that
+ // currently only results in warnings, so we issue an
+ // old-style WF obligation here so that we still get the
+ // errors that we used to get.
+ fcx.register_old_wf_obligation(arg_ty, arg.pat.span, traits::MiscObligation);
- visit.visit_expr(body);
+ // Check the pattern.
+ fcx.check_pat(&arg.pat, arg_ty);
+ fcx.write_ty(arg.id, arg_ty);
}
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
- fcx.check_expr_coercable_to_type(body, fcx.ret_ty.unwrap());
+ fcx.check_expr_coercable_to_type(&body.value, fcx.ret_ty.unwrap());
fcx
}
let _indenter = indenter();
match it.node {
// Consts can play a role in type-checking, so they are included here.
- hir::ItemStatic(.., ref e) |
- hir::ItemConst(_, ref e) => check_const(ccx, &e, it.id),
+ hir::ItemStatic(.., e) |
+ hir::ItemConst(_, e) => check_const(ccx, e, it.id),
hir::ItemEnum(ref enum_definition, _) => {
check_enum_variants(ccx,
it.span,
err.emit();
}
- if let hir::ForeignItemFn(ref fn_decl, _) = item.node {
+ if let hir::ForeignItemFn(ref fn_decl, _, _) = item.node {
require_c_abi_if_variadic(ccx.tcx, fn_decl, m.abi, item.span);
}
}
for impl_item_ref in impl_item_refs {
let impl_item = ccx.tcx.map.impl_item(impl_item_ref.id);
match impl_item.node {
- hir::ImplItemKind::Const(_, ref expr) => {
- check_const(ccx, &expr, impl_item.id)
+ hir::ImplItemKind::Const(_, expr) => {
+ check_const(ccx, expr, impl_item.id)
}
hir::ImplItemKind::Method(ref sig, body_id) => {
check_bare_fn(ccx, &sig.decl, body_id, impl_item.id, impl_item.span);
}
}
}
- hir::ItemTrait(.., ref trait_items) => {
- for trait_item in trait_items {
+ hir::ItemTrait(.., ref trait_item_refs) => {
+ for trait_item_ref in trait_item_refs {
+ let trait_item = ccx.tcx.map.trait_item(trait_item_ref.id);
match trait_item.node {
- hir::ConstTraitItem(_, Some(ref expr)) => {
- check_const(ccx, &expr, trait_item.id)
+ hir::TraitItemKind::Const(_, Some(expr)) => {
+ check_const(ccx, expr, trait_item.id)
}
- hir::MethodTraitItem(ref sig, Some(body_id)) => {
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body_id)) => {
check_bare_fn(ccx, &sig.decl, body_id, trait_item.id, trait_item.span);
}
- hir::MethodTraitItem(_, None) |
- hir::ConstTraitItem(_, None) |
- hir::TypeTraitItem(..) => {
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
+ hir::TraitItemKind::Const(_, None) |
+ hir::TraitItemKind::Type(..) => {
// Nothing to do.
}
}
compare_impl_method(ccx,
&ty_impl_item,
impl_item.span,
- body_id.node_id(),
+ body_id.node_id,
&ty_trait_item,
impl_trait_ref,
trait_span,
compare_impl_method(ccx,
&ty_impl_item,
impl_item.span,
- body_id.node_id(),
+ body_id.node_id,
&ty_trait_item,
impl_trait_ref,
trait_span,
/// Checks a constant with a given type.
fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
- expr: &'tcx hir::Expr,
+ body: hir::BodyId,
expected_type: Ty<'tcx>,
id: ast::NodeId) {
+ let body = ccx.tcx.map.body(body);
ccx.inherited(id).enter(|inh| {
- let fcx = FnCtxt::new(&inh, None, expr.id);
- fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
+ let fcx = FnCtxt::new(&inh, None, body.value.id);
+ fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
// Gather locals in statics (because of block expressions).
// This is technically unnecessary because locals in static items are forbidden,
// but prevents type checking from blowing up before const checking can properly
// emit an error.
- GatherLocalsVisitor { fcx: &fcx }.visit_expr(expr);
+ GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
- fcx.check_expr_coercable_to_type(expr, expected_type);
+ fcx.check_expr_coercable_to_type(&body.value, expected_type);
fcx.select_all_obligations_and_apply_defaults();
- fcx.closure_analyze(expr);
+ fcx.closure_analyze(body);
fcx.select_obligations_where_possible();
fcx.check_casts();
fcx.select_all_obligations_or_error();
- fcx.regionck_expr(expr);
- fcx.resolve_type_vars_in_expr(expr, id);
+ fcx.regionck_expr(body);
+ fcx.resolve_type_vars_in_body(body, id);
});
}
fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
- expr: &'tcx hir::Expr,
+ body: hir::BodyId,
id: ast::NodeId) {
let decl_ty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(id));
- check_const_with_type(ccx, expr, decl_ty, id);
+ check_const_with_type(ccx, body, decl_ty, id);
}
/// Checks whether a type can be represented in memory. In particular, it
let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
for v in vs {
- if let Some(ref e) = v.node.disr_expr {
- check_const_with_type(ccx, e, repr_type_ty, e.id);
+ if let Some(e) = v.node.disr_expr {
+ check_const_with_type(ccx, e, repr_type_ty, e.node_id);
}
}
let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
let variant_i = ccx.tcx.map.expect_variant(variant_i_node_id);
let i_span = match variant_i.node.disr_expr {
- Some(ref expr) => expr.span,
+ Some(expr) => ccx.tcx.map.span(expr.node_id),
None => ccx.tcx.map.span(variant_i_node_id)
};
let span = match v.node.disr_expr {
- Some(ref expr) => expr.span,
+ Some(expr) => ccx.tcx.map.span(expr.node_id),
None => v.span
};
struct_span_err!(ccx.tcx.sess, span, E0081,
match self.locals.borrow().get(&nid) {
Some(&t) => t,
None => {
- struct_span_err!(self.tcx.sess, span, E0513,
- "no type for local variable {}",
- self.tcx.map.node_to_string(nid))
- .span_label(span, &"no type for variable")
- .emit();
- self.tcx.types.err
+ span_bug!(span, "no type for local variable {}",
+ self.tcx.map.node_to_string(nid));
}
}
}
}
ty::TyRawPtr(..) => {
err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
- `(*{0}).{1}`", pprust::expr_to_string(base), field.node));
+ `(*{0}).{1}`",
+ self.tcx.map.node_to_pretty_string(base.id),
+ field.node));
}
_ => {}
}
self.diverges.set(self.diverges.get() | old_diverges);
self.has_errors.set(self.has_errors.get() | old_has_errors);
- debug!("type of expr({}) {} is...", expr.id,
- pprust::expr_to_string(expr));
- debug!("... {:?}, expected is {:?}",
- ty,
- expected);
+ debug!("type of {} is...", self.tcx.map.node_to_string(expr.id));
+ debug!("... {:?}, expected is {:?}", ty, expected);
// Add adjustments to !-expressions
if ty.is_never() {
self.check_method_call(expr, name, args, &tps[..], expected, lvalue_pref)
}
hir::ExprCast(ref e, ref t) => {
- if let hir::TyArray(_, ref count_expr) = t.node {
- self.check_expr_with_hint(&count_expr, tcx.types.usize);
- }
-
// Find the type of `e`. Supply hints based on the type we are casting to,
// if appropriate.
let t_cast = self.to_ty(t);
}
tcx.mk_array(unified, args.len())
}
- hir::ExprRepeat(ref element, ref count_expr) => {
- self.check_expr_has_type(&count_expr, tcx.types.usize);
- let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count")
+ hir::ExprRepeat(ref element, count) => {
+ let count_expr = &tcx.map.body(count).value;
+ let count = eval_length(self.tcx.global_tcx(), count_expr, "repeat count")
.unwrap_or(0);
let uty = match expected {
// PUBLIC ENTRY POINTS
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn regionck_expr(&self, e: &'gcx hir::Expr) {
- let mut rcx = RegionCtxt::new(self, RepeatingScope(e.id), e.id, Subject(e.id));
+ pub fn regionck_expr(&self, body: &'gcx hir::Body) {
+ let id = body.value.id;
+ let mut rcx = RegionCtxt::new(self, RepeatingScope(id), id, Subject(id));
if self.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
- rcx.visit_expr(e);
- rcx.visit_region_obligations(e.id);
+ rcx.visit_body(body);
+ rcx.visit_region_obligations(id);
}
rcx.resolve_regions_and_report_errors();
}
pub fn regionck_fn(&self,
fn_id: ast::NodeId,
- decl: &hir::FnDecl,
- body_id: hir::ExprId) {
+ body: &'gcx hir::Body) {
debug!("regionck_fn(id={})", fn_id);
- let node_id = body_id.node_id();
+ let node_id = body.value.id;
let mut rcx = RegionCtxt::new(self, RepeatingScope(node_id), node_id, Subject(fn_id));
if self.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
- rcx.visit_fn_body(fn_id, decl, body_id, self.tcx.map.span(fn_id));
+ rcx.visit_fn_body(fn_id, body, self.tcx.map.span(fn_id));
}
rcx.free_region_map.relate_free_regions_from_predicates(
fn visit_fn_body(&mut self,
id: ast::NodeId, // the id of the fn itself
- fn_decl: &hir::FnDecl,
- body_id: hir::ExprId,
+ body: &'gcx hir::Body,
span: Span)
{
// When we enter a function, we can derive
debug!("visit_fn_body(id={})", id);
+ let body_id = body.id();
+
let call_site = self.tcx.region_maps.lookup_code_extent(
- region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id() });
+ region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
let old_call_site_scope = self.set_call_site_scope(Some(call_site));
let fn_sig = {
let fn_sig_tys: Vec<_> =
fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect();
- let old_body_id = self.set_body_id(body_id.node_id());
- self.relate_free_regions(&fn_sig_tys[..], body_id.node_id(), span);
- self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id()),
- &fn_decl.inputs[..]);
- let body = self.tcx.map.expr(body_id);
- self.visit_expr(body);
- self.visit_region_obligations(body_id.node_id());
+ let old_body_id = self.set_body_id(body_id.node_id);
+ self.relate_free_regions(&fn_sig_tys[..], body_id.node_id, span);
+ self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id), &body.arguments);
+ self.visit_body(body);
+ self.visit_region_obligations(body_id.node_id);
let call_site_scope = self.call_site_scope.unwrap();
- debug!("visit_fn_body body.id {} call_site_scope: {:?}",
- body.id, call_site_scope);
+ debug!("visit_fn_body body.id {:?} call_site_scope: {:?}",
+ body.id(), call_site_scope);
let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
self.type_of_node_must_outlive(infer::CallReturn(span),
- body_id.node_id(),
+ body_id.node_id,
call_site_region);
self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
// regions, until regionck, as described in #3238.
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
- NestedVisitorMap::OnlyBodies(&self.tcx.map)
+ NestedVisitorMap::None
}
- fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, fd: &'gcx hir::FnDecl,
- b: hir::ExprId, span: Span, id: ast::NodeId) {
- self.visit_fn_body(id, fd, b, span)
+ fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
+ b: hir::BodyId, span: Span, id: ast::NodeId) {
+ let body = self.tcx.map.body(b);
+ self.visit_fn_body(id, body, span)
}
//visit_pat: visit_pat, // (..) see above
fn check_expr_fn_block(&mut self,
expr: &'gcx hir::Expr,
- body_id: hir::ExprId) {
- let repeating_scope = self.set_repeating_scope(body_id.node_id());
+ body_id: hir::BodyId) {
+ let repeating_scope = self.set_repeating_scope(body_id.node_id);
intravisit::walk_expr(self, expr);
self.set_repeating_scope(repeating_scope);
}
for arg in args {
let arg_ty = self.node_ty(arg.id);
let re_scope = self.tcx.mk_region(ty::ReScope(body_scope));
- let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
+ let arg_cmt = mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty);
debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
arg_ty,
arg_cmt,
// PUBLIC ENTRY POINTS
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn closure_analyze(&self, body: &'gcx hir::Expr) {
+ pub fn closure_analyze(&self, body: &'gcx hir::Body) {
let mut seed = SeedBorrowKind::new(self);
- seed.visit_expr(body);
+ seed.visit_body(body);
let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
- adjust.visit_expr(body);
+ adjust.visit_body(body);
// it's our job to process these.
assert!(self.deferred_call_resolutions.borrow().is_empty());
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
- NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+ NestedVisitorMap::None
}
fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
match expr.node {
hir::ExprClosure(cc, _, body_id, _) => {
- self.check_closure(expr, cc, body_id);
+ let body = self.fcx.tcx.map.body(body_id);
+ self.visit_body(body);
+ self.check_closure(expr, cc);
}
_ => { }
fn check_closure(&mut self,
expr: &hir::Expr,
- capture_clause: hir::CaptureClause,
- _body_id: hir::ExprId)
+ capture_clause: hir::CaptureClause)
{
let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id);
if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
fn analyze_closure(&mut self,
id: ast::NodeId,
span: Span,
- decl: &hir::FnDecl,
- body_id: hir::ExprId) {
+ body: &hir::Body) {
/*!
* Analysis starting point.
*/
- debug!("analyze_closure(id={:?}, body.id={:?})", id, body_id);
+ debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
{
- let body = self.fcx.tcx.map.expr(body_id);
let mut euv =
euv::ExprUseVisitor::with_options(self,
self.fcx,
mc::MemCategorizationOptions {
during_closure_kind_inference: true
});
- euv.walk_fn(decl, body);
+ euv.consume_body(body);
}
// Now that we've analyzed the closure, we know how each
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
- NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+ NestedVisitorMap::None
}
fn visit_fn(&mut self,
fn_kind: intravisit::FnKind<'gcx>,
decl: &'gcx hir::FnDecl,
- body: hir::ExprId,
+ body: hir::BodyId,
span: Span,
id: ast::NodeId)
{
intravisit::walk_fn(self, fn_kind, decl, body, span, id);
- self.analyze_closure(id, span, decl, body);
+
+ let body = self.fcx.tcx.map.body(body);
+ self.visit_body(body);
+ self.analyze_closure(id, span, body);
}
}
}
}
- fn check_trait_or_impl_item(&mut self,
- item_id: ast::NodeId,
- span: Span,
- sig_if_method: Option<&hir::MethodSig>) {
+ fn check_associated_item(&mut self,
+ item_id: ast::NodeId,
+ span: Span,
+ sig_if_method: Option<&hir::MethodSig>) {
let code = self.code.clone();
self.for_id(item_id, span).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
fn check_item_fn(&mut self,
item: &hir::Item,
- body_id: hir::ExprId)
+ body_id: hir::BodyId)
{
self.for_item(item).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
let mut implied_bounds = vec![];
- let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id());
+ let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id);
this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates,
free_id_outlive, &mut implied_bounds);
implied_bounds
return;
}
- let span = method_sig.decl.inputs[0].pat.span;
+ let span = method_sig.decl.inputs[0].span;
let free_substs = &fcx.parameter_environment.free_substs;
let method_ty = fcx.tcx.item_type(method.def_id);
fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
debug!("visit_trait_item: {:?}", trait_item);
let method_sig = match trait_item.node {
- hir::TraitItem_::MethodTraitItem(ref sig, _) => Some(sig),
+ hir::TraitItemKind::Method(ref sig, _) => Some(sig),
_ => None
};
- self.check_trait_or_impl_item(trait_item.id, trait_item.span, method_sig);
+ self.check_associated_item(trait_item.id, trait_item.span, method_sig);
intravisit::walk_trait_item(self, trait_item)
}
hir::ImplItemKind::Method(ref sig, _) => Some(sig),
_ => None
};
- self.check_trait_or_impl_item(impl_item.id, impl_item.span, method_sig);
+ self.check_associated_item(impl_item.id, impl_item.span, method_sig);
intravisit::walk_impl_item(self, impl_item)
}
}
use syntax::ast;
use syntax_pos::Span;
-use rustc::hir::print::pat_to_string;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::hir::{self, PatKind};
+use rustc::hir;
///////////////////////////////////////////////////////////////////////////
-// Entry point functions
+// Entry point
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn resolve_type_vars_in_expr(&self, e: &'gcx hir::Expr, item_id: ast::NodeId) {
+ pub fn resolve_type_vars_in_body(&self,
+ body: &'gcx hir::Body,
+ item_id: ast::NodeId) {
assert_eq!(self.writeback_errors.get(), false);
let mut wbcx = WritebackCx::new(self);
- wbcx.visit_expr(e);
- wbcx.visit_upvar_borrow_map();
- wbcx.visit_closures();
- wbcx.visit_liberated_fn_sigs();
- wbcx.visit_fru_field_types();
- wbcx.visit_deferred_obligations(item_id);
- wbcx.visit_type_nodes();
- }
-
- pub fn resolve_type_vars_in_fn(&self,
- decl: &'gcx hir::FnDecl,
- body: &'gcx hir::Expr,
- item_id: ast::NodeId) {
- assert_eq!(self.writeback_errors.get(), false);
- let mut wbcx = WritebackCx::new(self);
- wbcx.visit_expr(body);
- for arg in &decl.inputs {
+ for arg in &body.arguments {
wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
- wbcx.visit_pat(&arg.pat);
-
- // Privacy needs the type for the whole pattern, not just each binding
- if let PatKind::Binding(..) = arg.pat.node {} else {
- wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.pat.id);
- }
}
+ wbcx.visit_body(body);
wbcx.visit_upvar_borrow_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
- NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+ NestedVisitorMap::None
}
fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
self.visit_method_map_entry(ResolvingExpr(e.span),
MethodCall::expr(e.id));
- if let hir::ExprClosure(_, ref decl, ..) = e.node {
- for input in &decl.inputs {
- self.visit_node_id(ResolvingExpr(e.span), input.id);
+ if let hir::ExprClosure(_, _, body, _) = e.node {
+ let body = self.fcx.tcx.map.body(body);
+ for arg in &body.arguments {
+ self.visit_node_id(ResolvingExpr(e.span), arg.id);
}
+
+ self.visit_body(body);
}
intravisit::walk_expr(self, e);
self.visit_node_id(ResolvingPattern(p.span), p.id);
debug!("Type for pattern binding {} (id {}) resolved to {:?}",
- pat_to_string(p),
+ self.tcx().map.node_to_pretty_string(p.id),
p.id,
self.tcx().tables().node_id_to_type(p.id));
self.write_ty_to_tcx(l.id, var_ty);
intravisit::walk_local(self, l);
}
-
- fn visit_ty(&mut self, t: &'gcx hir::Ty) {
- match t.node {
- hir::TyArray(ref ty, ref count_expr) => {
- self.visit_ty(&ty);
- self.write_ty_to_tcx(count_expr.id, self.tcx().types.usize);
- }
- hir::TyBareFn(ref function_declaration) => {
- intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
- walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
- }
- _ => intravisit::walk_ty(self, t)
- }
- }
}
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
}
}
+}
+impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
/// Checks exactly one impl for orphan rules and other such
/// restrictions. In this fn, it can happen that multiple errors
/// apply to a specific impl, so just return after reporting one
/// to prevent inundating the user with a bunch of similar error
/// reports.
- fn check_item(&self, item: &hir::Item) {
+ fn visit_item(&mut self, item: &hir::Item) {
let def_id = self.tcx.map.local_def_id(item.id);
match item.node {
hir::ItemImpl(.., None, ref ty, _) => {
the crate they're defined in; define a new trait instead")
.span_label(item_trait_ref.path.span,
&format!("`{}` trait not defined in this crate",
- item_trait_ref.path))
+ self.tcx.map.node_to_pretty_string(item_trait_ref.ref_id)))
.emit();
return;
}
}
}
}
-}
-impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
- fn visit_item(&mut self, item: &hir::Item) {
- self.check_item(item);
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
use syntax::symbol::{Symbol, keywords};
use syntax_pos::Span;
-use rustc::hir::{self, map as hir_map, print as pprust};
+use rustc::hir::{self, map as hir_map};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
intravisit::walk_ty(self, ty);
}
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+ self.with_collect_item_sig(trait_item.id, || {
+ convert_trait_item(self.ccx, trait_item)
+ });
+ intravisit::walk_trait_item(self, trait_item);
+ }
+
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.with_collect_item_sig(impl_item.id, || {
convert_impl_item(self.ccx, impl_item)
id: ast::NodeId,
sig: &hir::MethodSig,
untransformed_rcvr_ty: Ty<'tcx>,
- rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
+ body: Option<hir::BodyId>,
+ rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) {
let def_id = ccx.tcx.map.local_def_id(id);
let ty_generics = generics_of_def_id(ccx, def_id);
ImplContainer(_) => Some(AnonTypeScope::new(def_id)),
TraitContainer(_) => None
};
+ let assoc_item = ccx.tcx.associated_item(def_id);
+ let self_value_ty = if assoc_item.method_has_self_argument {
+ Some(untransformed_rcvr_ty)
+ } else {
+ None
+ };
let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
- sig, untransformed_rcvr_ty, anon_scope);
+ sig, self_value_ty, body, anon_scope);
let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
ccx.tcx.map.span(id), def_id);
tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
},
- hir::ItemTrait(.., ref trait_items) => {
+ hir::ItemTrait(..) => {
generics_of_def_id(ccx, def_id);
trait_def_of_item(ccx, it);
let _: Result<(), ErrorReported> = // any error is already reported, can ignore
ccx.ensure_super_predicates(it.span, def_id);
convert_trait_predicates(ccx, it);
- let trait_predicates = tcx.item_predicates(def_id);
-
- debug!("convert: trait_bounds={:?}", trait_predicates);
-
- // FIXME: is the ordering here important? I think it is.
- let container = TraitContainer(def_id);
-
- // Convert all the associated constants.
- for trait_item in trait_items {
- if let hir::ConstTraitItem(ref ty, _) = trait_item.node {
- let const_def_id = ccx.tcx.map.local_def_id(trait_item.id);
- generics_of_def_id(ccx, const_def_id);
- let ty = ccx.icx(&trait_predicates)
- .to_ty(&ExplicitRscope, ty);
- tcx.item_types.borrow_mut().insert(const_def_id, ty);
- convert_associated_const(ccx, container, trait_item.id, ty)
- }
- }
-
- // Convert all the associated types.
- for trait_item in trait_items {
- if let hir::TypeTraitItem(_, ref opt_ty) = trait_item.node {
- let type_def_id = ccx.tcx.map.local_def_id(trait_item.id);
- generics_of_def_id(ccx, type_def_id);
-
- let typ = opt_ty.as_ref().map({
- |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
- });
-
- convert_associated_type(ccx, container, trait_item.id, typ);
- }
- }
-
- // Convert all the methods
- for trait_item in trait_items {
- if let hir::MethodTraitItem(ref sig, _) = trait_item.node {
- convert_method(ccx,
- container,
- trait_item.id,
- sig,
- tcx.mk_self_type(),
- &trait_predicates);
- }
- }
},
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
}
}
+fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
+ let tcx = ccx.tcx;
+
+ // we can lookup details about the trait because items are visited
+ // before trait-items
+ let trait_def_id = tcx.map.get_parent_did(trait_item.id);
+ let trait_predicates = tcx.item_predicates(trait_def_id);
+
+ match trait_item.node {
+ hir::TraitItemKind::Const(ref ty, _) => {
+ let const_def_id = ccx.tcx.map.local_def_id(trait_item.id);
+ generics_of_def_id(ccx, const_def_id);
+ let ty = ccx.icx(&trait_predicates)
+ .to_ty(&ExplicitRscope, &ty);
+ tcx.item_types.borrow_mut().insert(const_def_id, ty);
+ convert_associated_const(ccx, TraitContainer(trait_def_id),
+ trait_item.id, ty);
+ }
+
+ hir::TraitItemKind::Type(_, ref opt_ty) => {
+ let type_def_id = ccx.tcx.map.local_def_id(trait_item.id);
+ generics_of_def_id(ccx, type_def_id);
+
+ let typ = opt_ty.as_ref().map({
+ |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
+ });
+
+ convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
+ }
+
+ hir::TraitItemKind::Method(ref sig, ref method) => {
+ let body = match *method {
+ hir::TraitMethod::Required(_) => None,
+ hir::TraitMethod::Provided(body) => Some(body)
+ };
+ convert_method(ccx, TraitContainer(trait_def_id),
+ trait_item.id, sig, tcx.mk_self_type(),
+ body, &trait_predicates);
+ }
+ }
+}
+
fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
let tcx = ccx.tcx;
convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
}
- hir::ImplItemKind::Method(ref sig, _) => {
+ hir::ImplItemKind::Method(ref sig, body) => {
convert_method(ccx, ImplContainer(impl_def_id),
impl_item.id, sig, impl_self_ty,
- &impl_predicates);
+ Some(body), &impl_predicates);
}
}
}
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
-> Option<ty::Disr> {
- debug!("disr expr, checking {}", pprust::expr_to_string(e));
+ debug!("disr expr, checking {}", ccx.tcx.map.node_to_pretty_string(e.id));
let ty_hint = repr_ty.to_ty(ccx.tcx);
let print_err = |cv: ConstVal| {
let mut prev_disr = None::<ty::Disr>;
let variants = def.variants.iter().map(|v| {
let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
- let disr = if let Some(ref e) = v.node.disr_expr {
+ let disr = if let Some(e) = v.node.disr_expr {
+ let e = &tcx.map.body(e).value;
evaluate_disr_expr(ccx, repr_type, e)
} else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) {
Some(disr)
ast_generics: &hir::Generics,
trait_predicates: &ty::GenericPredicates<'tcx>,
self_trait_ref: ty::TraitRef<'tcx>,
- trait_items: &[hir::TraitItem])
+ trait_item_refs: &[hir::TraitItemRef])
-> Vec<ty::Predicate<'tcx>>
{
- trait_items.iter().flat_map(|trait_item| {
+ trait_item_refs.iter().flat_map(|trait_item_ref| {
+ let trait_item = ccx.tcx.map.trait_item(trait_item_ref.id);
let bounds = match trait_item.node {
- hir::TypeTraitItem(ref bounds, _) => bounds,
+ hir::TraitItemKind::Type(ref bounds, _) => bounds,
_ => {
return vec![].into_iter();
}
let ast_generics = match node {
NodeTraitItem(item) => {
match item.node {
- MethodTraitItem(ref sig, _) => &sig.generics,
+ TraitItemKind::Method(ref sig, _) => &sig.generics,
_ => &no_generics
}
}
NodeForeignItem(item) => {
match item.node {
ForeignItemStatic(..) => &no_generics,
- ForeignItemFn(_, ref generics) => generics
+ ForeignItemFn(_, _, ref generics) => generics
}
}
ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t)
}
- ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
+ ItemFn(ref decl, unsafety, _, abi, ref generics, body) => {
let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl,
- Some(AnonTypeScope::new(def_id)));
+ body, Some(AnonTypeScope::new(def_id)));
let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
ccx.tcx.mk_fn_def(def_id, substs, tofd)
}
let abi = ccx.tcx.map.get_foreign_abi(node_id);
match foreign_item.node {
- ForeignItemFn(ref fn_decl, ref generics) => {
+ ForeignItemFn(ref fn_decl, _, ref generics) => {
compute_type_of_foreign_fn_decl(
ccx, ccx.tcx.map.local_def_id(foreign_item.id),
fn_decl, generics, abi)
let no_generics = hir::Generics::empty();
let generics = match it.node {
- hir::ForeignItemFn(_, ref generics) => generics,
+ hir::ForeignItemFn(_, _, ref generics) => generics,
hir::ForeignItemStatic(..) => &no_generics
};
ccx.tcx.sess.struct_span_err(ast_ty.span,
&format!("use of SIMD type `{}` in FFI is highly experimental and \
may result in invalid code",
- pprust::ty_to_string(ast_ty)))
+ ccx.tcx.map.node_to_pretty_string(ast_ty.id)))
.help("add #![feature(simd_ffi)] to the crate attributes to enable")
.emit();
}
};
for (input, ty) in decl.inputs.iter().zip(&input_tys) {
- check(&input.ty, ty)
+ check(&input, ty)
}
if let hir::Return(ref ty) = decl.output {
check(&ty, output)
```
"##,
-E0513: r##"
-The type of the variable couldn't be found out.
-
-Erroneous code example:
-
-```compile_fail,E0513
-use std::mem;
-
-unsafe {
- let size = mem::size_of::<u32>();
- mem::transmute_copy::<u32, [u8; size]>(&8_8);
- // error: no type for local variable
-}
-```
-
-To fix this error, please use a constant size instead of `size`. To make
-this error more obvious, you could run:
-
-```compile_fail,E0080
-use std::mem;
-
-unsafe {
- mem::transmute_copy::<u32, [u8; mem::size_of::<u32>()]>(&8_8);
- // error: constant evaluation error
-}
-```
-
-So now, you can fix your code by setting the size directly:
-
-```
-use std::mem;
-
-unsafe {
- mem::transmute_copy::<u32, [u8; 4]>(&8_8);
- // `u32` is 4 bytes so we replace the `mem::size_of` call with its size
-}
-```
-"##,
-
E0516: r##"
The `typeof` keyword is currently reserved but unimplemented.
Erroneous code example:
}
}
+ fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) { }
+
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc::ty::subst::Substs;
#[derive(Clone)]
pub struct ElisionFailureInfo {
- pub name: String,
+ /// Where we can find the argument pattern.
+ pub parent: Option<hir::BodyId>,
+ /// The index of the argument in the original definition.
+ pub index: usize,
pub lifetime_count: usize,
pub have_bound_regions: bool
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
//! Support for inlining external documentation into the current AST.
+use std::collections::BTreeMap;
+use std::io;
use std::iter::once;
use syntax::ast;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
-use rustc::hir::print as pprust;
use rustc::ty;
use rustc::util::nodemap::FxHashSet;
-use rustc_const_eval::lookup_const_by_id;
-
use core::{DocContext, DocAccessLevels};
use doctree;
use clean::{self, GetDefId};
match item.kind {
ty::AssociatedKind::Const => {
let default = if item.defaultness.has_value() {
- Some(pprust::expr_to_string(
- lookup_const_by_id(tcx, item.def_id, None).unwrap().0))
+ Some(print_inlined_const(cx, item.def_id))
} else {
None
};
}
}
-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);
+struct InlinedConst {
+ nested_bodies: BTreeMap<hir::BodyId, hir::Body>
+}
+
+impl hir::print::PpAnn for InlinedConst {
+ fn nested(&self, state: &mut hir::print::State, nested: hir::print::Nested)
+ -> io::Result<()> {
+ if let hir::print::Nested::Body(body) = nested {
+ state.print_expr(&self.nested_bodies[&body].value)
+ } else {
+ Ok(())
+ }
+ }
+}
+fn print_inlined_const(cx: &DocContext, did: DefId) -> String {
+ let body = cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap();
+ let inlined = InlinedConst {
+ nested_bodies: cx.tcx.sess.cstore.item_body_nested_bodies(did)
+ };
+ hir::print::to_string(&inlined, |s| s.print_expr(&body.value))
+}
+
+fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
clean::Constant {
- type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| cx.tcx.item_type(did).clean(cx)),
- expr: sn
+ type_: cx.tcx.item_type(did).clean(cx),
+ expr: print_inlined_const(cx, did)
}
}
use rustc::middle::lang_items;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
-use rustc::hir::print as pprust;
use rustc::ty::subst::Substs;
use rustc::ty::{self, AdtKind};
use rustc::middle::stability;
pub abi: Abi,
}
-impl Clean<Method> for hir::MethodSig {
+impl<'a> Clean<Method> for (&'a hir::MethodSig, hir::BodyId) {
fn clean(&self, cx: &DocContext) -> Method {
- let decl = FnDecl {
- inputs: Arguments {
- values: self.decl.inputs.clean(cx),
- },
- output: self.decl.output.clean(cx),
- variadic: false,
- attrs: Attributes::default()
- };
Method {
- generics: self.generics.clean(cx),
- unsafety: self.unsafety,
- constness: self.constness,
- decl: decl,
- abi: self.abi
+ generics: self.0.generics.clean(cx),
+ unsafety: self.0.unsafety,
+ constness: self.0.constness,
+ decl: (&*self.0.decl, self.1).clean(cx),
+ abi: self.0.abi
}
}
}
pub abi: Abi,
}
-impl Clean<TyMethod> for hir::MethodSig {
- fn clean(&self, cx: &DocContext) -> TyMethod {
- let decl = FnDecl {
- inputs: Arguments {
- values: self.decl.inputs.clean(cx),
- },
- output: self.decl.output.clean(cx),
- variadic: false,
- attrs: Attributes::default()
- };
- TyMethod {
- unsafety: self.unsafety.clone(),
- decl: decl,
- generics: self.generics.clean(cx),
- abi: self.abi
- }
- }
-}
-
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Function {
pub decl: FnDecl,
deprecation: self.depr.clean(cx),
def_id: cx.tcx.map.local_def_id(self.id),
inner: FunctionItem(Function {
- decl: self.decl.clean(cx),
+ decl: (&self.decl, self.body).clean(cx),
generics: self.generics.clean(cx),
unsafety: self.unsafety,
constness: self.constness,
pub values: Vec<Argument>,
}
-impl Clean<FnDecl> for hir::FnDecl {
+impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], &'a [Spanned<ast::Name>]) {
+ fn clean(&self, cx: &DocContext) -> Arguments {
+ Arguments {
+ values: self.0.iter().enumerate().map(|(i, ty)| {
+ let mut name = self.1.get(i).map(|n| n.node.to_string())
+ .unwrap_or(String::new());
+ if name.is_empty() {
+ name = "_".to_string();
+ }
+ Argument {
+ name: name,
+ type_: ty.clean(cx),
+ }
+ }).collect()
+ }
+ }
+}
+
+impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], hir::BodyId) {
+ fn clean(&self, cx: &DocContext) -> Arguments {
+ let body = cx.tcx.map.body(self.1);
+
+ Arguments {
+ values: self.0.iter().enumerate().map(|(i, ty)| {
+ Argument {
+ name: name_from_pat(&body.arguments[i].pat),
+ type_: ty.clean(cx),
+ }
+ }).collect()
+ }
+ }
+}
+
+impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
+ where (&'a [P<hir::Ty>], A): Clean<Arguments>
+{
fn clean(&self, cx: &DocContext) -> FnDecl {
FnDecl {
- inputs: Arguments {
- values: self.inputs.clean(cx),
- },
- output: self.output.clean(cx),
- variadic: self.variadic,
+ inputs: (&self.0.inputs[..], self.1).clean(cx),
+ output: self.0.output.clean(cx),
+ variadic: self.0.variadic,
attrs: Attributes::default()
}
}
values: sig.skip_binder().inputs().iter().map(|t| {
Argument {
type_: t.clean(cx),
- id: ast::CRATE_NODE_ID,
name: names.next().map_or("".to_string(), |name| name.to_string()),
}
}).collect(),
pub struct Argument {
pub type_: Type,
pub name: String,
- pub id: ast::NodeId,
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
impl Argument {
pub fn to_self(&self) -> Option<SelfTy> {
- if self.name == "self" {
- match self.type_ {
- Infer => Some(SelfValue),
- BorrowedRef{ref lifetime, mutability, ref type_} if **type_ == Infer => {
- Some(SelfBorrowed(lifetime.clone(), mutability))
- }
- _ => Some(SelfExplicit(self.type_.clone()))
- }
- } else {
- None
+ if self.name != "self" {
+ return None;
}
- }
-}
-
-impl Clean<Argument> for hir::Arg {
- fn clean(&self, cx: &DocContext) -> Argument {
- Argument {
- name: name_from_pat(&*self.pat),
- type_: (self.ty.clean(cx)),
- id: self.id
+ if self.type_.is_self_type() {
+ return Some(SelfValue);
+ }
+ match self.type_ {
+ BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
+ Some(SelfBorrowed(lifetime.clone(), mutability))
+ }
+ _ => Some(SelfExplicit(self.type_.clone()))
}
}
}
impl Clean<Item> for hir::TraitItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
- hir::ConstTraitItem(ref ty, ref default) => {
+ hir::TraitItemKind::Const(ref ty, default) => {
AssociatedConstItem(ty.clean(cx),
- default.as_ref().map(|e| pprust::expr_to_string(&e)))
+ default.map(|e| print_const_expr(cx, e)))
}
- hir::MethodTraitItem(ref sig, Some(_)) => {
- MethodItem(sig.clean(cx))
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
+ MethodItem((sig, body).clean(cx))
}
- hir::MethodTraitItem(ref sig, None) => {
- TyMethodItem(sig.clean(cx))
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
+ TyMethodItem(TyMethod {
+ unsafety: sig.unsafety.clone(),
+ decl: (&*sig.decl, &names[..]).clean(cx),
+ generics: sig.generics.clean(cx),
+ abi: sig.abi
+ })
}
- hir::TypeTraitItem(ref bounds, ref default) => {
+ hir::TraitItemKind::Type(ref bounds, ref default) => {
AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
}
};
impl Clean<Item> for hir::ImplItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
- hir::ImplItemKind::Const(ref ty, ref expr) => {
+ hir::ImplItemKind::Const(ref ty, expr) => {
AssociatedConstItem(ty.clean(cx),
- Some(pprust::expr_to_string(expr)))
+ Some(print_const_expr(cx, expr)))
}
- hir::ImplItemKind::Method(ref sig, _) => {
- MethodItem(sig.clean(cx))
+ hir::ImplItemKind::Method(ref sig, body) => {
+ MethodItem((sig, body).clean(cx))
}
hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
type_: ty.clean(cx),
};
let self_arg_ty = *fty.sig.input(0).skip_binder();
if self_arg_ty == self_ty {
- decl.inputs.values[0].type_ = Infer;
+ decl.inputs.values[0].type_ = Generic(String::from("Self"));
} else if let ty::TyRef(_, mt) = self_arg_ty.sty {
if mt.ty == self_ty {
match decl.inputs.values[0].type_ {
- BorrowedRef{ref mut type_, ..} => **type_ = Infer,
+ BorrowedRef{ref mut type_, ..} => {
+ **type_ = Generic(String::from("Self"))
+ }
_ => unreachable!(),
}
}
_ => false,
}
}
+
+ pub fn is_self_type(&self) -> bool {
+ match *self {
+ Generic(ref name) => name == "Self",
+ _ => false
+ }
+ }
}
impl GetDefId for Type {
BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
type_: box m.ty.clean(cx)},
TySlice(ref ty) => Vector(box ty.clean(cx)),
- TyArray(ref ty, ref e) => {
+ TyArray(ref ty, e) => {
use rustc_const_math::{ConstInt, ConstUsize};
use rustc_const_eval::eval_const_expr;
use rustc::middle::const_val::ConstVal;
+ let e = &cx.tcx.map.body(e).value;
let n = match eval_const_expr(cx.tcx, e) {
ConstVal::Integral(ConstInt::Usize(u)) => match u {
ConstUsize::Us16(u) => u.to_string(),
type_params: Vec::new(),
where_predicates: Vec::new()
},
- decl: self.decl.clean(cx),
+ decl: (&*self.decl, &[][..]).clean(cx),
abi: self.abi,
}
}
inner: StaticItem(Static {
type_: self.type_.clean(cx),
mutability: self.mutability.clean(cx),
- expr: pprust::expr_to_string(&self.expr),
+ expr: print_const_expr(cx, self.expr),
}),
}
}
deprecation: self.depr.clean(cx),
inner: ConstantItem(Constant {
type_: self.type_.clean(cx),
- expr: pprust::expr_to_string(&self.expr),
+ expr: print_const_expr(cx, self.expr),
}),
}
}
impl Clean<Item> for hir::ForeignItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
- hir::ForeignItemFn(ref decl, ref generics) => {
+ hir::ForeignItemFn(ref decl, ref names, ref generics) => {
ForeignFunctionItem(Function {
- decl: decl.clean(cx),
+ decl: (&**decl, &names[..]).clean(cx),
generics: generics.clean(cx),
unsafety: hir::Unsafety::Unsafe,
abi: Abi::Rust,
}
}
+fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
+ cx.tcx.map.node_to_pretty_string(body.node_id)
+}
+
/// Given a type Path, resolve it to a Type using the TyCtxt
fn resolve_type(cx: &DocContext,
path: Path,
pub whence: Span,
pub generics: hir::Generics,
pub abi: abi::Abi,
+ pub body: hir::BodyId,
}
pub struct Typedef {
pub struct Static {
pub type_: P<hir::Ty>,
pub mutability: hir::Mutability,
- pub expr: P<hir::Expr>,
+ pub expr: hir::BodyId,
pub name: Name,
pub attrs: hir::HirVec<ast::Attribute>,
pub vis: hir::Visibility,
pub struct Constant {
pub type_: P<hir::Ty>,
- pub expr: P<hir::Expr>,
+ pub expr: hir::BodyId,
pub name: Name,
pub attrs: hir::HirVec<ast::Attribute>,
pub vis: hir::Visibility,
}
fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
- for stability in short_stability(item, cx, true) {
- write!(w, "<div class='stability'>{}</div>", stability)?;
+ let stabilities = short_stability(item, cx, true);
+ if !stabilities.is_empty() {
+ write!(w, "<div class='stability'>")?;
+ for stability in stabilities {
+ write!(w, "{}", stability)?;
+ }
+ write!(w, "</div>")?;
}
Ok(())
}
String::new()
};
let text = format!("Deprecated{}{}", since, Markdown(&deprecated_reason));
- stability.push(format!("<em class='stab deprecated'>{}</em>", text))
+ stability.push(format!("<div class='stab deprecated'>{}</div>", text))
};
if stab.level == stability::Unstable {
String::new()
};
let text = format!("Unstable{}{}", unstable_extra, Markdown(&unstable_reason));
- stability.push(format!("<em class='stab unstable'>{}</em>", text))
+ stability.push(format!("<div class='stab unstable'>{}</div>", text))
};
} else if let Some(depr) = item.deprecation.as_ref() {
let note = if show_reason && !depr.note.is_empty() {
};
let text = format!("Deprecated{}{}", since, Markdown(¬e));
- stability.push(format!("<em class='stab deprecated'>{}</em>", text))
+ stability.push(format!("<div class='stab deprecated'>{}</div>", text))
}
stability
padding: 20px;
}
-em.stab {
- display: inline-block;
+.stab {
+ display: table;
border-width: 1px;
border-style: solid;
padding: 3px;
margin-bottom: 5px;
font-size: 90%;
- font-style: normal;
}
-em.stab p {
+.stab p {
display: inline;
}
.module-item .stab {
+ display: inline;
border-width: 0;
padding: 0;
margin: 0;
background-color: white;
}
-div.stability > em > code {
- background-color: initial;
-}
-
.docblock code, .docblock-short code {
background-color: #F5F5F5;
}
background-color: white;
}
-em.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
-em.stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
+.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
+.stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
};
let crate_name = matches.opt_str("crate-name");
let playground_url = matches.opt_str("playground-url");
+ let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
match (should_test, markdown_input) {
(true, true) => {
- return markdown::test(input, cfgs, libs, externs, test_args)
+ return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot)
}
(true, false) => {
- return test::run(input, cfgs, libs, externs, test_args, crate_name)
+ return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot)
}
(false, true) => return markdown::render(input,
output.unwrap_or(PathBuf::from("doc")),
/// Run any tests/code examples in the markdown file `input`.
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
- mut test_args: Vec<String>) -> isize {
+ mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>) -> isize {
let input_str = match load_string(input) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
let mut opts = TestOptions::default();
opts.no_crate_inject = true;
let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
- true, opts);
+ true, opts, maybe_sysroot);
find_testable_code(&input_str, &mut collector);
test_args.insert(0, "rustdoctest".to_string());
testing::test_main(&test_args, collector.tests);
libs: SearchPaths,
externs: Externs,
mut test_args: Vec<String>,
- crate_name: Option<String>)
+ crate_name: Option<String>,
+ maybe_sysroot: Option<PathBuf>)
-> isize {
let input_path = PathBuf::from(input);
let input = config::Input::File(input_path.clone());
let sessopts = config::Options {
- maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap()
- .parent().unwrap().to_path_buf()),
+ maybe_sysroot: maybe_sysroot.clone().or_else(
+ || Some(env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_path_buf())),
search_paths: libs.clone(),
crate_types: vec![config::CrateTypeDylib],
externs: externs.clone(),
libs,
externs,
false,
- opts);
+ opts,
+ maybe_sysroot);
{
let dep_graph = DepGraph::new(false);
fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
externs: Externs,
should_panic: bool, no_run: bool, as_test_harness: bool,
- compile_fail: bool, mut error_codes: Vec<String>, opts: &TestOptions) {
+ compile_fail: bool, mut error_codes: Vec<String>, opts: &TestOptions,
+ maybe_sysroot: Option<PathBuf>) {
// the test harness wants its own `main` & top level functions, so
// never wrap the test in `fn main() { ... }`
let test = maketest(test, Some(cratename), as_test_harness, opts);
let outputs = OutputTypes::new(&[(OutputType::Exe, None)]);
let sessopts = config::Options {
- maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap()
- .parent().unwrap().to_path_buf()),
+ maybe_sysroot: maybe_sysroot.or_else(
+ || Some(env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_path_buf())),
search_paths: libs,
crate_types: vec![config::CrateTypeExecutable],
output_types: outputs,
current_header: Option<String>,
cratename: String,
opts: TestOptions,
+ maybe_sysroot: Option<PathBuf>,
}
impl Collector {
pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
- use_headers: bool, opts: TestOptions) -> Collector {
+ use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>) -> Collector {
Collector {
tests: Vec::new(),
names: Vec::new(),
current_header: None,
cratename: cratename,
opts: opts,
+ maybe_sysroot: maybe_sysroot,
}
}
let externs = self.externs.clone();
let cratename = self.cratename.to_string();
let opts = self.opts.clone();
+ let maybe_sysroot = self.maybe_sysroot.clone();
debug!("Creating test {}: {}", name, test);
self.tests.push(testing::TestDescAndFn {
desc: testing::TestDesc {
as_test_harness,
compile_fail,
error_codes,
- &opts);
+ &opts,
+ maybe_sysroot);
})
});
}
fn visit_item(&mut self, item: &'hir hir::Item) {
let name = if let hir::ItemImpl(.., ref ty, _) = item.node {
- hir::print::ty_to_string(ty)
+ self.map.node_to_pretty_string(ty.id)
} else {
item.name.to_string()
};
unsafety: &hir::Unsafety,
constness: hir::Constness,
abi: &abi::Abi,
- gen: &hir::Generics) -> Function {
+ gen: &hir::Generics,
+ body: hir::BodyId) -> Function {
debug!("Visiting fn");
Function {
id: item.id,
unsafety: *unsafety,
constness: constness,
abi: *abi,
+ body: body,
}
}
om.structs.push(self.visit_variant_data(item, name, sd, gen)),
hir::ItemUnion(ref sd, ref gen) =>
om.unions.push(self.visit_union_data(item, name, sd, gen)),
- hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
+ hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, body) =>
om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
- constness, abi, gen)),
+ constness, abi, gen, body)),
hir::ItemTy(ref ty, ref gen) => {
let t = Typedef {
ty: ty.clone(),
};
om.constants.push(s);
},
- hir::ItemTrait(unsafety, ref gen, ref b, ref items) => {
+ hir::ItemTrait(unsafety, ref gen, ref b, ref item_ids) => {
+ let items = item_ids.iter()
+ .map(|ti| self.cx.tcx.map.trait_item(ti.id).clone())
+ .collect();
let t = Trait {
unsafety: unsafety,
name: name,
- items: items.clone(),
+ items: items,
generics: gen.clone(),
bounds: b.iter().cloned().collect(),
id: item.id,
mod imp {
use os::unix::prelude::*;
use mem;
- use ffi::OsString;
+ use ffi::{CStr, OsString};
use marker::PhantomData;
- use slice;
- use str;
+ use libc;
use super::Args;
use sys_common::mutex::Mutex;
static LOCK: Mutex = Mutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
- let mut args: Vec<Vec<u8>> = Vec::new();
- for i in 0..argc {
- let len = *(argv.offset(i * 2)) as usize;
- let ptr = *(argv.offset(i * 2 + 1));
- args.push(slice::from_raw_parts(ptr, len).to_vec());
- }
+ let args = (0..argc).map(|i| {
+ CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
+ }).collect();
LOCK.lock();
let ptr = get_global_ptr();
name: Box<[u8]>
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct OpenOptions {
// generic
read: bool,
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileType { mode: u16 }
+#[derive(Debug)]
pub struct DirBuilder { mode: u16 }
impl FileAttr {
}
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
- let flags = syscall::O_CREAT | syscall::O_DIRECTORY | syscall::O_EXCL;
+ let flags = syscall::O_CREAT | syscall::O_CLOEXEC | syscall::O_DIRECTORY | syscall::O_EXCL;
let fd = cvt(syscall::open(p.to_str().unwrap(), flags | (self.mode as usize & 0o777)))?;
let _ = syscall::close(fd);
Ok(())
ExceptionCollidedUnwind
}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct CONSOLE_READCONSOLE_CONTROL {
+ pub nLength: ULONG,
+ pub nInitialChars: ULONG,
+ pub dwCtrlWakeupMask: ULONG,
+ pub dwControlKeyState: ULONG,
+}
+pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL;
+
#[link(name = "ws2_32")]
#[link(name = "userenv")]
#[link(name = "shell32")]
pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
- // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL
pub fn ReadConsoleW(hConsoleInput: HANDLE,
lpBuffer: LPVOID,
nNumberOfCharsToRead: DWORD,
lpNumberOfCharsRead: LPDWORD,
- pInputControl: LPVOID) -> BOOL;
+ pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;
pub fn WriteConsoleW(hConsoleOutput: HANDLE,
lpBuffer: LPCVOID,
if utf8.position() as usize == utf8.get_ref().len() {
let mut utf16 = vec![0u16; 0x1000];
let mut num = 0;
+ let mut input_control = readconsole_input_control(CTRL_Z_MASK);
cvt(unsafe {
c::ReadConsoleW(handle,
utf16.as_mut_ptr() as c::LPVOID,
utf16.len() as u32,
&mut num,
- ptr::null_mut())
+ &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL)
})?;
utf16.truncate(num as usize);
// FIXME: what to do about this data that has already been read?
- let data = match String::from_utf16(&utf16) {
+ let mut data = match String::from_utf16(&utf16) {
Ok(utf8) => utf8.into_bytes(),
Err(..) => return Err(invalid_encoding()),
};
+ if let Output::Console(_) = self.handle {
+ if let Some(&last_byte) = data.last() {
+ if last_byte == CTRL_Z {
+ data.pop();
+ }
+ }
+ }
*utf8 = Cursor::new(data);
}
io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
}
+fn readconsole_input_control(wakeup_mask: c::ULONG) -> c::CONSOLE_READCONSOLE_CONTROL {
+ c::CONSOLE_READCONSOLE_CONTROL {
+ nLength: ::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG,
+ nInitialChars: 0,
+ dwCtrlWakeupMask: wakeup_mask,
+ dwControlKeyState: 0,
+ }
+}
+
+const CTRL_Z: u8 = 0x1A;
+const CTRL_Z_MASK: c::ULONG = 0x4000000; //1 << 0x1A
+
pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
// The default buffer capacity is 64k, but apparently windows
// doesn't like 64k reads on stdin. See #13304 for details, but the
/// Thread configuration. Provides detailed control over the properties
/// and behavior of new threads.
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+///
+/// let builder = thread::Builder::new();
+///
+/// let handler = builder.spawn(|| {
+/// // thread code
+/// }).unwrap();
+///
+/// handler.join().unwrap();
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Builder {
impl Builder {
/// Generates the base configuration for spawning a thread, from which
/// configuration methods can be chained.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new()
+ /// .name("foo".into())
+ /// .stack_size(10);
+ ///
+ /// let handler = builder.spawn(|| {
+ /// // thread code
+ /// }).unwrap();
+ ///
+ /// handler.join().unwrap();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> Builder {
Builder {
///
/// # Examples
///
- /// ```rust
+ /// ```
/// use std::thread;
///
/// let builder = thread::Builder::new()
}
/// Sets the size of the stack for the new thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new().stack_size(10);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stack_size(mut self, size: usize) -> Builder {
self.stack_size = Some(size);
///
/// # Errors
///
- /// Unlike the `spawn` free function, this method yields an
- /// `io::Result` to capture any failure to create the thread at
+ /// Unlike the [`spawn`] free function, this method yields an
+ /// [`io::Result`] to capture any failure to create the thread at
/// the OS level.
+ ///
+ /// [`spawn`]: ../../std/thread/fn.spawn.html
+ /// [`io::Result`]: ../../std/io/type.Result.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new();
+ ///
+ /// let handler = builder.spawn(|| {
+ /// // thread code
+ /// }).unwrap();
+ ///
+ /// handler.join().unwrap();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
}
pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg {
+ let span = mk_sp(eself.span.lo, eself_ident.span.hi);
let infer_ty = P(Ty {
id: DUMMY_NODE_ID,
node: TyKind::ImplicitSelf,
- span: DUMMY_SP,
+ span: span,
});
- let arg = |mutbl, ty, span| Arg {
+ let arg = |mutbl, ty| Arg {
pat: P(Pat {
id: DUMMY_NODE_ID,
node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None),
id: DUMMY_NODE_ID,
};
match eself.node {
- SelfKind::Explicit(ty, mutbl) => {
- arg(mutbl, ty, mk_sp(eself.span.lo, eself_ident.span.hi))
- }
- SelfKind::Value(mutbl) => arg(mutbl, infer_ty, eself.span),
+ SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty),
+ SelfKind::Value(mutbl) => arg(mutbl, infer_ty),
SelfKind::Region(lt, mutbl) => arg(Mutability::Immutable, P(Ty {
id: DUMMY_NODE_ID,
node: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl: mutbl }),
- span: DUMMY_SP,
- }), eself.span),
+ span: span,
+ })),
}
}
}
# tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was
# released on `$date`
-rustc: beta-2016-12-16
-cargo: fbeea902d2c9a5be6d99cc35681565d8f7832592
+rustc: beta-2016-12-20
+cargo: bfee18f73287687c543bda8c35e4e33808792715
+++ /dev/null
-// 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.
-
-use std::mem;
-
-fn main() {
- unsafe {
- let size = mem::size_of::<u32>();
- mem::transmute_copy::<u32, [u8; size]>(&8_8); //~ ERROR E0513
- //~| NOTE no type for variable
- }
-}
}
pub fn test<A: Foo, B: Foo>() {
- let _array = [4; <A as Foo>::Y]; //~ ERROR E0080
- //~| non-constant path in constant
+ let _array = [4; <A as Foo>::Y];
+ //~^ ERROR cannot use an outer type parameter in this context [E0402]
+ //~| ERROR constant evaluation error [E0080]
+ //~| non-constant path in constant
}
fn main() {
pub fn test<A: Foo, B: Foo>() {
let _array: [u32; <A as Foo>::Y];
- //~^ ERROR the trait bound `A: Foo` is not satisfied
+ //~^ ERROR cannot use an outer type parameter in this context [E0402]
+ //~| ERROR constant evaluation error [E0080]
+ //~| non-constant path in constant
}
fn main() {
// except according to those terms.
// no-prefer-dynamic
+// compile-flags: --emit=metadata
-#![crate_type="metadata"]
+#![crate_type="rlib"]
pub struct Foo {
pub field: i32,
mod signatures {
use WillChange;
- #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
- #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK
+ #[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
+ #[rustc_then_this_would_need(CollectItem)] //~ ERROR no path
trait Bar {
+ #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
+ #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK
fn do_something(x: WillChange);
}
Variant2(i32)
}
-#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
+#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
trait Trait {
+ #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
fn method(&self, _: TypeAlias);
}
}
impl<'a,'b> Foo<'a,'b> {
- fn bar(
- self
+ fn bar(self:
+ Foo<'b,'a>
//~^ ERROR mismatched method receiver
//~| expected type `Foo<'a, 'b>`
//~| found type `Foo<'b, 'a>`
//~| expected type `Foo<'a, 'b>`
//~| found type `Foo<'b, 'a>`
//~| lifetime mismatch
- : Foo<'b,'a>) {}
+ ) {}
}
fn main() {}
//~| expected type `usize`
//~| found type `S`
//~| expected usize, found struct `S`
- //~| ERROR expected `usize` for repeat count, found struct [E0306]
- //~| expected `usize`
}
fn main() {
fn bar(n: isize) {
- // FIXME (#24414): This error message needs improvement.
let _x: [isize; n];
- //~^ ERROR no type for local variable
+ //~^ ERROR attempt to use a non-constant value in a constant [E0435]
+ //~| ERROR constant evaluation error [E0080]
}
}
fn main() {
fn bar(n: usize) {
let _x = [0; n];
- //~^ ERROR constant evaluation error
- //~| non-constant path in constant expression
- //~| NOTE `n` is a variable
+ //~^ ERROR attempt to use a non-constant value in a constant [E0435]
+ //~| NOTE non-constant used with constant
+ //~| NOTE unresolved path in constant expression
+ //~| ERROR constant evaluation error [E0080]
}
}
fn main() {
let n = 1;
let a = [0; n];
- //~^ ERROR constant evaluation error
- //~| non-constant path in constant expression
+ //~^ ERROR attempt to use a non-constant value in a constant [E0435]
let b = [0; ()];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `()`
//~| expected usize, found ()
- //~| ERROR expected `usize` for repeat count, found tuple [E0306]
- //~| expected `usize`
let c = [0; true];
//~^ ERROR mismatched types
//~| expected usize, found bool
- //~| ERROR expected `usize` for repeat count, found boolean [E0306]
- //~| expected `usize`
let d = [0; 0.5];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `{float}`
//~| expected usize, found floating-point variable
- //~| ERROR expected `usize` for repeat count, found float [E0306]
- //~| expected `usize`
let e = [0; "foo"];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `&'static str`
//~| expected usize, found reference
- //~| ERROR expected `usize` for repeat count, found string literal [E0306]
- //~| expected `usize`
let f = [0; -4_isize];
- //~^ ERROR constant evaluation error
- //~| expected usize, found isize
- //~| ERROR mismatched types
+ //~^ ERROR mismatched types
//~| expected usize, found isize
let f = [0_usize; -1_isize];
- //~^ ERROR constant evaluation error
- //~| expected usize, found isize
- //~| ERROR mismatched types
+ //~^ ERROR mismatched types
//~| expected usize, found isize
struct G {
g: (),
//~| expected type `usize`
//~| found type `main::G`
//~| expected usize, found struct `main::G`
- //~| ERROR expected `usize` for repeat count, found struct [E0306]
- //~| expected `usize`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-flags: --emit=metadata
// aux-build:rmeta_rlib.rs
// no-prefer-dynamic
// must-compile-successfully
// Check that building a metadata crate works with a dependent, rlib crate.
// This is a cfail test since there is no executable to run.
-#![crate_type="metadata"]
-
extern crate rmeta_rlib;
use rmeta_rlib::Foo;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-flags: --emit=metadata
// aux-build:rmeta_meta.rs
// no-prefer-dynamic
// must-compile-successfully
// crate.
// This is a cfail test since there is no executable to run.
-#![crate_type="metadata"]
-
extern crate rmeta_meta;
use rmeta_meta::Foo;
--- /dev/null
+// 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.
+
+// compile-flags: --emit=metadata
+// no-prefer-dynamic
+// must-compile-successfully
+
+#[deny(warnings)]
+
+// Test that we don't get warnings for non-pub main when only emitting metadata.
+// (#38273)
+
+fn main() {
+}
// except according to those terms.
// no-prefer-dynamic
+// compile-flags: --emit=metadata
// Check that building a metadata crate finds an error.
-#![crate_type="metadata"]
-
fn main() {
let _ = Foo; //~ ERROR unresolved value `Foo`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-flags: --emit=metadata
// aux-build:rmeta_meta.rs
// no-prefer-dynamic
// Check that building a metadata crate finds an error with a dependent,
// metadata-only crate.
-#![crate_type="metadata"]
extern crate rmeta_meta;
use rmeta_meta::Foo;
// except according to those terms.
// min-lldb-version: 310
+// ignore-macos FIXME(#37479)
// compile-flags:-g
const CONST_CHANGE_VALUE_1: i16 = 1;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
const CONST_CHANGE_VALUE_1: i16 = 2;
const CONST_CHANGE_VALUE_2: i16 = 1 + 1;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
const CONST_CHANGE_VALUE_2: i16 = 1 + 2;
const CONST_CHANGE_VALUE_3: i16 = 2 + 3;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
const CONST_CHANGE_VALUE_3: i16 = 2 * 3;
const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
enum EnumChangeValueCStyleVariant0 {
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
enum EnumChangeValueCStyleVariant1 {
--- /dev/null
+// 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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for `extern` modules.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![feature(unboxed_closures)]
+#![feature(link_args)]
+#![crate_type="rlib"]
+
+
+// Change function name --------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn change_function_name1(c: i64) -> i32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn change_function_name2(c: i64) -> i32;
+}
+
+
+
+// Change parameter name -------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn change_parameter_name(c: i64) -> i32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn change_parameter_name(d: i64) -> i32;
+}
+
+
+
+// Change parameter type -------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn change_parameter_type(c: i64) -> i32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn change_parameter_type(c: i32) -> i32;
+}
+
+
+
+// Change return type ----------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn change_return_type(c: i32) -> i32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn change_return_type(c: i32) -> i8;
+}
+
+
+
+// Add parameter ---------------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn add_parameter(c: i32) -> i32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn add_parameter(c: i32, d: i32) -> i32;
+}
+
+
+
+// Add return type -------------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn add_return_type(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn add_return_type(c: i32) -> i32;
+}
+
+
+
+// Make function variadic ------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn make_function_variadic(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn make_function_variadic(c: i32, ...);
+}
+
+
+
+// Change calling convention ---------------------------------------------------
+#[cfg(cfail1)]
+extern "C" {
+ pub fn change_calling_convention(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern "rust-call" {
+ pub fn change_calling_convention(c: i32);
+}
+
+
+
+// Make function public --------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ fn make_function_public(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn make_function_public(c: i32);
+}
+
+
+
+// Add function ----------------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn add_function1(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn add_function1(c: i32);
+ pub fn add_function2();
+}
+
+
+
+// Change link-args ------------------------------------------------------------
+#[cfg(cfail1)]
+#[link_args = "-foo -bar"]
+extern {
+ pub fn change_link_args(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[link_args = "-foo -bar -baz"]
+extern {
+ pub fn change_link_args(c: i32);
+}
+
+
+
+// Change link-name ------------------------------------------------------------
+#[cfg(cfail1)]
+#[link(name = "foo")]
+extern {
+ pub fn change_link_name(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[link(name = "bar")]
+extern {
+ pub fn change_link_name(c: i32);
+}
+
+type c_i32 = i32;
+type c_i64 = i64;
+
+// Indirectly change parameter type --------------------------------------------
+mod indirectly_change_parameter_type {
+ #[cfg(cfail1)]
+ use super::c_i32 as c_int;
+ #[cfg(not(cfail1))]
+ use super::c_i64 as c_int;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ extern {
+ pub fn indirectly_change_parameter_type(c: c_int);
+ }
+}
+
+
+
+// Indirectly change return type --------------------------------------------
+mod indirectly_change_return_type {
+ #[cfg(cfail1)]
+ use super::c_i32 as c_int;
+ #[cfg(not(cfail1))]
+ use super::c_i64 as c_int;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ extern {
+ pub fn indirectly_change_return_type() -> c_int;
+ }
+}
static STATIC_CHANGE_VALUE_1: i16 = 1;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
static STATIC_CHANGE_VALUE_1: i16 = 2;
static STATIC_CHANGE_VALUE_2: i16 = 1 + 1;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
static STATIC_CHANGE_VALUE_2: i16 = 1 + 2;
static STATIC_CHANGE_VALUE_3: i16 = 2 + 3;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
static STATIC_CHANGE_VALUE_3: i16 = 2 * 3;
static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddReturnType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method() -> u32;
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeReturnType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method() -> u64;
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddParameterToMethod {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(a: u32);
}
#[cfg(cfail1)]
trait TraitChangeMethodParameterName {
fn method(a: u32);
+ fn with_default(x: i32) {}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeMethodParameterName {
+ // FIXME(#38501) This should preferably always be clean.
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(b: u32);
+
+ #[rustc_clean(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_dirty(label="HirBody", cfg="cfail2")]
+ #[rustc_clean(label="HirBody", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ fn with_default(y: i32) {}
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeMethodParameterType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(a: i64);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeMethodParameterTypeRef {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(a: &mut i32);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeMethodParametersOrder {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(b: i64, a: i32);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeModeSelfRefToMut {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(&mut self);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeModeSelfOwnToMut: Sized {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(mut self) {}
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeModeSelfOwnToRef {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(&self);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddUnsafeModifier {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
unsafe fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddExternModifier {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
extern fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeExternCToRustIntrinsic {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
extern "rust-intrinsic" fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddTypeParameterToMethod {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddLifetimeParameterToMethod {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<'a>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddTraitBoundToMethodTypeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T: ReferencedTrait0>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundToMethodTypeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T: Sized>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToMethodLifetimeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddSecondTraitBoundToMethodTypeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T: ReferencedTrait0 + ReferencedTrait1>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T: Sized + Sync>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddTraitBoundToAssociatedType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
type Associated: ReferencedTrait0;
fn mathod();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToAssociatedType<'a> {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
type Associated: 'a;
fn mathod();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeTypeOfAssociatedConstant {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
const Value: f64;
fn mathod();
#[cfg(not(cfail1))]
use super::ReferenceType1 as ReturnType;
- #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeReturnType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method() -> ReturnType;
}
}
#[cfg(not(cfail1))]
use super::ReferenceType1 as ArgType;
- #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeArgType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(a: ArgType);
}
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeBoundOfMethodTypeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T: Bound>(a: T);
}
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeBoundOfMethodTypeParameterWhere {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T>(a: T) where T: Bound;
}
}
mod x {
#[cfg(rpass1)]
pub fn x() {
- println!("1");
+ println!("{}", "1");
}
#[cfg(rpass2)]
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
#[rustc_dirty(label="TransCrateItem", cfg="rpass2")]
pub fn x() {
- println!("2");
+ println!("{}", "2");
}
}
digraph block {
N0[label="entry"];
N1[label="exit"];
- N2[label="stmt "];
+ N2[label="stmt fn inner(x: isize) -> isize { x + x }"];
N3[label="expr inner"];
N4[label="expr inner"];
N5[label="expr 18"];
N6[label="expr inner(18)"];
N7[label="expr inner(inner(18))"];
N8[label="stmt inner(inner(18));"];
- N9[label="block { inner(inner(18)); }"];
- N10[label="expr { inner(inner(18)); }"];
+ N9[label="block {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"];
+ N10[label="expr {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
digraph block {
N0[label="entry"];
N1[label="exit"];
- N2[label="stmt "];
- N3[label="stmt "];
+ N2[label="stmt struct S19 {\l x: isize,\l}\l"];
+ N3[label="stmt impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l}\l"];
N4[label="expr 19"];
N5[label="expr S19{x: 19,}"];
N6[label="local s"];
N9[label="expr s.inner()"];
N10[label="expr s.inner().inner()"];
N11[label="stmt s.inner().inner();"];
- N12[label="block { let s = S19{x: 19,}; s.inner().inner(); }"];
- N13[label="expr { let s = S19{x: 19,}; s.inner().inner(); }"];
+ N12[label="block {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"];
+ N13[label="expr {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
--- /dev/null
+-include ../tools.mk
+
+all:
+ $(RUSTC) foo.rs; $(RUSTC) bar.rs
+ $(RUSTDOC) baz.rs -L $(TMPDIR) -o $(TMPDIR)
--- /dev/null
+// 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.
+
+#![crate_type = "lib"]
+
+#[derive(Debug)]
+pub struct S;
--- /dev/null
+// 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.
+
+extern crate foo;
+extern crate bar;
+
+pub struct Bar;
+impl ::std::ops::Deref for Bar {
+ type Target = bar::S;
+ fn deref(&self) -> &Self::Target { unimplemented!() }
+}
--- /dev/null
+// 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.
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro, proc_macro_lib)]
+
+extern crate proc_macro;
+
+#[proc_macro_derive(A)]
+pub fn derive(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { ts }
+
+#[derive(Debug)]
+struct S;
-fn foo_method(&self) -> &'static str { return "i am very similar to foo."; }
-/* nest::{{impl}}::foo_method */
+fn foo_method(self: &Self)
+ -> &'static str { return "i am very similar to foo."; } /*
+nest::{{impl}}::foo_method */
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_fn(&mut self, cx: &LateContext,
- fk: FnKind, _: &hir::FnDecl, expr: &hir::Expr,
+ fk: FnKind, _: &hir::FnDecl, body: &hir::Body,
span: Span, node: ast::NodeId)
{
if let FnKind::Closure(..) = fk { return }
- let mut extent = cx.tcx.region_maps.node_extent(expr.id);
+ let mut extent = cx.tcx.region_maps.node_extent(body.value.id);
while let Some(parent) = cx.tcx.region_maps.opt_encl_scope(extent) {
extent = parent;
}
// except according to those terms.
// no-prefer-dynamic
+// compile-flags: --emit=metadata
-#![crate_type="metadata"]
+#![crate_type="rlib"]
#![crate_name="rmeta_aux"]
pub struct Foo {
--- /dev/null
+// 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.
+
+// Check that drop elaboration clears the "master" discriminant
+// drop flag even if it protects no fields.
+
+struct Good(usize);
+impl Drop for Good {
+ #[inline(never)]
+ fn drop(&mut self) {
+ println!("dropping Good({})", self.0);
+ }
+}
+
+struct Void;
+impl Drop for Void {
+ #[inline(never)]
+ fn drop(&mut self) {
+ panic!("Suddenly, a Void appears.");
+ }
+}
+
+enum E {
+ Never(Void),
+ Fine(Good)
+}
+
+fn main() {
+ let mut go = true;
+
+ loop {
+ let next;
+ match go {
+ true => next = E::Fine(Good(123)),
+ false => return,
+ }
+
+ match next {
+ E::Never(_) => return,
+ E::Fine(_good) => go = false,
+ }
+
+ // `next` is dropped and StorageDead'd here. We must reset the
+ // discriminant's drop flag to avoid random variants being
+ // dropped.
+ }
+}
-error: cannot borrow immutable borrowed content `*a` as mutable
- --> $DIR/mut-arg-hint.rs:13:9
- |
-12 | fn foo(mut a: &String) {
- | ------- use `&mut String` here to make mutable
-13 | a.push_str("bar");
- | ^
-
error: cannot borrow immutable borrowed content `*a` as mutable
--> $DIR/mut-arg-hint.rs:18:5
|
18 | a.push_str("foo");
| ^
+error: cannot borrow immutable borrowed content `*a` as mutable
+ --> $DIR/mut-arg-hint.rs:13:9
+ |
+12 | fn foo(mut a: &String) {
+ | ------- use `&mut String` here to make mutable
+13 | a.push_str("bar");
+ | ^
+
error: cannot borrow immutable borrowed content `*a` as mutable
--> $DIR/mut-arg-hint.rs:25:9
|
lock: Option<&'static str>,
}
-const TEST_REPOS: &'static [Test] = &[Test {
- name: "cargo",
- repo: "https://github.com/rust-lang/cargo",
- sha: "b7be4f2ef2cf743492edc6dfb55d087ed88f2d76",
- lock: None,
- },
- Test {
- name: "iron",
- repo: "https://github.com/iron/iron",
- sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
- lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
- }];
-
+const TEST_REPOS: &'static [Test] = &[
+ Test {
+ name: "cargo",
+ repo: "https://github.com/rust-lang/cargo",
+ sha: "b7be4f2ef2cf743492edc6dfb55d087ed88f2d76",
+ lock: None,
+ },
+ Test {
+ name: "iron",
+ repo: "https://github.com/iron/iron",
+ sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
+ lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
+ },
+ Test {
+ name: "ripgrep",
+ repo: "https://github.com/BurntSushi/ripgrep",
+ sha: "b65bb37b14655e1a89c7cd19c8b011ef3e312791",
+ lock: None,
+ },
+ Test {
+ name: "tokei",
+ repo: "https://github.com/Aaronepower/tokei",
+ sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928",
+ lock: None,
+ },
+ Test {
+ name: "treeify",
+ repo: "https://github.com/dzamlo/treeify",
+ sha: "999001b223152441198f117a68fb81f57bc086dd",
+ lock: None,
+ },
+ Test {
+ name: "xsv",
+ repo: "https://github.com/BurntSushi/xsv",
+ sha: "5ec4fff4a3f507eda887049469897f02c6fae036",
+ lock: None,
+ },
+];
fn main() {
// One of the projects being tested here is Cargo, and when being tested
authors = ["The Rust Project Developers"]
name = "rustbook"
version = "0.0.0"
+build = false
[[bin]]
name = "rustbook"