use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, NodeId};
use rustc_ast_pretty::pprust;
-use rustc_expand::base::{ExtCtxt, ResolverExpand};
+use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
use rustc_session::Session;
use rustc_span::hygiene::AstPass;
}
fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
- // 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,
- };
- if list.len() != 1 && list.len() != 2 {
- self.handler.span_err(attr.span, "attribute must have either one or two arguments");
- return;
- }
- let trait_attr = match list[0].meta_item() {
- Some(meta_item) => meta_item,
- _ => {
- self.handler.span_err(list[0].span(), "not a meta item");
- return;
- }
- };
- let trait_ident = match trait_attr.ident() {
- Some(trait_ident) if trait_attr.is_word() => trait_ident,
- _ => {
- self.handler.span_err(trait_attr.span, "must only be one word");
- return;
- }
- };
-
- if !trait_ident.name.can_be_raw() {
- self.handler.span_err(
- trait_attr.span,
- &format!("`{}` cannot be a name of derive macro", trait_ident),
- );
- }
-
- let attributes_attr = list.get(1);
- let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
- if !attr.has_name(sym::attributes) {
- self.handler.span_err(attr.span(), "second argument must be `attributes`")
- }
- attr.meta_item_list()
- .unwrap_or_else(|| {
- self.handler
- .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,
- _ => {
- self.handler.span_err(attr.span(), "not a meta item");
- return None;
- }
- };
-
- let ident = match attr.ident() {
- Some(ident) if attr.is_word() => ident,
- _ => {
- self.handler.span_err(attr.span, "must only be one word");
- return None;
- }
- };
- if !ident.name.can_be_raw() {
- self.handler.span_err(
- attr.span,
- &format!("`{}` cannot be a name of derive helper attribute", ident),
- );
- }
-
- Some(ident.name)
- })
- .collect()
- } else {
- Vec::new()
- };
+ let (trait_name, proc_attrs) =
+ match parse_macro_name_and_helper_attrs(self.handler, attr, "derive") {
+ Some(name_and_attrs) => name_and_attrs,
+ None => return,
+ };
if self.in_root && item.vis.kind.is_pub() {
self.macros.push(ProcMacro::Derive(ProcMacroDerive {
id: item.id,
span: item.span,
- trait_name: trait_ident.name,
+ trait_name,
function_name: item.ident,
attrs: proc_attrs,
}));
}
}
- 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
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
// Internal attributes, Macro related:
// ==========================================================================
- rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word, NameValueStr: "name"), IMPL_DETAIL),
+ rustc_attr!(
+ rustc_builtin_macro, AssumedUsed,
+ template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"),
+ IMPL_DETAIL,
+ ),
rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
rustc_attr!(
rustc_macro_transparency, AssumedUsed,
#[doc = include_str!("panic.md")]
#[macro_export]
-#[rustc_builtin_macro = "core_panic"]
+#[cfg_attr(bootstrap, rustc_builtin_macro = "core_panic")]
+#[cfg_attr(not(bootstrap), rustc_builtin_macro(core_panic))]
#[allow_internal_unstable(edition_panic)]
#[stable(feature = "core", since = "1.6.0")]
#[rustc_diagnostic_item = "core_panic_macro"]
#[doc = include_str!("../../core/src/macros/panic.md")]
#[macro_export]
-#[rustc_builtin_macro = "std_panic"]
+#[cfg_attr(bootstrap, rustc_builtin_macro = "std_panic")]
+#[cfg_attr(not(bootstrap), rustc_builtin_macro(std_panic))]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(edition_panic)]
#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")]
--- /dev/null
+// check-pass
+// compile-flags: --crate-type=lib
+
+#![feature(decl_macro)]
+#![feature(lang_items)]
+#![feature(no_core)]
+#![feature(rustc_attrs)]
+
+#![no_core]
+
+#[rustc_builtin_macro]
+macro derive() {}
+
+#[rustc_builtin_macro(Default, attributes(default))]
+macro Default() {}
+
+mod default {
+ pub trait Default {
+ fn default() -> Self;
+ }
+
+ impl Default for u8 {
+ fn default() -> u8 {
+ 0
+ }
+ }
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+#[derive(Default)]
+struct S {
+ #[default] // OK
+ field: u8,
+}