diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2021-07-14 19:53:35 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-07-14 19:53:35 +0200 |
| commit | 4d141f5e4c5e09408345cb8fa74f4c2f30cddd5d (patch) | |
| tree | 94537c35e4ce79caba9da6a83bbd16acda7ec693 /compiler/rustc_expand/src | |
| parent | ee5ed4a88d6a869cdb152829ed697d6459650db3 (diff) | |
| parent | 6c9ea1e8a9c899979a8b4dd86b32c4c77f4b6b6a (diff) | |
| download | rust-4d141f5e4c5e09408345cb8fa74f4c2f30cddd5d.tar.gz rust-4d141f5e4c5e09408345cb8fa74f4c2f30cddd5d.zip | |
Rollup merge of #87027 - petrochenkov:builderhelp, r=oli-obk
expand: Support helper attributes for built-in derive macros This is needed for https://github.com/rust-lang/rust/pull/86735 (derive macro `Default` should have a helper attribute `default`). With this PR we can specify helper attributes for built-in derives using syntax `#[rustc_builtin_macro(MacroName, attributes(attr1, attr2, ...))]` which mirrors equivalent syntax for proc macros `#[proc_macro_derive(MacroName, attributes(attr1, attr2, ...))]`. Otherwise expansion infra was already ready for this. The attribute parsing code is shared between proc macro derives and built-in macros (`fn parse_macro_name_and_helper_attrs`).
Diffstat (limited to 'compiler/rustc_expand/src')
| -rw-r--r-- | compiler/rustc_expand/src/base.rs | 94 |
1 files changed, 92 insertions, 2 deletions
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b3e52502b07..0183add4957 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -745,9 +745,17 @@ impl SyntaxExtension { } } - let builtin_name = sess + let (builtin_name, helper_attrs) = sess .find_by_name(attrs, sym::rustc_builtin_macro) - .map(|a| a.value_str().unwrap_or(name)); + .map(|attr| { + // Override `helper_attrs` passed above if it's a built-in macro, + // marking `proc_macro_derive` macros as built-in is not a realistic use case. + parse_macro_name_and_helper_attrs(sess.diagnostic(), attr, "built-in").map_or_else( + || (Some(name), Vec::new()), + |(name, helper_attrs)| (Some(name), helper_attrs), + ) + }) + .unwrap_or_else(|| (None, helper_attrs)); let (stability, const_stability) = attr::find_stability(&sess, attrs, span); if let Some((_, sp)) = const_stability { sess.parse_sess @@ -1213,6 +1221,88 @@ pub fn get_exprs_from_tts( Some(es) } +pub fn parse_macro_name_and_helper_attrs( + diag: &rustc_errors::Handler, + attr: &Attribute, + descr: &str, +) -> Option<(Symbol, Vec<Symbol>)> { + // Once we've located the `#[proc_macro_derive]` attribute, verify + // that it's of the form `#[proc_macro_derive(Foo)]` or + // `#[proc_macro_derive(Foo, attributes(A, ..))]` + let list = match attr.meta_item_list() { + Some(list) => list, + None => return None, + }; + if list.len() != 1 && list.len() != 2 { + diag.span_err(attr.span, "attribute must have either one or two arguments"); + return None; + } + let trait_attr = match list[0].meta_item() { + Some(meta_item) => meta_item, + _ => { + diag.span_err(list[0].span(), "not a meta item"); + return None; + } + }; + let trait_ident = match trait_attr.ident() { + Some(trait_ident) if trait_attr.is_word() => trait_ident, + _ => { + diag.span_err(trait_attr.span, "must only be one word"); + return None; + } + }; + + if !trait_ident.name.can_be_raw() { + diag.span_err( + trait_attr.span, + &format!("`{}` cannot be a name of {} macro", trait_ident, descr), + ); + } + + let attributes_attr = list.get(1); + let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr { + if !attr.has_name(sym::attributes) { + diag.span_err(attr.span(), "second argument must be `attributes`") + } + attr.meta_item_list() + .unwrap_or_else(|| { + diag.span_err(attr.span(), "attribute must be of form: `attributes(foo, bar)`"); + &[] + }) + .iter() + .filter_map(|attr| { + let attr = match attr.meta_item() { + Some(meta_item) => meta_item, + _ => { + diag.span_err(attr.span(), "not a meta item"); + return None; + } + }; + + let ident = match attr.ident() { + Some(ident) if attr.is_word() => ident, + _ => { + diag.span_err(attr.span, "must only be one word"); + return None; + } + }; + if !ident.name.can_be_raw() { + diag.span_err( + attr.span, + &format!("`{}` cannot be a name of derive helper attribute", ident), + ); + } + + Some(ident.name) + }) + .collect() + } else { + Vec::new() + }; + + Some((trait_ident.name, proc_attrs)) +} + /// This nonterminal looks like some specific enums from /// `proc-macro-hack` and `procedural-masquerade` crates. /// We need to maintain some special pretty-printing behavior for them due to incorrect |
