diff --git a/Cargo.lock b/Cargo.lock index 1cfe57da6974d..c34a325a47492 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2722,6 +2722,7 @@ dependencies = [ "rustc_errors 0.0.0", "rustc_mir 0.0.0", "syntax 0.0.0", + "syntax_ext 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 88dac42997f36..f5e5f1f5c0b95 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1017,6 +1017,10 @@ where krate = ReplaceBodyWithLoop::new(sess).fold_crate(krate); } + let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || { + ast_validation::check_crate(sess, &krate) + }); + // If we're in rustdoc we're always compiling as an rlib, but that'll trip a // bunch of checks in the `modify` function below. For now just skip this // step entirely if we're rustdoc as it's not too useful anyway. @@ -1031,6 +1035,7 @@ where &mut resolver, krate, is_proc_macro_crate, + has_proc_macro_decls, is_test_crate, num_crate_types, sess.diagnostic(), @@ -1038,16 +1043,18 @@ where }); } - // Expand global allocators, which are treated as an in-tree proc macro - krate = time(sess, "creating allocators", || { - allocator::expand::modify( - &sess.parse_sess, - &mut resolver, - krate, - crate_name.to_string(), - sess.diagnostic(), - ) - }); + if has_global_allocator { + // Expand global allocators, which are treated as an in-tree proc macro + krate = time(sess, "creating allocators", || { + allocator::expand::modify( + &sess.parse_sess, + &mut resolver, + krate, + crate_name.to_string(), + sess.diagnostic(), + ) + }); + } // Done with macro expansion! @@ -1065,10 +1072,6 @@ where println!("{}", json::as_json(&krate)); } - time(sess, "AST validation", || { - ast_validation::check_crate(sess, &krate) - }); - time(sess, "name resolution", || { resolver.resolve_crate(&krate); }); diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index 2babb93eedbcf..f5154a033af8d 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -14,5 +14,6 @@ rustc = { path = "../librustc" } rustc_mir = { path = "../librustc_mir"} rustc_data_structures = { path = "../librustc_data_structures" } syntax = { path = "../libsyntax" } +syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 3b6328f320f78..3deb2ff8d8a0b 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -15,12 +15,15 @@ use syntax::source_map::Spanned; use syntax::symbol::keywords; use syntax::ptr::P; use syntax::visit::{self, Visitor}; +use syntax_ext::proc_macro_decls::is_proc_macro_attr; use syntax_pos::Span; use errors; use errors::Applicability; struct AstValidator<'a> { session: &'a Session, + has_proc_macro_decls: bool, + has_global_allocator: bool, // Used to ban nested `impl Trait`, e.g., `impl Into`. // Nested `impl Trait` _is_ allowed in associated type position, @@ -367,6 +370,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_item(&mut self, item: &'a Item) { + if item.attrs.iter().any(|attr| is_proc_macro_attr(attr) ) { + self.has_proc_macro_decls = true; + } + + if attr::contains_name(&item.attrs, "global_allocator") { + self.has_global_allocator = true; + } + match item.node { ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => { self.invalid_visibility(&item.vis, None); @@ -590,10 +601,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } -pub fn check_crate(session: &Session, krate: &Crate) { - visit::walk_crate(&mut AstValidator { +pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) { + let mut validator = AstValidator { session, + has_proc_macro_decls: false, + has_global_allocator: false, outer_impl_trait: None, is_impl_trait_banned: false, - }, krate) + }; + visit::walk_crate(&mut validator, krate); + + (validator.has_proc_macro_decls, validator.has_global_allocator) } diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index a181bc7e9b480..76605c58a7889 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -22,6 +22,7 @@ extern crate rustc_data_structures; extern crate log; #[macro_use] extern crate syntax; +extern crate syntax_ext; extern crate syntax_pos; extern crate rustc_errors as errors; diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs index 1d272712cacc8..46c502965eea8 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -48,6 +48,7 @@ pub fn modify(sess: &ParseSess, resolver: &mut dyn (::syntax::ext::base::Resolver), mut krate: ast::Crate, is_proc_macro_crate: bool, + has_proc_macro_decls: bool, is_test_crate: bool, num_crate_types: usize, handler: &errors::Handler) -> ast::Crate { @@ -64,7 +65,9 @@ pub fn modify(sess: &ParseSess, is_proc_macro_crate, is_test_crate, }; - visit::walk_crate(&mut collect, &krate); + if has_proc_macro_decls || is_proc_macro_crate { + visit::walk_crate(&mut collect, &krate); + } (collect.derives, collect.attr_macros, collect.bang_macros) }; @@ -85,7 +88,7 @@ pub fn modify(sess: &ParseSess, krate } -fn is_proc_macro_attr(attr: &ast::Attribute) -> bool { +pub fn is_proc_macro_attr(attr: &ast::Attribute) -> bool { PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(kind)) }