From 8b3f28cf0f0cd30ddba884b10c395391ff22beb0 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 27 Jul 2019 16:45:45 +0700 Subject: Make more informative error on outer attr after inner --- src/libsyntax/parse/attr.rs | 47 ++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 1758d0b0bb9..810af9b9246 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -4,6 +4,7 @@ use crate::parse::{SeqSep, PResult}; use crate::parse::token::{self, Nonterminal, DelimToken}; use crate::parse::parser::{Parser, TokenType, PathStyle}; use crate::tokenstream::{TokenStream, TokenTree}; +use crate::source_map::Span; use log::debug; use smallvec::smallvec; @@ -11,7 +12,7 @@ use smallvec::smallvec; #[derive(Debug)] enum InnerAttributeParsePolicy<'a> { Permitted, - NotPermitted { reason: &'a str }, + NotPermitted { reason: &'a str, prev_attr_sp: Option }, } const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ @@ -42,7 +43,8 @@ impl<'a> Parser<'a> { DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }; let inner_parse_policy = - InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason }; + InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason, + prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) }; let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; attrs.push(attr); just_parsed_doc_comment = false; @@ -77,7 +79,7 @@ impl<'a> Parser<'a> { InnerAttributeParsePolicy::Permitted } else { InnerAttributeParsePolicy::NotPermitted - { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG } + { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, prev_attr_sp: None } }; self.parse_attribute_with_inner_parse_policy(inner_parse_policy) } @@ -98,19 +100,9 @@ impl<'a> Parser<'a> { if let InnerAttributeParsePolicy::Permitted = inner_parse_policy { self.expected_tokens.push(TokenType::Token(token::Not)); } + let style = if self.token == token::Not { self.bump(); - if let InnerAttributeParsePolicy::NotPermitted { reason } = inner_parse_policy - { - let span = self.token.span; - self.diagnostic() - .struct_span_err(span, reason) - .note("inner attributes, like `#![no_std]`, annotate the item \ - enclosing them, and are usually found at the beginning of \ - source files. Outer attributes, like `#[test]`, annotate the \ - item following them.") - .emit() - } ast::AttrStyle::Inner } else { ast::AttrStyle::Outer @@ -121,7 +113,32 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Bracket))?; let hi = self.prev_span; - (lo.to(hi), path, tokens, style) + let attr_sp = lo.to(hi); + + // Emit error if inner attribute is encountered and not permitted + if style == ast::AttrStyle::Inner { + if let InnerAttributeParsePolicy::NotPermitted { reason, prev_attr_sp } + = inner_parse_policy { + let mut diagnostic = self + .diagnostic() + .struct_span_err(attr_sp, reason); + + if let Some(prev_attr_sp) = prev_attr_sp { + diagnostic + .span_label(attr_sp, "not permitted following an outer attibute") + .span_label(prev_attr_sp, "previous outer attribute"); + } + + diagnostic + .note("inner attributes, like `#![no_std]`, annotate the item \ + enclosing them, and are usually found at the beginning of \ + source files. Outer attributes, like `#[test]`, annotate the \ + item following them.") + .emit() + } + } + + (attr_sp, path, tokens, style) } _ => { let token_str = self.this_token_to_string(); -- cgit 1.4.1-3-g733a5 From 4d535bdf59136f69b55107caaa0f5492b5e84d2d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Jul 2019 22:29:07 +0300 Subject: Move standard library injection into libsyntax_ext --- src/librustc/hir/lowering.rs | 3 +- src/librustc_interface/passes.rs | 7 +- src/librustc_resolve/build_reduced_graph.rs | 7 +- src/libsyntax/lib.rs | 1 - src/libsyntax/parse/mod.rs | 5 +- src/libsyntax/print/pprust.rs | 3 +- src/libsyntax/std_inject.rs | 112 -------------------------- src/libsyntax_ext/lib.rs | 1 + src/libsyntax_ext/standard_library_imports.rs | 95 ++++++++++++++++++++++ 9 files changed, 112 insertions(+), 122 deletions(-) delete mode 100644 src/libsyntax/std_inject.rs create mode 100644 src/libsyntax_ext/standard_library_imports.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2d1835514d4..0d431b010d6 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -63,7 +63,6 @@ use syntax::errors; use syntax::ext::hygiene::ExpnId; use syntax::print::pprust; use syntax::source_map::{respan, ExpnInfo, ExpnKind, DesugaringKind, Spanned}; -use syntax::std_inject; use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::parse::token::{self, Token}; @@ -241,7 +240,7 @@ pub fn lower_crate( dep_graph.assert_ignored(); LoweringContext { - crate_root: std_inject::injected_crate_name().map(Symbol::intern), + crate_root: sess.parse_sess.injected_crate_name.try_get().copied(), sess, cstore, resolver, diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 58edb898c25..c7be6276f4a 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -278,7 +278,12 @@ pub fn register_plugins<'a>( krate = time(sess, "crate injection", || { let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s); - syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name, sess.edition()) + let (krate, name) = + syntax_ext::standard_library_imports::inject(krate, alt_std_name, sess.edition()); + if let Some(name) = name { + sess.parse_sess.injected_crate_name.set(name); + } + krate }); let registrars = time(sess, "plugin loading", || { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f52f7d9cfb3..41349cf72a1 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -34,7 +34,6 @@ use syntax::ext::hygiene::ExpnId; use syntax::feature_gate::is_builtin_attr; use syntax::parse::token::{self, Token}; use syntax::span_err; -use syntax::std_inject::injected_crate_name; use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; @@ -367,8 +366,10 @@ impl<'a> Resolver<'a> { }; self.populate_module_if_necessary(module); - if injected_crate_name().map_or(false, |name| ident.name.as_str() == name) { - self.injected_crate = Some(module); + if let Some(name) = self.session.parse_sess.injected_crate_name.try_get() { + if name.as_str() == ident.name.as_str() { + self.injected_crate = Some(module); + } } let used = self.process_legacy_macro_imports(item, module, &parent_scope); diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 17f379f31b2..bb6a8dfb141 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -153,7 +153,6 @@ pub mod mut_visit; pub mod parse; pub mod ptr; pub mod show_span; -pub mod std_inject; pub use syntax_pos::edition; pub use syntax_pos::symbol; pub mod tokenstream; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 225065c1cf1..1aac8bbb7aa 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -10,9 +10,10 @@ use crate::parse::token::TokenKind; use crate::tokenstream::{TokenStream, TokenTree}; use crate::diagnostics::plugin::ErrorMap; use crate::print::pprust; +use crate::symbol::Symbol; use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder}; -use rustc_data_structures::sync::{Lrc, Lock}; +use rustc_data_structures::sync::{Lrc, Lock, Once}; use syntax_pos::{Span, SourceFile, FileName, MultiSpan}; use syntax_pos::edition::Edition; @@ -58,6 +59,7 @@ pub struct ParseSess { pub let_chains_spans: Lock>, // Places where `async || ..` exprs were used and should be feature gated. pub async_closure_spans: Lock>, + pub injected_crate_name: Once, } impl ParseSess { @@ -86,6 +88,7 @@ impl ParseSess { param_attr_spans: Lock::new(Vec::new()), let_chains_spans: Lock::new(Vec::new()), async_closure_spans: Lock::new(Vec::new()), + injected_crate_name: Once::new(), } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 16e0bace925..c4623576395 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -10,7 +10,6 @@ use crate::parse::{self, ParseSess}; use crate::print::pp::{self, Breaks}; use crate::print::pp::Breaks::{Consistent, Inconsistent}; use crate::ptr::P; -use crate::std_inject; use crate::symbol::{kw, sym}; use crate::tokenstream::{self, TokenStream, TokenTree}; @@ -114,7 +113,7 @@ pub fn print_crate<'a>(cm: &'a SourceMap, is_expanded, }; - if is_expanded && std_inject::injected_crate_name().is_some() { + if is_expanded && sess.injected_crate_name.try_get().is_some() { // We need to print `#![no_std]` (and its feature gate) so that // compiling pretty-printed source won't inject libstd again. // However we don't want these attributes in the AST because diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs deleted file mode 100644 index 3fba81c0b69..00000000000 --- a/src/libsyntax/std_inject.rs +++ /dev/null @@ -1,112 +0,0 @@ -use crate::ast; -use crate::attr; -use crate::edition::Edition; -use crate::ext::hygiene::{ExpnId, MacroKind}; -use crate::symbol::{Ident, Symbol, kw, sym}; -use crate::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan}; -use crate::ptr::P; -use crate::tokenstream::TokenStream; - -use std::cell::Cell; -use std::iter; -use syntax_pos::DUMMY_SP; - -pub fn injected_crate_name() -> Option<&'static str> { - INJECTED_CRATE_NAME.with(|name| name.get()) -} - -thread_local! { - // A `Symbol` might make more sense here, but it doesn't work, probably for - // reasons relating to the use of thread-local storage for the Symbol - // interner. - static INJECTED_CRATE_NAME: Cell> = Cell::new(None); -} - -pub fn maybe_inject_crates_ref( - mut krate: ast::Crate, - alt_std_name: Option<&str>, - edition: Edition, -) -> ast::Crate { - let rust_2018 = edition >= Edition::Edition2018; - - // the first name in this list is the crate name of the crate with the prelude - let names: &[&str] = if attr::contains_name(&krate.attrs, sym::no_core) { - return krate; - } else if attr::contains_name(&krate.attrs, sym::no_std) { - if attr::contains_name(&krate.attrs, sym::compiler_builtins) { - &["core"] - } else { - &["core", "compiler_builtins"] - } - } else { - &["std"] - }; - - // .rev() to preserve ordering above in combination with insert(0, ...) - let alt_std_name = alt_std_name.map(Symbol::intern); - for orig_name_str in names.iter().rev() { - // HACK(eddyb) gensym the injected crates on the Rust 2018 edition, - // so they don't accidentally interfere with the new import paths. - let orig_name_sym = Symbol::intern(orig_name_str); - let orig_name_ident = Ident::with_empty_ctxt(orig_name_sym); - let (rename, orig_name) = if rust_2018 { - (orig_name_ident.gensym(), Some(orig_name_sym)) - } else { - (orig_name_ident, None) - }; - krate.module.items.insert(0, P(ast::Item { - attrs: vec![attr::mk_attr_outer( - DUMMY_SP, - attr::mk_attr_id(), - attr::mk_word_item(ast::Ident::with_empty_ctxt(sym::macro_use)) - )], - vis: dummy_spanned(ast::VisibilityKind::Inherited), - node: ast::ItemKind::ExternCrate(alt_std_name.or(orig_name)), - ident: rename, - id: ast::DUMMY_NODE_ID, - span: DUMMY_SP, - tokens: None, - })); - } - - // the crates have been injected, the assumption is that the first one is the one with - // the prelude. - let name = names[0]; - - INJECTED_CRATE_NAME.with(|opt_name| opt_name.set(Some(name))); - - let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::std_inject), DUMMY_SP, edition, - [sym::prelude_import][..].into(), - )); - - krate.module.items.insert(0, P(ast::Item { - attrs: vec![ast::Attribute { - style: ast::AttrStyle::Outer, - path: ast::Path::from_ident(ast::Ident::new(sym::prelude_import, span)), - tokens: TokenStream::empty(), - id: attr::mk_attr_id(), - is_sugared_doc: false, - span, - }], - vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), - node: ast::ItemKind::Use(P(ast::UseTree { - prefix: ast::Path { - segments: iter::once(ast::Ident::with_empty_ctxt(kw::PathRoot)) - .chain( - [name, "prelude", "v1"].iter().cloned() - .map(ast::Ident::from_str) - ).map(ast::PathSegment::from_ident).collect(), - span, - }, - kind: ast::UseTreeKind::Glob, - span, - })), - id: ast::DUMMY_NODE_ID, - ident: ast::Ident::invalid(), - span, - tokens: None, - })); - - krate -} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index cd0d0886239..f49c75d7424 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -43,6 +43,7 @@ mod trace_macros; pub mod plugin_macro_defs; pub mod proc_macro_decls; +pub mod standard_library_imports; pub mod test_harness; pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, edition: Edition) { diff --git a/src/libsyntax_ext/standard_library_imports.rs b/src/libsyntax_ext/standard_library_imports.rs new file mode 100644 index 00000000000..81bb32d79a2 --- /dev/null +++ b/src/libsyntax_ext/standard_library_imports.rs @@ -0,0 +1,95 @@ +use syntax::{ast, attr}; +use syntax::edition::Edition; +use syntax::ext::hygiene::{ExpnId, MacroKind}; +use syntax::ptr::P; +use syntax::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan}; +use syntax::symbol::{Ident, Symbol, kw, sym}; +use syntax::tokenstream::TokenStream; +use syntax_pos::DUMMY_SP; + +use std::iter; + +pub fn inject( + mut krate: ast::Crate, alt_std_name: Option<&str>, edition: Edition +) -> (ast::Crate, Option) { + let rust_2018 = edition >= Edition::Edition2018; + + // the first name in this list is the crate name of the crate with the prelude + let names: &[&str] = if attr::contains_name(&krate.attrs, sym::no_core) { + return (krate, None); + } else if attr::contains_name(&krate.attrs, sym::no_std) { + if attr::contains_name(&krate.attrs, sym::compiler_builtins) { + &["core"] + } else { + &["core", "compiler_builtins"] + } + } else { + &["std"] + }; + + // .rev() to preserve ordering above in combination with insert(0, ...) + let alt_std_name = alt_std_name.map(Symbol::intern); + for orig_name_str in names.iter().rev() { + // HACK(eddyb) gensym the injected crates on the Rust 2018 edition, + // so they don't accidentally interfere with the new import paths. + let orig_name_sym = Symbol::intern(orig_name_str); + let orig_name_ident = Ident::with_empty_ctxt(orig_name_sym); + let (rename, orig_name) = if rust_2018 { + (orig_name_ident.gensym(), Some(orig_name_sym)) + } else { + (orig_name_ident, None) + }; + krate.module.items.insert(0, P(ast::Item { + attrs: vec![attr::mk_attr_outer( + DUMMY_SP, + attr::mk_attr_id(), + attr::mk_word_item(ast::Ident::with_empty_ctxt(sym::macro_use)) + )], + vis: dummy_spanned(ast::VisibilityKind::Inherited), + node: ast::ItemKind::ExternCrate(alt_std_name.or(orig_name)), + ident: rename, + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + tokens: None, + })); + } + + // the crates have been injected, the assumption is that the first one is the one with + // the prelude. + let name = names[0]; + + let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable( + ExpnKind::Macro(MacroKind::Attr, sym::std_inject), DUMMY_SP, edition, + [sym::prelude_import][..].into(), + )); + + krate.module.items.insert(0, P(ast::Item { + attrs: vec![ast::Attribute { + style: ast::AttrStyle::Outer, + path: ast::Path::from_ident(ast::Ident::new(sym::prelude_import, span)), + tokens: TokenStream::empty(), + id: attr::mk_attr_id(), + is_sugared_doc: false, + span, + }], + vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), + node: ast::ItemKind::Use(P(ast::UseTree { + prefix: ast::Path { + segments: iter::once(ast::Ident::with_empty_ctxt(kw::PathRoot)) + .chain( + [name, "prelude", "v1"].iter().cloned() + .map(ast::Ident::from_str) + ).map(ast::PathSegment::from_ident).collect(), + span, + }, + kind: ast::UseTreeKind::Glob, + span, + })), + id: ast::DUMMY_NODE_ID, + ident: ast::Ident::invalid(), + span, + tokens: None, + })); + + (krate, Some(Symbol::intern(name))) +} -- cgit 1.4.1-3-g733a5 From b5a0e6ea807bcdc71f145038dd1129c22dcf17fd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Jul 2019 23:29:57 +0300 Subject: syntax_ext: `proc_macro_decls` -> `proc_macro_harness` Few other minor renamings for consistency. Remove one unused dependency from `rustc_passes`. Fix libsyntax tests. Fix rebase. --- Cargo.lock | 1 - src/librustc_interface/passes.rs | 4 +- src/librustc_passes/Cargo.toml | 1 - src/libsyntax/ext/base.rs | 2 +- src/libsyntax/ext/proc_macro.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 3 +- src/libsyntax_ext/lib.rs | 9 +- src/libsyntax_ext/proc_macro_decls.rs | 414 -------------------------------- src/libsyntax_ext/proc_macro_harness.rs | 414 ++++++++++++++++++++++++++++++++ src/libsyntax_ext/test.rs | 2 +- src/libsyntax_ext/test_harness.rs | 14 +- 11 files changed, 432 insertions(+), 434 deletions(-) delete mode 100644 src/libsyntax_ext/proc_macro_decls.rs create mode 100644 src/libsyntax_ext/proc_macro_harness.rs (limited to 'src/libsyntax/parse') diff --git a/Cargo.lock b/Cargo.lock index d1afe5944ee..46d8b3de806 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3052,7 +3052,6 @@ dependencies = [ "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", - "rustc_mir 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index c7be6276f4a..3c7d854b36b 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -461,7 +461,7 @@ fn configure_and_expand_inner<'a>( sess.profiler(|p| p.end_activity("macro expansion")); time(sess, "maybe building test harness", || { - syntax_ext::test_harness::modify_for_testing( + syntax_ext::test_harness::inject( &sess.parse_sess, &mut resolver, sess.opts.test, @@ -490,7 +490,7 @@ fn configure_and_expand_inner<'a>( let num_crate_types = crate_types.len(); let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro); let is_test_crate = sess.opts.test; - syntax_ext::proc_macro_decls::modify( + syntax_ext::proc_macro_harness::inject( &sess.parse_sess, &mut resolver, krate, diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index 5f378dacd25..596ec6c19bc 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -11,7 +11,6 @@ path = "lib.rs" [dependencies] log = "0.4" rustc = { path = "../librustc" } -rustc_mir = { path = "../librustc_mir"} rustc_data_structures = { path = "../librustc_data_structures" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index e53757dce3d..bb7834a133f 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -1,6 +1,6 @@ use crate::ast::{self, Attribute, Name, PatKind}; use crate::attr::{HasAttrs, Stability, Deprecation}; -use crate::source_map::{SourceMap, Spanned, FileName, respan}; +use crate::source_map::{SourceMap, Spanned, respan}; use crate::edition::Edition; use crate::ext::expand::{self, AstFragment, Invocation}; use crate::ext::hygiene::{ExpnId, SyntaxContext, Transparency}; diff --git a/src/libsyntax/ext/proc_macro.rs b/src/libsyntax/ext/proc_macro.rs index 4b4ac57207e..425b9813f59 100644 --- a/src/libsyntax/ext/proc_macro.rs +++ b/src/libsyntax/ext/proc_macro.rs @@ -231,7 +231,7 @@ crate fn add_derived_markers( names.insert(unwrap_or!(path.segments.get(0), continue).ident.name); } - let span = span.fresh_expansion(cx.current_expansion.mark, ExpnInfo::allow_unstable( + let span = span.fresh_expansion(cx.current_expansion.id, ExpnInfo::allow_unstable( ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span, cx.parse_sess.edition, cx.allow_derive_markers.clone(), )); diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 52f65e1b474..3cd5464f357 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -794,7 +794,7 @@ mod tests { use std::path::PathBuf; use syntax_pos::{BytePos, Span, NO_EXPANSION, edition::Edition}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; - use rustc_data_structures::sync::Lock; + use rustc_data_structures::sync::{Lock, Once}; fn mk_sess(sm: Lrc) -> ParseSess { let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), @@ -817,6 +817,7 @@ mod tests { param_attr_spans: Lock::new(Vec::new()), let_chains_spans: Lock::new(Vec::new()), async_closure_spans: Lock::new(Vec::new()), + injected_crate_name: Once::new(), } } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index f49c75d7424..fae884860ed 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -1,4 +1,5 @@ -//! Syntax extensions in the Rust compiler. +//! This crate contains implementations of built-in macros and other code generating facilities +//! injecting code into the crate before it is lowered to HIR. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] @@ -10,16 +11,12 @@ #![feature(mem_take)] #![feature(nll)] #![feature(rustc_diagnostic_macros)] -#![feature(unicode_internals)] - -extern crate proc_macro; use crate::deriving::*; use syntax::ast::Ident; use syntax::edition::Edition; use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, MacroExpanderFn}; -use syntax::ext::source_util; use syntax::symbol::sym; mod error_codes; @@ -42,7 +39,7 @@ mod test; mod trace_macros; pub mod plugin_macro_defs; -pub mod proc_macro_decls; +pub mod proc_macro_harness; pub mod standard_library_imports; pub mod test_harness; diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs deleted file mode 100644 index 357da6ba3c3..00000000000 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ /dev/null @@ -1,414 +0,0 @@ -use std::mem; - -use syntax::ast::{self, Ident}; -use syntax::attr; -use syntax::source_map::{ExpnInfo, ExpnKind, respan}; -use syntax::ext::base::{ExtCtxt, MacroKind}; -use syntax::ext::build::AstBuilder; -use syntax::ext::expand::ExpansionConfig; -use syntax::ext::hygiene::ExpnId; -use syntax::ext::proc_macro::is_proc_macro_attr; -use syntax::mut_visit::MutVisitor; -use syntax::parse::ParseSess; -use syntax::ptr::P; -use syntax::symbol::{kw, sym}; -use syntax::visit::{self, Visitor}; - -use syntax_pos::{Span, DUMMY_SP}; - -struct ProcMacroDerive { - trait_name: ast::Name, - function_name: Ident, - span: Span, - attrs: Vec, -} - -struct ProcMacroDef { - function_name: Ident, - span: Span, -} - -struct CollectProcMacros<'a> { - derives: Vec, - attr_macros: Vec, - bang_macros: Vec, - in_root: bool, - handler: &'a errors::Handler, - is_proc_macro_crate: bool, - is_test_crate: bool, -} - -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 { - let ecfg = ExpansionConfig::default("proc_macro".to_string()); - let mut cx = ExtCtxt::new(sess, ecfg, resolver); - - let (derives, attr_macros, bang_macros) = { - let mut collect = CollectProcMacros { - derives: Vec::new(), - attr_macros: Vec::new(), - bang_macros: Vec::new(), - in_root: true, - handler, - is_proc_macro_crate, - is_test_crate, - }; - if has_proc_macro_decls || is_proc_macro_crate { - visit::walk_crate(&mut collect, &krate); - } - (collect.derives, collect.attr_macros, collect.bang_macros) - }; - - if !is_proc_macro_crate { - return krate - } - - if num_crate_types > 1 { - handler.err("cannot mix `proc-macro` crate type with others"); - } - - if is_test_crate { - return krate; - } - - krate.module.items.push(mk_decls(&mut cx, &derives, &attr_macros, &bang_macros)); - - krate -} - -impl<'a> CollectProcMacros<'a> { - fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { - if self.is_proc_macro_crate && self.in_root && vis.node.is_pub() { - self.handler.span_err(sp, - "`proc-macro` crate types cannot \ - export any items other than functions \ - tagged with `#[proc_macro_derive]` currently"); - } - } - - fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) { - // Once we've located the `#[proc_macro_derive]` attribute, verify - // that it's of the form `#[proc_macro_derive(Foo)]` or - // `#[proc_macro_derive(Foo, attributes(A, ..))]` - let list = match attr.meta_item_list() { - Some(list) => list, - None => return, - }; - if list.len() != 1 && list.len() != 2 { - self.handler.span_err(attr.span, - "attribute must have either one or two arguments"); - return - } - let trait_attr = match list[0].meta_item() { - Some(meta_item) => meta_item, - _ => { - self.handler.span_err(list[0].span(), "not a meta item"); - return - } - }; - let trait_ident = match trait_attr.ident() { - Some(trait_ident) if trait_attr.is_word() => trait_ident, - _ => { - self.handler.span_err(trait_attr.span, "must only be one word"); - return - } - }; - - if !trait_ident.name.can_be_raw() { - self.handler.span_err(trait_attr.span, - &format!("`{}` cannot be a name of derive macro", trait_ident)); - } - - let attributes_attr = list.get(1); - let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr { - if !attr.check_name(sym::attributes) { - self.handler.span_err(attr.span(), "second argument must be `attributes`") - } - attr.meta_item_list().unwrap_or_else(|| { - self.handler.span_err(attr.span(), - "attribute must be of form: `attributes(foo, bar)`"); - &[] - }).into_iter().filter_map(|attr| { - let attr = match attr.meta_item() { - Some(meta_item) => meta_item, - _ => { - self.handler.span_err(attr.span(), "not a meta item"); - return None; - } - }; - - let ident = match attr.ident() { - Some(ident) if attr.is_word() => ident, - _ => { - self.handler.span_err(attr.span, "must only be one word"); - return None; - } - }; - if !ident.name.can_be_raw() { - self.handler.span_err( - attr.span, - &format!("`{}` cannot be a name of derive helper attribute", ident), - ); - } - - Some(ident.name) - }).collect() - } else { - Vec::new() - }; - - if self.in_root && item.vis.node.is_pub() { - self.derives.push(ProcMacroDerive { - span: item.span, - trait_name: trait_ident.name, - function_name: item.ident, - attrs: proc_attrs, - }); - } else { - let msg = if !self.in_root { - "functions tagged with `#[proc_macro_derive]` must \ - currently reside in the root of the crate" - } else { - "functions tagged with `#[proc_macro_derive]` must be `pub`" - }; - self.handler.span_err(item.span, msg); - } - } - - fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { - if self.in_root && item.vis.node.is_pub() { - self.attr_macros.push(ProcMacroDef { - span: item.span, - function_name: item.ident, - }); - } else { - let msg = if !self.in_root { - "functions tagged with `#[proc_macro_attribute]` must \ - currently reside in the root of the crate" - } else { - "functions tagged with `#[proc_macro_attribute]` must be `pub`" - }; - self.handler.span_err(item.span, msg); - } - } - - fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { - if self.in_root && item.vis.node.is_pub() { - self.bang_macros.push(ProcMacroDef { - span: item.span, - function_name: item.ident, - }); - } else { - let msg = if !self.in_root { - "functions tagged with `#[proc_macro]` must \ - currently reside in the root of the crate" - } else { - "functions tagged with `#[proc_macro]` must be `pub`" - }; - self.handler.span_err(item.span, msg); - } - } -} - -impl<'a> Visitor<'a> for CollectProcMacros<'a> { - fn visit_item(&mut self, item: &'a ast::Item) { - if let ast::ItemKind::MacroDef(..) = item.node { - if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) { - let msg = - "cannot export macro_rules! macros from a `proc-macro` crate type currently"; - self.handler.span_err(item.span, msg); - } - } - - // First up, make sure we're checking a bare function. If we're not then - // we're just not interested in this item. - // - // If we find one, try to locate a `#[proc_macro_derive]` attribute on it. - let is_fn = match item.node { - ast::ItemKind::Fn(..) => true, - _ => false, - }; - - let mut found_attr: Option<&'a ast::Attribute> = None; - - for attr in &item.attrs { - if is_proc_macro_attr(&attr) { - if let Some(prev_attr) = found_attr { - let msg = if attr.path.segments[0].ident.name == - prev_attr.path.segments[0].ident.name { - format!("only one `#[{}]` attribute is allowed on any given function", - attr.path) - } else { - format!("`#[{}]` and `#[{}]` attributes cannot both be applied \ - to the same function", attr.path, prev_attr.path) - }; - - self.handler.struct_span_err(attr.span, &msg) - .span_note(prev_attr.span, "previous attribute here") - .emit(); - - return; - } - - found_attr = Some(attr); - } - } - - let attr = match found_attr { - None => { - self.check_not_pub_in_root(&item.vis, item.span); - let prev_in_root = mem::replace(&mut self.in_root, false); - visit::walk_item(self, item); - self.in_root = prev_in_root; - return; - }, - Some(attr) => attr, - }; - - if !is_fn { - let msg = format!("the `#[{}]` attribute may only be used on bare functions", - attr.path); - - self.handler.span_err(attr.span, &msg); - return; - } - - if self.is_test_crate { - return; - } - - if !self.is_proc_macro_crate { - let msg = format!("the `#[{}]` attribute is only usable with crates of the \ - `proc-macro` crate type", attr.path); - - self.handler.span_err(attr.span, &msg); - return; - } - - if attr.check_name(sym::proc_macro_derive) { - self.collect_custom_derive(item, attr); - } else if attr.check_name(sym::proc_macro_attribute) { - self.collect_attr_proc_macro(item); - } else if attr.check_name(sym::proc_macro) { - self.collect_bang_proc_macro(item); - }; - - let prev_in_root = mem::replace(&mut self.in_root, false); - visit::walk_item(self, item); - self.in_root = prev_in_root; - } - - fn visit_mac(&mut self, mac: &'a ast::Mac) { - visit::walk_mac(self, mac) - } -} - -// Creates a new module which looks like: -// -// #[doc(hidden)] -// mod $gensym { -// extern crate proc_macro; -// -// use proc_macro::bridge::client::ProcMacro; -// -// #[rustc_proc_macro_decls] -// static DECLS: &[ProcMacro] = &[ -// ProcMacro::custom_derive($name_trait1, &[], ::$name1); -// ProcMacro::custom_derive($name_trait2, &["attribute_name"], ::$name2); -// // ... -// ]; -// } -fn mk_decls( - cx: &mut ExtCtxt<'_>, - custom_derives: &[ProcMacroDerive], - custom_attrs: &[ProcMacroDef], - custom_macros: &[ProcMacroDef], -) -> P { - let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, - [sym::rustc_attrs, sym::proc_macro_internals][..].into(), - )); - - let hidden = cx.meta_list_item_word(span, sym::hidden); - let doc = cx.meta_list(span, sym::doc, vec![hidden]); - let doc_hidden = cx.attribute(span, doc); - - let proc_macro = Ident::with_empty_ctxt(sym::proc_macro); - let krate = cx.item(span, - proc_macro, - Vec::new(), - ast::ItemKind::ExternCrate(None)); - - let bridge = Ident::from_str("bridge"); - let client = Ident::from_str("client"); - let proc_macro_ty = Ident::from_str("ProcMacro"); - let custom_derive = Ident::from_str("custom_derive"); - let attr = Ident::from_str("attr"); - let bang = Ident::from_str("bang"); - let crate_kw = Ident::with_empty_ctxt(kw::Crate); - - let decls = { - let local_path = |sp: Span, name| { - cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![crate_kw, name])) - }; - let proc_macro_ty_method_path = |method| cx.expr_path(cx.path(span, vec![ - proc_macro, bridge, client, proc_macro_ty, method, - ])); - custom_derives.iter().map(|cd| { - cx.expr_call(span, proc_macro_ty_method_path(custom_derive), vec![ - cx.expr_str(cd.span, cd.trait_name), - cx.expr_vec_slice( - span, - cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::>() - ), - local_path(cd.span, cd.function_name), - ]) - }).chain(custom_attrs.iter().map(|ca| { - cx.expr_call(span, proc_macro_ty_method_path(attr), vec![ - cx.expr_str(ca.span, ca.function_name.name), - local_path(ca.span, ca.function_name), - ]) - })).chain(custom_macros.iter().map(|cm| { - cx.expr_call(span, proc_macro_ty_method_path(bang), vec![ - cx.expr_str(cm.span, cm.function_name.name), - local_path(cm.span, cm.function_name), - ]) - })).collect() - }; - - let decls_static = cx.item_static( - span, - Ident::from_str("_DECLS"), - cx.ty_rptr(span, - cx.ty(span, ast::TyKind::Slice( - cx.ty_path(cx.path(span, - vec![proc_macro, bridge, client, proc_macro_ty])))), - None, ast::Mutability::Immutable), - ast::Mutability::Immutable, - cx.expr_vec_slice(span, decls), - ).map(|mut i| { - let attr = cx.meta_word(span, sym::rustc_proc_macro_decls); - i.attrs.push(cx.attribute(span, attr)); - i.vis = respan(span, ast::VisibilityKind::Public); - i - }); - - let module = cx.item_mod( - span, - span, - ast::Ident::from_str("decls").gensym(), - vec![doc_hidden], - vec![krate, decls_static], - ).map(|mut i| { - i.vis = respan(span, ast::VisibilityKind::Public); - i - }); - - cx.monotonic_expander().flat_map_item(module).pop().unwrap() -} diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs new file mode 100644 index 00000000000..fc6cd5dc94c --- /dev/null +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -0,0 +1,414 @@ +use std::mem; + +use syntax::ast::{self, Ident}; +use syntax::attr; +use syntax::source_map::{ExpnInfo, ExpnKind, respan}; +use syntax::ext::base::{ExtCtxt, MacroKind}; +use syntax::ext::build::AstBuilder; +use syntax::ext::expand::ExpansionConfig; +use syntax::ext::hygiene::ExpnId; +use syntax::ext::proc_macro::is_proc_macro_attr; +use syntax::mut_visit::MutVisitor; +use syntax::parse::ParseSess; +use syntax::ptr::P; +use syntax::symbol::{kw, sym}; +use syntax::visit::{self, Visitor}; + +use syntax_pos::{Span, DUMMY_SP}; + +struct ProcMacroDerive { + trait_name: ast::Name, + function_name: Ident, + span: Span, + attrs: Vec, +} + +struct ProcMacroDef { + function_name: Ident, + span: Span, +} + +struct CollectProcMacros<'a> { + derives: Vec, + attr_macros: Vec, + bang_macros: Vec, + in_root: bool, + handler: &'a errors::Handler, + is_proc_macro_crate: bool, + is_test_crate: bool, +} + +pub fn inject(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 { + let ecfg = ExpansionConfig::default("proc_macro".to_string()); + let mut cx = ExtCtxt::new(sess, ecfg, resolver); + + let (derives, attr_macros, bang_macros) = { + let mut collect = CollectProcMacros { + derives: Vec::new(), + attr_macros: Vec::new(), + bang_macros: Vec::new(), + in_root: true, + handler, + is_proc_macro_crate, + is_test_crate, + }; + if has_proc_macro_decls || is_proc_macro_crate { + visit::walk_crate(&mut collect, &krate); + } + (collect.derives, collect.attr_macros, collect.bang_macros) + }; + + if !is_proc_macro_crate { + return krate + } + + if num_crate_types > 1 { + handler.err("cannot mix `proc-macro` crate type with others"); + } + + if is_test_crate { + return krate; + } + + krate.module.items.push(mk_decls(&mut cx, &derives, &attr_macros, &bang_macros)); + + krate +} + +impl<'a> CollectProcMacros<'a> { + fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { + if self.is_proc_macro_crate && self.in_root && vis.node.is_pub() { + self.handler.span_err(sp, + "`proc-macro` crate types cannot \ + export any items other than functions \ + tagged with `#[proc_macro_derive]` currently"); + } + } + + fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) { + // Once we've located the `#[proc_macro_derive]` attribute, verify + // that it's of the form `#[proc_macro_derive(Foo)]` or + // `#[proc_macro_derive(Foo, attributes(A, ..))]` + let list = match attr.meta_item_list() { + Some(list) => list, + None => return, + }; + if list.len() != 1 && list.len() != 2 { + self.handler.span_err(attr.span, + "attribute must have either one or two arguments"); + return + } + let trait_attr = match list[0].meta_item() { + Some(meta_item) => meta_item, + _ => { + self.handler.span_err(list[0].span(), "not a meta item"); + return + } + }; + let trait_ident = match trait_attr.ident() { + Some(trait_ident) if trait_attr.is_word() => trait_ident, + _ => { + self.handler.span_err(trait_attr.span, "must only be one word"); + return + } + }; + + if !trait_ident.name.can_be_raw() { + self.handler.span_err(trait_attr.span, + &format!("`{}` cannot be a name of derive macro", trait_ident)); + } + + let attributes_attr = list.get(1); + let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr { + if !attr.check_name(sym::attributes) { + self.handler.span_err(attr.span(), "second argument must be `attributes`") + } + attr.meta_item_list().unwrap_or_else(|| { + self.handler.span_err(attr.span(), + "attribute must be of form: `attributes(foo, bar)`"); + &[] + }).into_iter().filter_map(|attr| { + let attr = match attr.meta_item() { + Some(meta_item) => meta_item, + _ => { + self.handler.span_err(attr.span(), "not a meta item"); + return None; + } + }; + + let ident = match attr.ident() { + Some(ident) if attr.is_word() => ident, + _ => { + self.handler.span_err(attr.span, "must only be one word"); + return None; + } + }; + if !ident.name.can_be_raw() { + self.handler.span_err( + attr.span, + &format!("`{}` cannot be a name of derive helper attribute", ident), + ); + } + + Some(ident.name) + }).collect() + } else { + Vec::new() + }; + + if self.in_root && item.vis.node.is_pub() { + self.derives.push(ProcMacroDerive { + span: item.span, + trait_name: trait_ident.name, + function_name: item.ident, + attrs: proc_attrs, + }); + } else { + let msg = if !self.in_root { + "functions tagged with `#[proc_macro_derive]` must \ + currently reside in the root of the crate" + } else { + "functions tagged with `#[proc_macro_derive]` must be `pub`" + }; + self.handler.span_err(item.span, msg); + } + } + + fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { + if self.in_root && item.vis.node.is_pub() { + self.attr_macros.push(ProcMacroDef { + span: item.span, + function_name: item.ident, + }); + } else { + let msg = if !self.in_root { + "functions tagged with `#[proc_macro_attribute]` must \ + currently reside in the root of the crate" + } else { + "functions tagged with `#[proc_macro_attribute]` must be `pub`" + }; + self.handler.span_err(item.span, msg); + } + } + + fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { + if self.in_root && item.vis.node.is_pub() { + self.bang_macros.push(ProcMacroDef { + span: item.span, + function_name: item.ident, + }); + } else { + let msg = if !self.in_root { + "functions tagged with `#[proc_macro]` must \ + currently reside in the root of the crate" + } else { + "functions tagged with `#[proc_macro]` must be `pub`" + }; + self.handler.span_err(item.span, msg); + } + } +} + +impl<'a> Visitor<'a> for CollectProcMacros<'a> { + fn visit_item(&mut self, item: &'a ast::Item) { + if let ast::ItemKind::MacroDef(..) = item.node { + if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) { + let msg = + "cannot export macro_rules! macros from a `proc-macro` crate type currently"; + self.handler.span_err(item.span, msg); + } + } + + // First up, make sure we're checking a bare function. If we're not then + // we're just not interested in this item. + // + // If we find one, try to locate a `#[proc_macro_derive]` attribute on it. + let is_fn = match item.node { + ast::ItemKind::Fn(..) => true, + _ => false, + }; + + let mut found_attr: Option<&'a ast::Attribute> = None; + + for attr in &item.attrs { + if is_proc_macro_attr(&attr) { + if let Some(prev_attr) = found_attr { + let msg = if attr.path.segments[0].ident.name == + prev_attr.path.segments[0].ident.name { + format!("only one `#[{}]` attribute is allowed on any given function", + attr.path) + } else { + format!("`#[{}]` and `#[{}]` attributes cannot both be applied \ + to the same function", attr.path, prev_attr.path) + }; + + self.handler.struct_span_err(attr.span, &msg) + .span_note(prev_attr.span, "previous attribute here") + .emit(); + + return; + } + + found_attr = Some(attr); + } + } + + let attr = match found_attr { + None => { + self.check_not_pub_in_root(&item.vis, item.span); + let prev_in_root = mem::replace(&mut self.in_root, false); + visit::walk_item(self, item); + self.in_root = prev_in_root; + return; + }, + Some(attr) => attr, + }; + + if !is_fn { + let msg = format!("the `#[{}]` attribute may only be used on bare functions", + attr.path); + + self.handler.span_err(attr.span, &msg); + return; + } + + if self.is_test_crate { + return; + } + + if !self.is_proc_macro_crate { + let msg = format!("the `#[{}]` attribute is only usable with crates of the \ + `proc-macro` crate type", attr.path); + + self.handler.span_err(attr.span, &msg); + return; + } + + if attr.check_name(sym::proc_macro_derive) { + self.collect_custom_derive(item, attr); + } else if attr.check_name(sym::proc_macro_attribute) { + self.collect_attr_proc_macro(item); + } else if attr.check_name(sym::proc_macro) { + self.collect_bang_proc_macro(item); + }; + + let prev_in_root = mem::replace(&mut self.in_root, false); + visit::walk_item(self, item); + self.in_root = prev_in_root; + } + + fn visit_mac(&mut self, mac: &'a ast::Mac) { + visit::walk_mac(self, mac) + } +} + +// Creates a new module which looks like: +// +// #[doc(hidden)] +// mod $gensym { +// extern crate proc_macro; +// +// use proc_macro::bridge::client::ProcMacro; +// +// #[rustc_proc_macro_decls] +// static DECLS: &[ProcMacro] = &[ +// ProcMacro::custom_derive($name_trait1, &[], ::$name1); +// ProcMacro::custom_derive($name_trait2, &["attribute_name"], ::$name2); +// // ... +// ]; +// } +fn mk_decls( + cx: &mut ExtCtxt<'_>, + custom_derives: &[ProcMacroDerive], + custom_attrs: &[ProcMacroDef], + custom_macros: &[ProcMacroDef], +) -> P { + let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable( + ExpnKind::Macro(MacroKind::Attr, sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, + [sym::rustc_attrs, sym::proc_macro_internals][..].into(), + )); + + let hidden = cx.meta_list_item_word(span, sym::hidden); + let doc = cx.meta_list(span, sym::doc, vec![hidden]); + let doc_hidden = cx.attribute(span, doc); + + let proc_macro = Ident::with_empty_ctxt(sym::proc_macro); + let krate = cx.item(span, + proc_macro, + Vec::new(), + ast::ItemKind::ExternCrate(None)); + + let bridge = Ident::from_str("bridge"); + let client = Ident::from_str("client"); + let proc_macro_ty = Ident::from_str("ProcMacro"); + let custom_derive = Ident::from_str("custom_derive"); + let attr = Ident::from_str("attr"); + let bang = Ident::from_str("bang"); + let crate_kw = Ident::with_empty_ctxt(kw::Crate); + + let decls = { + let local_path = |sp: Span, name| { + cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![crate_kw, name])) + }; + let proc_macro_ty_method_path = |method| cx.expr_path(cx.path(span, vec![ + proc_macro, bridge, client, proc_macro_ty, method, + ])); + custom_derives.iter().map(|cd| { + cx.expr_call(span, proc_macro_ty_method_path(custom_derive), vec![ + cx.expr_str(cd.span, cd.trait_name), + cx.expr_vec_slice( + span, + cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::>() + ), + local_path(cd.span, cd.function_name), + ]) + }).chain(custom_attrs.iter().map(|ca| { + cx.expr_call(span, proc_macro_ty_method_path(attr), vec![ + cx.expr_str(ca.span, ca.function_name.name), + local_path(ca.span, ca.function_name), + ]) + })).chain(custom_macros.iter().map(|cm| { + cx.expr_call(span, proc_macro_ty_method_path(bang), vec![ + cx.expr_str(cm.span, cm.function_name.name), + local_path(cm.span, cm.function_name), + ]) + })).collect() + }; + + let decls_static = cx.item_static( + span, + Ident::from_str("_DECLS"), + cx.ty_rptr(span, + cx.ty(span, ast::TyKind::Slice( + cx.ty_path(cx.path(span, + vec![proc_macro, bridge, client, proc_macro_ty])))), + None, ast::Mutability::Immutable), + ast::Mutability::Immutable, + cx.expr_vec_slice(span, decls), + ).map(|mut i| { + let attr = cx.meta_word(span, sym::rustc_proc_macro_decls); + i.attrs.push(cx.attribute(span, attr)); + i.vis = respan(span, ast::VisibilityKind::Public); + i + }); + + let module = cx.item_mod( + span, + span, + ast::Ident::from_str("decls").gensym(), + vec![doc_hidden], + vec![krate, decls_static], + ).map(|mut i| { + i.vis = respan(span, ast::VisibilityKind::Public); + i + }); + + cx.monotonic_expander().flat_map_item(module).pop().unwrap() +} diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index 36aeb3065ff..a2d93d01cec 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -30,7 +30,7 @@ pub fn expand_test_case( if !ecx.ecfg.should_test { return vec![]; } - let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.mark)); + let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id)); let mut item = anno_item.expect_item(); item = item.map(|mut item| { item.vis = respan(item.vis.span, ast::VisibilityKind::Public); diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs index 061f5c3408b..848c797856e 100644 --- a/src/libsyntax_ext/test_harness.rs +++ b/src/libsyntax_ext/test_harness.rs @@ -37,12 +37,14 @@ struct TestCtxt<'a> { // Traverse the crate, collecting all the test functions, eliding any // existing main functions, and synthesizing a main test harness -pub fn modify_for_testing(sess: &ParseSess, - resolver: &mut dyn Resolver, - should_test: bool, - krate: &mut ast::Crate, - span_diagnostic: &errors::Handler, - features: &Features) { +pub fn inject( + sess: &ParseSess, + resolver: &mut dyn Resolver, + should_test: bool, + krate: &mut ast::Crate, + span_diagnostic: &errors::Handler, + features: &Features, +) { // Check for #[reexport_test_harness_main = "some_name"] which // creates a `use __test::main as some_name;`. This needs to be // unconditional, so that the attribute is still marked as used in -- cgit 1.4.1-3-g733a5 From fc9bfd68b583852758d0a0f8ea67d5d5802f14d2 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 27 Jul 2019 18:24:17 +0700 Subject: Treat doc comments separately --- src/libsyntax/parse/attr.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 810af9b9246..af484c886ab 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -12,7 +12,7 @@ use smallvec::smallvec; #[derive(Debug)] enum InnerAttributeParsePolicy<'a> { Permitted, - NotPermitted { reason: &'a str, prev_attr_sp: Option }, + NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option }, } const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ @@ -43,8 +43,11 @@ impl<'a> Parser<'a> { DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }; let inner_parse_policy = - InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason, - prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) }; + InnerAttributeParsePolicy::NotPermitted { + reason: inner_error_reason, + saw_doc_comment: just_parsed_doc_comment, + prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) + }; let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; attrs.push(attr); just_parsed_doc_comment = false; @@ -78,8 +81,11 @@ impl<'a> Parser<'a> { let inner_parse_policy = if permit_inner { InnerAttributeParsePolicy::Permitted } else { - InnerAttributeParsePolicy::NotPermitted - { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, prev_attr_sp: None } + InnerAttributeParsePolicy::NotPermitted { + reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, + saw_doc_comment: false, + prev_attr_sp: None + } }; self.parse_attribute_with_inner_parse_policy(inner_parse_policy) } @@ -117,8 +123,14 @@ impl<'a> Parser<'a> { // Emit error if inner attribute is encountered and not permitted if style == ast::AttrStyle::Inner { - if let InnerAttributeParsePolicy::NotPermitted { reason, prev_attr_sp } - = inner_parse_policy { + if let InnerAttributeParsePolicy::NotPermitted { reason, + saw_doc_comment, prev_attr_sp } = inner_parse_policy { + let prev_attr_note = if saw_doc_comment { + "previous doc comment" + } else { + "previous outer attribute" + }; + let mut diagnostic = self .diagnostic() .struct_span_err(attr_sp, reason); @@ -126,7 +138,7 @@ impl<'a> Parser<'a> { if let Some(prev_attr_sp) = prev_attr_sp { diagnostic .span_label(attr_sp, "not permitted following an outer attibute") - .span_label(prev_attr_sp, "previous outer attribute"); + .span_label(prev_attr_sp, prev_attr_note); } diagnostic -- cgit 1.4.1-3-g733a5