Move proc macro server into libsyntax

This commit is contained in:
Vadim Petrochenkov 2019-07-18 21:02:34 +03:00
parent 3eeec1c5d2
commit 4ad0daa220
15 changed files with 271 additions and 343 deletions

View File

@ -3008,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",
]

View File

@ -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" }

View File

@ -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,

View File

@ -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;

View File

@ -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));
}
});
}

View File

@ -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};

View File

@ -1,7 +1,249 @@
use crate::ast::Attribute;
use crate::symbol::sym;
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.mark, 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));
}
});
}

View File

@ -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),

View File

@ -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;
@ -162,13 +167,14 @@ 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 proc_macro;
pub mod tt {

View File

@ -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
}
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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;

View File

@ -8,9 +8,6 @@
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(nll)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_span)]
#![feature(rustc_diagnostic_macros)]
#![feature(unicode_internals)]
@ -32,22 +29,20 @@ 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 fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, edition: Edition) {
let mut register = |name, kind| resolver.register_builtin_macro(

View File

@ -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();
}
}
}
}