diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ext/base.rs | 223 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 104 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 112 |
3 files changed, 166 insertions, 273 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 61c736662c7..38b7dee40c4 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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), - - /// 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, - } + /// 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 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, } } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 99605395553..084d4fd3820 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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)) } _ => { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 6f82f509465..5dbf21867af 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -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,65 +374,65 @@ 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 transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) { + Transparency::Transparent + } else if body.legacy { + Transparency::SemiTransparent + } else { + Transparency::Opaque + }; + + 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 }) - ); - 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); - } - } + .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 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 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); } - } else { - let is_transparent = attr::contains_name(&def.attrs, sym::rustc_transparent_macro); + } - SyntaxExtension::DeclMacro { - expander, - def_info: Some((def.id, def.span)), - is_transparent, - edition, + 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, } } |
