Rollup merge of #61606 - petrochenkov:legclean, r=pnkfelix

Remove some legacy proc macro flavors

Namely
- `IdentTT` (`foo! ident { ... }`). Can be replaced with `foo! { ident ... }` or something similar.
- `MultiDecorator`. Can be replaced by `MultiModifier` (aka `LegacyAttr` after renaming).
- `DeclMacro`. It was a less powerful duplicate of `NormalTT` (aka `LegacyBang` after renaming) and can be replaced by it.

Stuff like this slows down any attempts to refactor the expansion infra, so it's desirable to retire it already.
I'm not sure whether a lang team decision is necessary, but would be nice to land this sooner because I have some further work in this area scheduled.

The documentation commit (a9397fd0d5) describes how the remaining variants are different from each other and shows that there's actually some system behind them.

The last commit renames variants of `SyntaxExtension` in more systematic way.
- `ProcMacro` -> `Bang`
- `NormalTT` -> `LegacyBang`
- `AttrProcMacro` -> `Attr`
- `MultiModifier` -> `LegacyAttr`
- `ProcMacroDerive` -> `Derive`
- `BuiltinDerive` -> `LegacyDerive`

All the `Legacy*` variants are AST-based, as opposed to "modern" token-based variants.
This commit is contained in:
Mazdak Farrokhzad 2019-06-11 17:13:59 +02:00 committed by GitHub
commit b4419a8b05
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 225 additions and 696 deletions

View file

@ -614,7 +614,7 @@ impl<'a> CrateLoader<'a> {
match decl {
ProcMacro::CustomDerive { trait_name, attributes, client } => {
let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
(trait_name, SyntaxExtension::ProcMacroDerive(
(trait_name, SyntaxExtension::Derive(
Box::new(ProcMacroDerive {
client,
attrs: attrs.clone(),
@ -624,13 +624,13 @@ impl<'a> CrateLoader<'a> {
))
}
ProcMacro::Attr { name, client } => {
(name, SyntaxExtension::AttrProcMacro(
(name, SyntaxExtension::Attr(
Box::new(AttrProcMacro { client }),
root.edition,
))
}
ProcMacro::Bang { name, client } => {
(name, SyntaxExtension::ProcMacro {
(name, SyntaxExtension::Bang {
expander: Box::new(BangProcMacro { client }),
allow_internal_unstable: None,
edition: root.edition,

View file

@ -430,7 +430,7 @@ impl cstore::CStore {
use syntax_ext::proc_macro_impl::BangProcMacro;
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
let ext = SyntaxExtension::ProcMacro {
let ext = SyntaxExtension::Bang {
expander: Box::new(BangProcMacro { client }),
allow_internal_unstable: Some(vec![sym::proc_macro_def_site].into()),
edition: data.root.edition,

View file

@ -4,8 +4,9 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
use rustc::session::Session;
use rustc::util::nodemap::FxHashMap;
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT};
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension};
use syntax::ext::base::MacroExpanderFn;
use syntax::ext::hygiene::Transparency;
use syntax::symbol::{Symbol, sym};
use syntax::ast;
use syntax::feature_gate::AttributeType;
@ -84,47 +85,26 @@ impl<'a> Registry<'a> {
/// Register a syntax extension of any kind.
///
/// This is the most general hook into `libsyntax`'s expansion behavior.
pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) {
pub fn register_syntax_extension(&mut self, name: ast::Name, mut extension: SyntaxExtension) {
if name == sym::macro_rules {
panic!("user-defined macros may not be named `macro_rules`");
}
self.syntax_exts.push((name, match extension {
NormalTT {
expander,
def_info: _,
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
edition,
} => {
let nid = ast::CRATE_NODE_ID;
NormalTT {
expander,
def_info: Some((nid, self.krate_span)),
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
edition,
}
}
IdentTT { expander, span: _, allow_internal_unstable } => {
IdentTT { expander, span: Some(self.krate_span), allow_internal_unstable }
}
_ => extension,
}));
if let SyntaxExtension::LegacyBang { def_info: ref mut def_info @ None, .. } = extension {
*def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
}
self.syntax_exts.push((name, extension));
}
/// Register a macro of the usual kind.
///
/// This is a convenience wrapper for `register_syntax_extension`.
/// It builds for you a `NormalTT` that calls `expander`,
/// It builds for you a `SyntaxExtension::LegacyBang` that calls `expander`,
/// and also takes care of interning the macro's name.
pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) {
self.register_syntax_extension(Symbol::intern(name), NormalTT {
self.register_syntax_extension(Symbol::intern(name), SyntaxExtension::LegacyBang {
expander: Box::new(expander),
def_info: None,
transparency: Transparency::SemiTransparent,
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,

View file

@ -242,8 +242,7 @@ impl<'a> base::Resolver for Resolver<'a> {
fn check_unused_macros(&self) {
for did in self.unused_macros.iter() {
let id_span = match *self.macro_map[did] {
SyntaxExtension::NormalTT { def_info, .. } |
SyntaxExtension::DeclMacro { def_info, .. } => def_info,
SyntaxExtension::LegacyBang { def_info, .. } => def_info,
_ => None,
};
if let Some((id, span)) = id_span {
@ -587,7 +586,7 @@ impl<'a> Resolver<'a> {
match self.resolve_macro_to_res(derive, MacroKind::Derive,
&parent_scope, true, force) {
Ok((_, ext)) => {
if let SyntaxExtension::ProcMacroDerive(_, helpers, _) = &*ext {
if let SyntaxExtension::Derive(_, helpers, _) = &*ext {
if helpers.contains(&ident.name) {
let binding =
(Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),

View file

@ -471,7 +471,7 @@ fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemE
}
LoadedMacro::ProcMacro(ext) => {
let helpers = match &*ext {
&SyntaxExtension::ProcMacroDerive(_, ref syms, ..) => { syms.clean(cx) }
&SyntaxExtension::Derive(_, ref syms, ..) => { syms.clean(cx) }
_ => Vec::new(),
};

View file

@ -433,7 +433,7 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
if let Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) = res {
// skip proc-macro stubs, they'll cause `get_macro` to crash
} else {
if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(res) {
if let SyntaxExtension::LegacyBang { .. } = *resolver.get_macro(res) {
return Some(res.map_id(|_| panic!("unexpected id")));
}
}

View file

@ -1,6 +1,4 @@
pub use SyntaxExtension::*;
use crate::ast::{self, Attribute, Name, PatKind, MetaItem};
use crate::ast::{self, Attribute, Name, PatKind};
use crate::attr::HasAttrs;
use crate::source_map::{SourceMap, Spanned, respan};
use crate::edition::Edition;
@ -137,29 +135,6 @@ impl Annotatable {
}
}
// A more flexible ItemDecorator.
pub trait MultiItemDecorator {
fn expand(&self,
ecx: &mut ExtCtxt<'_>,
sp: Span,
meta_item: &ast::MetaItem,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable));
}
impl<F> MultiItemDecorator for F
where F : Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, &Annotatable, &mut dyn FnMut(Annotatable))
{
fn expand(&self,
ecx: &mut ExtCtxt<'_>,
sp: Span,
meta_item: &ast::MetaItem,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable)) {
(*self)(ecx, sp, meta_item, item, push)
}
}
// `meta_item` is the annotation, and `item` is the item being modified.
// FIXME Decorators should follow the same pattern too.
pub trait MultiItemModifier {
@ -288,34 +263,6 @@ impl<F> TTMacroExpander for F
}
}
pub trait IdentMacroExpander {
fn expand<'cx>(&self,
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
ident: ast::Ident,
token_tree: Vec<tokenstream::TokenTree>)
-> Box<dyn MacResult+'cx>;
}
pub type IdentMacroExpanderFn =
for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, ast::Ident, Vec<tokenstream::TokenTree>)
-> Box<dyn MacResult+'cx>;
impl<F> IdentMacroExpander for F
where F : for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, ast::Ident,
Vec<tokenstream::TokenTree>) -> Box<dyn MacResult+'cx>
{
fn expand<'cx>(&self,
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
ident: ast::Ident,
token_tree: Vec<tokenstream::TokenTree>)
-> Box<dyn MacResult+'cx>
{
(*self)(cx, sp, ident, token_tree)
}
}
// Use a macro because forwarding to a simple function has type system issues
macro_rules! make_stmts_default {
($me:expr) => {
@ -570,9 +517,6 @@ impl MacResult for DummyResult {
}
}
pub type BuiltinDeriveFn =
for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable));
/// Represents different kinds of macro invocations that can be resolved.
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum MacroKind {
@ -606,129 +550,116 @@ impl MacroKind {
/// An enum representing the different kinds of syntax extensions.
pub enum SyntaxExtension {
/// A trivial "extension" that does nothing, only keeps the attribute and marks it as known.
NonMacroAttr { mark_used: bool },
/// A syntax extension that is attached to an item and creates new items
/// based upon it.
///
/// `#[derive(...)]` is a `MultiItemDecorator`.
///
/// Prefer ProcMacro or MultiModifier since they are more flexible.
MultiDecorator(Box<dyn MultiItemDecorator + sync::Sync + sync::Send>),
/// A syntax extension that is attached to an item and modifies it
/// in-place. Also allows decoration, i.e., creating new items.
MultiModifier(Box<dyn MultiItemModifier + sync::Sync + sync::Send>),
/// A function-like procedural macro. TokenStream -> TokenStream.
ProcMacro {
/// A token-based function-like macro.
Bang {
/// An expander with signature TokenStream -> TokenStream.
expander: Box<dyn ProcMacro + sync::Sync + sync::Send>,
/// Whitelist of unstable features that are treated as stable inside this macro
/// Whitelist of unstable features that are treated as stable inside this macro.
allow_internal_unstable: Option<Lrc<[Symbol]>>,
/// Edition of the crate in which this macro is defined.
edition: Edition,
},
/// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream.
/// The first TokenSteam is the attribute, the second is the annotated item.
/// Allows modification of the input items and adding new items, similar to
/// MultiModifier, but uses TokenStreams, rather than AST nodes.
AttrProcMacro(Box<dyn AttrProcMacro + sync::Sync + sync::Send>, Edition),
/// A normal, function-like syntax extension.
///
/// `bytes!` is a `NormalTT`.
NormalTT {
/// An AST-based function-like macro.
LegacyBang {
/// An expander with signature TokenStream -> AST.
expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
/// Some info about the macro's definition point.
def_info: Option<(ast::NodeId, Span)>,
/// Whether the contents of the macro can
/// directly use `#[unstable]` things.
///
/// Only allows things that require a feature gate in the given whitelist
/// Hygienic properties of identifiers produced by this macro.
transparency: Transparency,
/// Whitelist of unstable features that are treated as stable inside this macro.
allow_internal_unstable: Option<Lrc<[Symbol]>>,
/// Whether the contents of the macro can use `unsafe`
/// without triggering the `unsafe_code` lint.
/// Suppresses the `unsafe_code` lint for code produced by this macro.
allow_internal_unsafe: bool,
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
/// for a given macro.
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
local_inner_macros: bool,
/// The macro's feature name if it is unstable, and the stability feature
/// The macro's feature name and tracking issue number if it is unstable.
unstable_feature: Option<(Symbol, u32)>,
/// Edition of the crate in which the macro is defined
/// Edition of the crate in which this macro is defined.
edition: Edition,
},
/// A function-like syntax extension that has an extra ident before
/// the block.
IdentTT {
expander: Box<dyn IdentMacroExpander + sync::Sync + sync::Send>,
span: Option<Span>,
allow_internal_unstable: Option<Lrc<[Symbol]>>,
/// A token-based attribute macro.
Attr(
/// An expander with signature (TokenStream, TokenStream) -> TokenStream.
/// The first TokenSteam is the attribute itself, the second is the annotated item.
/// The produced TokenSteam replaces the input TokenSteam.
Box<dyn AttrProcMacro + sync::Sync + sync::Send>,
/// Edition of the crate in which this macro is defined.
Edition,
),
/// An AST-based attribute macro.
LegacyAttr(
/// An expander with signature (AST, AST) -> AST.
/// The first AST fragment is the attribute itself, the second is the annotated item.
/// The produced AST fragment replaces the input AST fragment.
Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
),
/// A trivial attribute "macro" that does nothing,
/// only keeps the attribute and marks it as known.
NonMacroAttr {
/// Suppresses the `unused_attributes` lint for this attribute.
mark_used: bool,
},
/// An attribute-like procedural macro. TokenStream -> TokenStream.
/// The input is the annotated item.
/// Allows generating code to implement a Trait for a given struct
/// or enum item.
ProcMacroDerive(Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
Vec<Symbol> /* inert attribute names */, Edition),
/// A token-based derive macro.
Derive(
/// An expander with signature TokenStream -> TokenStream (not yet).
/// The produced TokenSteam is appended to the input TokenSteam.
Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
/// Names of helper attributes registered by this macro.
Vec<Symbol>,
/// Edition of the crate in which this macro is defined.
Edition,
),
/// An attribute-like procedural macro that derives a builtin trait.
BuiltinDerive(BuiltinDeriveFn),
/// A declarative macro, e.g., `macro m() {}`.
DeclMacro {
expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
def_info: Option<(ast::NodeId, Span)>,
is_transparent: bool,
edition: Edition,
}
/// An AST-based derive macro.
LegacyDerive(
/// An expander with signature AST -> AST.
/// The produced AST fragment is appended to the input AST fragment.
Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
),
}
impl SyntaxExtension {
/// Returns which kind of macro calls this syntax extension.
pub fn kind(&self) -> MacroKind {
match *self {
SyntaxExtension::DeclMacro { .. } |
SyntaxExtension::NormalTT { .. } |
SyntaxExtension::IdentTT { .. } |
SyntaxExtension::ProcMacro { .. } =>
MacroKind::Bang,
SyntaxExtension::NonMacroAttr { .. } |
SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) |
SyntaxExtension::AttrProcMacro(..) =>
MacroKind::Attr,
SyntaxExtension::ProcMacroDerive(..) |
SyntaxExtension::BuiltinDerive(..) =>
MacroKind::Derive,
SyntaxExtension::Bang { .. } |
SyntaxExtension::LegacyBang { .. } => MacroKind::Bang,
SyntaxExtension::Attr(..) |
SyntaxExtension::LegacyAttr(..) |
SyntaxExtension::NonMacroAttr { .. } => MacroKind::Attr,
SyntaxExtension::Derive(..) |
SyntaxExtension::LegacyDerive(..) => MacroKind::Derive,
}
}
pub fn default_transparency(&self) -> Transparency {
match *self {
SyntaxExtension::ProcMacro { .. } |
SyntaxExtension::AttrProcMacro(..) |
SyntaxExtension::ProcMacroDerive(..) |
SyntaxExtension::DeclMacro { is_transparent: false, .. } => Transparency::Opaque,
SyntaxExtension::DeclMacro { is_transparent: true, .. } => Transparency::Transparent,
_ => Transparency::SemiTransparent,
SyntaxExtension::LegacyBang { transparency, .. } => transparency,
SyntaxExtension::Bang { .. } |
SyntaxExtension::Attr(..) |
SyntaxExtension::Derive(..) |
SyntaxExtension::NonMacroAttr { .. } => Transparency::Opaque,
SyntaxExtension::LegacyAttr(..) |
SyntaxExtension::LegacyDerive(..) => Transparency::SemiTransparent,
}
}
pub fn edition(&self, default_edition: Edition) -> Edition {
match *self {
SyntaxExtension::NormalTT { edition, .. } |
SyntaxExtension::DeclMacro { edition, .. } |
SyntaxExtension::ProcMacro { edition, .. } |
SyntaxExtension::AttrProcMacro(.., edition) |
SyntaxExtension::ProcMacroDerive(.., edition) => edition,
SyntaxExtension::Bang { edition, .. } |
SyntaxExtension::LegacyBang { edition, .. } |
SyntaxExtension::Attr(.., edition) |
SyntaxExtension::Derive(.., edition) => edition,
// Unstable legacy stuff
SyntaxExtension::NonMacroAttr { .. } |
SyntaxExtension::IdentTT { .. } |
SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) |
SyntaxExtension::BuiltinDerive(..) => default_edition,
SyntaxExtension::LegacyAttr(..) |
SyntaxExtension::LegacyDerive(..) => default_edition,
}
}
}

View file

@ -389,7 +389,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let item = match self.cx.resolver.resolve_macro_path(
path, MacroKind::Derive, Mark::root(), Vec::new(), false) {
Ok(ext) => match *ext {
BuiltinDerive(..) => item_with_markers.clone(),
SyntaxExtension::LegacyDerive(..) => item_with_markers.clone(),
_ => item.clone(),
},
_ => item.clone(),
@ -548,7 +548,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
_ => unreachable!(),
};
if let NonMacroAttr { mark_used: false } = *ext {} else {
if let SyntaxExtension::NonMacroAttr { mark_used: false } = *ext {} else {
// Macro attrs are always used when expanded,
// non-macro attrs are considered used when the field says so.
attr::mark_used(&attr);
@ -564,26 +564,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
});
match *ext {
NonMacroAttr { .. } => {
SyntaxExtension::NonMacroAttr { .. } => {
attr::mark_known(&attr);
item.visit_attrs(|attrs| attrs.push(attr));
Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
}
MultiModifier(ref mac) => {
SyntaxExtension::LegacyAttr(ref mac) => {
let meta = attr.parse_meta(self.cx.parse_sess)
.map_err(|mut e| { e.emit(); }).ok()?;
let item = mac.expand(self.cx, attr.span, &meta, item);
Some(invoc.fragment_kind.expect_from_annotatables(item))
}
MultiDecorator(ref mac) => {
let mut items = Vec::new();
let meta = attr.parse_meta(self.cx.parse_sess)
.expect("derive meta should already have been parsed");
mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item));
items.push(item);
Some(invoc.fragment_kind.expect_from_annotatables(items))
}
AttrProcMacro(ref mac, ..) => {
SyntaxExtension::Attr(ref mac, ..) => {
self.gate_proc_macro_attr_item(attr.span, &item);
let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item {
Annotatable::Item(item) => token::NtItem(item),
@ -600,7 +592,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
self.gate_proc_macro_expansion(attr.span, &res);
res
}
ProcMacroDerive(..) | BuiltinDerive(..) => {
SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => {
self.cx.span_err(attr.span, &format!("`{}` is a derive macro", attr.path));
self.cx.trace_macros_diag();
invoc.fragment_kind.dummy(attr.span)
@ -755,17 +747,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
};
let opt_expanded = match *ext {
DeclMacro { ref expander, def_info, edition, .. } => {
if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
None, false, false, None,
edition) {
dummy_span
} else {
kind.make_from(expander.expand(self.cx, span, mac.node.stream(), None))
}
}
NormalTT {
SyntaxExtension::LegacyBang {
ref expander,
def_info,
ref allow_internal_unstable,
@ -773,6 +755,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
local_inner_macros,
unstable_feature,
edition,
..
} => {
if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
allow_internal_unstable.clone(),
@ -791,43 +774,22 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
}
IdentTT { ref expander, span: tt_span, ref allow_internal_unstable } => {
if ident.name == kw::Invalid {
self.cx.span_err(path.span,
&format!("macro {}! expects an ident argument", path));
self.cx.trace_macros_diag();
kind.dummy(span)
} else {
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
call_site: span,
def_site: tt_span,
format: macro_bang_format(path),
allow_internal_unstable: allow_internal_unstable.clone(),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: self.cx.parse_sess.edition,
});
let input: Vec<_> = mac.node.stream().into_trees().collect();
kind.make_from(expander.expand(self.cx, span, ident, input))
}
}
MultiDecorator(..) | MultiModifier(..) |
AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => {
SyntaxExtension::Attr(..) |
SyntaxExtension::LegacyAttr(..) |
SyntaxExtension::NonMacroAttr { .. } => {
self.cx.span_err(path.span,
&format!("`{}` can only be used in attributes", path));
self.cx.trace_macros_diag();
kind.dummy(span)
}
ProcMacroDerive(..) | BuiltinDerive(..) => {
SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => {
self.cx.span_err(path.span, &format!("`{}` is a derive macro", path));
self.cx.trace_macros_diag();
kind.dummy(span)
}
SyntaxExtension::ProcMacro { ref expander, ref allow_internal_unstable, edition } => {
SyntaxExtension::Bang { ref expander, ref allow_internal_unstable, edition } => {
if ident.name != kw::Invalid {
let msg =
format!("macro {}! expects no ident argument, given '{}'", path, ident);
@ -924,29 +886,29 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
edition: ext.edition(self.cx.parse_sess.edition),
};
match *ext {
ProcMacroDerive(ref ext, ..) => {
invoc.expansion_data.mark.set_expn_info(expn_info);
let span = span.with_ctxt(self.cx.backtrace());
let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
path: Path::from_ident(Ident::invalid()),
span: DUMMY_SP,
node: ast::MetaItemKind::Word,
match ext {
SyntaxExtension::Derive(expander, ..) | SyntaxExtension::LegacyDerive(expander) => {
let meta = match ext {
SyntaxExtension::Derive(..) => ast::MetaItem { // FIXME(jseyfried) avoid this
path: Path::from_ident(Ident::invalid()),
span: DUMMY_SP,
node: ast::MetaItemKind::Word,
},
_ => {
expn_info.allow_internal_unstable = Some(vec![
sym::rustc_attrs,
Symbol::intern("derive_clone_copy"),
Symbol::intern("derive_eq"),
// RustcDeserialize and RustcSerialize
Symbol::intern("libstd_sys_internals"),
].into());
attr.meta()?
}
};
let items = ext.expand(self.cx, span, &dummy, item);
Some(invoc.fragment_kind.expect_from_annotatables(items))
}
BuiltinDerive(func) => {
expn_info.allow_internal_unstable = Some(vec![
sym::rustc_attrs,
Symbol::intern("derive_clone_copy"),
Symbol::intern("derive_eq"),
Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
].into());
invoc.expansion_data.mark.set_expn_info(expn_info);
let span = span.with_ctxt(self.cx.backtrace());
let mut items = Vec::new();
func(self.cx, span, &attr.meta()?, &item, &mut |a| items.push(a));
let items = expander.expand(self.cx, span, &meta, item);
Some(invoc.fragment_kind.expect_from_annotatables(items))
}
_ => {

View file

@ -1,8 +1,8 @@
use crate::{ast, attr};
use crate::edition::Edition;
use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
use crate::ext::base::{NormalTT, TTMacroExpander};
use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension, TTMacroExpander};
use crate::ext::expand::{AstFragment, AstFragmentKind};
use crate::ext::hygiene::Transparency;
use crate::ext::tt::macro_parser::{Success, Error, Failure};
use crate::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use crate::ext::tt::macro_parser::{parse, parse_failure_msg};
@ -374,66 +374,66 @@ pub fn compile(
valid,
});
if body.legacy {
let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable)
.map(|attr| attr
.meta_item_list()
.map(|list| list.iter()
.filter_map(|it| {
let name = it.ident().map(|ident| ident.name);
if name.is_none() {
sess.span_diagnostic.span_err(it.span(),
"allow internal unstable expects feature names")
}
name
})
.collect::<Vec<Symbol>>().into()
)
.unwrap_or_else(|| {
sess.span_diagnostic.span_warn(
attr.span, "allow_internal_unstable expects list of feature names. In the \
future this will become a hard error. Please use `allow_internal_unstable(\
foo, bar)` to only allow the `foo` and `bar` features",
);
vec![sym::allow_internal_unstable_backcompat_hack].into()
})
);
let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe);
let mut local_inner_macros = false;
if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) {
if let Some(l) = macro_export.meta_item_list() {
local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
}
}
let unstable_feature = attr::find_stability(&sess,
&def.attrs, def.span).and_then(|stability| {
if let attr::StabilityLevel::Unstable { issue, .. } = stability.level {
Some((stability.feature, issue))
} else {
None
}
});
NormalTT {
expander,
def_info: Some((def.id, def.span)),
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
edition,
}
let transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) {
Transparency::Transparent
} else if body.legacy {
Transparency::SemiTransparent
} else {
let is_transparent = attr::contains_name(&def.attrs, sym::rustc_transparent_macro);
Transparency::Opaque
};
SyntaxExtension::DeclMacro {
expander,
def_info: Some((def.id, def.span)),
is_transparent,
edition,
let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable)
.map(|attr| attr
.meta_item_list()
.map(|list| list.iter()
.filter_map(|it| {
let name = it.ident().map(|ident| ident.name);
if name.is_none() {
sess.span_diagnostic.span_err(it.span(),
"allow internal unstable expects feature names")
}
name
})
.collect::<Vec<Symbol>>().into()
)
.unwrap_or_else(|| {
sess.span_diagnostic.span_warn(
attr.span, "allow_internal_unstable expects list of feature names. In the \
future this will become a hard error. Please use `allow_internal_unstable(\
foo, bar)` to only allow the `foo` and `bar` features",
);
vec![sym::allow_internal_unstable_backcompat_hack].into()
})
);
let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe);
let mut local_inner_macros = false;
if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) {
if let Some(l) = macro_export.meta_item_list() {
local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
}
}
let unstable_feature = attr::find_stability(&sess,
&def.attrs, def.span).and_then(|stability| {
if let attr::StabilityLevel::Unstable { issue, .. } = stability.level {
Some((stability.feature, issue))
} else {
None
}
});
SyntaxExtension::LegacyBang {
expander,
def_info: Some((def.id, def.span)),
transparency,
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
edition,
}
}
fn check_lhs_nt_follows(sess: &ParseSess,

View file

@ -1,8 +1,8 @@
//! The compiler code necessary to implement the `#[derive]` extensions.
use rustc_data_structures::sync::Lrc;
use syntax::ast;
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver};
use syntax::ast::{self, MetaItem};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver, MultiItemModifier};
use syntax::ext::build::AstBuilder;
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::ptr::P;
@ -39,9 +39,25 @@ pub mod partial_ord;
#[path="cmp/ord.rs"]
pub mod ord;
pub mod generic;
struct BuiltinDerive(
fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable))
);
impl MultiItemModifier for BuiltinDerive {
fn expand(&self,
ecx: &mut ExtCtxt<'_>,
span: Span,
meta_item: &MetaItem,
item: Annotatable)
-> Vec<Annotatable> {
let mut items = Vec::new();
(self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
items
}
}
macro_rules! derive_traits {
($( $name:expr => $func:path, )+) => {
pub fn is_builtin_trait(name: ast::Name) -> bool {
@ -55,7 +71,7 @@ macro_rules! derive_traits {
$(
resolver.add_builtin(
ast::Ident::with_empty_ctxt(Symbol::intern($name)),
Lrc::new(SyntaxExtension::BuiltinDerive($func))
Lrc::new(SyntaxExtension::LegacyDerive(Box::new(BuiltinDerive($func))))
);
)*
}

View file

@ -41,7 +41,9 @@ pub mod proc_macro_impl;
use rustc_data_structures::sync::Lrc;
use syntax::ast;
use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension, MultiModifier};
use syntax::ext::base::{MacroExpanderFn, NamedSyntaxExtension, SyntaxExtension};
use syntax::ext::hygiene::Transparency;
use syntax::edition::Edition;
use syntax::symbol::{sym, Symbol};
@ -56,9 +58,10 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
macro_rules! register {
($( $name:ident: $f:expr, )*) => { $(
register(Symbol::intern(stringify!($name)),
NormalTT {
SyntaxExtension::LegacyBang {
expander: Box::new($f as MacroExpanderFn),
def_info: None,
transparency: Transparency::SemiTransparent,
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,
@ -93,15 +96,16 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
assert: assert::expand_assert,
}
register(sym::test_case, MultiModifier(Box::new(test_case::expand)));
register(sym::test, MultiModifier(Box::new(test::expand_test)));
register(sym::bench, MultiModifier(Box::new(test::expand_bench)));
register(sym::test_case, SyntaxExtension::LegacyAttr(Box::new(test_case::expand)));
register(sym::test, SyntaxExtension::LegacyAttr(Box::new(test::expand_test)));
register(sym::bench, SyntaxExtension::LegacyAttr(Box::new(test::expand_bench)));
// format_args uses `unstable` things internally.
register(Symbol::intern("format_args"),
NormalTT {
SyntaxExtension::LegacyBang {
expander: Box::new(format::expand_format_args),
def_info: None,
transparency: Transparency::SemiTransparent,
allow_internal_unstable: Some(vec![sym::fmt_internals].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
@ -109,9 +113,10 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
edition,
});
register(sym::format_args_nl,
NormalTT {
SyntaxExtension::LegacyBang {
expander: Box::new(format::expand_format_args_nl),
def_info: None,
transparency: Transparency::SemiTransparent,
allow_internal_unstable: Some(vec![sym::fmt_internals].into()),
allow_internal_unsafe: false,
local_inner_macros: false,

View file

@ -1,71 +0,0 @@
// force-host
#![feature(plugin_registrar, rustc_private)]
extern crate syntax;
extern crate syntax_ext;
extern crate rustc_plugin;
use syntax_ext::deriving;
use deriving::generic::*;
use deriving::generic::ty::*;
use rustc_plugin::Registry;
use syntax::ast::*;
use syntax::source_map::Span;
use syntax::ext::base::*;
use syntax::ext::build::AstBuilder;
use syntax::symbol::Symbol;
use syntax::ptr::P;
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_syntax_extension(Symbol::intern("derive_CustomPartialEq"),
MultiDecorator(Box::new(expand_deriving_partial_eq)));
}
fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable,
push: &mut FnMut(Annotatable)) {
// structures are equal if all fields are equal, and non equal, if
// any fields are not equal or if the enum variants are different
fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
cs_fold(true,
|cx, span, subexpr, self_f, other_fs| {
let other_f = (other_fs.len(), other_fs.get(0)).1.unwrap();
let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone());
cx.expr_binary(span, BinOpKind::And, subexpr, eq)
},
cx.expr_bool(span, true),
Box::new(|cx, span, _, _| cx.expr_bool(span, false)),
cx,
span,
substr)
}
let inline = cx.meta_word(span, Symbol::intern("inline"));
let attrs = vec![cx.attribute(span, inline)];
let methods = vec![MethodDef {
name: "eq",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![(borrowed_self(), "other")],
ret_ty: Literal(deriving::generic::ty::Path::new_local("bool")),
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(cs_eq)),
}];
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
path: deriving::generic::ty::Path::new(vec!["cmp", "PartialEq"]),
additional_bounds: Vec::new(),
generics: LifetimeBounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: methods,
associated_types: Vec::new(),
};
trait_def.expand(cx, mitem, item, push)
}

View file

@ -1,84 +0,0 @@
// force-host
#![feature(plugin_registrar)]
#![feature(box_syntax)]
#![feature(rustc_private)]
extern crate syntax;
extern crate syntax_ext;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
use syntax::ast;
use syntax::attr;
use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::symbol::{Symbol, sym};
use syntax::ptr::P;
use syntax_ext::deriving::generic::{TraitDef, MethodDef, combine_substructure};
use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching};
use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
use syntax_pos::Span;
use rustc_plugin::Registry;
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_syntax_extension(
Symbol::intern("rustc_derive_TotalSum"),
MultiDecorator(box expand));
}
fn expand(cx: &mut ExtCtxt,
span: Span,
mitem: &ast::MetaItem,
item: &Annotatable,
push: &mut FnMut(Annotatable)) {
let trait_def = TraitDef {
span: span,
attributes: vec![],
path: Path::new_local("TotalSum"),
additional_bounds: vec![],
generics: LifetimeBounds::empty(),
associated_types: vec![],
is_unsafe: false,
supports_unions: false,
methods: vec![
MethodDef {
name: "total_sum",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![],
ret_ty: Literal(Path::new_local("isize")),
attributes: vec![],
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(totalsum_substructure)),
},
],
};
trait_def.expand(cx, mitem, item, push)
}
// Mostly copied from syntax::ext::deriving::hash
/// Defines how the implementation for `trace()` is to be generated
fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span,
substr: &Substructure) -> P<ast::Expr> {
let fields = match *substr.fields {
Struct(_, ref fs) | EnumMatching(.., ref fs) => fs,
_ => cx.span_bug(trait_span, "impossible substructure")
};
fields.iter().fold(cx.expr_isize(trait_span, 0), |acc, ref item| {
if attr::contains_name(&item.attrs, sym::ignore) {
acc
} else {
cx.expr_binary(item.span, ast::BinOpKind::Add, acc,
cx.expr_method_call(item.span,
item.self_.clone(),
substr.method_ident,
Vec::new()))
}
})
}

View file

@ -1,76 +0,0 @@
// force-host
#![feature(plugin_registrar)]
#![feature(box_syntax)]
#![feature(rustc_private)]
extern crate syntax;
extern crate syntax_ext;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
use syntax::ast;
use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::symbol::Symbol;
use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure};
use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
use syntax_pos::Span;
use rustc_plugin::Registry;
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_syntax_extension(
Symbol::intern("derive_TotalSum"),
MultiDecorator(box expand));
reg.register_syntax_extension(
Symbol::intern("derive_Nothing"),
MultiDecorator(box noop));
}
fn noop(_: &mut ExtCtxt, _: Span, _: &ast::MetaItem, _: &Annotatable, _: &mut FnMut(Annotatable)) {}
fn expand(cx: &mut ExtCtxt,
span: Span,
mitem: &ast::MetaItem,
item: &Annotatable,
push: &mut FnMut(Annotatable)) {
let trait_def = TraitDef {
span: span,
attributes: vec![],
path: Path::new_local("TotalSum"),
additional_bounds: vec![],
generics: LifetimeBounds::empty(),
associated_types: vec![],
is_unsafe: false,
supports_unions: false,
methods: vec![
MethodDef {
name: "total_sum",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![],
ret_ty: Literal(Path::new_local("isize")),
attributes: vec![],
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(box |cx, span, substr| {
let zero = cx.expr_isize(span, 0);
cs_fold(false,
|cx, span, subexpr, field, _| {
cx.expr_binary(span, ast::BinOpKind::Add, subexpr,
cx.expr_method_call(span, field,
ast::Ident::from_str("total_sum"), vec![]))
},
zero,
box |cx, span, _, _| { cx.span_bug(span, "wtf??"); },
cx, span, substr)
}),
},
],
};
trait_def.expand(cx, mitem, item, push)
}

View file

@ -10,11 +10,10 @@ extern crate rustc_plugin;
use std::borrow::ToOwned;
use syntax::ast;
use syntax::ext::hygiene;
use syntax::ext::build::AstBuilder;
use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT};
use syntax::ext::base::{SyntaxExtension, TTMacroExpander, ExtCtxt, MacResult, MacEager};
use syntax::ext::hygiene::Transparency;
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;
use syntax::tokenstream::TokenStream;
@ -29,7 +28,7 @@ impl TTMacroExpander for Expander {
ecx: &'cx mut ExtCtxt,
sp: Span,
_: TokenStream,
_: Option<Span>) -> Box<MacResult+'cx> {
_: Option<Span>) -> Box<dyn MacResult+'cx> {
let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i))
.collect::<Vec<_>>().join(", ");
MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args)))
@ -40,9 +39,10 @@ impl TTMacroExpander for Expander {
pub fn plugin_registrar(reg: &mut Registry) {
let args = reg.args().to_owned();
reg.register_syntax_extension(Symbol::intern("plugin_args"),
NormalTT {
SyntaxExtension::LegacyBang {
expander: Box::new(Expander { args: args, }),
def_info: None,
transparency: Transparency::SemiTransparent,
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,

View file

@ -1,10 +0,0 @@
// aux-build:custom-derive-partial-eq.rs
// ignore-stage1
#![feature(plugin)]
#![plugin(custom_derive_partial_eq)]
#![allow(unused)]
#[derive_CustomPartialEq] // Check that this is not a stability error.
enum E { V1, V2 }
fn main() {}

View file

@ -1,64 +0,0 @@
// aux-build:custom-derive-plugin-attr.rs
// ignore-stage1
#![feature(plugin, rustc_attrs)]
#![plugin(custom_derive_plugin_attr)]
trait TotalSum {
fn total_sum(&self) -> isize;
}
impl TotalSum for isize {
fn total_sum(&self) -> isize {
*self
}
}
struct Seven;
impl TotalSum for Seven {
fn total_sum(&self) -> isize {
7
}
}
#[rustc_derive_TotalSum]
struct Foo {
seven: Seven,
bar: Bar,
baz: isize,
#[ignore]
nan: NaN,
}
#[rustc_derive_TotalSum]
struct Bar {
quux: isize,
bleh: isize,
#[ignore]
nan: NaN2
}
struct NaN;
impl TotalSum for NaN {
fn total_sum(&self) -> isize {
panic!();
}
}
struct NaN2;
pub fn main() {
let v = Foo {
seven: Seven,
bar: Bar {
quux: 9,
bleh: 3,
nan: NaN2
},
baz: 80,
nan: NaN
};
assert_eq!(v.total_sum(), 99);
}

View file

@ -1,49 +0,0 @@
// aux-build:custom-derive-plugin.rs
// ignore-stage1
#![feature(plugin)]
#![plugin(custom_derive_plugin)]
trait TotalSum {
fn total_sum(&self) -> isize;
}
impl TotalSum for isize {
fn total_sum(&self) -> isize {
*self
}
}
struct Seven;
impl TotalSum for Seven {
fn total_sum(&self) -> isize {
7
}
}
#[derive_TotalSum]
struct Foo {
seven: Seven,
bar: Bar,
baz: isize,
}
#[derive_TotalSum]
struct Bar {
quux: isize,
bleh: isize,
}
pub fn main() {
let v = Foo {
seven: Seven,
bar: Bar {
quux: 9,
bleh: 3,
},
baz: 80,
};
assert_eq!(v.total_sum(), 99);
}

View file

@ -1,13 +0,0 @@
#![allow(dead_code)]
// aux-build:custom-derive-plugin.rs
// ignore-stage1
#![feature(plugin)]
#![plugin(custom_derive_plugin)]
#[derive_Nothing]
#[derive_Nothing]
#[derive_Nothing]
struct S;
fn main() {}

View file

@ -1,6 +1,9 @@
error: no rules expected the token `enum E { }`
--> $DIR/nonterminal-matching.rs:19:10
|
LL | macro n(a $nt_item b) {
| --------------------- when calling this macro
...
LL | n!(a $nt_item b);
| ^^^^^^^^ no rules expected this token in macro call
...