diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 682b3ff834fad1eca4ddb76284ed08d12881cf97..ea3112b2463f8ba27007e6e14405c475ef93e153 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -250,6 +250,32 @@ fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) } result } + + fn resolve_builtin_macro(&mut self, tname: Name) -> Result, Determinacy> { + match self.builtin_macros.get(&tname).cloned() { + Some(binding) => Ok(binding.get_macro(self)), + None => Err(Determinacy::Undetermined), + } + } + + fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) + -> Result, Determinacy> { + let ast::Path { span, .. } = *path; + match self.resolve_macro(scope, path, false) { + Ok(ext) => match *ext { + SyntaxExtension::BuiltinDerive(..) | + SyntaxExtension::ProcMacroDerive(..) => Ok(ext), + _ => Err(Determinacy::Determined), + }, + Err(Determinacy::Undetermined) if force => { + let msg = format!("cannot find derive macro `{}` in this scope", path); + let mut err = self.session.struct_span_err(span, &msg); + err.emit(); + Err(Determinacy::Determined) + }, + Err(err) => Err(err), + } + } } impl<'a> Resolver<'a> { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 17b0b97468df850fbde38ebf3ae7ca8a67289847..9a717b86d091ed6682cd67427c89bda2baadf850 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -536,6 +536,9 @@ pub trait Resolver { fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option; fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) -> Result, Determinacy>; + fn resolve_builtin_macro(&mut self, tname: Name) -> Result, Determinacy>; + fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) + -> Result, Determinacy>; } #[derive(Copy, Clone, Debug)] @@ -562,6 +565,13 @@ fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool) -> Result, Determinacy> { Err(Determinacy::Determined) } + fn resolve_builtin_macro(&mut self, _tname: Name) -> Result, Determinacy> { + Err(Determinacy::Determined) + } + fn resolve_derive_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool) + -> Result, Determinacy> { + Err(Determinacy::Determined) + } } #[derive(Clone)] diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs new file mode 100644 index 0000000000000000000000000000000000000000..946448eaaee99a2efbfe170e6c59515d7c24794f --- /dev/null +++ b/src/libsyntax/ext/derive.rs @@ -0,0 +1,218 @@ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ast::Name; +use attr; +use ast::{self, NestedMetaItem}; use ext::base::{ExtCtxt, SyntaxExtension}; +use codemap; +use ext::build::AstBuilder; +use feature_gate; +use symbol::Symbol; +use syntax_pos::Span; + +pub fn derive_attr_trait<'a>(cx: &mut ExtCtxt, attr: &'a ast::Attribute) + -> Option<&'a NestedMetaItem> { + if attr.name() != "derive" { + return None; + } + if attr.value_str().is_some() { + cx.span_err(attr.span, "unexpected value in `derive`"); + return None; + } + + let traits = attr.meta_item_list().unwrap_or(&[]); + + if traits.is_empty() { + cx.span_warn(attr.span, "empty trait list in `derive`"); + return None; + } + + return traits.get(0); +} + +pub fn verify_derive_attrs(cx: &mut ExtCtxt, attrs: &[ast::Attribute]) { + for attr in attrs { + if attr.name() != "derive" { + continue; + } + + if attr.value_str().is_some() { + cx.span_err(attr.span, "unexpected value in `derive`"); + } + + let traits = attr.meta_item_list().unwrap_or(&[]).to_owned(); + + if traits.is_empty() { + cx.span_warn(attr.span, "empty trait list in `derive`"); + attr::mark_used(&attr); + continue; + } + for titem in traits { + if titem.word().is_none() { + cx.span_err(titem.span, "malformed `derive` entry"); + } + } + } +} + +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum DeriveType { + Legacy, + ProcMacro, + Builtin +} + +impl DeriveType { + // Classify a derive trait name by resolving the macro. + pub fn classify(cx: &mut ExtCtxt, tname: Name) -> DeriveType { + let legacy_derive_name = Symbol::intern(&format!("derive_{}", tname)); + + if let Ok(_) = cx.resolver.resolve_builtin_macro(legacy_derive_name) { + return DeriveType::Legacy; + } + + match cx.resolver.resolve_builtin_macro(tname) { + Ok(ext) => match *ext { + SyntaxExtension::BuiltinDerive(..) => DeriveType::Builtin, + _ => DeriveType::ProcMacro, + }, + Err(_) => DeriveType::ProcMacro, + } + } +} + +pub fn get_derive_attr(cx: &mut ExtCtxt, attrs: &mut Vec, + derive_type: DeriveType) -> Option { + for i in 0..attrs.len() { + if attrs[i].name() != "derive" { + continue; + } + + if attrs[i].value_str().is_some() { + continue; + } + + let mut traits = attrs[i].meta_item_list().unwrap_or(&[]).to_owned(); + + // First, weed out malformed #[derive] + traits.retain(|titem| titem.word().is_some()); + + let mut titem = None; + + // See if we can find a matching trait. + for j in 0..traits.len() { + let tname = match traits[j].name() { + Some(tname) => tname, + _ => continue, + }; + + if DeriveType::classify(cx, tname) == derive_type { + titem = Some(traits.remove(j)); + break; + } + } + + // If we find a trait, remove the trait from the attribute. + if let Some(titem) = titem { + if traits.len() == 0 { + attrs.remove(i); + } else { + let derive = Symbol::intern("derive"); + let mitem = cx.meta_list(titem.span, derive, traits); + attrs[i] = cx.attribute(titem.span, mitem); + } + let derive = Symbol::intern("derive"); + let mitem = cx.meta_list(titem.span, derive, vec![titem]); + return Some(cx.attribute(mitem.span, mitem)); + } + } + return None; +} + +fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { + Span { + expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { + call_site: span, + callee: codemap::NameAndSpan { + format: codemap::MacroAttribute(Symbol::intern(attr_name)), + span: Some(span), + allow_internal_unstable: true, + }, + }), + ..span + } +} + +pub fn add_derived_markers(cx: &mut ExtCtxt, attrs: &mut Vec) { + if attrs.is_empty() { + return; + } + + let titems = attrs.iter().filter(|a| { + a.name() == "derive" + }).flat_map(|a| { + a.meta_item_list().unwrap_or(&[]).iter() + }).filter_map(|titem| { + titem.name() + }).collect::>(); + + let span = attrs[0].span; + + if !attrs.iter().any(|a| a.name() == "structural_match") && + titems.iter().any(|t| *t == "PartialEq") && titems.iter().any(|t| *t == "Eq") { + let structural_match = Symbol::intern("structural_match"); + let span = allow_unstable(cx, span, "derive(PartialEq, Eq)"); + let meta = cx.meta_word(span, structural_match); + attrs.push(cx.attribute(span, meta)); + } + + if !attrs.iter().any(|a| a.name() == "rustc_copy_clone_marker") && + titems.iter().any(|t| *t == "Copy") && titems.iter().any(|t| *t == "Clone") { + let structural_match = Symbol::intern("rustc_copy_clone_marker"); + let span = allow_unstable(cx, span, "derive(Copy, Clone)"); + let meta = cx.meta_word(span, structural_match); + attrs.push(cx.attribute(span, meta)); + } +} + +pub fn find_derive_attr(cx: &mut ExtCtxt, attrs: &mut Vec) + -> Option { + verify_derive_attrs(cx, attrs); + get_derive_attr(cx, attrs, DeriveType::Legacy).and_then(|a| { + let titem = derive_attr_trait(cx, &a); + titem.and_then(|titem| { + let tword = titem.word().unwrap(); + let tname = tword.name(); + if !cx.ecfg.enable_custom_derive() { + feature_gate::emit_feature_err( + &cx.parse_sess, + "custom_derive", + titem.span, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_CUSTOM_DERIVE + ); + None + } else { + let name = Symbol::intern(&format!("derive_{}", tname)); + if !cx.resolver.is_whitelisted_legacy_custom_derive(name) { + cx.span_warn(titem.span, + feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE); + } + let mitem = cx.meta_word(titem.span, name); + Some(cx.attribute(mitem.span, mitem)) + } + }) + }).or_else(|| { + get_derive_attr(cx, attrs, DeriveType::ProcMacro) + }).or_else(|| { + add_derived_markers(cx, attrs); + get_derive_attr(cx, attrs, DeriveType::Builtin) + }) +} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 01a8c215d47aa650a8c2143ab68471a8e278b3b9..8e7f8830eafbc586d2b2c04ad60d44487cc12dc9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,26 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{Block, Ident, Mac_, PatKind}; +use ast::{self, Block, Ident, Mac_, PatKind}; use ast::{Name, MacStmtStyle, StmtKind, ItemKind}; -use ast; -use ext::hygiene::Mark; -use ext::placeholders::{placeholder, PlaceholderExpander}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; -use syntax_pos::{self, Span, ExpnId}; use config::{is_test_or_bench, StripUnconfigured}; use ext::base::*; +use ext::derive::{find_derive_attr, derive_attr_trait}; +use ext::hygiene::Mark; +use ext::placeholders::{placeholder, PlaceholderExpander}; use feature_gate::{self, Features}; use fold; use fold::*; -use parse::{ParseSess, DirectoryOwnership, PResult, filemap_to_tts}; use parse::parser::Parser; use parse::token; +use parse::{ParseSess, DirectoryOwnership, PResult, filemap_to_tts}; use print::pprust; use ptr::P; use std_inject; +use symbol::Symbol; use symbol::keywords; +use syntax_pos::{self, Span, ExpnId}; use tokenstream::{TokenTree, TokenStream}; use util::small_vector::SmallVector; use visit::Visitor; @@ -166,6 +167,10 @@ pub enum InvocationKind { attr: ast::Attribute, item: Annotatable, }, + Derive { + attr: ast::Attribute, + item: Annotatable, + }, } impl Invocation { @@ -173,6 +178,7 @@ fn span(&self) -> Span { match self.kind { InvocationKind::Bang { span, .. } => span, InvocationKind::Attr { ref attr, .. } => attr.span, + InvocationKind::Derive { ref attr, .. } => attr.span, } } } @@ -250,6 +256,13 @@ fn expand(&mut self, expansion: Expansion) -> Expansion { let path = ast::Path::from_ident(attr.span, ident); self.cx.resolver.resolve_macro(scope, &path, force) } + InvocationKind::Derive { ref attr, .. } => { + let titem = derive_attr_trait(self.cx, &attr).unwrap(); + let tname = titem.name().expect("Expected derive macro name"); + let ident = Ident::with_empty_ctxt(tname); + let path = ast::Path::from_ident(attr.span, ident); + self.cx.resolver.resolve_derive_macro(scope, &path, force) + } }; let ext = match resolution { Ok(ext) => Some(ext), @@ -330,6 +343,7 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expan match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), + InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext), } } @@ -486,6 +500,71 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc) -> }) } + /// Expand a derive invocation. Returns the result of expansion. + fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { + let Invocation { expansion_kind: kind, .. } = invoc; + let (attr, item) = match invoc.kind { + InvocationKind::Derive { attr, item } => (attr, item), + _ => unreachable!(), + }; + + attr::mark_used(&attr); + let titem = derive_attr_trait(self.cx, &attr).unwrap(); + let tname = ast::Ident::with_empty_ctxt(titem.name().unwrap()); + let name = Symbol::intern(&format!("derive({})", tname)); + let mitem = &attr.value; + + self.cx.bt_push(ExpnInfo { + call_site: attr.span, + callee: NameAndSpan { + format: MacroAttribute(attr.name()), + span: Some(attr.span), + allow_internal_unstable: false, + } + }); + + match *ext { + SyntaxExtension::ProcMacroDerive(ref ext) => { + let span = Span { + expn_id: self.cx.codemap().record_expansion(ExpnInfo { + call_site: mitem.span, + callee: NameAndSpan { + format: MacroAttribute(Symbol::intern(&format!("derive({})", tname))), + span: None, + allow_internal_unstable: false, + }, + }), + ..mitem.span + }; + return kind.expect_from_annotatables(ext.expand(self.cx, span, &mitem, item)); + } + SyntaxExtension::BuiltinDerive(func) => { + let span = Span { + expn_id: self.cx.codemap().record_expansion(ExpnInfo { + call_site: titem.span, + callee: NameAndSpan { + format: MacroAttribute(name), + span: None, + allow_internal_unstable: true, + }, + }), + ..titem.span + }; + let mut items = Vec::new(); + func(self.cx, span, &mitem, &item, &mut |a| { + items.push(a) + }); + items.insert(0, item); + return kind.expect_from_annotatables(items); + } + _ => { + let msg = &format!("macro `{}` may not be used for derive attributes", name); + self.cx.span_err(attr.span, &msg); + kind.dummy(attr.span) + } + } + } + fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span) -> Expansion { let mut parser = self.cx.new_parser_from_tts(&toks.trees().cloned().collect::>()); @@ -595,16 +674,31 @@ fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Ex fn collect_attr(&mut self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind) -> Expansion { - self.collect(kind, InvocationKind::Attr { attr: attr, item: item }) + let invoc_kind = if attr.name() == "derive" { + if kind == ExpansionKind::TraitItems || kind == ExpansionKind::ImplItems { + self.cx.span_err(attr.span, "`derive` can be only be applied to items"); + return kind.expect_from_annotatables(::std::iter::once(item)); + } + InvocationKind::Derive { attr: attr, item: item } + } else { + InvocationKind::Attr { attr: attr, item: item } + }; + + self.collect(kind, invoc_kind) } // If `item` is an attr invocation, remove and return the macro attribute. fn classify_item(&mut self, mut item: T) -> (T, Option) { let mut attr = None; + item = item.map_attrs(|mut attrs| { - attr = self.cx.resolver.find_attr_invoc(&mut attrs); + attr = self.cx.resolver.find_attr_invoc(&mut attrs).or_else(|| { + find_derive_attr(self.cx, &mut attrs) + }); + attrs }); + (item, attr) } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 25be9e91a6ac92a70cedb6573d161c42e631df25..87a03adf6b77c018784aa535a3939f0ba1db4a2c 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -128,6 +128,7 @@ pub mod print { pub mod ext { pub mod base; pub mod build; + pub mod derive; pub mod expand; pub mod placeholders; pub mod hygiene; diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index e118ef1ea01f46822765a65b0907da9057a1aca1..974e86a57412446d0b2457b48704e8e46a91f927 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -54,7 +54,7 @@ fn expand(&self, Annotatable::Item(item) => item, Annotatable::ImplItem(_) | Annotatable::TraitItem(_) => { - ecx.span_err(span, "proc_macro_derive attributes may only be \ + ecx.span_err(span, "proc-macro derives may only be \ applied to struct/enum items"); return Vec::new() } @@ -63,7 +63,7 @@ fn expand(&self, ItemKind::Struct(..) | ItemKind::Enum(..) => {}, _ => { - ecx.span_err(span, "proc_macro_derive attributes may only be \ + ecx.span_err(span, "proc-macro derives may only be \ applied to struct/enum items"); return Vec::new() } @@ -81,7 +81,7 @@ fn expand(&self, let stream = match res { Ok(stream) => stream, Err(e) => { - let msg = "proc_macro_derive attribute panicked"; + let msg = "proc-macro derive panicked"; let mut err = ecx.struct_span_fatal(span, msg); if let Some(s) = e.downcast_ref::() { err.help(&format!("message: {}", s)); @@ -100,7 +100,7 @@ fn expand(&self, Ok(new_items) => new_items, Err(_) => { // FIXME: handle this better - let msg = "proc_macro_derive produced unparseable tokens"; + let msg = "proc-macro derive produced unparseable tokens"; ecx.struct_span_fatal(span, msg).emit(); panic!(FatalError); } diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 6359d642d157cf4159c955e784f476aca4126e8e..498f2348b80f109157f55992e684e7e91111b864 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -13,6 +13,7 @@ use deriving; use deriving::generic::*; use deriving::generic::ty::*; +use deriving::warn_if_deprecated; use syntax::ast; use syntax::ast::{Expr, MetaItem, Mutability}; @@ -35,7 +36,7 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt, mitem: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable)) { - deriving::warn_if_deprecated(cx, span, "Decodable"); + warn_if_deprecated(cx, span, "Decodable"); expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize") } diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index a276193e81b979de9df1cd96701f9fb359d03527..9d155c22ad031d86f4f3508d4195c5c051b5a5d8 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -91,6 +91,7 @@ use deriving; use deriving::generic::*; use deriving::generic::ty::*; +use deriving::warn_if_deprecated; use syntax::ast::{Expr, ExprKind, MetaItem, Mutability}; use syntax::ext::base::{Annotatable, ExtCtxt}; @@ -112,7 +113,7 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt, mitem: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable)) { - deriving::warn_if_deprecated(cx, span, "Encodable"); + warn_if_deprecated(cx, span, "Encodable"); expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize") } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 311b8ae41f8b9cf331dc982afecaad7e396d6cb5..3bceb02f3d6c5af6a2e2cff0a5cb9c452ce275c5 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,12 +11,10 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use std::rc::Rc; -use syntax::ast::{self, MetaItem}; -use syntax::attr::HasAttrs; +use syntax::ast; use syntax::codemap; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver}; use syntax::ext::build::AstBuilder; -use syntax::feature_gate; use syntax::ptr::P; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -90,241 +88,6 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { } } -pub fn expand_derive(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - annotatable: Annotatable) - -> Vec { - debug!("expand_derive: span = {:?}", span); - debug!("expand_derive: mitem = {:?}", mitem); - debug!("expand_derive: annotatable input = {:?}", annotatable); - let mut item = match annotatable { - Annotatable::Item(item) => item, - other => { - cx.span_err(span, "`derive` can only be applied to items"); - return vec![other] - } - }; - - let derive = Symbol::intern("derive"); - let mut derive_attrs = Vec::new(); - item = item.map_attrs(|attrs| { - let partition = attrs.into_iter().partition(|attr| attr.name() == derive); - derive_attrs = partition.0; - partition.1 - }); - - // Expand `#[derive]`s after other attribute macro invocations. - if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() { - return vec![Annotatable::Item(item.map_attrs(|mut attrs| { - attrs.push(cx.attribute(span, mitem.clone())); - attrs.extend(derive_attrs); - attrs - }))]; - } - - let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| { - if mitem.value_str().is_some() { - cx.span_err(mitem.span, "unexpected value in `derive`"); - } - - let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned(); - if traits.is_empty() { - cx.span_warn(mitem.span, "empty trait list in `derive`"); - } - traits - }; - - let mut traits = get_traits(mitem, cx); - for derive_attr in derive_attrs { - traits.extend(get_traits(&derive_attr.value, cx)); - } - - // First, weed out malformed #[derive] - traits.retain(|titem| { - if titem.word().is_none() { - cx.span_err(titem.span, "malformed `derive` entry"); - false - } else { - true - } - }); - - // Next, check for old-style #[derive(Foo)] - // - // These all get expanded to `#[derive_Foo]` and will get expanded first. If - // we actually add any attributes here then we return to get those expanded - // and then eventually we'll come back to finish off the other derive modes. - let mut new_attributes = Vec::new(); - traits.retain(|titem| { - let tword = titem.word().unwrap(); - let tname = tword.name(); - - if is_builtin_trait(tname) || { - let derive_mode = ast::Path::from_ident(titem.span, ast::Ident::with_empty_ctxt(tname)); - cx.resolver.resolve_macro(cx.current_expansion.mark, &derive_mode, false).map(|ext| { - if let SyntaxExtension::ProcMacroDerive(_) = *ext { true } else { false } - }).unwrap_or(false) - } { - return true; - } - - if !cx.ecfg.enable_custom_derive() { - feature_gate::emit_feature_err(&cx.parse_sess, - "custom_derive", - titem.span, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_CUSTOM_DERIVE); - } else { - let name = Symbol::intern(&format!("derive_{}", tname)); - if !cx.resolver.is_whitelisted_legacy_custom_derive(name) { - cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE); - } - let mitem = cx.meta_word(titem.span, name); - new_attributes.push(cx.attribute(mitem.span, mitem)); - } - false - }); - if new_attributes.len() > 0 { - item = item.map(|mut i| { - i.attrs.extend(new_attributes); - if traits.len() > 0 { - let list = cx.meta_list(mitem.span, derive, traits); - i.attrs.push(cx.attribute(mitem.span, list)); - } - i - }); - return vec![Annotatable::Item(item)] - } - - // Now check for macros-1.1 style custom #[derive]. - // - // Expand each of them in order given, but *before* we expand any built-in - // derive modes. The logic here is to: - // - // 1. Collect the remaining `#[derive]` annotations into a list. If - // there are any left, attach a `#[derive]` attribute to the item - // that we're currently expanding with the remaining derive modes. - // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander. - // 3. Expand the current item we're expanding, getting back a list of - // items that replace it. - // 4. Extend the returned list with the current list of items we've - // collected so far. - // 5. Return everything! - // - // If custom derive extensions end up threading through the `#[derive]` - // attribute, we'll get called again later on to continue expanding - // those modes. - let macros_11_derive = traits.iter() - .cloned() - .enumerate() - .filter(|&(_, ref name)| !is_builtin_trait(name.name().unwrap())) - .next(); - if let Some((i, titem)) = macros_11_derive { - let tname = ast::Ident::with_empty_ctxt(titem.name().unwrap()); - let path = ast::Path::from_ident(titem.span, tname); - let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap(); - - traits.remove(i); - if traits.len() > 0 { - item = item.map(|mut i| { - let list = cx.meta_list(mitem.span, derive, traits); - i.attrs.push(cx.attribute(mitem.span, list)); - i - }); - } - let titem = cx.meta_list_item_word(titem.span, titem.name().unwrap()); - let mitem = cx.meta_list(titem.span, derive, vec![titem]); - let item = Annotatable::Item(item); - - let span = Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: mitem.span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern(&format!("derive({})", tname))), - span: None, - allow_internal_unstable: false, - }, - }), - ..mitem.span - }; - - if let SyntaxExtension::ProcMacroDerive(ref ext) = *ext { - return ext.expand(cx, span, &mitem, item); - } else { - unreachable!() - } - } - - // Ok, at this point we know that there are no old-style `#[derive_Foo]` nor - // any macros-1.1 style `#[derive(Foo)]`. Expand all built-in traits here. - - // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted) - // `#[structural_match]` attribute. - let (partial_eq, eq) = (Symbol::intern("PartialEq"), Symbol::intern("Eq")); - if traits.iter().any(|t| t.name() == Some(partial_eq)) && - traits.iter().any(|t| t.name() == Some(eq)) { - let structural_match = Symbol::intern("structural_match"); - let span = allow_unstable(cx, span, "derive(PartialEq, Eq)"); - let meta = cx.meta_word(span, structural_match); - item = item.map(|mut i| { - i.attrs.push(cx.attribute(span, meta)); - i - }); - } - - // RFC #1521. `Clone` can assume that `Copy` types' clone implementation is - // the same as the copy implementation. - // - // Add a marker attribute here picked up during #[derive(Clone)] - let (copy, clone) = (Symbol::intern("Copy"), Symbol::intern("Clone")); - if traits.iter().any(|t| t.name() == Some(clone)) && - traits.iter().any(|t| t.name() == Some(copy)) { - let marker = Symbol::intern("rustc_copy_clone_marker"); - let span = allow_unstable(cx, span, "derive(Copy, Clone)"); - let meta = cx.meta_word(span, marker); - item = item.map(|mut i| { - i.attrs.push(cx.attribute(span, meta)); - i - }); - } - - let mut items = Vec::new(); - for titem in traits.iter() { - let tname = titem.word().unwrap().name(); - let name = Symbol::intern(&format!("derive({})", tname)); - let tname_cx = ast::Ident::with_empty_ctxt(titem.name().unwrap()); - let mitem = cx.meta_word(titem.span, name); - let path = ast::Path::from_ident(titem.span, tname_cx); - let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap(); - - let span = Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: titem.span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(name), - span: None, - allow_internal_unstable: true, - }, - }), - ..titem.span - }; - - if let SyntaxExtension::BuiltinDerive(ref func) = *ext { - let my_item = Annotatable::Item(item); - func(cx, span, &mitem, &my_item, &mut |a| { - items.push(a) - }); - item = my_item.expect_item(); - } else { - unreachable!(); - } - } - - items.insert(0, Annotatable::Item(item)); - return items -} - macro_rules! derive_traits { ($( $name:expr => $func:path, )+) => { pub fn is_builtin_trait(name: ast::Name) -> bool { diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index e872cfaeacb7b512542c79bbc43cc19e04679418..7533171b08556df082f2fcabfd27dbcb11e3e3d0 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -24,7 +24,6 @@ #![feature(staged_api)] extern crate fmt_macros; -#[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -51,7 +50,7 @@ use std::rc::Rc; use syntax::ast; -use syntax::ext::base::{MacroExpanderFn, NormalTT, MultiModifier, NamedSyntaxExtension}; +use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension}; use syntax::symbol::Symbol; pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, @@ -114,8 +113,6 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, register(Symbol::intern("format_args"), NormalTT(Box::new(format::expand_format_args), None, true)); - register(Symbol::intern("derive"), MultiModifier(Box::new(deriving::expand_derive))); - for (name, ext) in user_exts { register(name, ext); } diff --git a/src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs b/src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs index bc4da9fee47ee23270ec46093e775335449d28bb..42fad803bfa68ae345d5643ff0ae3b0e99fbdadb 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs @@ -16,7 +16,7 @@ #[derive( A )] -//~^^ ERROR: proc_macro_derive produced unparseable tokens +//~^^ ERROR: proc-macro derive produced unparseable tokens struct A; fn main() {} diff --git a/src/test/compile-fail-fulldeps/proc-macro/load-panic.rs b/src/test/compile-fail-fulldeps/proc-macro/load-panic.rs index 107273d012dd6c8765369c57caef2808a604897c..c483c048b418f11f437a37a8f13a03200cd472a6 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/load-panic.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/load-panic.rs @@ -14,7 +14,7 @@ extern crate derive_panic; #[derive(A)] -//~^ ERROR: proc_macro_derive attribute panicked +//~^ ERROR: proc-macro derive panicked //~| HELP: message: nope! struct Foo; diff --git a/src/test/compile-fail/deriving-meta-unknown-trait.rs b/src/test/compile-fail/deriving-meta-unknown-trait.rs index 596cc1e7d58163e8af3b843089e08092e1ccc43b..d388ece084417160ce98517533942f71e0387ca5 100644 --- a/src/test/compile-fail/deriving-meta-unknown-trait.rs +++ b/src/test/compile-fail/deriving-meta-unknown-trait.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength #[derive(Eqr)] -//~^ ERROR `#[derive]` for custom traits is not stable enough for use. It is deprecated and will be removed in v1.15 (see issue #29644) +//~^ ERROR cannot find derive macro `Eqr` in this scope struct Foo; pub fn main() {} diff --git a/src/test/compile-fail/deriving-primitive.rs b/src/test/compile-fail/deriving-primitive.rs index be822a173ab5821053a21d7b05abb6eb24562f55..97a39a46c19a81774f5e06f1b45118b65c7253da 100644 --- a/src/test/compile-fail/deriving-primitive.rs +++ b/src/test/compile-fail/deriving-primitive.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[derive(FromPrimitive)] //~ERROR `#[derive]` for custom traits is not stable +#[derive(FromPrimitive)] //~ERROR cannot find derive macro `FromPrimitive` in this scope enum Foo {} fn main() {} diff --git a/src/test/compile-fail/macro-error.rs b/src/test/compile-fail/macro-error.rs index 4a6dbf014a1cace35ae973c1daa5cf77ca3bade8..f467ba3b1e19521a8e161573ea538c494ea5e34a 100644 --- a/src/test/compile-fail/macro-error.rs +++ b/src/test/compile-fail/macro-error.rs @@ -16,5 +16,5 @@ fn main() { foo!(0); // Check that we report errors at macro definition, not expansion. let _: cfg!(foo) = (); //~ ERROR non-type macro in type position - derive!(); //~ ERROR `derive` can only be used in attributes + derive!(); //~ ERROR macro undefined: 'derive!' } diff --git a/src/test/compile-fail/macros-nonfatal-errors.rs b/src/test/compile-fail/macros-nonfatal-errors.rs index 723e936212a5b76efa3a82765c1ba03df7b906c8..3f710af8ac9a883f0c31ac5161e2828b3998771f 100644 --- a/src/test/compile-fail/macros-nonfatal-errors.rs +++ b/src/test/compile-fail/macros-nonfatal-errors.rs @@ -14,9 +14,11 @@ #![feature(asm)] #![feature(trace_macros, concat_idents)] -#[derive(Default, //~ ERROR - Zero)] //~ ERROR -enum CantDeriveThose {} +#[derive(Zero)] //~ ERROR +struct CantDeriveThis; + +#[derive(Default)] //~ ERROR +enum OrDeriveThis {} fn main() { doesnt_exist!(); //~ ERROR diff --git a/src/test/ui/custom-derive/issue-36935.stderr b/src/test/ui/custom-derive/issue-36935.stderr index ad1382cbc8e4b51e1cd8f26b4c6fd884715c6cc4..9a5e2de14e3b0788754bee7982778fea7adb0253 100644 --- a/src/test/ui/custom-derive/issue-36935.stderr +++ b/src/test/ui/custom-derive/issue-36935.stderr @@ -1,4 +1,4 @@ -error: proc_macro_derive attribute panicked +error: proc-macro derive panicked --> $DIR/issue-36935.rs:17:15 | 17 | #[derive(Foo, Bar)]