Rollup merge of #62771 - petrochenkov:depext, r=eddyb
Break dependencies between `syntax_ext` and other crates Move `source_util` macros into `syntax_ext`. Move other early code generation facilities like standard library injection into `syntax_ext`. The only crate that depends on `syntax_ext` now is `rustc_interface` which is one of the "final" crates that depend on everything. Minor: Cleanup dependencies of `rustc_driver`, many of them are no longer used after introduction of `rustc_interface`. r? @eddyb
This commit is contained in:
commit
ca0cd73f49
32 changed files with 393 additions and 545 deletions
14
Cargo.lock
14
Cargo.lock
|
|
@ -2863,31 +2863,20 @@ dependencies = [
|
|||
name = "rustc_driver"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arena 0.0.0",
|
||||
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"graphviz 0.0.0",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_ast_borrowck 0.0.0",
|
||||
"rustc_codegen_utils 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_incremental 0.0.0",
|
||||
"rustc_interface 0.0.0",
|
||||
"rustc_lint 0.0.0",
|
||||
"rustc_metadata 0.0.0",
|
||||
"rustc_mir 0.0.0",
|
||||
"rustc_passes 0.0.0",
|
||||
"rustc_plugin 0.0.0",
|
||||
"rustc_privacy 0.0.0",
|
||||
"rustc_resolve 0.0.0",
|
||||
"rustc_save_analysis 0.0.0",
|
||||
"rustc_target 0.0.0",
|
||||
"rustc_traits 0.0.0",
|
||||
"rustc_typeck 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
|
@ -3019,7 +3008,6 @@ dependencies = [
|
|||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntax 0.0.0",
|
||||
"syntax_ext 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
|
|
@ -3064,9 +3052,7 @@ 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_ext 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -10,30 +10,19 @@ path = "lib.rs"
|
|||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
arena = { path = "../libarena" }
|
||||
graphviz = { path = "../libgraphviz" }
|
||||
log = "0.4"
|
||||
env_logger = { version = "0.5", default-features = false }
|
||||
rayon = { version = "0.2.0", package = "rustc-rayon" }
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_ast_borrowck = { path = "../librustc_ast_borrowck" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||
rustc_incremental = { path = "../librustc_incremental" }
|
||||
rustc_lint = { path = "../librustc_lint" }
|
||||
rustc_metadata = { path = "../librustc_metadata" }
|
||||
rustc_mir = { path = "../librustc_mir" }
|
||||
rustc_passes = { path = "../librustc_passes" }
|
||||
rustc_plugin = { path = "../librustc_plugin" }
|
||||
rustc_privacy = { path = "../librustc_privacy" }
|
||||
rustc_resolve = { path = "../librustc_resolve" }
|
||||
rustc_save_analysis = { path = "../librustc_save_analysis" }
|
||||
rustc_traits = { path = "../librustc_traits" }
|
||||
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
|
||||
rustc_typeck = { path = "../librustc_typeck" }
|
||||
rustc_interface = { path = "../librustc_interface" }
|
||||
rustc_serialize = { path = "../libserialize", package = "serialize" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
|
|
|
|||
|
|
@ -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", || {
|
||||
|
|
@ -456,7 +461,7 @@ fn configure_and_expand_inner<'a>(
|
|||
sess.profiler(|p| p.end_activity("macro expansion"));
|
||||
|
||||
time(sess, "maybe building test harness", || {
|
||||
syntax::test::modify_for_testing(
|
||||
syntax_ext::test_harness::inject(
|
||||
&sess.parse_sess,
|
||||
&mut resolver,
|
||||
sess.opts.test,
|
||||
|
|
@ -485,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,
|
||||
|
|
|
|||
|
|
@ -21,5 +21,4 @@ rustc_target = { path = "../librustc_target" }
|
|||
rustc_serialize = { path = "../libserialize", package = "serialize" }
|
||||
stable_deref_trait = "1.0.0"
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_ext = { path = "../libsyntax_ext" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
|
|
|
|||
|
|
@ -586,8 +586,7 @@ impl<'a> CrateLoader<'a> {
|
|||
use std::{env, mem};
|
||||
use crate::dynamic_lib::DynamicLibrary;
|
||||
use proc_macro::bridge::client::ProcMacro;
|
||||
use syntax_ext::deriving::custom::ProcMacroDerive;
|
||||
use syntax_ext::proc_macro_impl::{AttrProcMacro, BangProcMacro};
|
||||
use syntax::ext::proc_macro::{BangProcMacro, AttrProcMacro, ProcMacroDerive};
|
||||
|
||||
let path = match dylib {
|
||||
Some(dylib) => dylib,
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ use syntax::attr;
|
|||
use syntax::source_map;
|
||||
use syntax::edition::Edition;
|
||||
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||
use syntax::ext::proc_macro::BangProcMacro;
|
||||
use syntax::parse::source_file_to_stream;
|
||||
use syntax::parse::parser::emit_unclosed_delims;
|
||||
use syntax::symbol::{Symbol, sym};
|
||||
use syntax_ext::proc_macro_impl::BangProcMacro;
|
||||
use syntax_pos::{Span, NO_EXPANSION, FileName};
|
||||
use rustc_data_structures::bit_set::BitSet;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@ 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_ext = { path = "../libsyntax_ext" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ use rustc::session::Session;
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use syntax::ast::*;
|
||||
use syntax::attr;
|
||||
use syntax::ext::proc_macro::is_proc_macro_attr;
|
||||
use syntax::feature_gate::is_builtin_attr;
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::symbol::{kw, sym};
|
||||
use syntax::visit::{self, Visitor};
|
||||
use syntax::{span_err, struct_span_err, walk_list};
|
||||
use syntax_ext::proc_macro_decls::is_proc_macro_attr;
|
||||
use syntax_pos::{Span, MultiSpan};
|
||||
use errors::{Applicability, FatalError};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
@ -14,7 +14,7 @@ use crate::tokenstream::{self, TokenStream, TokenTree};
|
|||
|
||||
use errors::{DiagnosticBuilder, DiagnosticId};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use syntax_pos::{Span, MultiSpan, DUMMY_SP};
|
||||
use syntax_pos::{FileName, Span, MultiSpan, DUMMY_SP};
|
||||
use syntax_pos::hygiene::{ExpnInfo, ExpnKind};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
use crate::attr::HasAttrs;
|
||||
use crate::ast;
|
||||
use crate::source_map::{ExpnInfo, ExpnKind};
|
||||
use crate::ext::base::{ExtCtxt, MacroKind};
|
||||
use crate::ext::build::AstBuilder;
|
||||
use crate::parse::parser::PathStyle;
|
||||
use crate::symbol::{Symbol, sym};
|
||||
use crate::errors::Applicability;
|
||||
|
||||
use syntax_pos::Span;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
|
||||
let mut result = Vec::new();
|
||||
attrs.retain(|attr| {
|
||||
if attr.path != sym::derive {
|
||||
return true;
|
||||
}
|
||||
if !attr.is_meta_item_list() {
|
||||
cx.struct_span_err(attr.span, "malformed `derive` attribute input")
|
||||
.span_suggestion(
|
||||
attr.span,
|
||||
"missing traits to be derived",
|
||||
"#[derive(Trait1, Trait2, ...)]".to_owned(),
|
||||
Applicability::HasPlaceholders,
|
||||
).emit();
|
||||
return false;
|
||||
}
|
||||
|
||||
match attr.parse_list(cx.parse_sess,
|
||||
|parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
|
||||
Ok(traits) => {
|
||||
result.extend(traits);
|
||||
true
|
||||
}
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
false
|
||||
}
|
||||
}
|
||||
});
|
||||
result
|
||||
}
|
||||
|
||||
pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T)
|
||||
where T: HasAttrs,
|
||||
{
|
||||
let (mut names, mut pretty_name) = (FxHashSet::default(), String::new());
|
||||
for (i, path) in traits.iter().enumerate() {
|
||||
if i > 0 {
|
||||
pretty_name.push_str(", ");
|
||||
}
|
||||
pretty_name.push_str(&path.to_string());
|
||||
names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
|
||||
}
|
||||
|
||||
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(),
|
||||
));
|
||||
|
||||
item.visit_attrs(|attrs| {
|
||||
if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) {
|
||||
let meta = cx.meta_word(span, sym::structural_match);
|
||||
attrs.push(cx.attribute(span, meta));
|
||||
}
|
||||
if names.contains(&sym::Copy) {
|
||||
let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
|
||||
attrs.push(cx.attribute(span, meta));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ use crate::attr::{self, HasAttrs};
|
|||
use crate::source_map::{dummy_spanned, respan};
|
||||
use crate::config::StripUnconfigured;
|
||||
use crate::ext::base::*;
|
||||
use crate::ext::derive::{add_derived_markers, collect_derives};
|
||||
use crate::ext::proc_macro::{add_derived_markers, collect_derives};
|
||||
use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnInfo, ExpnKind};
|
||||
use crate::ext::placeholders::{placeholder, PlaceholderExpander};
|
||||
use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
|
||||
|
|
|
|||
249
src/libsyntax/ext/proc_macro.rs
Normal file
249
src/libsyntax/ext/proc_macro.rs
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
use crate::ast::{self, ItemKind, Attribute, Mac};
|
||||
use crate::attr::{mark_used, mark_known, HasAttrs};
|
||||
use crate::errors::{Applicability, FatalError};
|
||||
use crate::ext::base::{self, *};
|
||||
use crate::ext::build::AstBuilder;
|
||||
use crate::ext::proc_macro_server;
|
||||
use crate::parse::{self, token};
|
||||
use crate::parse::parser::PathStyle;
|
||||
use crate::symbol::{sym, Symbol};
|
||||
use crate::tokenstream::{self, TokenStream};
|
||||
use crate::visit::Visitor;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use syntax_pos::hygiene::{ExpnInfo, ExpnKind};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
|
||||
proc_macro::bridge::server::SameThread;
|
||||
|
||||
pub struct BangProcMacro {
|
||||
pub client: proc_macro::bridge::client::Client<
|
||||
fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
|
||||
>,
|
||||
}
|
||||
|
||||
impl base::ProcMacro for BangProcMacro {
|
||||
fn expand<'cx>(&self,
|
||||
ecx: &'cx mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
input: TokenStream)
|
||||
-> TokenStream {
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
match self.client.run(&EXEC_STRATEGY, server, input) {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
let msg = "proc macro panicked";
|
||||
let mut err = ecx.struct_span_fatal(span, msg);
|
||||
if let Some(s) = e.as_str() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AttrProcMacro {
|
||||
pub client: proc_macro::bridge::client::Client<
|
||||
fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
|
||||
>,
|
||||
}
|
||||
|
||||
impl base::AttrProcMacro for AttrProcMacro {
|
||||
fn expand<'cx>(&self,
|
||||
ecx: &'cx mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
annotation: TokenStream,
|
||||
annotated: TokenStream)
|
||||
-> TokenStream {
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
let msg = "custom attribute panicked";
|
||||
let mut err = ecx.struct_span_fatal(span, msg);
|
||||
if let Some(s) = e.as_str() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProcMacroDerive {
|
||||
pub client: proc_macro::bridge::client::Client<
|
||||
fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
|
||||
>,
|
||||
pub attrs: Vec<ast::Name>,
|
||||
}
|
||||
|
||||
impl MultiItemModifier for ProcMacroDerive {
|
||||
fn expand(&self,
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
_meta_item: &ast::MetaItem,
|
||||
item: Annotatable)
|
||||
-> Vec<Annotatable> {
|
||||
let item = match item {
|
||||
Annotatable::Item(item) => item,
|
||||
Annotatable::ImplItem(_) |
|
||||
Annotatable::TraitItem(_) |
|
||||
Annotatable::ForeignItem(_) |
|
||||
Annotatable::Stmt(_) |
|
||||
Annotatable::Expr(_) => {
|
||||
ecx.span_err(span, "proc-macro derives may only be \
|
||||
applied to a struct, enum, or union");
|
||||
return Vec::new()
|
||||
}
|
||||
};
|
||||
match item.node {
|
||||
ItemKind::Struct(..) |
|
||||
ItemKind::Enum(..) |
|
||||
ItemKind::Union(..) => {},
|
||||
_ => {
|
||||
ecx.span_err(span, "proc-macro derives may only be \
|
||||
applied to a struct, enum, or union");
|
||||
return Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
// Mark attributes as known, and used.
|
||||
MarkAttrs(&self.attrs).visit_item(&item);
|
||||
|
||||
let token = token::Interpolated(Lrc::new(token::NtItem(item)));
|
||||
let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
|
||||
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
let msg = "proc-macro derive panicked";
|
||||
let mut err = ecx.struct_span_fatal(span, msg);
|
||||
if let Some(s) = e.as_str() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
};
|
||||
|
||||
let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
|
||||
let msg = "proc-macro derive produced unparseable tokens";
|
||||
|
||||
let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
|
||||
let mut items = vec![];
|
||||
|
||||
loop {
|
||||
match parser.parse_item() {
|
||||
Ok(None) => break,
|
||||
Ok(Some(item)) => {
|
||||
items.push(Annotatable::Item(item))
|
||||
}
|
||||
Err(mut err) => {
|
||||
// FIXME: handle this better
|
||||
err.cancel();
|
||||
ecx.struct_span_fatal(span, msg).emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// fail if there have been errors emitted
|
||||
if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
|
||||
ecx.struct_span_fatal(span, msg).emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
|
||||
items
|
||||
}
|
||||
}
|
||||
|
||||
struct MarkAttrs<'a>(&'a [ast::Name]);
|
||||
|
||||
impl<'a> Visitor<'a> for MarkAttrs<'a> {
|
||||
fn visit_attribute(&mut self, attr: &Attribute) {
|
||||
if let Some(ident) = attr.ident() {
|
||||
if self.0.contains(&ident.name) {
|
||||
mark_used(attr);
|
||||
mark_known(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mac(&mut self, _mac: &Mac) {}
|
||||
}
|
||||
|
||||
pub fn is_proc_macro_attr(attr: &Attribute) -> bool {
|
||||
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
|
||||
.iter().any(|kind| attr.check_name(*kind))
|
||||
}
|
||||
|
||||
crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
|
||||
let mut result = Vec::new();
|
||||
attrs.retain(|attr| {
|
||||
if attr.path != sym::derive {
|
||||
return true;
|
||||
}
|
||||
if !attr.is_meta_item_list() {
|
||||
cx.struct_span_err(attr.span, "malformed `derive` attribute input")
|
||||
.span_suggestion(
|
||||
attr.span,
|
||||
"missing traits to be derived",
|
||||
"#[derive(Trait1, Trait2, ...)]".to_owned(),
|
||||
Applicability::HasPlaceholders,
|
||||
).emit();
|
||||
return false;
|
||||
}
|
||||
|
||||
match attr.parse_list(cx.parse_sess,
|
||||
|parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
|
||||
Ok(traits) => {
|
||||
result.extend(traits);
|
||||
true
|
||||
}
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
false
|
||||
}
|
||||
}
|
||||
});
|
||||
result
|
||||
}
|
||||
|
||||
crate fn add_derived_markers<T: HasAttrs>(
|
||||
cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T
|
||||
) {
|
||||
let (mut names, mut pretty_name) = (FxHashSet::default(), String::new());
|
||||
for (i, path) in traits.iter().enumerate() {
|
||||
if i > 0 {
|
||||
pretty_name.push_str(", ");
|
||||
}
|
||||
pretty_name.push_str(&path.to_string());
|
||||
names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
|
||||
}
|
||||
|
||||
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(),
|
||||
));
|
||||
|
||||
item.visit_attrs(|attrs| {
|
||||
if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) {
|
||||
let meta = cx.meta_word(span, sym::structural_match);
|
||||
attrs.push(cx.attribute(span, meta));
|
||||
}
|
||||
if names.contains(&sym::Copy) {
|
||||
let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
|
||||
attrs.push(cx.attribute(span, meta));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1,21 +1,19 @@
|
|||
use crate::ast;
|
||||
use crate::ext::base::ExtCtxt;
|
||||
use crate::parse::{self, token, ParseSess};
|
||||
use crate::parse::lexer::comments;
|
||||
use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
|
||||
|
||||
use errors::{Diagnostic, DiagnosticBuilder};
|
||||
|
||||
use std::panic;
|
||||
|
||||
use proc_macro::bridge::{server, TokenTree};
|
||||
use proc_macro::{Delimiter, Level, LineColumn, Spacing};
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use std::ascii;
|
||||
use std::ops::Bound;
|
||||
use syntax::ast;
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::parse::lexer::comments;
|
||||
use syntax::parse::{self, token, ParseSess};
|
||||
use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
|
||||
use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
|
||||
use syntax_pos::hygiene::{SyntaxContext, Transparency};
|
||||
use syntax_pos::symbol::{kw, sym, Symbol};
|
||||
use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
|
||||
|
||||
use proc_macro::{Delimiter, Level, LineColumn, Spacing};
|
||||
use proc_macro::bridge::{server, TokenTree};
|
||||
use std::{ascii, panic};
|
||||
use std::ops::Bound;
|
||||
|
||||
trait FromInternal<T> {
|
||||
fn from_internal(x: T) -> Self;
|
||||
|
|
@ -52,7 +50,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
|
|||
{
|
||||
fn from_internal(((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec<Self>))
|
||||
-> Self {
|
||||
use syntax::parse::token::*;
|
||||
use crate::parse::token::*;
|
||||
|
||||
let joint = is_joint == Joint;
|
||||
let Token { kind, span } = match tree {
|
||||
|
|
@ -193,7 +191,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
|
|||
|
||||
impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
|
||||
fn to_internal(self) -> TokenStream {
|
||||
use syntax::parse::token::*;
|
||||
use crate::parse::token::*;
|
||||
|
||||
let (ch, joint, span) = match self {
|
||||
TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
|
||||
|
|
@ -18,12 +18,17 @@
|
|||
#![feature(label_break_value)]
|
||||
#![feature(mem_take)]
|
||||
#![feature(nll)]
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_span)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(try_trait)]
|
||||
#![feature(unicode_internals)]
|
||||
|
||||
#![recursion_limit="256"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
pub use errors;
|
||||
use rustc_data_structures::sync::Lock;
|
||||
use rustc_data_structures::bit_set::GrowableBitSet;
|
||||
|
|
@ -37,6 +42,7 @@ const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
|
|||
// way towards a non-panic!-prone parser. It should be used for fatal parsing
|
||||
// errors; eventually we plan to convert all code using panictry to just use
|
||||
// normal try.
|
||||
#[macro_export]
|
||||
macro_rules! panictry {
|
||||
($e:expr) => ({
|
||||
use std::result::Result::{Ok, Err};
|
||||
|
|
@ -147,10 +153,8 @@ 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 test;
|
||||
pub mod tokenstream;
|
||||
pub mod visit;
|
||||
|
||||
|
|
@ -161,14 +165,15 @@ pub mod print {
|
|||
}
|
||||
|
||||
pub mod ext {
|
||||
mod placeholders;
|
||||
mod proc_macro_server;
|
||||
|
||||
pub use syntax_pos::hygiene;
|
||||
pub mod allocator;
|
||||
pub mod base;
|
||||
pub mod build;
|
||||
pub mod derive;
|
||||
pub mod expand;
|
||||
pub mod placeholders;
|
||||
pub mod source_util;
|
||||
pub mod proc_macro;
|
||||
|
||||
pub mod tt {
|
||||
pub mod transcribe;
|
||||
|
|
|
|||
|
|
@ -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<SourceMap>) -> 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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Vec<Span>>,
|
||||
// Places where `async || ..` exprs were used and should be feature gated.
|
||||
pub async_closure_spans: Lock<Vec<Span>>,
|
||||
pub injected_crate_name: Once<Symbol>,
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ path = "lib.rs"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
fmt_macros = { path = "../libfmt_macros" }
|
||||
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
fmt_macros = { path = "../libfmt_macros" }
|
||||
log = "0.4"
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
|
||||
log = "0.4"
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
|
|
|
|||
|
|
@ -1,119 +0,0 @@
|
|||
use crate::proc_macro_impl::EXEC_STRATEGY;
|
||||
use crate::proc_macro_server;
|
||||
|
||||
use errors::FatalError;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use syntax::ast::{self, ItemKind, Attribute, Mac};
|
||||
use syntax::attr::{mark_used, mark_known};
|
||||
use syntax::source_map::Span;
|
||||
use syntax::ext::base::*;
|
||||
use syntax::parse;
|
||||
use syntax::parse::token;
|
||||
use syntax::tokenstream;
|
||||
use syntax::visit::Visitor;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
struct MarkAttrs<'a>(&'a [ast::Name]);
|
||||
|
||||
impl<'a> Visitor<'a> for MarkAttrs<'a> {
|
||||
fn visit_attribute(&mut self, attr: &Attribute) {
|
||||
if let Some(ident) = attr.ident() {
|
||||
if self.0.contains(&ident.name) {
|
||||
mark_used(attr);
|
||||
mark_known(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mac(&mut self, _mac: &Mac) {}
|
||||
}
|
||||
|
||||
pub struct ProcMacroDerive {
|
||||
pub client: proc_macro::bridge::client::Client<
|
||||
fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
|
||||
>,
|
||||
pub attrs: Vec<ast::Name>,
|
||||
}
|
||||
|
||||
impl MultiItemModifier for ProcMacroDerive {
|
||||
fn expand(&self,
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
_meta_item: &ast::MetaItem,
|
||||
item: Annotatable)
|
||||
-> Vec<Annotatable> {
|
||||
let item = match item {
|
||||
Annotatable::Item(item) => item,
|
||||
Annotatable::ImplItem(_) |
|
||||
Annotatable::TraitItem(_) |
|
||||
Annotatable::ForeignItem(_) |
|
||||
Annotatable::Stmt(_) |
|
||||
Annotatable::Expr(_) => {
|
||||
ecx.span_err(span, "proc-macro derives may only be \
|
||||
applied to a struct, enum, or union");
|
||||
return Vec::new()
|
||||
}
|
||||
};
|
||||
match item.node {
|
||||
ItemKind::Struct(..) |
|
||||
ItemKind::Enum(..) |
|
||||
ItemKind::Union(..) => {},
|
||||
_ => {
|
||||
ecx.span_err(span, "proc-macro derives may only be \
|
||||
applied to a struct, enum, or union");
|
||||
return Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
// Mark attributes as known, and used.
|
||||
MarkAttrs(&self.attrs).visit_item(&item);
|
||||
|
||||
let token = token::Interpolated(Lrc::new(token::NtItem(item)));
|
||||
let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
|
||||
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
let msg = "proc-macro derive panicked";
|
||||
let mut err = ecx.struct_span_fatal(span, msg);
|
||||
if let Some(s) = e.as_str() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
};
|
||||
|
||||
let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
|
||||
let msg = "proc-macro derive produced unparseable tokens";
|
||||
|
||||
let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
|
||||
let mut items = vec![];
|
||||
|
||||
loop {
|
||||
match parser.parse_item() {
|
||||
Ok(None) => break,
|
||||
Ok(Some(item)) => {
|
||||
items.push(Annotatable::Item(item))
|
||||
}
|
||||
Err(mut err) => {
|
||||
// FIXME: handle this better
|
||||
err.cancel();
|
||||
ecx.struct_span_fatal(span, msg).emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// fail if there have been errors emitted
|
||||
if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
|
||||
ecx.struct_span_fatal(span, msg).emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
|
||||
items
|
||||
}
|
||||
}
|
||||
|
|
@ -1770,50 +1770,6 @@ pub fn cs_fold1<F, B>(use_foldl: bool,
|
|||
}
|
||||
}
|
||||
|
||||
/// Call the method that is being derived on all the fields, and then
|
||||
/// process the collected results. i.e.
|
||||
///
|
||||
/// ```ignore (only-for-syntax-highlight)
|
||||
/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1),
|
||||
/// self_2.method(__arg_1_2, __arg_2_2)])
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cs_same_method<F>(f: F,
|
||||
mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
trait_span: Span,
|
||||
substructure: &Substructure<'_>)
|
||||
-> P<Expr>
|
||||
where F: FnOnce(&mut ExtCtxt<'_>, Span, Vec<P<Expr>>) -> P<Expr>
|
||||
{
|
||||
match *substructure.fields {
|
||||
EnumMatching(.., ref all_fields) |
|
||||
Struct(_, ref all_fields) => {
|
||||
// call self_n.method(other_1_n, other_2_n, ...)
|
||||
let called = all_fields.iter()
|
||||
.map(|field| {
|
||||
cx.expr_method_call(field.span,
|
||||
field.self_.clone(),
|
||||
substructure.method_ident,
|
||||
field.other
|
||||
.iter()
|
||||
.map(|e| cx.expr_addr_of(field.span, e.clone()))
|
||||
.collect())
|
||||
})
|
||||
.collect();
|
||||
|
||||
f(cx, trait_span, called)
|
||||
}
|
||||
EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => {
|
||||
enum_nonmatch_f(cx,
|
||||
trait_span,
|
||||
(&all_self_args[..], tuple),
|
||||
substructure.nonself_args)
|
||||
}
|
||||
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the type has no value fields
|
||||
/// (for an enum, no variant has any fields)
|
||||
pub fn is_type_without_fields(item: &Annotatable) -> bool {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ pub enum PtrTy<'a> {
|
|||
/// &'lifetime mut
|
||||
Borrowed(Option<&'a str>, ast::Mutability),
|
||||
/// *mut
|
||||
#[allow(dead_code)]
|
||||
Raw(ast::Mutability),
|
||||
}
|
||||
|
||||
|
|
@ -107,13 +108,6 @@ pub enum Ty<'a> {
|
|||
Tuple(Vec<Ty<'a>>),
|
||||
}
|
||||
|
||||
/// A const expression. Supports literals and blocks.
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub enum Const {
|
||||
Literal,
|
||||
Block,
|
||||
}
|
||||
|
||||
pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
|
||||
Borrowed(None, ast::Mutability::Immutable)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ pub mod decodable;
|
|||
pub mod hash;
|
||||
pub mod debug;
|
||||
pub mod default;
|
||||
pub mod custom;
|
||||
|
||||
#[path="cmp/partial_eq.rs"]
|
||||
pub mod partial_eq;
|
||||
|
|
|
|||
|
|
@ -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/")]
|
||||
|
||||
|
|
@ -7,21 +8,15 @@
|
|||
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(mem_take)]
|
||||
#![feature(nll)]
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_span)]
|
||||
#![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;
|
||||
|
|
@ -32,21 +27,21 @@ mod cfg;
|
|||
mod compile_error;
|
||||
mod concat;
|
||||
mod concat_idents;
|
||||
mod deriving;
|
||||
mod env;
|
||||
mod format;
|
||||
mod format_foreign;
|
||||
mod global_allocator;
|
||||
mod global_asm;
|
||||
mod log_syntax;
|
||||
mod proc_macro_server;
|
||||
mod source_util;
|
||||
mod test;
|
||||
mod test_case;
|
||||
mod trace_macros;
|
||||
|
||||
pub mod deriving;
|
||||
pub mod plugin_macro_defs;
|
||||
pub mod proc_macro_decls;
|
||||
pub mod proc_macro_impl;
|
||||
pub mod proc_macro_harness;
|
||||
pub mod standard_library_imports;
|
||||
pub mod test_harness;
|
||||
|
||||
pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, edition: Edition) {
|
||||
let mut register = |name, kind| resolver.register_builtin_macro(
|
||||
|
|
@ -93,7 +88,7 @@ pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, e
|
|||
bench: test::expand_bench,
|
||||
global_allocator: global_allocator::expand,
|
||||
test: test::expand_test,
|
||||
test_case: test_case::expand,
|
||||
test_case: test::expand_test_case,
|
||||
}
|
||||
|
||||
register_derive! {
|
||||
|
|
|
|||
|
|
@ -7,21 +7,15 @@ 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::Symbol;
|
||||
use syntax::symbol::{kw, sym};
|
||||
use syntax::visit::{self, Visitor};
|
||||
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
const PROC_MACRO_KINDS: [Symbol; 3] = [
|
||||
sym::proc_macro_derive,
|
||||
sym::proc_macro_attribute,
|
||||
sym::proc_macro
|
||||
];
|
||||
|
||||
struct ProcMacroDerive {
|
||||
trait_name: ast::Name,
|
||||
function_name: Ident,
|
||||
|
|
@ -44,7 +38,7 @@ struct CollectProcMacros<'a> {
|
|||
is_test_crate: bool,
|
||||
}
|
||||
|
||||
pub fn modify(sess: &ParseSess,
|
||||
pub fn inject(sess: &ParseSess,
|
||||
resolver: &mut dyn (::syntax::ext::base::Resolver),
|
||||
mut krate: ast::Crate,
|
||||
is_proc_macro_crate: bool,
|
||||
|
|
@ -88,10 +82,6 @@ pub fn modify(sess: &ParseSess,
|
|||
krate
|
||||
}
|
||||
|
||||
pub fn is_proc_macro_attr(attr: &ast::Attribute) -> bool {
|
||||
PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(*kind))
|
||||
}
|
||||
|
||||
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() {
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
use crate::proc_macro_server;
|
||||
|
||||
use errors::FatalError;
|
||||
use syntax::source_map::Span;
|
||||
use syntax::ext::base::{self, *};
|
||||
use syntax::tokenstream::TokenStream;
|
||||
|
||||
pub const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
|
||||
proc_macro::bridge::server::SameThread;
|
||||
|
||||
pub struct AttrProcMacro {
|
||||
pub client: proc_macro::bridge::client::Client<
|
||||
fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
|
||||
>,
|
||||
}
|
||||
|
||||
impl base::AttrProcMacro for AttrProcMacro {
|
||||
fn expand<'cx>(&self,
|
||||
ecx: &'cx mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
annotation: TokenStream,
|
||||
annotated: TokenStream)
|
||||
-> TokenStream {
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
let msg = "custom attribute panicked";
|
||||
let mut err = ecx.struct_span_fatal(span, msg);
|
||||
if let Some(s) = e.as_str() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BangProcMacro {
|
||||
pub client: proc_macro::bridge::client::Client<
|
||||
fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
|
||||
>,
|
||||
}
|
||||
|
||||
impl base::ProcMacro for BangProcMacro {
|
||||
fn expand<'cx>(&self,
|
||||
ecx: &'cx mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
input: TokenStream)
|
||||
-> TokenStream {
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
match self.client.run(&EXEC_STRATEGY, server, input) {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
let msg = "proc macro panicked";
|
||||
let mut err = ecx.struct_span_fatal(span, msg);
|
||||
if let Some(s) = e.as_str() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::ast;
|
||||
use crate::ext::base::{self, *};
|
||||
use crate::ext::build::AstBuilder;
|
||||
use crate::parse::{self, token, DirectoryOwnership};
|
||||
use crate::print::pprust;
|
||||
use crate::ptr::P;
|
||||
use crate::symbol::Symbol;
|
||||
use crate::tokenstream;
|
||||
use syntax::{ast, panictry};
|
||||
use syntax::ext::base::{self, *};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::parse::{self, token, DirectoryOwnership};
|
||||
use syntax::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax::tokenstream;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use syntax_pos::{self, Pos, Span};
|
||||
|
|
@ -94,7 +94,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea
|
|||
while self.p.token != token::Eof {
|
||||
match panictry!(self.p.parse_item()) {
|
||||
Some(item) => ret.push(item),
|
||||
None => self.p.diagnostic().span_fatal(self.p.token.span,
|
||||
None => self.p.sess.span_diagnostic.span_fatal(self.p.token.span,
|
||||
&format!("expected item, found `{}`",
|
||||
self.p.this_token_to_string()))
|
||||
.raise()
|
||||
|
|
@ -1,37 +1,22 @@
|
|||
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::{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;
|
||||
|
||||
pub fn injected_crate_name() -> Option<&'static str> {
|
||||
INJECTED_CRATE_NAME.with(|name| name.get())
|
||||
}
|
||||
use std::iter;
|
||||
|
||||
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<Option<&'static str>> = Cell::new(None);
|
||||
}
|
||||
|
||||
pub fn maybe_inject_crates_ref(
|
||||
mut krate: ast::Crate,
|
||||
alt_std_name: Option<&str>,
|
||||
edition: Edition,
|
||||
) -> ast::Crate {
|
||||
pub fn inject(
|
||||
mut krate: ast::Crate, alt_std_name: Option<&str>, edition: Edition
|
||||
) -> (ast::Crate, Option<Symbol>) {
|
||||
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;
|
||||
return (krate, None);
|
||||
} else if attr::contains_name(&krate.attrs, sym::no_std) {
|
||||
if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
|
||||
&["core"]
|
||||
|
|
@ -73,8 +58,6 @@ pub fn maybe_inject_crates_ref(
|
|||
// 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(),
|
||||
|
|
@ -108,5 +91,5 @@ pub fn maybe_inject_crates_ref(
|
|||
tokens: None,
|
||||
}));
|
||||
|
||||
krate
|
||||
(krate, Some(Symbol::intern(name)))
|
||||
}
|
||||
|
|
@ -7,11 +7,44 @@ use syntax::ext::base::*;
|
|||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::ext::hygiene::SyntaxContext;
|
||||
use syntax::print::pprust;
|
||||
use syntax::source_map::respan;
|
||||
use syntax::symbol::{Symbol, sym};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use std::iter;
|
||||
|
||||
// #[test_case] is used by custom test authors to mark tests
|
||||
// When building for test, it needs to make the item public and gensym the name
|
||||
// Otherwise, we'll omit the item. This behavior means that any item annotated
|
||||
// with #[test_case] is never addressable.
|
||||
//
|
||||
// We mark item with an inert attribute "rustc_test_marker" which the test generation
|
||||
// logic will pick up on.
|
||||
pub fn expand_test_case(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
attr_sp: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
anno_item: Annotatable
|
||||
) -> Vec<Annotatable> {
|
||||
check_builtin_macro_attribute(ecx, meta_item, sym::test_case);
|
||||
|
||||
if !ecx.ecfg.should_test { return vec![]; }
|
||||
|
||||
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);
|
||||
item.ident = item.ident.gensym();
|
||||
item.attrs.push(
|
||||
ecx.attribute(sp,
|
||||
ecx.meta_word(sp, sym::rustc_test_marker))
|
||||
);
|
||||
item
|
||||
});
|
||||
|
||||
return vec![Annotatable::Item(item)]
|
||||
}
|
||||
|
||||
pub fn expand_test(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
attr_sp: Span,
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
||||
// #[test_case] is used by custom test authors to mark tests
|
||||
// When building for test, it needs to make the item public and gensym the name
|
||||
// Otherwise, we'll omit the item. This behavior means that any item annotated
|
||||
// with #[test_case] is never addressable.
|
||||
//
|
||||
// We mark item with an inert attribute "rustc_test_marker" which the test generation
|
||||
// logic will pick up on.
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::attr::check_builtin_macro_attribute;
|
||||
use syntax::ext::base::*;
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::ext::hygiene::SyntaxContext;
|
||||
use syntax::source_map::respan;
|
||||
use syntax::symbol::sym;
|
||||
use syntax_pos::Span;
|
||||
|
||||
pub fn expand(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
attr_sp: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
anno_item: Annotatable
|
||||
) -> Vec<Annotatable> {
|
||||
check_builtin_macro_attribute(ecx, meta_item, sym::test_case);
|
||||
|
||||
if !ecx.ecfg.should_test { return vec![]; }
|
||||
|
||||
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);
|
||||
item.ident = item.ident.gensym();
|
||||
item.attrs.push(
|
||||
ecx.attribute(sp,
|
||||
ecx.meta_word(sp, sym::rustc_test_marker))
|
||||
);
|
||||
item
|
||||
});
|
||||
|
||||
return vec![Annotatable::Item(item)]
|
||||
}
|
||||
|
|
@ -1,35 +1,23 @@
|
|||
// Code that generates a test runner to run all the tests in a crate
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use HasTestSignature::*;
|
||||
|
||||
use std::iter;
|
||||
use std::slice;
|
||||
use std::mem;
|
||||
use std::vec;
|
||||
|
||||
use log::debug;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use syntax_pos::{DUMMY_SP, NO_EXPANSION, Span, SourceFile, BytePos};
|
||||
use syntax::ast::{self, Ident};
|
||||
use syntax::attr;
|
||||
use syntax::entry::{self, EntryPointType};
|
||||
use syntax::ext::base::{ExtCtxt, Resolver};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::ext::expand::ExpansionConfig;
|
||||
use syntax::ext::hygiene::{ExpnId, MacroKind};
|
||||
use syntax::feature_gate::Features;
|
||||
use syntax::mut_visit::{*, ExpectOne};
|
||||
use syntax::parse::ParseSess;
|
||||
use syntax::ptr::P;
|
||||
use syntax::source_map::{ExpnInfo, ExpnKind, dummy_spanned};
|
||||
use syntax::symbol::{kw, sym, Symbol};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
use crate::attr::{self, HasAttrs};
|
||||
use crate::source_map::{self, SourceMap, ExpnInfo, ExpnKind, dummy_spanned, respan};
|
||||
use crate::config;
|
||||
use crate::entry::{self, EntryPointType};
|
||||
use crate::ext::base::{ExtCtxt, Resolver};
|
||||
use crate::ext::build::AstBuilder;
|
||||
use crate::ext::expand::ExpansionConfig;
|
||||
use crate::ext::hygiene::{self, ExpnId, SyntaxContext, MacroKind};
|
||||
use crate::mut_visit::{*, ExpectOne};
|
||||
use crate::feature_gate::Features;
|
||||
use crate::util::map_in_place::MapInPlace;
|
||||
use crate::parse::{token, ParseSess};
|
||||
use crate::ast::{self, Ident};
|
||||
use crate::ptr::P;
|
||||
use crate::symbol::{self, Symbol, kw, sym};
|
||||
use crate::ThinVec;
|
||||
use std::{iter, mem};
|
||||
|
||||
struct Test {
|
||||
span: Span,
|
||||
|
|
@ -42,22 +30,21 @@ struct TestCtxt<'a> {
|
|||
ext_cx: ExtCtxt<'a>,
|
||||
test_cases: Vec<Test>,
|
||||
reexport_test_harness_main: Option<Symbol>,
|
||||
is_libtest: bool,
|
||||
features: &'a Features,
|
||||
test_runner: Option<ast::Path>,
|
||||
|
||||
// top-level re-export submodule, filled out after folding is finished
|
||||
toplevel_reexport: Option<Ident>,
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -267,11 +254,7 @@ fn generate_test_harness(sess: &ParseSess,
|
|||
path: Vec::new(),
|
||||
test_cases: Vec::new(),
|
||||
reexport_test_harness_main,
|
||||
// N.B., doesn't consider the value of `--crate-name` passed on the command line.
|
||||
is_libtest: attr::find_crate_name(&krate.attrs)
|
||||
.map(|s| s == sym::test).unwrap_or(false),
|
||||
toplevel_reexport: None,
|
||||
features,
|
||||
test_runner
|
||||
};
|
||||
|
||||
|
|
@ -282,19 +265,6 @@ fn generate_test_harness(sess: &ParseSess,
|
|||
}.visit_crate(krate);
|
||||
}
|
||||
|
||||
enum HasTestSignature {
|
||||
Yes,
|
||||
No(BadTestSignature),
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum BadTestSignature {
|
||||
NotEvenAFunction,
|
||||
WrongTypeSignature,
|
||||
NoArgumentsAllowed,
|
||||
ShouldPanicOnlyWithNoArgs,
|
||||
}
|
||||
|
||||
/// Creates a function item for use as the main function of a test build.
|
||||
/// This function will call the `test_runner` as specified by the crate attribute
|
||||
fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
|
||||
Loading…
Add table
Add a link
Reference in a new issue