Auto merge of #36601 - jseyfried:build_reduced_graph_in_expansion, r=nrc
Assign def ids and build the module graph during expansion r? @nrc
This commit is contained in:
commit
a059cb2f33
src
librustc/hir/map
librustc_driver
librustc_metadata
librustc_resolve
libsyntax
test
codegen-units/item-collection
compile-fail-fulldeps
compile-fail
@ -18,31 +18,39 @@ use middle::cstore::InlinedItem;
|
||||
|
||||
use syntax::ast::*;
|
||||
use syntax::visit;
|
||||
use syntax::parse::token;
|
||||
use syntax::parse::token::{self, keywords};
|
||||
|
||||
/// Creates def ids for nodes in the HIR.
|
||||
pub struct DefCollector<'ast> {
|
||||
pub struct DefCollector<'a> {
|
||||
// If we are walking HIR (c.f., AST), we need to keep a reference to the
|
||||
// crate.
|
||||
hir_crate: Option<&'ast hir::Crate>,
|
||||
definitions: &'ast mut Definitions,
|
||||
hir_crate: Option<&'a hir::Crate>,
|
||||
definitions: &'a mut Definitions,
|
||||
parent_def: Option<DefIndex>,
|
||||
pub visit_macro_invoc: Option<&'a mut FnMut(MacroInvocationData)>,
|
||||
}
|
||||
|
||||
impl<'ast> DefCollector<'ast> {
|
||||
pub fn new(definitions: &'ast mut Definitions) -> DefCollector<'ast> {
|
||||
pub struct MacroInvocationData {
|
||||
pub id: NodeId,
|
||||
pub def_index: DefIndex,
|
||||
pub const_integer: bool,
|
||||
}
|
||||
|
||||
impl<'a> DefCollector<'a> {
|
||||
pub fn new(definitions: &'a mut Definitions) -> Self {
|
||||
DefCollector {
|
||||
hir_crate: None,
|
||||
definitions: definitions,
|
||||
parent_def: None,
|
||||
visit_macro_invoc: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extend(parent_node: NodeId,
|
||||
parent_def_path: DefPath,
|
||||
parent_def_id: DefId,
|
||||
definitions: &'ast mut Definitions)
|
||||
-> DefCollector<'ast> {
|
||||
definitions: &'a mut Definitions)
|
||||
-> Self {
|
||||
let mut collector = DefCollector::new(definitions);
|
||||
|
||||
assert_eq!(parent_def_path.krate, parent_def_id.krate);
|
||||
@ -65,7 +73,7 @@ impl<'ast> DefCollector<'ast> {
|
||||
self.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
|
||||
}
|
||||
|
||||
pub fn walk_item(&mut self, ii: &'ast InlinedItem, krate: &'ast hir::Crate) {
|
||||
pub fn walk_item(&mut self, ii: &'a InlinedItem, krate: &'a hir::Crate) {
|
||||
self.hir_crate = Some(krate);
|
||||
ii.visit(self);
|
||||
}
|
||||
@ -84,29 +92,28 @@ impl<'ast> DefCollector<'ast> {
|
||||
self.definitions.create_def_with_parent(parent, node_id, data)
|
||||
}
|
||||
|
||||
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
|
||||
pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
|
||||
let parent = self.parent_def;
|
||||
self.parent_def = Some(parent_def);
|
||||
f(self);
|
||||
self.parent_def = parent;
|
||||
}
|
||||
|
||||
fn visit_ast_const_integer(&mut self, expr: &Expr) {
|
||||
// Find the node which will be used after lowering.
|
||||
if let ExprKind::Paren(ref inner) = expr.node {
|
||||
return self.visit_ast_const_integer(inner);
|
||||
}
|
||||
|
||||
// FIXME(eddyb) Closures should have separate
|
||||
// function definition IDs and expression IDs.
|
||||
if let ExprKind::Closure(..) = expr.node {
|
||||
return;
|
||||
pub fn visit_ast_const_integer(&mut self, expr: &Expr) {
|
||||
match expr.node {
|
||||
// Find the node which will be used after lowering.
|
||||
ExprKind::Paren(ref inner) => return self.visit_ast_const_integer(inner),
|
||||
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, true),
|
||||
// FIXME(eddyb) Closures should have separate
|
||||
// function definition IDs and expression IDs.
|
||||
ExprKind::Closure(..) => return,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.create_def(expr.id, DefPathData::Initializer);
|
||||
}
|
||||
|
||||
fn visit_hir_const_integer(&mut self, expr: &'ast hir::Expr) {
|
||||
fn visit_hir_const_integer(&mut self, expr: &hir::Expr) {
|
||||
// FIXME(eddyb) Closures should have separate
|
||||
// function definition IDs and expression IDs.
|
||||
if let hir::ExprClosure(..) = expr.node {
|
||||
@ -115,9 +122,19 @@ impl<'ast> DefCollector<'ast> {
|
||||
|
||||
self.create_def(expr.id, DefPathData::Initializer);
|
||||
}
|
||||
|
||||
fn visit_macro_invoc(&mut self, id: NodeId, const_integer: bool) {
|
||||
if let Some(ref mut visit) = self.visit_macro_invoc {
|
||||
visit(MacroInvocationData {
|
||||
id: id,
|
||||
const_integer: const_integer,
|
||||
def_index: self.parent_def.unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> visit::Visitor for DefCollector<'ast> {
|
||||
impl<'a> visit::Visitor for DefCollector<'a> {
|
||||
fn visit_item(&mut self, i: &Item) {
|
||||
debug!("visit_item: {:?}", i);
|
||||
|
||||
@ -129,10 +146,14 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
|
||||
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
|
||||
ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
|
||||
DefPathData::TypeNs(i.ident.name.as_str()),
|
||||
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
|
||||
return visit::walk_item(self, i);
|
||||
}
|
||||
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
|
||||
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
|
||||
DefPathData::ValueNs(i.ident.name.as_str()),
|
||||
ItemKind::Mac(..) => DefPathData::MacroDef(i.ident.name.as_str()),
|
||||
ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder
|
||||
ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false),
|
||||
ItemKind::Use(..) => DefPathData::Misc,
|
||||
};
|
||||
let def = self.create_def(i.id, def_data);
|
||||
@ -198,7 +219,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
|
||||
TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
|
||||
DefPathData::ValueNs(ti.ident.name.as_str()),
|
||||
TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
|
||||
TraitItemKind::Macro(..) => DefPathData::MacroDef(ti.ident.name.as_str()),
|
||||
TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
|
||||
};
|
||||
|
||||
let def = self.create_def(ti.id, def_data);
|
||||
@ -216,7 +237,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
|
||||
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
|
||||
DefPathData::ValueNs(ii.ident.name.as_str()),
|
||||
ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
|
||||
ImplItemKind::Macro(..) => DefPathData::MacroDef(ii.ident.name.as_str()),
|
||||
ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
|
||||
};
|
||||
|
||||
let def = self.create_def(ii.id, def_data);
|
||||
@ -232,9 +253,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
|
||||
fn visit_pat(&mut self, pat: &Pat) {
|
||||
let parent_def = self.parent_def;
|
||||
|
||||
if let PatKind::Ident(_, id, _) = pat.node {
|
||||
let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
|
||||
self.parent_def = Some(def);
|
||||
match pat.node {
|
||||
PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false),
|
||||
PatKind::Ident(_, id, _) => {
|
||||
let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
|
||||
self.parent_def = Some(def);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
visit::walk_pat(self, pat);
|
||||
@ -244,13 +269,14 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
|
||||
fn visit_expr(&mut self, expr: &Expr) {
|
||||
let parent_def = self.parent_def;
|
||||
|
||||
if let ExprKind::Repeat(_, ref count) = expr.node {
|
||||
self.visit_ast_const_integer(count);
|
||||
}
|
||||
|
||||
if let ExprKind::Closure(..) = expr.node {
|
||||
let def = self.create_def(expr.id, DefPathData::ClosureExpr);
|
||||
self.parent_def = Some(def);
|
||||
match expr.node {
|
||||
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, false),
|
||||
ExprKind::Repeat(_, ref count) => self.visit_ast_const_integer(count),
|
||||
ExprKind::Closure(..) => {
|
||||
let def = self.create_def(expr.id, DefPathData::ClosureExpr);
|
||||
self.parent_def = Some(def);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
visit::walk_expr(self, expr);
|
||||
@ -258,11 +284,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &Ty) {
|
||||
if let TyKind::FixedLengthVec(_, ref length) = ty.node {
|
||||
self.visit_ast_const_integer(length);
|
||||
}
|
||||
if let TyKind::ImplTrait(..) = ty.node {
|
||||
self.create_def(ty.id, DefPathData::ImplTrait);
|
||||
match ty.node {
|
||||
TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false),
|
||||
TyKind::FixedLengthVec(_, ref length) => self.visit_ast_const_integer(length),
|
||||
TyKind::ImplTrait(..) => {
|
||||
self.create_def(ty.id, DefPathData::ImplTrait);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_ty(self, ty);
|
||||
}
|
||||
@ -274,6 +302,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
|
||||
fn visit_macro_def(&mut self, macro_def: &MacroDef) {
|
||||
self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str()));
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, stmt: &Stmt) {
|
||||
match stmt.node {
|
||||
StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),
|
||||
_ => visit::walk_stmt(self, stmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We walk the HIR rather than the AST when reading items from metadata.
|
||||
|
@ -9,11 +9,10 @@
|
||||
// except according to those terms.
|
||||
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
|
||||
use hir::map::def_collector::DefCollector;
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use std::fmt::Write;
|
||||
use std::hash::{Hash, Hasher, SipHasher};
|
||||
use syntax::{ast, visit};
|
||||
use syntax::ast;
|
||||
use syntax::parse::token::{self, InternedString};
|
||||
use ty::TyCtxt;
|
||||
use util::nodemap::NodeMap;
|
||||
@ -224,12 +223,6 @@ impl Definitions {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect(&mut self, krate: &ast::Crate) {
|
||||
let mut def_collector = DefCollector::new(self);
|
||||
def_collector.collect_root();
|
||||
visit::walk_crate(&mut def_collector, krate);
|
||||
}
|
||||
|
||||
/// Get the number of definitions.
|
||||
pub fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
|
@ -11,7 +11,7 @@
|
||||
pub use self::Node::*;
|
||||
use self::MapEntry::*;
|
||||
use self::collector::NodeCollector;
|
||||
use self::def_collector::DefCollector;
|
||||
pub use self::def_collector::{DefCollector, MacroInvocationData};
|
||||
pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
|
||||
DisambiguatedDefPathData, InlinedRootPath};
|
||||
|
||||
|
@ -639,6 +639,12 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
|
||||
}
|
||||
sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess))?;
|
||||
|
||||
// Currently, we ignore the name resolution data structures for the purposes of dependency
|
||||
// tracking. Instead we will run name resolution and include its output in the hash of each
|
||||
// item, much like we do for macro expansion. In other words, the hash reflects not just
|
||||
// its contents but the results of name resolution on those contents. Hopefully we'll push
|
||||
// this back at some point.
|
||||
let _ignore = sess.dep_graph.in_ignore();
|
||||
let mut crate_loader = CrateLoader::new(sess, &cstore, &krate, crate_name);
|
||||
let resolver_arenas = Resolver::arenas();
|
||||
let mut resolver =
|
||||
@ -733,9 +739,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
|
||||
})
|
||||
})?;
|
||||
|
||||
// Collect defintions for def ids.
|
||||
time(sess.time_passes(), "collecting defs", || resolver.definitions.collect(&krate));
|
||||
|
||||
time(sess.time_passes(),
|
||||
"early lint checks",
|
||||
|| lint::check_ast_crate(sess, &krate));
|
||||
@ -745,13 +748,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
|
||||
|| ast_validation::check_crate(sess, &krate));
|
||||
|
||||
time(sess.time_passes(), "name resolution", || -> CompileResult {
|
||||
// Currently, we ignore the name resolution data structures for the purposes of dependency
|
||||
// tracking. Instead we will run name resolution and include its output in the hash of each
|
||||
// item, much like we do for macro expansion. In other words, the hash reflects not just
|
||||
// its contents but the results of name resolution on those contents. Hopefully we'll push
|
||||
// this back at some point.
|
||||
let _ignore = sess.dep_graph.in_ignore();
|
||||
resolver.build_reduced_graph(&krate);
|
||||
resolver.resolve_imports();
|
||||
|
||||
// Since import resolution will eventually happen in expansion,
|
||||
|
@ -98,10 +98,10 @@ Erroneous code examples:
|
||||
|
||||
```compile_fail,E0466
|
||||
#[macro_use(a_macro(another_macro))] // error: invalid import declaration
|
||||
extern crate some_crate;
|
||||
extern crate core as some_crate;
|
||||
|
||||
#[macro_use(i_want = "some_macros")] // error: invalid import declaration
|
||||
extern crate another_crate;
|
||||
extern crate core as another_crate;
|
||||
```
|
||||
|
||||
This is a syntax error at the level of attribute declarations. The proper
|
||||
@ -135,10 +135,10 @@ Erroneous code examples:
|
||||
|
||||
```compile_fail,E0467
|
||||
#[macro_reexport] // error: no macros listed for export
|
||||
extern crate macros_for_good;
|
||||
extern crate core as macros_for_good;
|
||||
|
||||
#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier
|
||||
extern crate other_macros_for_good;
|
||||
extern crate core as other_macros_for_good;
|
||||
```
|
||||
|
||||
This is a syntax error at the level of attribute declarations.
|
||||
@ -165,8 +165,8 @@ Example of erroneous code:
|
||||
```compile_fail,E0468
|
||||
mod foo {
|
||||
#[macro_use(helpful_macro)] // error: must be at crate root to import
|
||||
extern crate some_crate; // macros from another crate
|
||||
helpful_macro!(...)
|
||||
extern crate core; // macros from another crate
|
||||
helpful_macro!(...);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -20,21 +20,25 @@ use {NameBinding, NameBindingKind, ToNameBinding};
|
||||
use Resolver;
|
||||
use {resolve_error, resolve_struct_error, ResolutionError};
|
||||
|
||||
use rustc::middle::cstore::LoadedMacro;
|
||||
use rustc::hir::def::*;
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
use rustc::hir::map::DefPathData;
|
||||
use rustc::ty;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use syntax::ast::Name;
|
||||
use syntax::attr;
|
||||
use syntax::parse::token;
|
||||
|
||||
use syntax::ast::{Block, Crate};
|
||||
use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind};
|
||||
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind};
|
||||
use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind};
|
||||
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
|
||||
use syntax::ext::base::{MultiItemModifier, Resolver as SyntaxResolver};
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::feature_gate::{self, emit_feature_err};
|
||||
use syntax::parse::token::keywords;
|
||||
use syntax::visit::{self, Visitor};
|
||||
|
||||
@ -53,11 +57,6 @@ impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) {
|
||||
}
|
||||
|
||||
impl<'b> Resolver<'b> {
|
||||
/// Constructs the reduced graph for the entire crate.
|
||||
pub fn build_reduced_graph(&mut self, krate: &Crate) {
|
||||
visit::walk_crate(&mut BuildReducedGraphVisitor { resolver: self }, krate);
|
||||
}
|
||||
|
||||
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
|
||||
/// otherwise, reports an error.
|
||||
fn define<T>(&mut self, parent: Module<'b>, name: Name, ns: Namespace, def: T)
|
||||
@ -72,15 +71,13 @@ impl<'b> Resolver<'b> {
|
||||
fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
|
||||
// If any statements are items, we need to create an anonymous module
|
||||
block.stmts.iter().any(|statement| match statement.node {
|
||||
StmtKind::Item(_) => true,
|
||||
StmtKind::Item(_) | StmtKind::Mac(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Constructs the reduced graph for one item.
|
||||
fn build_reduced_graph_for_item(&mut self, item: &Item) {
|
||||
self.crate_loader.process_item(item, &self.definitions);
|
||||
|
||||
let parent = self.current_module;
|
||||
let name = item.ident.name;
|
||||
let sp = item.span;
|
||||
@ -188,8 +185,20 @@ impl<'b> Resolver<'b> {
|
||||
}
|
||||
|
||||
ItemKind::ExternCrate(_) => {
|
||||
// n.b. we don't need to look at the path option here, because cstore already
|
||||
// did
|
||||
// We need to error on `#[macro_use] extern crate` when it isn't at the
|
||||
// crate root, because `$crate` won't work properly.
|
||||
let is_crate_root = self.current_module.parent.is_none();
|
||||
for def in self.crate_loader.load_macros(item, is_crate_root) {
|
||||
match def {
|
||||
LoadedMacro::Def(def) => self.add_macro(Mark::root(), def),
|
||||
LoadedMacro::CustomDerive(name, ext) => {
|
||||
self.insert_custom_derive(&name, ext, item.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.crate_loader.process_item(item, &self.definitions);
|
||||
|
||||
// n.b. we don't need to look at the path option here, because cstore already did
|
||||
if let Some(crate_id) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
|
||||
let def_id = DefId {
|
||||
krate: crate_id,
|
||||
@ -206,6 +215,8 @@ impl<'b> Resolver<'b> {
|
||||
}
|
||||
}
|
||||
|
||||
ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
|
||||
|
||||
ItemKind::Mod(..) => {
|
||||
let def = Def::Mod(self.definitions.local_def_id(item.id));
|
||||
let module = self.arenas.alloc_module(ModuleS {
|
||||
@ -213,6 +224,7 @@ impl<'b> Resolver<'b> {
|
||||
attr::contains_name(&item.attrs, "no_implicit_prelude")
|
||||
},
|
||||
normal_ancestor_id: Some(item.id),
|
||||
macros_escape: self.contains_macro_use(&item.attrs),
|
||||
..ModuleS::new(Some(parent), ModuleKind::Def(def, name))
|
||||
});
|
||||
self.define(parent, name, TypeNS, (module, sp, vis));
|
||||
@ -222,7 +234,7 @@ impl<'b> Resolver<'b> {
|
||||
self.current_module = module;
|
||||
}
|
||||
|
||||
ItemKind::ForeignMod(..) => {}
|
||||
ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions),
|
||||
|
||||
// These items live in the value namespace.
|
||||
ItemKind::Static(_, m, _) => {
|
||||
@ -476,14 +488,79 @@ impl<'b> Resolver<'b> {
|
||||
}
|
||||
module.populated.set(true)
|
||||
}
|
||||
|
||||
// does this attribute list contain "macro_use"?
|
||||
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
|
||||
for attr in attrs {
|
||||
if attr.check_name("macro_escape") {
|
||||
let msg = "macro_escape is a deprecated synonym for macro_use";
|
||||
let mut err = self.session.struct_span_warn(attr.span, msg);
|
||||
if let ast::AttrStyle::Inner = attr.node.style {
|
||||
err.help("consider an outer attribute, #[macro_use] mod ...").emit();
|
||||
} else {
|
||||
err.emit();
|
||||
}
|
||||
} else if !attr.check_name("macro_use") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !attr.is_word() {
|
||||
self.session.span_err(attr.span, "arguments to macro_use are not allowed here");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
|
||||
if !self.session.features.borrow().rustc_macro {
|
||||
let sess = &self.session.parse_sess;
|
||||
let msg = "loading custom derive macro crates is experimentally supported";
|
||||
emit_feature_err(sess, "rustc_macro", sp, feature_gate::GateIssue::Language, msg);
|
||||
}
|
||||
if self.derive_modes.insert(token::intern(name), ext).is_some() {
|
||||
self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BuildReducedGraphVisitor<'a, 'b: 'a> {
|
||||
resolver: &'a mut Resolver<'b>,
|
||||
pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
|
||||
pub resolver: &'a mut Resolver<'b>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||
fn visit_invoc(&mut self, id: ast::NodeId) {
|
||||
self.resolver.expansion_data.get_mut(&id.as_u32()).unwrap().module =
|
||||
self.resolver.current_module;
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! method {
|
||||
($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
|
||||
fn $visit(&mut self, node: &$ty) {
|
||||
match node.node {
|
||||
$invoc(..) => self.visit_invoc(node.id),
|
||||
_ => visit::$walk(self, node),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
|
||||
method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
|
||||
method!(visit_stmt: ast::Stmt, ast::StmtKind::Mac, walk_stmt);
|
||||
method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr);
|
||||
method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat);
|
||||
method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty);
|
||||
|
||||
fn visit_item(&mut self, item: &Item) {
|
||||
match item.node {
|
||||
ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder
|
||||
ItemKind::Mac(..) => return self.visit_invoc(item.id),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let parent = self.resolver.current_module;
|
||||
self.resolver.build_reduced_graph_for_item(item);
|
||||
visit::walk_item(self, item);
|
||||
@ -492,6 +569,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
|
||||
self.resolver.build_reduced_graph_for_foreign_item(foreign_item);
|
||||
visit::walk_foreign_item(self, foreign_item);
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, block: &Block) {
|
||||
@ -515,7 +593,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
|
||||
(Def::Method(item_def_id), ValueNS)
|
||||
}
|
||||
TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS),
|
||||
TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"),
|
||||
TraitItemKind::Macro(_) => return self.visit_invoc(item.id),
|
||||
};
|
||||
|
||||
self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method);
|
||||
|
@ -42,7 +42,7 @@ use self::RibKind::*;
|
||||
use self::UseLexicalScopeFlag::*;
|
||||
use self::ModulePrefixResult::*;
|
||||
|
||||
use rustc::hir::map::Definitions;
|
||||
use rustc::hir::map::{Definitions, DefCollector};
|
||||
use rustc::hir::{self, PrimTy, TyBool, TyChar, TyFloat, TyInt, TyUint, TyStr};
|
||||
use rustc::middle::cstore::CrateLoader;
|
||||
use rustc::session::Session;
|
||||
@ -57,6 +57,7 @@ use syntax::ext::base::MultiItemModifier;
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::ast::{self, FloatTy};
|
||||
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy};
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
use syntax::parse::token::{self, keywords};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
|
||||
@ -72,9 +73,9 @@ use syntax_pos::{Span, DUMMY_SP};
|
||||
use errors::DiagnosticBuilder;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use std::fmt;
|
||||
use std::mem::replace;
|
||||
use std::rc::Rc;
|
||||
|
||||
use resolve_imports::{ImportDirective, NameResolution};
|
||||
|
||||
@ -791,6 +792,9 @@ pub struct ModuleS<'a> {
|
||||
// access the children must be preceded with a
|
||||
// `populate_module_if_necessary` call.
|
||||
populated: Cell<bool>,
|
||||
|
||||
macros: RefCell<FnvHashMap<Name, Rc<SyntaxExtension>>>,
|
||||
macros_escape: bool,
|
||||
}
|
||||
|
||||
pub type Module<'a> = &'a ModuleS<'a>;
|
||||
@ -808,6 +812,8 @@ impl<'a> ModuleS<'a> {
|
||||
globs: RefCell::new((Vec::new())),
|
||||
traits: RefCell::new(None),
|
||||
populated: Cell::new(true),
|
||||
macros: RefCell::new(FnvHashMap()),
|
||||
macros_escape: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1079,7 +1085,7 @@ pub struct Resolver<'a> {
|
||||
macro_names: FnvHashSet<Name>,
|
||||
|
||||
// Maps the `Mark` of an expansion to its containing module or block.
|
||||
expansion_data: FnvHashMap<u32, macros::ExpansionData>,
|
||||
expansion_data: FnvHashMap<u32, macros::ExpansionData<'a>>,
|
||||
}
|
||||
|
||||
pub struct ResolverArenas<'a> {
|
||||
@ -1193,13 +1199,16 @@ impl<'a> Resolver<'a> {
|
||||
let mut module_map = NodeMap();
|
||||
module_map.insert(CRATE_NODE_ID, graph_root);
|
||||
|
||||
let mut definitions = Definitions::new();
|
||||
DefCollector::new(&mut definitions).collect_root();
|
||||
|
||||
let mut expansion_data = FnvHashMap();
|
||||
expansion_data.insert(0, macros::ExpansionData::default()); // Crate root expansion
|
||||
expansion_data.insert(0, macros::ExpansionData::root(graph_root)); // Crate root expansion
|
||||
|
||||
Resolver {
|
||||
session: session,
|
||||
|
||||
definitions: Definitions::new(),
|
||||
definitions: definitions,
|
||||
macros_at_scope: FnvHashMap(),
|
||||
|
||||
// The outermost module has def ID 0; this is not reflected in the
|
||||
@ -1269,6 +1278,13 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
/// Entry point to crate resolution.
|
||||
pub fn resolve_crate(&mut self, krate: &Crate) {
|
||||
// Collect `DefId`s for exported macro defs.
|
||||
for def in &krate.exported_macros {
|
||||
DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
|
||||
collector.visit_macro_def(def)
|
||||
})
|
||||
}
|
||||
|
||||
self.current_module = self.graph_root;
|
||||
visit::walk_crate(self, krate);
|
||||
|
||||
|
@ -8,36 +8,38 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use Resolver;
|
||||
use rustc::middle::cstore::LoadedMacro;
|
||||
use rustc::util::nodemap::FnvHashMap;
|
||||
use std::cell::RefCell;
|
||||
use std::mem;
|
||||
use {Module, Resolver};
|
||||
use build_reduced_graph::BuildReducedGraphVisitor;
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
|
||||
use rustc::hir::map::{self, DefCollector};
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::{self, Name};
|
||||
use syntax::ast;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
|
||||
use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
|
||||
use syntax::ext::base::{NormalTT, SyntaxExtension};
|
||||
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::ext::tt::macro_rules;
|
||||
use syntax::feature_gate::{self, emit_feature_err};
|
||||
use syntax::parse::token::{self, intern};
|
||||
use syntax::parse::token::intern;
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax::visit::{self, Visitor};
|
||||
use syntax_pos::Span;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ExpansionData {
|
||||
module: Rc<ModuleData>,
|
||||
#[derive(Clone)]
|
||||
pub struct ExpansionData<'a> {
|
||||
pub module: Module<'a>,
|
||||
def_index: DefIndex,
|
||||
// True if this expansion is in a `const_integer` position, for example `[u32; m!()]`.
|
||||
// c.f. `DefCollector::visit_ast_const_integer`.
|
||||
const_integer: bool,
|
||||
}
|
||||
|
||||
// FIXME(jseyfried): merge with `::ModuleS`.
|
||||
#[derive(Default)]
|
||||
struct ModuleData {
|
||||
parent: Option<Rc<ModuleData>>,
|
||||
macros: RefCell<FnvHashMap<Name, Rc<SyntaxExtension>>>,
|
||||
macros_escape: bool,
|
||||
impl<'a> ExpansionData<'a> {
|
||||
pub fn root(graph_root: Module<'a>) -> Self {
|
||||
ExpansionData {
|
||||
module: graph_root,
|
||||
def_index: CRATE_DEF_INDEX,
|
||||
const_integer: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> base::Resolver for Resolver<'a> {
|
||||
@ -45,11 +47,21 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
self.session.next_node_id()
|
||||
}
|
||||
|
||||
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
|
||||
expansion.visit_with(&mut ExpansionVisitor {
|
||||
current_module: self.expansion_data[&mark.as_u32()].module.clone(),
|
||||
resolver: self,
|
||||
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
|
||||
let mark = Mark::fresh();
|
||||
let module = self.module_map[&id];
|
||||
self.expansion_data.insert(mark.as_u32(), ExpansionData {
|
||||
module: module,
|
||||
def_index: module.def_id().unwrap().index,
|
||||
const_integer: false,
|
||||
});
|
||||
mark
|
||||
}
|
||||
|
||||
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
|
||||
self.collect_def_ids(mark, expansion);
|
||||
self.current_module = self.expansion_data[&mark.as_u32()].module;
|
||||
expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self });
|
||||
}
|
||||
|
||||
fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
|
||||
@ -71,9 +83,9 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
self.macro_names.insert(ident.name);
|
||||
}
|
||||
|
||||
let mut module = self.expansion_data[&scope.as_u32()].module.clone();
|
||||
let mut module = self.expansion_data[&scope.as_u32()].module;
|
||||
while module.macros_escape {
|
||||
module = module.parent.clone().unwrap();
|
||||
module = module.parent.unwrap();
|
||||
}
|
||||
module.macros.borrow_mut().insert(ident.name, ext);
|
||||
}
|
||||
@ -113,12 +125,12 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
|
||||
};
|
||||
|
||||
let mut module = self.expansion_data[&scope.as_u32()].module.clone();
|
||||
let mut module = self.expansion_data[&scope.as_u32()].module;
|
||||
loop {
|
||||
if let Some(ext) = module.macros.borrow().get(&name) {
|
||||
return Some(ext.clone());
|
||||
}
|
||||
match module.parent.clone() {
|
||||
match module.parent {
|
||||
Some(parent) => module = parent,
|
||||
None => break,
|
||||
}
|
||||
@ -147,116 +159,23 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
|
||||
if !self.session.features.borrow().rustc_macro {
|
||||
let sess = &self.session.parse_sess;
|
||||
let msg = "loading custom derive macro crates is experimentally supported";
|
||||
emit_feature_err(sess, "rustc_macro", sp, feature_gate::GateIssue::Language, msg);
|
||||
}
|
||||
if self.derive_modes.insert(token::intern(name), ext).is_some() {
|
||||
self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
|
||||
}
|
||||
}
|
||||
}
|
||||
fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) {
|
||||
let expansion_data = &mut self.expansion_data;
|
||||
let ExpansionData { def_index, const_integer, module } = expansion_data[&mark.as_u32()];
|
||||
let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| {
|
||||
expansion_data.entry(invoc.id.as_u32()).or_insert(ExpansionData {
|
||||
def_index: invoc.def_index,
|
||||
const_integer: invoc.const_integer,
|
||||
module: module,
|
||||
});
|
||||
};
|
||||
|
||||
struct ExpansionVisitor<'b, 'a: 'b> {
|
||||
resolver: &'b mut Resolver<'a>,
|
||||
current_module: Rc<ModuleData>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> ExpansionVisitor<'a, 'b> {
|
||||
fn visit_invoc(&mut self, id: ast::NodeId) {
|
||||
self.resolver.expansion_data.insert(id.as_u32(), ExpansionData {
|
||||
module: self.current_module.clone(),
|
||||
let mut def_collector = DefCollector::new(&mut self.definitions);
|
||||
def_collector.visit_macro_invoc = Some(visit_macro_invoc);
|
||||
def_collector.with_parent(def_index, |def_collector| if !const_integer {
|
||||
expansion.visit_with(def_collector)
|
||||
} else if let Expansion::Expr(ref expr) = *expansion {
|
||||
def_collector.visit_ast_const_integer(expr);
|
||||
});
|
||||
}
|
||||
|
||||
// does this attribute list contain "macro_use"?
|
||||
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
|
||||
for attr in attrs {
|
||||
if attr.check_name("macro_escape") {
|
||||
let msg = "macro_escape is a deprecated synonym for macro_use";
|
||||
let mut err = self.resolver.session.struct_span_warn(attr.span, msg);
|
||||
if let ast::AttrStyle::Inner = attr.node.style {
|
||||
err.help("consider an outer attribute, #[macro_use] mod ...").emit();
|
||||
} else {
|
||||
err.emit();
|
||||
}
|
||||
} else if !attr.check_name("macro_use") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !attr.is_word() {
|
||||
self.resolver.session.span_err(attr.span,
|
||||
"arguments to macro_use are not allowed here");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! method {
|
||||
($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
|
||||
fn $visit(&mut self, node: &$ty) {
|
||||
match node.node {
|
||||
$invoc(..) => self.visit_invoc(node.id),
|
||||
_ => visit::$walk(self, node),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Visitor for ExpansionVisitor<'a, 'b> {
|
||||
method!(visit_trait_item: ast::TraitItem, ast::TraitItemKind::Macro, walk_trait_item);
|
||||
method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
|
||||
method!(visit_stmt: ast::Stmt, ast::StmtKind::Mac, walk_stmt);
|
||||
method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr);
|
||||
method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat);
|
||||
method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty);
|
||||
|
||||
fn visit_item(&mut self, item: &ast::Item) {
|
||||
match item.node {
|
||||
ast::ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => {} // Scope placeholder
|
||||
ast::ItemKind::Mac(..) => self.visit_invoc(item.id),
|
||||
ast::ItemKind::Mod(..) => {
|
||||
let module_data = ModuleData {
|
||||
parent: Some(self.current_module.clone()),
|
||||
macros: RefCell::new(FnvHashMap()),
|
||||
macros_escape: self.contains_macro_use(&item.attrs),
|
||||
};
|
||||
let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
|
||||
visit::walk_item(self, item);
|
||||
self.current_module = orig_module;
|
||||
}
|
||||
ast::ItemKind::ExternCrate(..) => {
|
||||
// We need to error on `#[macro_use] extern crate` when it isn't at the
|
||||
// crate root, because `$crate` won't work properly.
|
||||
// FIXME(jseyfried): This will be nicer once `ModuleData` is merged with `ModuleS`.
|
||||
let is_crate_root = self.current_module.parent.as_ref().unwrap().parent.is_none();
|
||||
for def in self.resolver.crate_loader.load_macros(item, is_crate_root) {
|
||||
match def {
|
||||
LoadedMacro::Def(def) => self.resolver.add_macro(Mark::root(), def),
|
||||
LoadedMacro::CustomDerive(name, ext) => {
|
||||
self.resolver.insert_custom_derive(&name, ext, item.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
_ => visit::walk_item(self, item),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, block: &ast::Block) {
|
||||
let module_data = ModuleData {
|
||||
parent: Some(self.current_module.clone()),
|
||||
macros: RefCell::new(FnvHashMap()),
|
||||
macros_escape: false,
|
||||
};
|
||||
let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
|
||||
visit::walk_block(self, block);
|
||||
self.current_module = orig_module;
|
||||
}
|
||||
}
|
||||
|
@ -303,6 +303,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
|
||||
attr.check_name("cfg")
|
||||
}
|
||||
|
||||
fn is_test_or_bench(attr: &ast::Attribute) -> bool {
|
||||
pub fn is_test_or_bench(attr: &ast::Attribute) -> bool {
|
||||
attr.check_name("test") || attr.check_name("bench")
|
||||
}
|
||||
|
@ -515,6 +515,7 @@ pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
||||
|
||||
pub trait Resolver {
|
||||
fn next_node_id(&mut self) -> ast::NodeId;
|
||||
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
|
||||
|
||||
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
|
||||
fn add_macro(&mut self, scope: Mark, def: ast::MacroDef);
|
||||
@ -530,6 +531,7 @@ pub struct DummyResolver;
|
||||
|
||||
impl Resolver for DummyResolver {
|
||||
fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
|
||||
fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
|
||||
|
||||
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
|
||||
fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {}
|
||||
@ -567,6 +569,7 @@ pub struct ExtCtxt<'a> {
|
||||
pub ecfg: expand::ExpansionConfig<'a>,
|
||||
pub crate_root: Option<&'static str>,
|
||||
pub resolver: &'a mut Resolver,
|
||||
pub resolve_err_count: usize,
|
||||
pub current_expansion: ExpansionData,
|
||||
}
|
||||
|
||||
@ -581,6 +584,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
ecfg: ecfg,
|
||||
crate_root: None,
|
||||
resolver: resolver,
|
||||
resolve_err_count: 0,
|
||||
current_expansion: ExpansionData {
|
||||
mark: Mark::root(),
|
||||
depth: 0,
|
||||
|
@ -16,7 +16,7 @@ use ext::placeholders::{placeholder, PlaceholderExpander};
|
||||
use attr::{self, HasAttrs};
|
||||
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
|
||||
use syntax_pos::{self, Span, ExpnId};
|
||||
use config::StripUnconfigured;
|
||||
use config::{is_test_or_bench, StripUnconfigured};
|
||||
use ext::base::*;
|
||||
use feature_gate::{self, Features};
|
||||
use fold;
|
||||
@ -206,7 +206,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
|
||||
if self.cx.parse_sess.span_diagnostic.err_count() - self.cx.resolve_err_count > err_count {
|
||||
self.cx.parse_sess.span_diagnostic.abort_if_errors();
|
||||
}
|
||||
|
||||
@ -277,8 +277,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
self.cx.cfg = crate_config;
|
||||
|
||||
if self.monotonic {
|
||||
let err_count = self.cx.parse_sess.span_diagnostic.err_count();
|
||||
let mark = self.cx.current_expansion.mark;
|
||||
self.cx.resolver.visit_expansion(mark, &result.0);
|
||||
self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count;
|
||||
}
|
||||
|
||||
result
|
||||
@ -674,7 +676,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
|
||||
let item = configure!(self, item);
|
||||
|
||||
let (item, attr) = self.classify_item(item);
|
||||
let (mut item, attr) = self.classify_item(item);
|
||||
if let Some(attr) = attr {
|
||||
let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item));
|
||||
return self.collect_attr(attr, item, ExpansionKind::Items).make_items();
|
||||
@ -731,6 +733,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||
self.cx.current_expansion.module = orig_module;
|
||||
return result;
|
||||
}
|
||||
// Ensure that test functions are accessible from the test harness.
|
||||
ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => {
|
||||
if item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
|
||||
item = item.map(|mut item| { item.vis = ast::Visibility::Public; item });
|
||||
}
|
||||
noop_fold_item(item, self)
|
||||
}
|
||||
_ => noop_fold_item(item, self),
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
|
||||
}
|
||||
debug!("current path: {}", path_name_i(&self.cx.path));
|
||||
|
||||
let i = if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
|
||||
if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
|
||||
match i.node {
|
||||
ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => {
|
||||
let diag = self.cx.span_diagnostic;
|
||||
@ -136,54 +136,37 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
|
||||
};
|
||||
self.cx.testfns.push(test);
|
||||
self.tests.push(i.ident);
|
||||
// debug!("have {} test/bench functions",
|
||||
// cx.testfns.len());
|
||||
|
||||
// Make all tests public so we can call them from outside
|
||||
// the module (note that the tests are re-exported and must
|
||||
// be made public themselves to avoid privacy errors).
|
||||
i.map(|mut i| {
|
||||
i.vis = ast::Visibility::Public;
|
||||
i
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i
|
||||
};
|
||||
}
|
||||
|
||||
let mut item = i.unwrap();
|
||||
// We don't want to recurse into anything other than mods, since
|
||||
// mods or tests inside of functions will break things
|
||||
let res = match i.node {
|
||||
ast::ItemKind::Mod(..) => fold::noop_fold_item(i, self),
|
||||
_ => SmallVector::one(i),
|
||||
};
|
||||
if let ast::ItemKind::Mod(module) = item.node {
|
||||
let tests = mem::replace(&mut self.tests, Vec::new());
|
||||
let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
|
||||
let mut mod_folded = fold::noop_fold_mod(module, self);
|
||||
let tests = mem::replace(&mut self.tests, tests);
|
||||
let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
|
||||
|
||||
if !tests.is_empty() || !tested_submods.is_empty() {
|
||||
let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods);
|
||||
mod_folded.items.push(it);
|
||||
|
||||
if !self.cx.path.is_empty() {
|
||||
self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
|
||||
} else {
|
||||
debug!("pushing nothing, sym: {:?}", sym);
|
||||
self.cx.toplevel_reexport = Some(sym);
|
||||
}
|
||||
}
|
||||
item.node = ast::ItemKind::Mod(mod_folded);
|
||||
}
|
||||
if ident.name != keywords::Invalid.name() {
|
||||
self.cx.path.pop();
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn fold_mod(&mut self, m: ast::Mod) -> ast::Mod {
|
||||
let tests = mem::replace(&mut self.tests, Vec::new());
|
||||
let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
|
||||
let mut mod_folded = fold::noop_fold_mod(m, self);
|
||||
let tests = mem::replace(&mut self.tests, tests);
|
||||
let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
|
||||
|
||||
if !tests.is_empty() || !tested_submods.is_empty() {
|
||||
let (it, sym) = mk_reexport_mod(&mut self.cx, tests, tested_submods);
|
||||
mod_folded.items.push(it);
|
||||
|
||||
if !self.cx.path.is_empty() {
|
||||
self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
|
||||
} else {
|
||||
debug!("pushing nothing, sym: {:?}", sym);
|
||||
self.cx.toplevel_reexport = Some(sym);
|
||||
}
|
||||
}
|
||||
|
||||
mod_folded
|
||||
SmallVector::one(P(item))
|
||||
}
|
||||
|
||||
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
|
||||
@ -239,7 +222,7 @@ impl fold::Folder for EntryPointCleaner {
|
||||
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
|
||||
}
|
||||
|
||||
fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
|
||||
fn mk_reexport_mod(cx: &mut TestCtxt, parent: ast::NodeId, tests: Vec<ast::Ident>,
|
||||
tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P<ast::Item>, ast::Ident) {
|
||||
let super_ = token::str_to_ident("super");
|
||||
|
||||
@ -257,6 +240,8 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
|
||||
};
|
||||
|
||||
let sym = token::gensym_ident("__test_reexports");
|
||||
let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
|
||||
cx.ext_cx.current_expansion.mark = cx.ext_cx.resolver.get_module_scope(parent);
|
||||
let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item {
|
||||
ident: sym.clone(),
|
||||
attrs: Vec::new(),
|
||||
|
@ -45,8 +45,8 @@ impl IndexMut<usize> for Indexable {
|
||||
}
|
||||
|
||||
|
||||
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::eq[0]
|
||||
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::ne[0]
|
||||
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::eq[0]
|
||||
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::ne[0]
|
||||
#[derive(PartialEq)]
|
||||
pub struct Equatable(u32);
|
||||
|
||||
@ -54,7 +54,7 @@ pub struct Equatable(u32);
|
||||
impl Add<u32> for Equatable {
|
||||
type Output = u32;
|
||||
|
||||
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::add[0]
|
||||
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::add[0]
|
||||
fn add(self, rhs: u32) -> u32 {
|
||||
self.0 + rhs
|
||||
}
|
||||
@ -63,7 +63,7 @@ impl Add<u32> for Equatable {
|
||||
impl Deref for Equatable {
|
||||
type Target = u32;
|
||||
|
||||
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::deref[0]
|
||||
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::deref[0]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#![no_std]
|
||||
|
||||
extern crate core;
|
||||
extern crate rand;
|
||||
extern crate serialize as rustc_serialize;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate bäz; //~ ERROR non-ascii idents
|
||||
extern crate core as bäz; //~ ERROR non-ascii idents
|
||||
|
||||
use föö::bar; //~ ERROR non-ascii idents
|
||||
|
||||
|
@ -38,11 +38,17 @@ pub fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
use std::option::Option as Self;
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
mod m1 {
|
||||
extern crate core as Self;
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
}
|
||||
|
||||
extern crate Self;
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
mod m2 {
|
||||
use std::option::Option as Self;
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
}
|
||||
|
||||
trait Self {}
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
mod m3 {
|
||||
trait Self {}
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user