about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_resolve/macros.rs26
-rw-r--r--src/libsyntax/ext/base.rs10
-rw-r--r--src/libsyntax/ext/derive.rs218
-rw-r--r--src/libsyntax/ext/expand.rs110
-rw-r--r--src/libsyntax/lib.rs1
-rw-r--r--src/libsyntax_ext/deriving/custom.rs8
-rw-r--r--src/libsyntax_ext/deriving/decodable.rs3
-rw-r--r--src/libsyntax_ext/deriving/encodable.rs3
-rw-r--r--src/libsyntax_ext/deriving/mod.rs239
-rw-r--r--src/libsyntax_ext/lib.rs5
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/load-panic.rs2
-rw-r--r--src/test/compile-fail/deriving-meta-unknown-trait.rs2
-rw-r--r--src/test/compile-fail/deriving-primitive.rs2
-rw-r--r--src/test/compile-fail/macro-error.rs2
-rw-r--r--src/test/compile-fail/macros-nonfatal-errors.rs8
-rw-r--r--src/test/ui/custom-derive/issue-36935.stderr2
17 files changed, 378 insertions, 265 deletions
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 682b3ff834f..ea3112b2463 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -250,6 +250,32 @@ impl<'a> base::Resolver for Resolver<'a> {
         }
         result
     }
+
+    fn resolve_builtin_macro(&mut self, tname: Name) -> Result<Rc<SyntaxExtension>, 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<Rc<SyntaxExtension>, 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 17b0b97468d..9a717b86d09 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<Attribute>) -> Option<Attribute>;
     fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
                      -> Result<Rc<SyntaxExtension>, Determinacy>;
+    fn resolve_builtin_macro(&mut self, tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy>;
+    fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
+                            -> Result<Rc<SyntaxExtension>, Determinacy>;
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -562,6 +565,13 @@ impl Resolver for DummyResolver {
                      -> Result<Rc<SyntaxExtension>, Determinacy> {
         Err(Determinacy::Determined)
     }
+    fn resolve_builtin_macro(&mut self, _tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy> {
+        Err(Determinacy::Determined)
+    }
+    fn resolve_derive_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
+                            -> Result<Rc<SyntaxExtension>, 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 00000000000..946448eaaee
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<ast::Attribute>,
+                       derive_type: DeriveType) -> Option<ast::Attribute> {
+    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<ast::Attribute>) {
+    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::<Vec<_>>();
+
+    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<ast::Attribute>)
+                        -> Option<ast::Attribute> {
+    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 01a8c215d47..8e7f8830eaf 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 @@ impl Invocation {
         match self.kind {
             InvocationKind::Bang { span, .. } => span,
             InvocationKind::Attr { ref attr, .. } => attr.span,
+            InvocationKind::Derive { ref attr, .. } => attr.span,
         }
     }
 }
@@ -250,6 +256,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     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 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         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 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         })
     }
 
+    /// Expand a derive invocation. Returns the result of expansion.
+    fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> 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::<Vec<_>>());
@@ -595,16 +674,31 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
 
     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<T: HasAttrs>(&mut self, mut item: T) -> (T, Option<ast::Attribute>) {
         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 25be9e91a6a..87a03adf6b7 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 e118ef1ea01..974e86a5741 100644
--- a/src/libsyntax_ext/deriving/custom.rs
+++ b/src/libsyntax_ext/deriving/custom.rs
@@ -54,7 +54,7 @@ impl MultiItemModifier for ProcMacroDerive {
             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 @@ impl MultiItemModifier for ProcMacroDerive {
             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 @@ impl MultiItemModifier for ProcMacroDerive {
         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::<String>() {
                     err.help(&format!("message: {}", s));
@@ -100,7 +100,7 @@ impl MultiItemModifier for ProcMacroDerive {
                 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 6359d642d15..498f2348b80 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 a276193e81b..9d155c22ad0 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 311b8ae41f8..3bceb02f3d6 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<Annotatable> {
-    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 e872cfaeacb..7533171b085 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 @@ pub mod proc_macro_impl;
 
 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 bc4da9fee47..42fad803bfa 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 @@ extern crate derive_bad;
 #[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 107273d012d..c483c048b41 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 596cc1e7d58..d388ece0844 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 be822a173ab..97a39a46c19 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 4a6dbf014a1..f467ba3b1e1 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 723e936212a..3f710af8ac9 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 ad1382cbc8e..9a5e2de14e3 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)]