]> git.lizzy.rs Git - rust.git/commitdiff
rustc: Implement custom derive (macros 1.1)
authorAlex Crichton <alex@alexcrichton.com>
Tue, 23 Aug 2016 00:07:11 +0000 (17:07 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 2 Sep 2016 19:52:56 +0000 (12:52 -0700)
This commit is an implementation of [RFC 1681] which adds support to the
compiler for first-class user-define custom `#[derive]` modes with a far more
stable API than plugins have today.

[RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md

The main features added by this commit are:

* A new `rustc-macro` crate-type. This crate type represents one which will
  provide custom `derive` implementations and perhaps eventually flower into the
  implementation of macros 2.0 as well.

* A new `rustc_macro` crate in the standard distribution. This crate will
  provide the runtime interface between macro crates and the compiler. The API
  here is particularly conservative right now but has quite a bit of room to
  expand into any manner of APIs required by macro authors.

* The ability to load new derive modes through the `#[macro_use]` annotations on
  other crates.

All support added here is gated behind the `rustc_macro` feature gate, both for
the library support (the `rustc_macro` crate) as well as the language features.

There are a few minor differences from the implementation outlined in the RFC,
such as the `rustc_macro` crate being available as a dylib and all symbols are
`dlsym`'d directly instead of having a shim compiled. These should only affect
the implementation, however, not the public interface.

This commit also ended up touching a lot of code related to `#[derive]`, making
a few notable changes:

* Recognized derive attributes are no longer desugared to `derive_Foo`. Wasn't
  sure how to keep this behavior and *not* expose it to custom derive.

* Derive attributes no longer have access to unstable features by default, they
  have to opt in on a granular level.

* The `derive(Copy,Clone)` optimization is now done through another "obscure
  attribute" which is just intended to ferry along in the compiler that such an
  optimization is possible. The `derive(PartialEq,Eq)` optimization was also
  updated to do something similar.

---

One part of this PR which needs to be improved before stabilizing are the errors
and exact interfaces here. The error messages are relatively poor quality and
there are surprising spects of this such as `#[derive(PartialEq, Eq, MyTrait)]`
not working by default. The custom attributes added by the compiler end up
becoming unstable again when going through a custom impl.

Hopefully though this is enough to start allowing experimentation on crates.io!

syntax-[breaking-change]

85 files changed:
mk/crates.mk
src/librustc/middle/dependency_format.rs
src/librustc/middle/reachable.rs
src/librustc/middle/weak_lang_items.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/ty/context.rs
src/librustc_driver/derive_registrar.rs [new file with mode: 0644]
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_macro/Cargo.toml [new file with mode: 0644]
src/librustc_macro/lib.rs [new file with mode: 0644]
src/librustc_metadata/Cargo.toml
src/librustc_metadata/common.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/lib.rs
src/librustc_metadata/macro_import.rs
src/librustc_plugin/registry.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/linker.rs
src/librustc_trans/back/symbol_names.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/feature_gate.rs
src/libsyntax_ext/Cargo.toml
src/libsyntax_ext/deriving/clone.rs
src/libsyntax_ext/deriving/custom.rs [new file with mode: 0644]
src/libsyntax_ext/deriving/mod.rs
src/libsyntax_ext/lib.rs
src/libsyntax_ext/rustc_macro_registrar.rs [new file with mode: 0644]
src/rustc/Cargo.lock
src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/attribute.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/define-two.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/exports.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/import.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/shadow.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/signature.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs [new file with mode: 0644]
src/test/compile-fail/issue-32655.rs
src/test/run-pass-fulldeps/rustc-macro/add-impl.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/load-two.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/rustc-macro/smoke.rs [new file with mode: 0644]
src/test/run-pass/associated-types-normalize-unifield-struct.rs
src/test/run-pass/builtin-superkinds-in-metadata.rs
src/test/run-pass/coherence-impl-in-fn.rs
src/test/run-pass/deriving-bounds.rs
src/test/run-pass/issue-20797.rs
src/test/run-pass/issue-2288.rs
src/test/run-pass/single-derive-attr-with-gate.rs [deleted file]
src/test/run-pass/sync-send-iterators-in-libcollections.rs

index a915d07384f3cd712dc012af7e5684e1ddb61c92..06ad07de136b1acea1de0f6db88140c22c66f851 100644 (file)
@@ -59,7 +59,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_
                 rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
                 rustc_data_structures rustc_platform_intrinsics rustc_errors \
                 rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \
-                rustc_const_eval rustc_const_math rustc_incremental
+                rustc_const_eval rustc_const_math rustc_incremental rustc_macro
 HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \
                flate arena graphviz rbml log serialize
 TOOLS := compiletest rustdoc rustc rustbook error_index_generator
@@ -99,7 +99,7 @@ DEPS_term := std
 DEPS_test := std getopts term native:rust_test_helpers
 
 DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos
-DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros
+DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro
 DEPS_proc_macro := syntax syntax_pos rustc_plugin log
 DEPS_syntax_pos := serialize
 
@@ -118,11 +118,13 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo
                      rustc_trans rustc_privacy rustc_lint rustc_plugin \
                      rustc_metadata syntax_ext proc_macro \
                      rustc_passes rustc_save_analysis rustc_const_eval \
-                     rustc_incremental syntax_pos rustc_errors
+                     rustc_incremental syntax_pos rustc_errors rustc_macro
 DEPS_rustc_errors := log libc serialize syntax_pos
 DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval
 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
-DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math
+DEPS_rustc_macro := std syntax
+DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math \
+                       rustc_macro syntax_ext
 DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors
 DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags
 DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors
index cf6905ecf439ab24400902c25129f22647894715..7822fe2536f1f7d06dba29ef227eb4689622b8ca 100644 (file)
@@ -139,8 +139,13 @@ fn calculate_type(sess: &session::Session,
             }
         }
 
-        // Everything else falls through below
-        config::CrateTypeExecutable | config::CrateTypeDylib => {},
+        // Everything else falls through below. This will happen either with the
+        // `-C prefer-dynamic` or because we're a rustc-macro crate. Note that
+        // rustc-macro crates are required to be dylibs, and they're currently
+        // required to link to libsyntax as well.
+        config::CrateTypeExecutable |
+        config::CrateTypeDylib |
+        config::CrateTypeRustcMacro => {},
     }
 
     let mut formats = FnvHashMap();
index e29a7cf9d68467a332147ee06ccf853825231ff6..1f9738556d9252b7dee6cf55e8c02c4ecce9fad0 100644 (file)
@@ -138,7 +138,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
     // Creates a new reachability computation context.
     fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> {
         let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
-            *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib
+            *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib ||
+            *ty == config::CrateTypeRustcMacro
         });
         ReachableContext {
             tcx: tcx,
index 6fb1b16705fe47fce509e180202bc25cf0a75cdd..c2f275e6deaf82671a27c49f4aad8e88b1bf43ad 100644 (file)
@@ -70,6 +70,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
     let needs_check = sess.crate_types.borrow().iter().any(|kind| {
         match *kind {
             config::CrateTypeDylib |
+            config::CrateTypeRustcMacro |
             config::CrateTypeCdylib |
             config::CrateTypeExecutable |
             config::CrateTypeStaticlib => true,
index 562dce6a1b129d9403f7552b24a9c9b08718725b..a2f926aa92c5232dce362799e18caa16c105a5d9 100644 (file)
@@ -475,6 +475,7 @@ pub enum CrateType {
     CrateTypeRlib,
     CrateTypeStaticlib,
     CrateTypeCdylib,
+    CrateTypeRustcMacro,
 }
 
 #[derive(Clone, Hash)]
@@ -962,6 +963,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
     if sess.opts.debug_assertions {
         ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
     }
+    if sess.opts.crate_types.contains(&CrateTypeRustcMacro) {
+        ret.push(attr::mk_word_item(InternedString::new("rustc_macro")));
+    }
     return ret;
 }
 
@@ -1547,6 +1551,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
                 "dylib"     => CrateTypeDylib,
                 "cdylib"    => CrateTypeCdylib,
                 "bin"       => CrateTypeExecutable,
+                "rustc-macro" => CrateTypeRustcMacro,
                 _ => {
                     return Err(format!("unknown crate type: `{}`",
                                        part));
@@ -1635,6 +1640,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             CrateTypeRlib => "rlib".fmt(f),
             CrateTypeStaticlib => "staticlib".fmt(f),
             CrateTypeCdylib => "cdylib".fmt(f),
+            CrateTypeRustcMacro => "rustc-macro".fmt(f),
         }
     }
 }
index 338c65637995919216cd0bb5148e091fe4452cd2..ee2837e7bf1ab5abc6ebaf626a1196439b69a49c 100644 (file)
@@ -62,6 +62,7 @@ pub struct Session {
     pub entry_fn: RefCell<Option<(NodeId, Span)>>,
     pub entry_type: Cell<Option<config::EntryFnType>>,
     pub plugin_registrar_fn: Cell<Option<ast::NodeId>>,
+    pub derive_registrar_fn: Cell<Option<ast::NodeId>>,
     pub default_sysroot: Option<PathBuf>,
     // The name of the root source file of the crate, in the local file system.
     // The path is always expected to be absolute. `None` means that there is no
@@ -314,6 +315,12 @@ pub fn generate_plugin_registrar_symbol(&self, svh: &Svh, index: DefIndex)
         format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize())
     }
 
+    pub fn generate_derive_registrar_symbol(&self,
+                                            svh: &Svh,
+                                            index: DefIndex) -> String {
+        format!("__rustc_derive_registrar__{}_{}", svh, index.as_usize())
+    }
+
     pub fn sysroot<'a>(&'a self) -> &'a Path {
         match self.opts.maybe_sysroot {
             Some (ref sysroot) => sysroot,
@@ -501,6 +508,7 @@ pub fn build_session_(sopts: config::Options,
         entry_fn: RefCell::new(None),
         entry_type: Cell::new(None),
         plugin_registrar_fn: Cell::new(None),
+        derive_registrar_fn: Cell::new(None),
         default_sysroot: default_sysroot,
         local_crate_source_file: local_crate_source_file,
         working_dir: env::current_dir().unwrap(),
index e048e618e84d66951cd38467f3b9b0c0d2037f2c..725bbf6adfd42c333d1433286a386c13d7f7ec1a 100644 (file)
@@ -495,6 +495,10 @@ pub struct GlobalCtxt<'tcx> {
 
     /// Cache for layouts computed from types.
     pub layout_cache: RefCell<FnvHashMap<Ty<'tcx>, &'tcx Layout>>,
+
+    /// Map from function to the `#[derive]` mode that it's defining. Only used
+    /// by `rustc-macro` crates.
+    pub derive_macros: RefCell<NodeMap<token::InternedString>>,
 }
 
 impl<'tcx> GlobalCtxt<'tcx> {
@@ -756,6 +760,7 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             crate_name: token::intern_and_get_ident(crate_name),
             data_layout: data_layout,
             layout_cache: RefCell::new(FnvHashMap()),
+            derive_macros: RefCell::new(NodeMap()),
        }, f)
     }
 }
diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs
new file mode 100644 (file)
index 0000000..ea7621e
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2016 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 rustc::dep_graph::DepNode;
+use rustc::hir::intravisit::Visitor;
+use rustc::hir::map::Map;
+use rustc::hir;
+use syntax::ast;
+use syntax::attr;
+
+pub fn find(hir_map: &Map) -> Option<ast::NodeId> {
+    let _task = hir_map.dep_graph.in_task(DepNode::PluginRegistrar);
+    let krate = hir_map.krate();
+
+    let mut finder = Finder { registrar: None };
+    krate.visit_all_items(&mut finder);
+    finder.registrar
+}
+
+struct Finder {
+    registrar: Option<ast::NodeId>,
+}
+
+impl<'v> Visitor<'v> for Finder {
+    fn visit_item(&mut self, item: &hir::Item) {
+        if attr::contains_name(&item.attrs, "rustc_derive_registrar") {
+            self.registrar = Some(item.id);
+        }
+    }
+}
index 94092be4922b52fd35fb764ca9293e5d04acc811..47a0399b63283ec4898d27a7cf462791c6e52253 100644 (file)
@@ -55,6 +55,8 @@
 use syntax;
 use syntax_ext;
 
+use derive_registrar;
+
 #[derive(Clone)]
 pub struct Resolutions {
     pub def_map: DefMap,
@@ -696,6 +698,18 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
                                          sess.diagnostic())
     });
 
+    krate = time(time_passes, "maybe creating a macro crate", || {
+        let crate_types = sess.crate_types.borrow();
+        let is_rustc_macro_crate = crate_types.contains(&config::CrateTypeRustcMacro);
+        let num_crate_types = crate_types.len();
+        syntax_ext::rustc_macro_registrar::modify(&sess.parse_sess,
+                                                  krate,
+                                                  is_rustc_macro_crate,
+                                                  num_crate_types,
+                                                  sess.diagnostic(),
+                                                  &sess.features.borrow())
+    });
+
     let resolver_arenas = Resolver::arenas();
     let mut resolver = Resolver::new(sess, make_glob_map, &resolver_arenas);
 
@@ -838,6 +852,7 @@ macro_rules! try_with_f {
     sess.plugin_registrar_fn.set(time(time_passes, "looking for plugin registrar", || {
         plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map)
     }));
+    sess.derive_registrar_fn.set(derive_registrar::find(&hir_map));
 
     let region_map = time(time_passes,
                           "region resolution",
@@ -1171,6 +1186,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
                          Some(ref n) if *n == "staticlib" => {
                              Some(config::CrateTypeStaticlib)
                          }
+                         Some(ref n) if *n == "rustc-macro" => {
+                             Some(config::CrateTypeRustcMacro)
+                         }
                          Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
                          Some(_) => {
                              session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
index efadf1ff488dfbee24919b4a0504c3246129d893..6616e9579e818dd2c190e9e645521302ad2b23e3 100644 (file)
 pub mod driver;
 pub mod pretty;
 pub mod target_features;
-
+mod derive_registrar;
 
 const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
                                       md#bug-reports";
diff --git a/src/librustc_macro/Cargo.toml b/src/librustc_macro/Cargo.toml
new file mode 100644 (file)
index 0000000..6b3ee21
--- /dev/null
@@ -0,0 +1,12 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_macro"
+version = "0.0.0"
+
+[lib]
+name = "rustc_macro"
+path = "lib.rs"
+crate-type = ["dylib"]
+
+[dependencies]
+syntax = { path = "../libsyntax" }
diff --git a/src/librustc_macro/lib.rs b/src/librustc_macro/lib.rs
new file mode 100644 (file)
index 0000000..c2a2cc2
--- /dev/null
@@ -0,0 +1,169 @@
+// Copyright 2016 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.
+
+//! A support library for macro authors when defining new macros.
+//!
+//! This library, provided by the standard distribution, provides the types
+//! consumed in the interfaces of procedurally defined macro definitions.
+//! Currently the primary use of this crate is to provide the ability to define
+//! new custom derive modes through `#[rustc_macro_derive]`.
+//!
+//! Added recently as part of [RFC 1681] this crate is currently *unstable* and
+//! requires the `#![feature(rustc_macro_lib)]` directive to use. Eventually,
+//! though, it is intended for this crate to become stable to use (perhaps under
+//! a different name).
+//!
+//! [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
+//!
+//! Note that this crate is intentionally very bare-bones currently. The main
+//! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
+//! implementations, indicating that it can only go to and come from a string.
+//! This functionality is intended to be expanded over time as more surface
+//! area for macro authors is stabilized.
+
+#![crate_name = "rustc_macro"]
+#![unstable(feature = "rustc_macro_lib", issue = "27812")]
+#![crate_type = "rlib"]
+#![crate_type = "dylib"]
+#![cfg_attr(not(stage0), deny(warnings))]
+#![deny(missing_docs)]
+
+#![feature(rustc_private)]
+#![feature(staged_api)]
+#![feature(lang_items)]
+
+extern crate syntax;
+
+use std::fmt;
+use std::str::FromStr;
+
+use syntax::ast;
+use syntax::parse;
+use syntax::ptr::P;
+
+/// The main type provided by this crate, representing an abstract stream of
+/// tokens.
+///
+/// This is both the input and output of `#[rustc_macro_derive]` definitions.
+/// Currently it's required to be a list of valid Rust items, but this
+/// restriction may be lifted in the future.
+///
+/// The API of this type is intentionally bare-bones, but it'll be expanded over
+/// time!
+pub struct TokenStream {
+    inner: Vec<P<ast::Item>>,
+}
+
+/// Error returned from `TokenStream::from_str`.
+#[derive(Debug)]
+pub struct LexError {
+    _inner: (),
+}
+
+/// Permanently unstable internal implementation details of this crate. This
+/// should not be used.
+///
+/// These methods are used by the rest of the compiler to generate instances of
+/// `TokenStream` to hand to macro definitions, as well as consume the output.
+///
+/// Note that this module is also intentionally separate from the rest of the
+/// crate. This allows the `#[unstable]` directive below to naturally apply to
+/// all of the contents.
+#[unstable(feature = "rustc_macro_internals", issue = "27812")]
+#[doc(hidden)]
+pub mod __internal {
+    use std::cell::Cell;
+
+    use syntax::ast;
+    use syntax::ptr::P;
+    use syntax::parse::ParseSess;
+    use super::TokenStream;
+
+    pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
+        TokenStream { inner: vec![item] }
+    }
+
+    pub fn token_stream_items(stream: TokenStream) -> Vec<P<ast::Item>> {
+        stream.inner
+    }
+
+    pub trait Registry {
+        fn register_custom_derive(&mut self,
+                                  trait_name: &str,
+                                  expand: fn(TokenStream) -> TokenStream);
+    }
+
+    // Emulate scoped_thread_local!() here essentially
+    thread_local! {
+        static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _);
+    }
+
+    pub fn set_parse_sess<F, R>(sess: &ParseSess, f: F) -> R
+        where F: FnOnce() -> R
+    {
+        struct Reset { prev: *const ParseSess }
+
+        impl Drop for Reset {
+            fn drop(&mut self) {
+                CURRENT_SESS.with(|p| p.set(self.prev));
+            }
+        }
+
+        CURRENT_SESS.with(|p| {
+            let _reset = Reset { prev: p.get() };
+            p.set(sess);
+            f()
+        })
+    }
+
+    pub fn with_parse_sess<F, R>(f: F) -> R
+        where F: FnOnce(&ParseSess) -> R
+    {
+        let p = CURRENT_SESS.with(|p| p.get());
+        assert!(!p.is_null());
+        f(unsafe { &*p })
+    }
+}
+
+impl FromStr for TokenStream {
+    type Err = LexError;
+
+    fn from_str(src: &str) -> Result<TokenStream, LexError> {
+        __internal::with_parse_sess(|sess| {
+            let src = src.to_string();
+            let cfg = Vec::new();
+            let name = "rustc-macro source code".to_string();
+            let mut parser = parse::new_parser_from_source_str(sess, cfg, name,
+                                                               src);
+            let mut ret = TokenStream { inner: Vec::new() };
+            loop {
+                match parser.parse_item() {
+                    Ok(Some(item)) => ret.inner.push(item),
+                    Ok(None) => return Ok(ret),
+                    Err(mut err) => {
+                        err.cancel();
+                        return Err(LexError { _inner: () })
+                    }
+                }
+            }
+        })
+    }
+}
+
+impl fmt::Display for TokenStream {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        for item in self.inner.iter() {
+            let item = syntax::print::pprust::item_to_string(item);
+            try!(f.write_str(&item));
+            try!(f.write_str("\n"));
+        }
+        Ok(())
+    }
+}
index 2d3302c2eef3a8078a4c6683a94f546770ed19b0..d70510896b96e97f7bd28a589a4bc16c79b48b72 100644 (file)
@@ -19,6 +19,8 @@ rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_llvm = { path = "../librustc_llvm" }
+rustc_macro = { path = "../librustc_macro" }
 serialize = { path = "../libserialize" }
 syntax = { path = "../libsyntax" }
-syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
+syntax_ext = { path = "../libsyntax_ext" }
+syntax_pos = { path = "../libsyntax_pos" }
index 85cf41e42a2737194e583093c55dd389970e0561..1e6c74bef8da570e2e3d8ec86a99c80dfd6609fa 100644 (file)
@@ -234,6 +234,8 @@ pub fn rustc_version() -> String {
 
 pub const tag_panic_strategy: usize = 0x114;
 
+pub const tag_macro_derive_registrar: usize = 0x115;
+
 // NB: increment this if you change the format of metadata such that
 // rustc_version can't be found.
 pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2];
index 7e1f3ea618c979f597a3f17128ad4aabfd565e74..2524348dc1a96e52f47fde721ee4236c31cd1159 100644 (file)
@@ -130,18 +130,23 @@ struct ExtensionCrate {
     metadata: PMDSource,
     dylib: Option<PathBuf>,
     target_only: bool,
+
+    ident: String,
+    name: String,
+    span: Span,
+    should_link: bool,
 }
 
 enum PMDSource {
     Registered(Rc<cstore::CrateMetadata>),
-    Owned(MetadataBlob),
+    Owned(loader::Library),
 }
 
 impl PMDSource {
     pub fn as_slice<'a>(&'a self) -> &'a [u8] {
         match *self {
             PMDSource::Registered(ref cmd) => cmd.data(),
-            PMDSource::Owned(ref mdb) => mdb.as_slice(),
+            PMDSource::Owned(ref lib) => lib.metadata.as_slice(),
         }
     }
 }
@@ -151,6 +156,17 @@ enum LoadResult {
     Loaded(loader::Library),
 }
 
+pub struct Macros {
+    pub macro_rules: Vec<ast::MacroDef>,
+
+    /// An array of pairs where the first element is the name of the custom
+    /// derive (e.g. the trait being derived) and the second element is the
+    /// index of the definition.
+    pub custom_derive_registrar: Option<DefIndex>,
+    pub svh: Svh,
+    pub dylib: Option<PathBuf>,
+}
+
 impl<'a> CrateReader<'a> {
     pub fn new(sess: &'a Session,
                cstore: &'a CStore,
@@ -281,6 +297,7 @@ fn register_crate(&mut self,
                       explicitly_linked: bool)
                       -> (ast::CrateNum, Rc<cstore::CrateMetadata>,
                           cstore::CrateSource) {
+        info!("register crate `extern crate {} as {}`", name, ident);
         self.verify_no_symbol_conflicts(span, &lib.metadata);
 
         // Claim this crate number and cache it
@@ -319,6 +336,11 @@ fn register_crate(&mut self,
             explicitly_linked: Cell::new(explicitly_linked),
         });
 
+        if decoder::get_derive_registrar_fn(cmeta.data.as_slice()).is_some() {
+            self.sess.span_err(span, "crates of the `rustc-macro` crate type \
+                                      cannot be linked at runtime");
+        }
+
         let source = cstore::CrateSource {
             dylib: dylib,
             rlib: rlib,
@@ -349,9 +371,11 @@ fn resolve_crate(&mut self,
                      kind: PathKind,
                      explicitly_linked: bool)
                      -> (ast::CrateNum, Rc<cstore::CrateMetadata>, cstore::CrateSource) {
+        info!("resolving crate `extern crate {} as {}`", name, ident);
         let result = match self.existing_match(name, hash, kind) {
             Some(cnum) => LoadResult::Previous(cnum),
             None => {
+                info!("falling back to a load");
                 let mut load_ctxt = loader::Context {
                     sess: self.sess,
                     span: span,
@@ -412,6 +436,7 @@ fn load(&mut self, loader: &mut loader::Context) -> Option<LoadResult> {
             self.cstore.iter_crate_data(|cnum, data| {
                 if data.name() == meta_name && meta_hash == data.hash() {
                     assert!(loader.hash.is_none());
+                    info!("load success, going to previous cnum: {}", cnum);
                     result = LoadResult::Previous(cnum);
                 }
             });
@@ -483,6 +508,8 @@ fn resolve_crate_deps(&mut self,
     }
 
     fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate {
+        info!("read extension crate {} `extern crate {} as {}` linked={}",
+              info.id, info.name, info.ident, info.should_link);
         let target_triple = &self.sess.opts.target_triple[..];
         let is_cross = target_triple != config::host_triple();
         let mut should_link = info.should_link && !is_cross;
@@ -533,16 +560,7 @@ fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCra
             }
             LoadResult::Loaded(library) => {
                 let dylib = library.dylib.clone();
-                let metadata = if should_link {
-                    // Register crate now to avoid double-reading metadata
-                    let (_, cmd, _) = self.register_crate(&None, &info.ident,
-                                                          &info.name, span,
-                                                          library, true);
-                    PMDSource::Registered(cmd)
-                } else {
-                    // Not registering the crate; just hold on to the metadata
-                    PMDSource::Owned(library.metadata)
-                };
+                let metadata = PMDSource::Owned(library);
                 (dylib, metadata)
             }
         };
@@ -551,59 +569,97 @@ fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCra
             metadata: metadata,
             dylib: dylib.map(|p| p.0),
             target_only: target_only,
+            name: info.name.to_string(),
+            ident: info.ident.to_string(),
+            span: span,
+            should_link: should_link,
         }
     }
 
-    /// Read exported macros.
-    pub fn read_exported_macros(&mut self, item: &ast::Item) -> Vec<ast::MacroDef> {
+    pub fn read_macros(&mut self, item: &ast::Item) -> Macros {
         let ci = self.extract_crate_info(item).unwrap();
         let ekrate = self.read_extension_crate(item.span, &ci);
 
         let source_name = format!("<{} macros>", item.ident);
-        let mut macros = vec![];
+        let mut ret = Macros {
+            macro_rules: Vec::new(),
+            custom_derive_registrar: None,
+            svh: decoder::get_crate_hash(ekrate.metadata.as_slice()),
+            dylib: None,
+        };
         decoder::each_exported_macro(ekrate.metadata.as_slice(),
-            |name, attrs, span, body| {
-                // NB: Don't use parse::parse_tts_from_source_str because it parses with
-                // quote_depth > 0.
-                let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
-                                                              self.local_crate_config.clone(),
-                                                              source_name.clone(),
-                                                              body);
-                let lo = p.span.lo;
-                let body = match p.parse_all_token_trees() {
-                    Ok(body) => body,
-                    Err(mut err) => {
-                        err.emit();
-                        self.sess.abort_if_errors();
-                        unreachable!();
-                    }
-                };
-                let local_span = mk_sp(lo, p.last_span.hi);
-
-                // Mark the attrs as used
-                for attr in &attrs {
-                    attr::mark_used(attr);
+                                     |name, attrs, span, body| {
+            // NB: Don't use parse::parse_tts_from_source_str because it parses with
+            // quote_depth > 0.
+            let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
+                                                          self.local_crate_config.clone(),
+                                                          source_name.clone(),
+                                                          body);
+            let lo = p.span.lo;
+            let body = match p.parse_all_token_trees() {
+                Ok(body) => body,
+                Err(mut err) => {
+                    err.emit();
+                    self.sess.abort_if_errors();
+                    unreachable!();
                 }
+            };
+            let local_span = mk_sp(lo, p.last_span.hi);
 
-                macros.push(ast::MacroDef {
-                    ident: ast::Ident::with_empty_ctxt(name),
-                    attrs: attrs,
-                    id: ast::DUMMY_NODE_ID,
-                    span: local_span,
-                    imported_from: Some(item.ident),
-                    // overridden in plugin/load.rs
-                    export: false,
-                    use_locally: false,
-                    allow_internal_unstable: false,
-
-                    body: body,
-                });
-                self.sess.imported_macro_spans.borrow_mut()
-                    .insert(local_span, (name.as_str().to_string(), span));
-                true
+            // Mark the attrs as used
+            for attr in &attrs {
+                attr::mark_used(attr);
+            }
+
+            ret.macro_rules.push(ast::MacroDef {
+                ident: ast::Ident::with_empty_ctxt(name),
+                attrs: attrs,
+                id: ast::DUMMY_NODE_ID,
+                span: local_span,
+                imported_from: Some(item.ident),
+                // overridden in plugin/load.rs
+                export: false,
+                use_locally: false,
+                allow_internal_unstable: false,
+
+                body: body,
+            });
+            self.sess.imported_macro_spans.borrow_mut()
+                .insert(local_span, (name.as_str().to_string(), span));
+            true
+        });
+
+        match decoder::get_derive_registrar_fn(ekrate.metadata.as_slice()) {
+            Some(id) => ret.custom_derive_registrar = Some(id),
+
+            // If this crate is not a rustc-macro crate then we might be able to
+            // register it with the local crate store to prevent loading the
+            // metadata twice.
+            //
+            // If it's a rustc-macro crate, though, then we definitely don't
+            // want to register it with the local crate store as we're just
+            // going to use it as we would a plugin.
+            None => {
+                ekrate.register(self);
+                return ret
             }
-        );
-        macros
+        }
+
+        self.cstore.add_used_for_derive_macros(item);
+        ret.dylib = ekrate.dylib.clone();
+        if ret.dylib.is_none() {
+            span_bug!(item.span, "rustc-macro crate not dylib");
+        }
+
+        if ekrate.target_only {
+            let message = format!("rustc-macro crate is not available for \
+                                   triple `{}` (only found {})",
+                                  config::host_triple(),
+                                  self.sess.opts.target_triple);
+            self.sess.span_fatal(item.span, &message);
+        }
+
+        return ret
     }
 
     /// Look for a plugin registrar. Returns library path, crate
@@ -774,6 +830,7 @@ fn inject_allocator_crate(&mut self) {
             match *ct {
                 config::CrateTypeExecutable => need_exe_alloc = true,
                 config::CrateTypeDylib |
+                config::CrateTypeRustcMacro |
                 config::CrateTypeCdylib |
                 config::CrateTypeStaticlib => need_lib_alloc = true,
                 config::CrateTypeRlib => {}
@@ -858,6 +915,27 @@ fn inject_dependency_if(&self,
     }
 }
 
+impl ExtensionCrate {
+    fn register(self, creader: &mut CrateReader) {
+        if !self.should_link {
+            return
+        }
+
+        let library = match self.metadata {
+            PMDSource::Owned(lib) => lib,
+            PMDSource::Registered(_) => return,
+        };
+
+        // Register crate now to avoid double-reading metadata
+        creader.register_crate(&None,
+                               &self.ident,
+                               &self.name,
+                               self.span,
+                               library,
+                               true);
+    }
+}
+
 impl<'a> LocalCrateReader<'a> {
     fn new(sess: &'a Session,
            cstore: &'a CStore,
@@ -906,11 +984,25 @@ fn process_crate(&self, c: &ast::Crate) {
     fn process_item(&mut self, i: &ast::Item) {
         match i.node {
             ast::ItemKind::ExternCrate(_) => {
-                if !should_link(i) {
-                    return;
+                // If this `extern crate` item has `#[macro_use]` then we can
+                // safely skip it. These annotations were processed during macro
+                // expansion and are already loaded (if necessary) into our
+                // crate store.
+                //
+                // Note that it's important we *don't* fall through below as
+                // some `#[macro_use]` crate are explicitly not linked (e.g.
+                // macro crates) so we want to ensure we avoid `resolve_crate`
+                // with those.
+                if attr::contains_name(&i.attrs, "macro_use") {
+                    if self.cstore.was_used_for_derive_macros(i) {
+                        return
+                    }
                 }
 
                 if let Some(info) = self.creader.extract_crate_info(i) {
+                    if !info.should_link {
+                        return;
+                    }
                     let (cnum, _, _) = self.creader.resolve_crate(&None,
                                                                   &info.ident,
                                                                   &info.name,
index d786cc5ba0eb7865bbc58e4f2e3c267a1417e58b..952d7008d0f272546ea8bac832c178f131e5d234 100644 (file)
 use rustc::middle::cstore::ExternCrate;
 use rustc::session::config::PanicStrategy;
 use rustc_data_structures::indexed_vec::IndexVec;
-use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
+use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet};
 
 use std::cell::{RefCell, Ref, Cell};
 use std::rc::Rc;
 use std::path::PathBuf;
 use flate::Bytes;
-use syntax::ast;
+use syntax::ast::{self, Ident};
 use syntax::attr;
 use syntax::codemap;
 use syntax_pos;
@@ -115,6 +115,7 @@ pub struct CStore {
     pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
     pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
     pub visible_parent_map: RefCell<DefIdMap<DefId>>,
+    pub used_for_derive_macro: RefCell<FnvHashSet<Ident>>,
 }
 
 impl CStore {
@@ -130,6 +131,7 @@ pub fn new(dep_graph: &DepGraph) -> CStore {
             visible_parent_map: RefCell::new(FnvHashMap()),
             inlined_item_cache: RefCell::new(FnvHashMap()),
             defid_for_inlined_node: RefCell::new(FnvHashMap()),
+            used_for_derive_macro: RefCell::new(FnvHashSet()),
         }
     }
 
@@ -286,6 +288,14 @@ pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<ast::Crate
     {
         self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
     }
+
+    pub fn was_used_for_derive_macros(&self, i: &ast::Item) -> bool {
+        self.used_for_derive_macro.borrow().contains(&i.ident)
+    }
+
+    pub fn add_used_for_derive_macros(&self, i: &ast::Item) {
+        self.used_for_derive_macro.borrow_mut().insert(i.ident);
+    }
 }
 
 impl CrateMetadata {
index 7117cdb731cf37ead26f56676ac61bd8854d43a0..9a13be8ade52a9ff26d79e61a54db41a9d5f2046 100644 (file)
@@ -1398,6 +1398,11 @@ pub fn each_exported_macro<F>(data: &[u8], mut f: F) where
     }
 }
 
+pub fn get_derive_registrar_fn(data: &[u8]) -> Option<DefIndex> {
+    reader::maybe_get_doc(rbml::Doc::new(data), tag_macro_derive_registrar)
+        .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc)))
+}
+
 pub fn get_macro_span(doc: rbml::Doc) -> Span {
     let lo_doc = reader::get_doc(doc, tag_macro_def_span_lo);
     let lo = BytePos(reader::doc_as_u32(lo_doc));
index b3ac678d7120d276eddbaf6a68f9ede0799c8420..bb4cf70bd3b3e0435c1fa7633a3edac86815b380 100644 (file)
@@ -31,7 +31,7 @@
 
 use rustc::hir::svh::Svh;
 use rustc::mir::mir_map::MirMap;
-use rustc::session::config::{self, PanicStrategy};
+use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro};
 use rustc::util::nodemap::{FnvHashMap, NodeSet};
 
 use rustc_serialize::Encodable;
@@ -1567,7 +1567,8 @@ fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) {
 
 /// Serialize the text of the exported macros
 fn encode_macro_defs(rbml_w: &mut Encoder,
-                     krate: &hir::Crate) {
+                     krate: &hir::Crate,
+                     tcx: TyCtxt) {
     rbml_w.start_tag(tag_macro_defs);
     for def in &krate.exported_macros {
         rbml_w.start_tag(tag_macro_def);
@@ -1585,6 +1586,12 @@ fn encode_macro_defs(rbml_w: &mut Encoder,
         rbml_w.end_tag();
     }
     rbml_w.end_tag();
+
+    if tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro) {
+        let id = tcx.sess.derive_registrar_fn.get().unwrap();
+        let did = tcx.map.local_def_id(id);
+        rbml_w.wr_tagged_u32(tag_macro_derive_registrar, did.index.as_u32());
+    }
 }
 
 fn encode_struct_field_attrs(ecx: &EncodeContext,
@@ -1882,7 +1889,7 @@ struct Stats {
 
     // Encode macro definitions
     i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_macro_defs(rbml_w, krate);
+    encode_macro_defs(rbml_w, krate, ecx.tcx);
     stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
 
     // Encode the def IDs of impls, for coherence checking.
index a96fa8a006d8967bb4039147d0104c255c1d0993..a3afb9d84bd30d22e19283b9a5eec3639bdf001c 100644 (file)
 
 #![feature(box_patterns)]
 #![feature(enumset)]
+#![feature(question_mark)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(rustc_macro_lib)]
+#![feature(rustc_macro_internals)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(question_mark)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
 extern crate rbml;
 extern crate serialize as rustc_serialize; // used by deriving
 extern crate rustc_errors as errors;
+extern crate syntax_ext;
 
 #[macro_use]
 extern crate rustc;
 extern crate rustc_data_structures;
 extern crate rustc_back;
 extern crate rustc_llvm;
+extern crate rustc_macro;
 extern crate rustc_const_math;
 
 pub use rustc::middle;
index fa31b6f4c7224e0ae7e899b41ea422dfe59d7296..22691975050e5f8750416b2d44f926e3e00e85d2 100644 (file)
 
 //! Used by `rustc` when loading a crate with exported macros.
 
-use creader::CrateReader;
+use std::collections::HashSet;
+use std::env;
+use std::mem;
+
+use creader::{CrateReader, Macros};
 use cstore::CStore;
 
+use rustc::hir::def_id::DefIndex;
 use rustc::session::Session;
-use rustc::util::nodemap::{FnvHashSet, FnvHashMap};
-
-use syntax::parse::token;
+use rustc::util::nodemap::FnvHashMap;
+use rustc_back::dynamic_lib::DynamicLibrary;
+use rustc_macro::TokenStream;
+use rustc_macro::__internal::Registry;
 use syntax::ast;
 use syntax::attr;
+use syntax::ext::base::LoadedMacro;
 use syntax::ext;
+use syntax::parse::token;
+use syntax_ext::deriving::custom::CustomDerive;
 use syntax_pos::Span;
 
 pub struct MacroLoader<'a> {
@@ -47,7 +56,9 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) {
 pub type MacroSelection = FnvHashMap<token::InternedString, Span>;
 
 impl<'a> ext::base::MacroLoader for MacroLoader<'a> {
-    fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<ast::MacroDef> {
+    fn load_crate(&mut self,
+                  extern_crate: &ast::Item,
+                  allows_macros: bool) -> Vec<LoadedMacro> {
         // Parse the attributes relating to macros.
         let mut import = Some(FnvHashMap());  // None => load all
         let mut reexport = FnvHashMap();
@@ -105,7 +116,7 @@ fn load_macros<'b>(&mut self,
                        allows_macros: bool,
                        import: Option<MacroSelection>,
                        reexport: MacroSelection)
-                       -> Vec<ast::MacroDef> {
+                       -> Vec<LoadedMacro> {
         if let Some(sel) = import.as_ref() {
             if sel.is_empty() && reexport.is_empty() {
                 return Vec::new();
@@ -118,10 +129,11 @@ fn load_macros<'b>(&mut self,
             return Vec::new();
         }
 
-        let mut macros = Vec::new();
-        let mut seen = FnvHashSet();
+        let mut macros = self.reader.read_macros(vi);
+        let mut ret = Vec::new();
+        let mut seen = HashSet::new();
 
-        for mut def in self.reader.read_exported_macros(vi) {
+        for mut def in macros.macro_rules.drain(..) {
             let name = def.ident.name.as_str();
 
             def.use_locally = match import.as_ref() {
@@ -132,10 +144,29 @@ fn load_macros<'b>(&mut self,
             def.allow_internal_unstable = attr::contains_name(&def.attrs,
                                                               "allow_internal_unstable");
             debug!("load_macros: loaded: {:?}", def);
-            macros.push(def);
+            ret.push(LoadedMacro::Def(def));
             seen.insert(name);
         }
 
+        if let Some(index) = macros.custom_derive_registrar {
+            // custom derive crates currently should not have any macro_rules!
+            // exported macros, enforced elsewhere
+            assert_eq!(ret.len(), 0);
+
+            if import.is_some() {
+                self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \
+                                             selectively imported from, must \
+                                             use `#[macro_use]`");
+            }
+
+            if reexport.len() > 0 {
+                self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \
+                                             reexported from");
+            }
+
+            self.load_derive_macros(vi.span, &macros, index, &mut ret);
+        }
+
         if let Some(sel) = import.as_ref() {
             for (name, span) in sel {
                 if !seen.contains(&name) {
@@ -152,6 +183,54 @@ fn load_macros<'b>(&mut self,
             }
         }
 
-        macros
+        return ret
+    }
+
+    /// Load the custom derive macros into the list of macros we're loading.
+    ///
+    /// Note that this is intentionally similar to how we load plugins today,
+    /// but also intentionally separate. Plugins are likely always going to be
+    /// implemented as dynamic libraries, but we have a possible future where
+    /// custom derive (and other macro-1.1 style features) are implemented via
+    /// executables and custom IPC.
+    fn load_derive_macros(&mut self,
+                          span: Span,
+                          macros: &Macros,
+                          index: DefIndex,
+                          ret: &mut Vec<LoadedMacro>) {
+        // Make sure the path contains a / or the linker will search for it.
+        let path = macros.dylib.as_ref().unwrap();
+        let path = env::current_dir().unwrap().join(path);
+        let lib = match DynamicLibrary::open(Some(&path)) {
+            Ok(lib) => lib,
+            Err(err) => self.sess.span_fatal(span, &err),
+        };
+
+        let sym = self.sess.generate_derive_registrar_symbol(&macros.svh, index);
+        let registrar = unsafe {
+            let sym = match lib.symbol(&sym) {
+                Ok(f) => f,
+                Err(err) => self.sess.span_fatal(span, &err),
+            };
+            mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
+        };
+
+        struct MyRegistrar<'a>(&'a mut Vec<LoadedMacro>);
+
+        impl<'a> Registry for MyRegistrar<'a> {
+            fn register_custom_derive(&mut self,
+                                      trait_name: &str,
+                                      expand: fn(TokenStream) -> TokenStream) {
+                let derive = Box::new(CustomDerive::new(expand));
+                self.0.push(LoadedMacro::CustomDerive(trait_name.to_string(),
+                                                      derive));
+            }
+        }
+
+        registrar(&mut MyRegistrar(ret));
+
+        // Intentionally leak the dynamic library. We can't ever unload it
+        // since the library can make things that will live arbitrarily long.
+        mem::forget(lib);
     }
 }
index 5ae6584aed4259ed204fd71bf96a67fa6a1a103c..6db821b2cd8d19e3001110f251000e10c62cf243 100644 (file)
@@ -156,7 +156,6 @@ pub fn register_llvm_pass(&mut self, name: &str) {
         self.llvm_passes.push(name.to_owned());
     }
 
-
     /// Register an attribute with an attribute type.
     ///
     /// Registered attributes will bypass the `custom_attribute` feature gate.
index b21785c27dae5e50967ec55912ece1c227af1118..b970c63a2243369d66785f66b757d6b7456a6a1e 100644 (file)
@@ -238,6 +238,7 @@ pub fn invalid_output_for_target(sess: &Session,
     match (sess.target.target.options.dynamic_linking,
            sess.target.target.options.executables, crate_type) {
         (false, _, config::CrateTypeCdylib) |
+        (false, _, config::CrateTypeRustcMacro) |
         (false, _, config::CrateTypeDylib) => true,
         (_, false, config::CrateTypeExecutable) => true,
         _ => false
@@ -261,6 +262,7 @@ pub fn filename_for_input(sess: &Session,
             outputs.out_directory.join(&format!("lib{}.rlib", libname))
         }
         config::CrateTypeCdylib |
+        config::CrateTypeRustcMacro |
         config::CrateTypeDylib => {
             let (prefix, suffix) = (&sess.target.target.options.dll_prefix,
                                     &sess.target.target.options.dll_suffix);
@@ -291,7 +293,8 @@ pub fn each_linked_rlib(sess: &Session,
     let fmts = sess.dependency_formats.borrow();
     let fmts = fmts.get(&config::CrateTypeExecutable)
                    .or_else(|| fmts.get(&config::CrateTypeStaticlib))
-                   .or_else(|| fmts.get(&config::CrateTypeCdylib));
+                   .or_else(|| fmts.get(&config::CrateTypeCdylib))
+                   .or_else(|| fmts.get(&config::CrateTypeRustcMacro));
     let fmts = fmts.unwrap_or_else(|| {
         bug!("could not find formats for rlibs")
     });
@@ -738,7 +741,8 @@ fn link_args(cmd: &mut Linker,
     // When linking a dynamic library, we put the metadata into a section of the
     // executable. This metadata is in a separate object file from the main
     // object file, so we link that in here.
-    if crate_type == config::CrateTypeDylib {
+    if crate_type == config::CrateTypeDylib ||
+       crate_type == config::CrateTypeRustcMacro {
         cmd.add_object(&outputs.with_extension("metadata.o"));
     }
 
index f2d5b128d270533ed9ebea7ccf17788d29e367a0..58cad5c117f934a5b7908935c49cc340c15cc66c 100644 (file)
@@ -8,10 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::collections::HashMap;
 use std::ffi::OsString;
 use std::fs::{self, File};
-use std::io::{self, BufWriter};
 use std::io::prelude::*;
+use std::io::{self, BufWriter};
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
 /// For all the linkers we support, and information they might
 /// need out of the shared crate context before we get rid of it.
 pub struct LinkerInfo {
-    dylib_exports: Vec<String>,
-    cdylib_exports: Vec<String>
+    exports: HashMap<CrateType, Vec<String>>,
 }
 
 impl<'a, 'tcx> LinkerInfo {
     pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
                reachable: &[String]) -> LinkerInfo {
         LinkerInfo {
-            dylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeDylib),
-            cdylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeCdylib)
+            exports: scx.sess().crate_types.borrow().iter().map(|&c| {
+                (c, exported_symbols(scx, reachable, c))
+            }).collect(),
         }
     }
 
@@ -243,7 +244,8 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
         // exported symbols to ensure we don't expose any more. The object files
         // have far more public symbols than we actually want to export, so we
         // hide them all here.
-        if crate_type == CrateType::CrateTypeDylib {
+        if crate_type == CrateType::CrateTypeDylib ||
+           crate_type == CrateType::CrateTypeRustcMacro {
             return
         }
 
@@ -254,7 +256,7 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
             let res = (|| -> io::Result<()> {
                 let mut f = BufWriter::new(File::create(&path)?);
                 writeln!(f, "{{\n  global:")?;
-                for sym in &self.info.cdylib_exports {
+                for sym in self.info.exports[&crate_type].iter() {
                     writeln!(f, "    {};", sym)?;
                 }
                 writeln!(f, "\n  local:\n    *;\n}};")?;
@@ -274,7 +276,7 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
             };
             let res = (|| -> io::Result<()> {
                 let mut f = BufWriter::new(File::create(&path)?);
-                for sym in &self.info.cdylib_exports {
+                for sym in self.info.exports[&crate_type].iter() {
                     writeln!(f, "{}{}", prefix, sym)?;
                 }
                 Ok(())
@@ -427,12 +429,7 @@ fn export_symbols(&mut self,
             // straight to exports.
             writeln!(f, "LIBRARY")?;
             writeln!(f, "EXPORTS")?;
-            let symbols = if crate_type == CrateType::CrateTypeCdylib {
-                &self.info.cdylib_exports
-            } else {
-                &self.info.dylib_exports
-            };
-            for symbol in symbols {
+            for symbol in self.info.exports[&crate_type].iter() {
                 writeln!(f, "  {}", symbol)?;
             }
             Ok(())
@@ -450,13 +447,10 @@ fn exported_symbols(scx: &SharedCrateContext,
                     reachable: &[String],
                     crate_type: CrateType)
                     -> Vec<String> {
-    if !scx.sess().crate_types.borrow().contains(&crate_type) {
-        return vec![];
-    }
-
     // See explanation in GnuLinker::export_symbols, for
     // why we don't ever need dylib symbols on non-MSVC.
-    if crate_type == CrateType::CrateTypeDylib {
+    if crate_type == CrateType::CrateTypeDylib ||
+       crate_type == CrateType::CrateTypeRustcMacro {
         if !scx.sess().target.target.options.is_like_msvc {
             return vec![];
         }
index 9b02cbe6721f34e6dd3118250373c1345240fa02..143275fa7117b4eed8755191b8de8e147a426864 100644 (file)
@@ -188,6 +188,11 @@ pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
                 let idx = def_id.index;
                 return scx.sess().generate_plugin_registrar_symbol(svh, idx);
             }
+            if scx.sess().derive_registrar_fn.get() == Some(id) {
+                let svh = &scx.link_meta().crate_hash;
+                let idx = def_id.index;
+                return scx.sess().generate_derive_registrar_symbol(svh, idx);
+            }
         }
 
         // FIXME(eddyb) Precompute a custom symbol name based on attributes.
index 43e190f5deb813d26cfcb13f2c11ec919df40fc1..3b1c01319c492fc6b825250da7433c35038a50e1 100644 (file)
 use util::small_vector::SmallVector;
 use util::lev_distance::find_best_match_for_name;
 use fold::Folder;
+use feature_gate;
 
 use std::collections::{HashMap, HashSet};
 use std::rc::Rc;
-use std::default::Default;
 use tokenstream;
 
 
@@ -568,12 +568,18 @@ fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
 }
 
 pub trait MacroLoader {
-    fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<ast::MacroDef>;
+    fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool)
+                  -> Vec<LoadedMacro>;
+}
+
+pub enum LoadedMacro {
+    Def(ast::MacroDef),
+    CustomDerive(String, Box<MultiItemModifier>),
 }
 
 pub struct DummyMacroLoader;
 impl MacroLoader for DummyMacroLoader {
-    fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec<ast::MacroDef> {
+    fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec<LoadedMacro> {
         Vec::new()
     }
 }
@@ -593,6 +599,7 @@ pub struct ExtCtxt<'a> {
     pub exported_macros: Vec<ast::MacroDef>,
 
     pub syntax_env: SyntaxEnv,
+    pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
     pub recursion_count: usize,
 
     pub filename: Option<String>,
@@ -616,6 +623,7 @@ pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
             exported_macros: Vec::new(),
             loader: loader,
             syntax_env: env,
+            derive_modes: HashMap::new(),
             recursion_count: 0,
 
             filename: None,
@@ -714,6 +722,25 @@ pub fn insert_macro(&mut self, def: ast::MacroDef) {
         }
     }
 
+    pub fn insert_custom_derive(&mut self,
+                                name: &str,
+                                ext: Box<MultiItemModifier>,
+                                sp: Span) {
+        if !self.ecfg.enable_rustc_macro() {
+            feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic,
+                                           "rustc_macro",
+                                           sp,
+                                           feature_gate::GateIssue::Language,
+                                           "loading custom derive macro crates \
+                                            is experimentally supported");
+        }
+        let name = token::intern_and_get_ident(name);
+        if self.derive_modes.insert(name.clone(), ext).is_some() {
+            self.span_err(sp, &format!("cannot shadow existing derive mode `{}`",
+                                       name));
+        }
+    }
+
     pub fn struct_span_warn(&self,
                             sp: Span,
                             msg: &str)
index 15ebf95d6239370e76ce470dae113680613dbfd4..d06b77a5b0549a0eb2d5c32d0096667996b045c8 100644 (file)
@@ -440,8 +440,7 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVe
                 callee: NameAndSpan {
                     format: MacroAttribute(intern(&attr.name())),
                     span: Some(attr.span),
-                    // attributes can do whatever they like, for now
-                    allow_internal_unstable: true,
+                    allow_internal_unstable: false,
                 }
             });
 
@@ -538,7 +537,12 @@ fn visit_item(&mut self, item: &ast::Item) {
                     // We need to error on `#[macro_use] extern crate` when it isn't at the
                     // crate root, because `$crate` won't work properly.
                     for def in self.cx.loader.load_crate(item, self.at_crate_root) {
-                        self.cx.insert_macro(def);
+                        match def {
+                            LoadedMacro::Def(def) => self.cx.insert_macro(def),
+                            LoadedMacro::CustomDerive(name, ext) => {
+                                self.cx.insert_custom_derive(&name, ext, item.span);
+                            }
+                        }
                     }
                 } else {
                     let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false);
@@ -688,6 +692,7 @@ fn enable_trace_macros = trace_macros,
         fn enable_allow_internal_unstable = allow_internal_unstable,
         fn enable_custom_derive = custom_derive,
         fn enable_pushpop_unsafe = pushpop_unsafe,
+        fn enable_rustc_macro = rustc_macro,
     }
 }
 
index 02c44c3a56d7e61e31c8820535a54aebe5332de4..683d5277359e84e430dd8504a81aab2bf4d0fe64 100644 (file)
@@ -47,7 +47,7 @@ fn f(features: &mut Features) -> &mut bool {
 }
 
 macro_rules! declare_features {
-    ($((active, $feature: ident, $ver: expr, $issue: expr)),+) => {
+    ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => {
         /// Represents active features that are currently being implemented or
         /// currently being considered for addition/removal.
         const ACTIVE_FEATURES: &'static [(&'static str, &'static str,
@@ -75,14 +75,14 @@ pub fn new() -> Features {
         }
     };
 
-    ($((removed, $feature: ident, $ver: expr, $issue: expr)),+) => {
+    ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
         /// Represents features which has since been removed (it was once Active)
         const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
             $((stringify!($feature), $ver, $issue)),+
         ];
     };
 
-    ($((accepted, $feature: ident, $ver: expr, $issue: expr)),+) => {
+    ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
         /// Those language feature has since been Accepted (it was once Active)
         const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
             $((stringify!($feature), $ver, $issue)),+
@@ -288,7 +288,10 @@ pub fn new() -> Features {
     (active, abi_sysv64, "1.13.0", Some(36167)),
 
     // Use the import semantics from RFC 1560.
-    (active, item_like_imports, "1.13.0", Some(35120))
+    (active, item_like_imports, "1.13.0", Some(35120)),
+
+    // Macros 1.1
+    (active, rustc_macro, "1.13.0", Some(35900)),
 );
 
 declare_features! (
@@ -302,7 +305,6 @@ pub fn new() -> Features {
     (removed, struct_inherit, "1.0.0", None),
     (removed, test_removed_feature, "1.0.0", None),
     (removed, visible_private_types, "1.0.0", None),
-    (removed, unsafe_no_drop_flag, "1.0.0", None)
 );
 
 declare_features! (
@@ -330,7 +332,7 @@ pub fn new() -> Features {
     (accepted, type_macros, "1.13.0", Some(27245)),
     (accepted, while_let, "1.0.0", None),
     // Allows `#[deprecated]` attribute
-    (accepted, deprecated, "1.9.0", Some(29935))
+    (accepted, deprecated, "1.9.0", Some(29935)),
 );
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -543,6 +545,15 @@ fn f(features: &Features) -> bool {
                                    is an experimental feature",
                                   cfg_fn!(linked_from))),
 
+    ("rustc_macro_derive", Normal, Gated("rustc_macro",
+                                         "the `#[rustc_macro_derive]` attribute \
+                                          is an experimental feature",
+                                         cfg_fn!(rustc_macro))),
+
+    ("rustc_copy_clone_marker", Whitelisted, Gated("rustc_attrs",
+                                                   "internal implementation detail",
+                                                   cfg_fn!(rustc_attrs))),
+
     // FIXME: #14408 whitelist docs since rustdoc looks at them
     ("doc", Whitelisted, Ungated),
 
@@ -616,6 +627,7 @@ fn f(features: &Features) -> bool {
     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
     ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
     ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
+    ("rustc_macro", "rustc_macro", cfg_fn!(rustc_macro)),
 ];
 
 #[derive(Debug, Eq, PartialEq)]
index 040c6c8ebff26db4dc39724b2117cfa0cae9675b..6910e6400d4f8e42966c11ee1d8e793742d5bdd6 100644 (file)
@@ -11,6 +11,7 @@ crate-type = ["dylib"]
 [dependencies]
 fmt_macros = { path = "../libfmt_macros" }
 log = { path = "../liblog" }
+rustc_errors = { path = "../librustc_errors" }
+rustc_macro = { path = "../librustc_macro" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
-rustc_errors = { path = "../librustc_errors" }
\ No newline at end of file
index f1a3a1f41b14ee37cb4b7ed025700f99112ca1e1..c7afaaf4796a4d7229276f39771370e371f1cddc 100644 (file)
@@ -49,7 +49,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
                 ItemKind::Struct(_, Generics { ref ty_params, .. }) |
                 ItemKind::Enum(_, Generics { ref ty_params, .. })
                     if ty_params.is_empty() &&
-                       attr::contains_name(&annitem.attrs, "derive_Copy") => {
+                       attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") => {
 
                     bounds = vec![Literal(path_std!(cx, core::marker::Copy))];
                     unify_fieldless_variants = true;
@@ -110,12 +110,12 @@ fn cs_clone(name: &str,
         Mode::Shallow => cx.std_path(&["clone", "assert_receiver_is_clone"]),
         Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]),
     };
-    let subcall = |field: &FieldInfo| {
+    let subcall = |cx: &mut ExtCtxt, field: &FieldInfo| {
         let args = vec![cx.expr_addr_of(field.span, field.self_.clone())];
 
         let span = if mode == Mode::Shallow {
             // set the expn ID so we can call the unstable method
-            Span { expn_id: cx.backtrace(), ..trait_span }
+            super::allow_unstable(cx, field.span, "derive(Clone)")
         } else {
             field.span
         };
@@ -147,8 +147,10 @@ fn cs_clone(name: &str,
 
     match mode {
         Mode::Shallow => {
-            let mut stmts: Vec<_> =
-                all_fields.iter().map(subcall).map(|e| cx.stmt_expr(e)).collect();
+            let mut stmts = all_fields.iter().map(|f| {
+                let call = subcall(cx, f);
+                cx.stmt_expr(call)
+            }).collect::<Vec<_>>();
             stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span))));
             cx.expr_block(cx.block(trait_span, stmts))
         }
@@ -166,14 +168,15 @@ fn cs_clone(name: &str,
                                                          name))
                                 }
                             };
-                            cx.field_imm(field.span, ident, subcall(field))
+                            let call = subcall(cx, field);
+                            cx.field_imm(field.span, ident, call)
                         })
                         .collect::<Vec<_>>();
 
                     cx.expr_struct(trait_span, ctor_path, fields)
                 }
                 VariantData::Tuple(..) => {
-                    let subcalls = all_fields.iter().map(subcall).collect();
+                    let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect();
                     let path = cx.expr_path(ctor_path);
                     cx.expr_call(trait_span, path, subcalls)
                 }
diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs
new file mode 100644 (file)
index 0000000..1f9c24a
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2016 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 std::panic;
+
+use rustc_macro::{TokenStream, __internal};
+use syntax::ast::{self, ItemKind};
+use syntax::codemap::Span;
+use syntax::ext::base::*;
+use syntax::fold::{self, Folder};
+use errors::FatalError;
+
+pub struct CustomDerive {
+    inner: fn(TokenStream) -> TokenStream,
+}
+
+impl CustomDerive {
+    pub fn new(inner: fn(TokenStream) -> TokenStream) -> CustomDerive {
+        CustomDerive { inner: inner }
+    }
+}
+
+impl MultiItemModifier for CustomDerive {
+    fn expand(&self,
+              ecx: &mut ExtCtxt,
+              span: Span,
+              _meta_item: &ast::MetaItem,
+              item: Annotatable)
+              -> Vec<Annotatable> {
+        let item = match item {
+            Annotatable::Item(item) => item,
+            Annotatable::ImplItem(_) |
+            Annotatable::TraitItem(_) => {
+                ecx.span_err(span, "custom derive attributes may only be \
+                                    applied to struct/enum items");
+                return Vec::new()
+            }
+        };
+        match item.node {
+            ItemKind::Struct(..) |
+            ItemKind::Enum(..) => {}
+            _ => {
+                ecx.span_err(span, "custom derive attributes may only be \
+                                    applied to struct/enum items");
+                return Vec::new()
+            }
+        }
+
+        let input = __internal::new_token_stream(item);
+        let res = __internal::set_parse_sess(&ecx.parse_sess, || {
+            let inner = self.inner;
+            panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input)))
+        });
+        let item = match res {
+            Ok(stream) => __internal::token_stream_items(stream),
+            Err(e) => {
+                let msg = "custom derive attribute panicked";
+                let mut err = ecx.struct_span_fatal(span, msg);
+                if let Some(s) = e.downcast_ref::<String>() {
+                    err.help(&format!("message: {}", s));
+                }
+                if let Some(s) = e.downcast_ref::<&'static str>() {
+                    err.help(&format!("message: {}", s));
+                }
+
+                err.emit();
+                panic!(FatalError);
+            }
+        };
+
+        // Right now we have no knowledge of spans at all in custom derive
+        // macros, everything is just parsed as a string. Reassign all spans to
+        // the #[derive] attribute for better errors here.
+        item.into_iter().flat_map(|item| {
+            ChangeSpan { span: span }.fold_item(item)
+        }).map(Annotatable::Item).collect()
+    }
+}
+
+struct ChangeSpan { span: Span }
+
+impl Folder for ChangeSpan {
+    fn new_span(&mut self, _sp: Span) -> Span {
+        self.span
+    }
+
+    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
+        fold::noop_fold_mac(mac, self)
+    }
+}
index 81085122e875bf47ce8799d51e6478ac171f93aa..5582166c12e9cb6c5cd293bbeca139fea0e41aa8 100644 (file)
@@ -12,7 +12,7 @@
 
 use syntax::ast::{self, MetaItem};
 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv};
-use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier};
+use syntax::ext::base::MultiModifier;
 use syntax::ext::build::AstBuilder;
 use syntax::feature_gate;
 use syntax::codemap;
@@ -61,6 +61,7 @@ macro_rules! path_std {
 pub mod hash;
 pub mod debug;
 pub mod default;
+pub mod custom;
 
 #[path="cmp/partial_eq.rs"]
 pub mod partial_eq;
@@ -74,156 +75,201 @@ macro_rules! path_std {
 
 pub mod generic;
 
+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(intern(attr_name)),
+                span: Some(span),
+                allow_internal_unstable: true,
+            },
+        }),
+        ..span
+    }
+}
+
 fn expand_derive(cx: &mut ExtCtxt,
                  span: Span,
                  mitem: &MetaItem,
                  annotatable: Annotatable)
-                 -> Annotatable {
+                 -> Vec<Annotatable> {
     debug!("expand_derive: span = {:?}", span);
     debug!("expand_derive: mitem = {:?}", mitem);
     debug!("expand_derive: annotatable input  = {:?}", annotatable);
-    let annot = annotatable.map_item_or(|item| {
-        item.map(|mut item| {
-            if mitem.value_str().is_some() {
-                cx.span_err(mitem.span, "unexpected value in `derive`");
-            }
+    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 traits = mitem.meta_item_list().unwrap_or(&[]);
-            if traits.is_empty() {
-                cx.span_warn(mitem.span, "empty trait list in `derive`");
-            }
+    if mitem.value_str().is_some() {
+        cx.span_err(mitem.span, "unexpected value in `derive`");
+    }
 
-            let mut found_partial_eq = false;
-            let mut eq_span = None;
-
-            for titem in traits.iter().rev() {
-                let tname = if let Some(word) = titem.word() {
-                    word.name()
-                } else {
-                    cx.span_err(titem.span, "malformed `derive` entry");
-                    continue;
-                };
-
-                if !(is_builtin_trait(&tname) || cx.ecfg.enable_custom_derive()) {
-                    feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
-                                                   "custom_derive",
-                                                   titem.span,
-                                                   feature_gate::GateIssue::Language,
-                                                   feature_gate::EXPLAIN_CUSTOM_DERIVE);
-                    continue;
-                }
+    let traits = mitem.meta_item_list().unwrap_or(&[]);
+    if traits.is_empty() {
+        cx.span_warn(mitem.span, "empty trait list in `derive`");
+    }
 
-                let span = Span {
-                    expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
-                        call_site: titem.span,
-                        callee: codemap::NameAndSpan {
-                            format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
-                            span: Some(titem.span),
-                            allow_internal_unstable: true,
-                        },
-                    }),
-                    ..titem.span
-                };
-
-                if &tname[..] == "Eq" {
-                    eq_span = Some(span);
-                } else if &tname[..] == "PartialEq" {
-                    found_partial_eq = true;
-                }
+    // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
+    // `#[structural_match]` attribute.
+    if traits.iter().filter_map(|t| t.name()).any(|t| t == "PartialEq") &&
+       traits.iter().filter_map(|t| t.name()).any(|t| t == "Eq") {
+        let structural_match = intern_and_get_ident("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
+        });
+    }
 
-                // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
-                item.attrs.push(cx.attribute(span,
-                               cx.meta_word(titem.span,
-                                            intern_and_get_ident(&format!("derive_{}", tname)))));
-            }
+    // 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)]
+    if traits.iter().filter_map(|t| t.name()).any(|t| t == "Clone") &&
+       traits.iter().filter_map(|t| t.name()).any(|t| t == "Copy") {
+        let marker = intern_and_get_ident("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
+        });
+    }
 
-            // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
-            // `#[structural_match]` attribute.
-            if let Some(eq_span) = eq_span {
-                if found_partial_eq {
-                    let structural_match = intern_and_get_ident("structural_match");
-                    item.attrs.push(cx.attribute(eq_span, cx.meta_word(eq_span, structural_match)));
-                }
+    let mut other_items = Vec::new();
+
+    let mut iter = traits.iter();
+    while let Some(titem) = iter.next() {
+
+        let tword = match titem.word() {
+            Some(name) => name,
+            None => {
+                cx.span_err(titem.span, "malformed `derive` entry");
+                continue
             }
+        };
+        let tname = tword.name();
+
+        // If this is a built-in derive mode, then we expand it immediately
+        // here.
+        if is_builtin_trait(&tname) {
+            let name = intern_and_get_ident(&format!("derive({})", tname));
+            let mitem = cx.meta_word(titem.span, name);
+
+            let span = Span {
+                expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
+                    call_site: titem.span,
+                    callee: codemap::NameAndSpan {
+                        format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
+                        span: Some(titem.span),
+                        allow_internal_unstable: true,
+                    },
+                }),
+                ..titem.span
+            };
+
+            let my_item = Annotatable::Item(item);
+            expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| {
+                other_items.push(a);
+            });
+            item = my_item.expect_item();
+
+        // Otherwise if this is a `rustc_macro`-style derive mode, we process it
+        // here. 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.
+        } else if let Some(ext) = cx.derive_modes.remove(&tname) {
+            let remaining_derives = iter.cloned().collect::<Vec<_>>();
+            if remaining_derives.len() > 0 {
+                let list = cx.meta_list(titem.span,
+                                        intern_and_get_ident("derive"),
+                                        remaining_derives);
+                let attr = cx.attribute(titem.span, list);
+                item = item.map(|mut i| {
+                    i.attrs.push(attr);
+                    i
+                });
+            }
+            let titem = cx.meta_list_item_word(titem.span, tname.clone());
+            let mitem = cx.meta_list(titem.span,
+                                     intern_and_get_ident("derive"),
+                                     vec![titem]);
+            let item = Annotatable::Item(item);
+            let mut items = ext.expand(cx, mitem.span, &mitem, item);
+            items.extend(other_items);
+            cx.derive_modes.insert(tname.clone(), ext);
+            return items
+
+        // If we've gotten this far then it means that we're in the territory of
+        // the old custom derive mechanism. If the feature isn't enabled, we
+        // issue an error, otherwise manufacture the `derive_Foo` attribute.
+        } else if !cx.ecfg.enable_custom_derive() {
+            feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
+                                           "custom_derive",
+                                           titem.span,
+                                           feature_gate::GateIssue::Language,
+                                           feature_gate::EXPLAIN_CUSTOM_DERIVE);
+        } else {
+            let name = intern_and_get_ident(&format!("derive_{}", tname));
+            let mitem = cx.meta_word(titem.span, name);
+            item = item.map(|mut i| {
+                i.attrs.push(cx.attribute(mitem.span, mitem));
+                i
+            });
+        }
+    }
 
-            item
-        })
-    },
-                                        |a| {
-                                            cx.span_err(span,
-                                                        "`derive` can only be applied to items");
-                                            a
-                                        });
-    debug!("expand_derive: annotatable output = {:?}", annot);
-    annot
+    other_items.insert(0, Annotatable::Item(item));
+    return other_items
 }
 
 macro_rules! derive_traits {
     ($( $name:expr => $func:path, )+) => {
         pub fn register_all(env: &mut SyntaxEnv) {
-            // Define the #[derive_*] extensions.
-            $({
-                struct DeriveExtension;
-
-                impl MultiItemDecorator for DeriveExtension {
-                    fn expand(&self,
-                              ecx: &mut ExtCtxt,
-                              sp: Span,
-                              mitem: &MetaItem,
-                              annotatable: &Annotatable,
-                              push: &mut FnMut(Annotatable)) {
-                        if !ecx.parse_sess.codemap().span_allows_unstable(sp)
-                            && !ecx.ecfg.features.unwrap().custom_derive {
-                            // FIXME:
-                            // https://github.com/rust-lang/rust/pull/32671#issuecomment-206245303
-                            // This is just to avoid breakage with syntex.
-                            // Remove that to spawn an error instead.
-                            let cm = ecx.parse_sess.codemap();
-                            let parent = cm.with_expn_info(ecx.backtrace(),
-                                                           |info| info.unwrap().call_site.expn_id);
-                            cm.with_expn_info(parent, |info| {
-                                if info.is_some() {
-                                    let mut w = ecx.parse_sess.span_diagnostic.struct_span_warn(
-                                        sp, feature_gate::EXPLAIN_DERIVE_UNDERSCORE,
-                                    );
-                                    if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_none() {
-                                        w.help(
-                                            &format!("add #![feature(custom_derive)] to \
-                                                      the crate attributes to enable")
-                                        );
-                                    }
-                                    w.emit();
-                                } else {
-                                    feature_gate::emit_feature_err(
-                                        &ecx.parse_sess.span_diagnostic,
-                                        "custom_derive", sp, feature_gate::GateIssue::Language,
-                                        feature_gate::EXPLAIN_DERIVE_UNDERSCORE
-                                    );
-
-                                    return;
-                                }
-                            })
-                        }
-
-                        warn_if_deprecated(ecx, sp, $name);
-                        $func(ecx, sp, mitem, annotatable, push);
-                    }
-                }
-
-                env.insert(intern(concat!("derive_", $name)),
-                           MultiDecorator(Box::new(DeriveExtension)));
-            })+
-
-            env.insert(intern("derive"),
-                       MultiModifier(Box::new(expand_derive)));
+            env.insert(intern("derive"), MultiModifier(Box::new(expand_derive)));
         }
 
-        fn is_builtin_trait(name: &str) -> bool {
+        pub fn is_builtin_trait(name: &str) -> bool {
             match name {
                 $( $name )|+ => true,
                 _ => false,
             }
         }
+
+        fn expand_builtin(name: &str,
+                          ecx: &mut ExtCtxt,
+                          span: Span,
+                          mitem: &MetaItem,
+                          item: &Annotatable,
+                          push: &mut FnMut(Annotatable)) {
+            match name {
+                $(
+                    $name => {
+                        warn_if_deprecated(ecx, span, $name);
+                        $func(ecx, span, mitem, item, push);
+                    }
+                )*
+                _ => panic!("not a builtin derive mode: {}", name),
+            }
+        }
     }
 }
 
index 3aa62339b477efac75e4313fa5fa2b9ce54eb0f7..4bae9ec5a1a1f8c994b65564840614364a58a69c 100644 (file)
@@ -19,6 +19,8 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(rustc_macro_lib)]
+#![feature(rustc_macro_internals)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
 
@@ -28,6 +30,7 @@
 #[macro_use]
 extern crate syntax;
 extern crate syntax_pos;
+extern crate rustc_macro;
 extern crate rustc_errors as errors;
 
 use syntax::ext::base::{MacroExpanderFn, NormalTT};
@@ -44,6 +47,8 @@
 mod log_syntax;
 mod trace_macros;
 
+pub mod rustc_macro_registrar;
+
 // for custom_derive
 pub mod deriving;
 
diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs
new file mode 100644 (file)
index 0000000..7693e24
--- /dev/null
@@ -0,0 +1,280 @@
+// Copyright 2016 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 std::mem;
+
+use errors;
+use syntax::ast::{self, Ident, NodeId};
+use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute};
+use syntax::ext::base::{ExtCtxt, DummyMacroLoader};
+use syntax::ext::build::AstBuilder;
+use syntax::ext::expand::ExpansionConfig;
+use syntax::parse::ParseSess;
+use syntax::parse::token::{self, InternedString};
+use syntax::feature_gate::Features;
+use syntax::ptr::P;
+use syntax_pos::{Span, DUMMY_SP};
+use syntax::visit::{self, Visitor};
+
+use deriving;
+
+struct CustomDerive {
+    trait_name: InternedString,
+    function_name: Ident,
+    span: Span,
+}
+
+struct CollectCustomDerives<'a> {
+    derives: Vec<CustomDerive>,
+    in_root: bool,
+    handler: &'a errors::Handler,
+    is_rustc_macro_crate: bool,
+}
+
+pub fn modify(sess: &ParseSess,
+              mut krate: ast::Crate,
+              is_rustc_macro_crate: bool,
+              num_crate_types: usize,
+              handler: &errors::Handler,
+              features: &Features) -> ast::Crate {
+    let mut loader = DummyMacroLoader;
+    let mut cx = ExtCtxt::new(sess,
+                              Vec::new(),
+                              ExpansionConfig::default("rustc_macro".to_string()),
+                              &mut loader);
+
+    let mut collect = CollectCustomDerives {
+        derives: Vec::new(),
+        in_root: true,
+        handler: handler,
+        is_rustc_macro_crate: is_rustc_macro_crate,
+    };
+    visit::walk_crate(&mut collect, &krate);
+
+    if !is_rustc_macro_crate {
+        return krate
+    } else if !features.rustc_macro {
+        let mut err = handler.struct_err("the `rustc-macro` crate type is \
+                                          experimental");
+        err.help("add #![feature(rustc_macro)] to the crate attributes to \
+                  enable");
+        err.emit();
+    }
+
+    if num_crate_types > 1 {
+        handler.err("cannot mix `rustc-macro` crate type with others");
+    }
+
+    krate.module.items.push(mk_registrar(&mut cx, &collect.derives));
+
+    if krate.exported_macros.len() > 0 {
+        handler.err("cannot export macro_rules! macros from a `rustc-macro` \
+                     crate type currently");
+    }
+
+    return krate
+}
+
+impl<'a> CollectCustomDerives<'a> {
+    fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
+        if self.is_rustc_macro_crate &&
+           self.in_root &&
+           *vis == ast::Visibility::Public {
+            self.handler.span_err(sp,
+                                  "`rustc-macro` crate types cannot \
+                                   export any items other than functions \
+                                   tagged with `#[rustc_macro_derive]` \
+                                   currently");
+        }
+    }
+}
+
+impl<'a> Visitor for CollectCustomDerives<'a> {
+    fn visit_item(&mut self, item: &ast::Item) {
+        // First up, make sure we're checking a bare function. If we're not then
+        // we're just not interested in this item.
+        //
+        // If we find one, try to locate a `#[rustc_macro_derive]` attribute on
+        // it.
+        match item.node {
+            ast::ItemKind::Fn(..) => {}
+            _ => {
+                self.check_not_pub_in_root(&item.vis, item.span);
+                return visit::walk_item(self, item)
+            }
+        }
+
+        let mut attrs = item.attrs.iter()
+                            .filter(|a| a.check_name("rustc_macro_derive"));
+        let attr = match attrs.next() {
+            Some(attr) => attr,
+            None => {
+                self.check_not_pub_in_root(&item.vis, item.span);
+                return visit::walk_item(self, item)
+            }
+        };
+
+        if let Some(a) = attrs.next() {
+            self.handler.span_err(a.span(), "multiple `#[rustc_macro_derive]` \
+                                             attributes found");
+        }
+
+        if !self.is_rustc_macro_crate {
+            self.handler.span_err(attr.span(),
+                                  "the `#[rustc_macro_derive]` attribute is \
+                                   only usable with crates of the `rustc-macro` \
+                                   crate type");
+        }
+
+        // Once we've located the `#[rustc_macro_derive]` attribute, verify
+        // that it's of the form `#[rustc_macro_derive(Foo)]`
+        let list = match attr.meta_item_list() {
+            Some(list) => list,
+            None => {
+                self.handler.span_err(attr.span(),
+                                      "attribute must be of form: \
+                                       #[rustc_macro_derive(TraitName)]");
+                return
+            }
+        };
+        if list.len() != 1 {
+            self.handler.span_err(attr.span(),
+                                  "attribute must only have one argument");
+            return
+        }
+        let attr = &list[0];
+        let trait_name = match attr.name() {
+            Some(name) => name,
+            _ => {
+                self.handler.span_err(attr.span(), "not a meta item");
+                return
+            }
+        };
+        if !attr.is_word() {
+            self.handler.span_err(attr.span(), "must only be one word");
+        }
+
+        if deriving::is_builtin_trait(&trait_name) {
+            self.handler.span_err(attr.span(),
+                                  "cannot override a built-in #[derive] mode");
+        }
+
+        if self.derives.iter().any(|d| d.trait_name == trait_name) {
+            self.handler.span_err(attr.span(),
+                                  "derive mode defined twice in this crate");
+        }
+
+        if self.in_root {
+            self.derives.push(CustomDerive {
+                span: item.span,
+                trait_name: trait_name,
+                function_name: item.ident,
+            });
+        } else {
+            let msg = "functions tagged with `#[rustc_macro_derive]` must \
+                       currently reside in the root of the crate";
+            self.handler.span_err(item.span, msg);
+        }
+
+        visit::walk_item(self, item);
+    }
+
+    fn visit_mod(&mut self, m: &ast::Mod, _s: Span, id: NodeId) {
+        let mut prev_in_root = self.in_root;
+        if id != ast::CRATE_NODE_ID {
+            prev_in_root = mem::replace(&mut self.in_root, false);
+        }
+        visit::walk_mod(self, m);
+        self.in_root = prev_in_root;
+    }
+
+    fn visit_mac(&mut self, mac: &ast::Mac) {
+        visit::walk_mac(self, mac)
+    }
+}
+
+// Creates a new module which looks like:
+//
+//      mod $gensym {
+//          extern crate rustc_macro;
+//
+//          use rustc_macro::__internal::Registry;
+//
+//          #[plugin_registrar]
+//          fn registrar(registrar: &mut Registry) {
+//              registrar.register_custom_derive($name_trait1, ::$name1);
+//              registrar.register_custom_derive($name_trait2, ::$name2);
+//              // ...
+//          }
+//      }
+fn mk_registrar(cx: &mut ExtCtxt,
+                custom_derives: &[CustomDerive]) -> P<ast::Item> {
+    let eid = cx.codemap().record_expansion(ExpnInfo {
+        call_site: DUMMY_SP,
+        callee: NameAndSpan {
+            format: MacroAttribute(token::intern("rustc_macro")),
+            span: None,
+            allow_internal_unstable: true,
+        }
+    });
+    let span = Span { expn_id: eid, ..DUMMY_SP };
+
+    let rustc_macro = token::str_to_ident("rustc_macro");
+    let krate = cx.item(span,
+                        rustc_macro,
+                        Vec::new(),
+                        ast::ItemKind::ExternCrate(None));
+
+    let __internal = token::str_to_ident("__internal");
+    let registry = token::str_to_ident("Registry");
+    let registrar = token::str_to_ident("registrar");
+    let register_custom_derive = token::str_to_ident("register_custom_derive");
+    let stmts = custom_derives.iter().map(|cd| {
+        let path = cx.path_global(cd.span, vec![cd.function_name]);
+        let trait_name = cx.expr_str(cd.span, cd.trait_name.clone());
+        (path, trait_name)
+    }).map(|(path, trait_name)| {
+        let registrar = cx.expr_ident(span, registrar);
+        let ufcs_path = cx.path(span, vec![rustc_macro, __internal, registry,
+                                           register_custom_derive]);
+        cx.expr_call(span,
+                     cx.expr_path(ufcs_path),
+                     vec![registrar, trait_name, cx.expr_path(path)])
+    }).map(|expr| {
+        cx.stmt_expr(expr)
+    }).collect::<Vec<_>>();
+
+    let path = cx.path(span, vec![rustc_macro, __internal, registry]);
+    let registrar_path = cx.ty_path(path);
+    let arg_ty = cx.ty_rptr(span, registrar_path, None, ast::Mutability::Mutable);
+    let func = cx.item_fn(span,
+                          registrar,
+                          vec![cx.arg(span, registrar, arg_ty)],
+                          cx.ty(span, ast::TyKind::Tup(Vec::new())),
+                          cx.block(span, stmts));
+
+    let derive_registrar = token::intern_and_get_ident("rustc_derive_registrar");
+    let derive_registrar = cx.meta_word(span, derive_registrar);
+    let derive_registrar = cx.attribute(span, derive_registrar);
+    let func = func.map(|mut i| {
+        i.attrs.push(derive_registrar);
+        i.vis = ast::Visibility::Public;
+        i
+    });
+    let module = cx.item_mod(span,
+                             span,
+                             ast::Ident::with_empty_ctxt(token::gensym("registrar")),
+                             Vec::new(),
+                             vec![krate, func]);
+    module.map(|mut i| {
+        i.vis = ast::Visibility::Public;
+        i
+    })
+}
index fde2f83e220f92b4a5784904f0f37e9fb3b6a4f0..3377fc43d8a605cd511c81c483b9c87b33f1a1b3 100644 (file)
@@ -214,6 +214,13 @@ dependencies = [
  "rustc_bitflags 0.0.0",
 ]
 
+[[package]]
+name = "rustc_macro"
+version = "0.0.0"
+dependencies = [
+ "syntax 0.0.0",
+]
+
 [[package]]
 name = "rustc_metadata"
 version = "0.0.0"
@@ -228,8 +235,10 @@ dependencies = [
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
  "rustc_llvm 0.0.0",
+ "rustc_macro 0.0.0",
  "serialize 0.0.0",
  "syntax 0.0.0",
+ "syntax_ext 0.0.0",
  "syntax_pos 0.0.0",
 ]
 
@@ -400,6 +409,7 @@ dependencies = [
  "fmt_macros 0.0.0",
  "log 0.0.0",
  "rustc_errors 0.0.0",
+ "rustc_macro 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs
new file mode 100644 (file)
index 0000000..fa0b576
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2016 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.
+
+// aux-build:append-impl.rs
+
+#![feature(rustc_macro)]
+#![allow(warnings)]
+
+#[macro_use]
+extern crate append_impl;
+
+trait Append {
+    fn foo(&self);
+}
+
+#[derive(PartialEq,
+         Append,
+         Eq)]
+//~^^ ERROR: the semantics of constant patterns is not yet settled
+struct A {
+    inner: u32,
+}
+
+fn main() {
+    A { inner: 3 }.foo();
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs b/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs
new file mode 100644 (file)
index 0000000..4672452
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+
+extern crate rustc_macro;
+
+pub mod a { //~ `rustc-macro` crate types cannot export any items
+    use rustc_macro::TokenStream;
+
+    #[rustc_macro_derive(B)]
+    pub fn bar(a: TokenStream) -> TokenStream {
+    //~^ ERROR: must currently reside in the root of the crate
+        a
+    }
+}
+
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs b/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs
new file mode 100644 (file)
index 0000000..7740238
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2016 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.
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+
+extern crate rustc_macro;
+
+#[rustc_macro_derive]
+//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)]
+pub fn foo1(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
+    input
+}
+
+#[rustc_macro_derive = "foo"]
+//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)]
+pub fn foo2(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
+    input
+}
+
+#[rustc_macro_derive(
+    a = "b"
+)]
+//~^^ ERROR: must only be one word
+pub fn foo3(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
+    input
+}
+
+#[rustc_macro_derive(b, c)]
+//~^ ERROR: attribute must only have one argument
+pub fn foo4(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
+    input
+}
+
+#[rustc_macro_derive(d(e))]
+//~^ ERROR: must only be one word
+pub fn foo5(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
+    input
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs
new file mode 100644 (file)
index 0000000..c3d295e
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2016 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.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+#![crate_type = "rustc-macro"]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(Append)]
+pub fn derive_a(input: TokenStream) -> TokenStream {
+    let mut input = input.to_string();
+    input.push_str("
+        impl Append for A {
+            fn foo(&self) {}
+        }
+    ");
+    input.parse().unwrap()
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs
new file mode 100644 (file)
index 0000000..ff00a9d
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+#![crate_type = "rustc-macro"]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(A)]
+pub fn derive_a(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs
new file mode 100644 (file)
index 0000000..ff00a9d
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+#![crate_type = "rustc-macro"]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(A)]
+pub fn derive_a(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs
new file mode 100644 (file)
index 0000000..5dd42d2
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+// force-host
+
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+#![crate_type = "rustc-macro"]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(A)]
+pub fn derive_a(_input: TokenStream) -> TokenStream {
+    "struct A { inner }".parse().unwrap()
+}
+
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs
new file mode 100644 (file)
index 0000000..d867082
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+// force-host
+
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+#![crate_type = "rustc-macro"]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(A)]
+pub fn derive_a(_input: TokenStream) -> TokenStream {
+    panic!("nope!");
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs
new file mode 100644 (file)
index 0000000..9eebad8
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2016 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.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+#![crate_type = "rustc-macro"]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(Unstable)]
+pub fn derive(_input: TokenStream) -> TokenStream {
+
+    "
+        #[rustc_foo]
+        fn foo() {}
+    ".parse().unwrap()
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs
new file mode 100644 (file)
index 0000000..f4a1ec9
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 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.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+#![crate_type = "rustc-macro"]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(Unstable)]
+pub fn derive(_input: TokenStream) -> TokenStream {
+
+    "unsafe fn foo() -> u32 { ::std::intrinsics::init() }".parse().unwrap()
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs b/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs
new file mode 100644 (file)
index 0000000..1f13533
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2016 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.
+
+// aux-build:derive-a.rs
+
+extern crate derive_a;
+//~^ ERROR: crates of the `rustc-macro` crate type cannot be linked at runtime
+
+fn main() {}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs b/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs
new file mode 100644 (file)
index 0000000..e4f21dc
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(A)]
+pub fn foo(input: TokenStream) -> TokenStream {
+    input
+}
+
+#[rustc_macro_derive(A)] //~ ERROR: derive mode defined twice in this crate
+pub fn bar(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs b/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs
new file mode 100644 (file)
index 0000000..f3a73af
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+// aux-build:derive-bad.rs
+
+#![feature(rustc_macro)]
+
+#[macro_use]
+extern crate derive_bad;
+
+#[derive(
+    A
+)]
+//~^^ ERROR: custom derive attribute panicked
+//~| HELP: called `Result::unwrap()` on an `Err` value: LexError
+struct A;
+
+fn main() {}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs b/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs
new file mode 100644 (file)
index 0000000..a46d79f
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2016 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.
+
+// aux-build:derive-a.rs
+
+#![feature(rustc_macro)]
+#![allow(warnings)]
+
+#[macro_use]
+extern crate derive_a;
+
+#[derive_A] //~ ERROR: attributes of the form `#[derive_*]` are reserved for the compiler
+struct A;
+
+fn main() {}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs
new file mode 100644 (file)
index 0000000..29b9fd2
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+// aux-build:derive-unstable-2.rs
+
+#![feature(rustc_macro)]
+#![allow(warnings)]
+
+#[macro_use]
+extern crate derive_unstable_2;
+
+#[derive(Unstable)]
+//~^ ERROR: reserved for internal compiler
+struct A;
+
+fn main() {
+    foo();
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs
new file mode 100644 (file)
index 0000000..8740817
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+// aux-build:derive-unstable.rs
+
+#![feature(rustc_macro)]
+#![allow(warnings)]
+
+#[macro_use]
+extern crate derive_unstable;
+
+#[derive(Unstable)]
+//~^ ERROR: use of unstable library feature
+struct A;
+
+fn main() {
+    unsafe { foo(); }
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs b/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs
new file mode 100644 (file)
index 0000000..759f3d3
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2016 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.
+
+// error-pattern: cannot export macro_rules! macros from a `rustc-macro` crate
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+
+#[macro_export]
+macro_rules! foo {
+    ($e:expr) => ($e)
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/exports.rs b/src/test/compile-fail-fulldeps/rustc-macro/exports.rs
new file mode 100644 (file)
index 0000000..e985356
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2016 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.
+
+#![crate_type = "rustc-macro"]
+#![allow(warnings)]
+
+pub fn a() {} //~ ERROR: cannot export any items
+pub struct B; //~ ERROR: cannot export any items
+pub enum C {} //~ ERROR: cannot export any items
+pub mod d {} //~ ERROR: cannot export any items
+
+mod e {}
+struct F;
+enum G {}
+fn h() {}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs
new file mode 100644 (file)
index 0000000..86afc08
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2016 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.
+
+// error-pattern: the `rustc-macro` crate type is experimental
+
+#![crate_type = "rustc-macro"]
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs
new file mode 100644 (file)
index 0000000..1a19f60
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2016 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.
+
+extern crate rustc_macro; //~ ERROR: use of unstable library feature
+
+fn main() {}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs
new file mode 100644 (file)
index 0000000..9f47f07
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2016 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.
+
+#![crate_type = "rustc-macro"]
+
+#[rustc_macro_derive(Foo)] //~ ERROR: is an experimental feature
+pub fn foo() {
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs
new file mode 100644 (file)
index 0000000..0fdd13b
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2016 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.
+
+// aux-build:derive-a.rs
+
+#[macro_use]
+extern crate derive_a;
+//~^ ERROR: loading custom derive macro crates is experimentally supported
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs
new file mode 100644 (file)
index 0000000..e44b29a
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2016 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.
+
+#[cfg(rustc_macro)] //~ ERROR: experimental and subject to change
+fn foo() {}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/import.rs b/src/test/compile-fail-fulldeps/rustc-macro/import.rs
new file mode 100644 (file)
index 0000000..c1d0823
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2016 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.
+
+// aux-build:derive-a.rs
+
+#![feature(rustc_macro)]
+#![allow(warnings)]
+
+#[macro_use]
+extern crate derive_a;
+
+use derive_a::derive_a;
+//~^ ERROR: unresolved import `derive_a::derive_a`
+
+fn main() {}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs b/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs
new file mode 100644 (file)
index 0000000..0d08d27
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2016 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.
+
+// aux-build:derive-panic.rs
+
+#![feature(rustc_macro)]
+
+#[macro_use]
+extern crate derive_panic;
+
+#[derive(A)]
+//~^ ERROR: custom derive attribute panicked
+//~| HELP: message: nope!
+struct Foo;
+
+fn main() {}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs b/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs
new file mode 100644 (file)
index 0000000..cdc50ac
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 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.
+
+#![feature(rustc_macro)]
+
+extern crate rustc_macro;
+
+#[rustc_macro_derive(Foo)]
+//~^ ERROR: only usable with crates of the `rustc-macro` crate type
+pub fn foo(a: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
+    a
+}
+
+fn main() {}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs b/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs
new file mode 100644 (file)
index 0000000..1353a23
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2016 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.
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(PartialEq)]
+//~^ ERROR: cannot override a built-in #[derive] mode
+pub fn foo(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs b/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs
new file mode 100644 (file)
index 0000000..33330ed
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 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.
+
+// aux-build:derive-a.rs
+// aux-build:derive-a-2.rs
+
+#![feature(rustc_macro)]
+
+#[macro_use]
+extern crate derive_a;
+#[macro_use]
+extern crate derive_a_2; //~ ERROR: cannot shadow existing derive mode `A`
+
+fn main() {}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/signature.rs b/src/test/compile-fail-fulldeps/rustc-macro/signature.rs
new file mode 100644 (file)
index 0000000..9662cc6
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2016 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.
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+#![allow(warnings)]
+
+extern crate rustc_macro;
+
+#[rustc_macro_derive(A)]
+unsafe extern fn foo(a: i32, b: u32) -> u32 {
+    //~^ ERROR: mismatched types
+    //~| NOTE: expected normal fn, found unsafe fn
+    //~| NOTE: expected type `fn(rustc_macro::TokenStream) -> rustc_macro::TokenStream`
+    //~| NOTE: found type `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
+    loop {}
+}
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs
new file mode 100644 (file)
index 0000000..35f6149
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2016 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.
+
+// error-pattern: cannot mix `rustc-macro` crate type with others
+
+#![crate_type = "rustc-macro"]
+#![crate_type = "rlib"]
diff --git a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs
new file mode 100644 (file)
index 0000000..ec95e3e
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2016 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.
+
+// error-pattern: cannot mix `rustc-macro` crate type with others
+// compile-flags: --crate-type rlib --crate-type rustc-macro
index edd7fe4a1e588a098db660ec0666eb1c45146391..25ecd5d08626ddc0ccdf699ff66be735889efff8 100644 (file)
@@ -13,7 +13,7 @@
 
 macro_rules! foo (
     () => (
-        #[derive_Clone] //~ WARN attributes of the form
+        #[derive_Clone] //~ ERROR attributes of the form
         struct T;
     );
 );
@@ -25,9 +25,8 @@ macro_rules! bar (
 foo!();
 
 bar!(
-    #[derive_Clone] //~ WARN attributes of the form
+    #[derive_Clone] //~ ERROR attributes of the form
     struct S;
 );
 
-#[rustc_error]
-fn main() {} //~ ERROR compilation successful
+fn main() {}
diff --git a/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs b/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs
new file mode 100644 (file)
index 0000000..226c082
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+// aux-build:add-impl.rs
+
+#![feature(rustc_macro)]
+
+#[macro_use]
+extern crate add_impl;
+
+#[derive(AddImpl)]
+struct B;
+
+fn main() {
+    B.foo();
+    foo();
+    bar::foo();
+}
diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs
new file mode 100644 (file)
index 0000000..8aab423
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(AddImpl)]
+// #[cfg(rustc_macro)]
+pub fn derive(input: TokenStream) -> TokenStream {
+    (input.to_string() + "
+        impl B {
+            fn foo(&self) {}
+        }
+
+        fn foo() {}
+
+        mod bar { pub fn foo() {} }
+    ").parse().unwrap()
+}
diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs
new file mode 100644 (file)
index 0000000..4dd6ad8
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(A)]
+pub fn derive(input: TokenStream) -> TokenStream {
+    let input = input.to_string();
+    assert!(input.contains("struct A;"));
+    assert!(input.contains("#[derive(Eq, Copy, Clone)]"));
+    "#[derive(Eq, Copy, Clone)] struct A;".parse().unwrap()
+}
diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs
new file mode 100644 (file)
index 0000000..5b85e2b
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(AToB)]
+pub fn derive(input: TokenStream) -> TokenStream {
+    let input = input.to_string();
+    assert_eq!(input, "struct A;\n");
+    "struct B;".parse().unwrap()
+}
diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs
new file mode 100644 (file)
index 0000000..54f8dff
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(CToD)]
+pub fn derive(input: TokenStream) -> TokenStream {
+    let input = input.to_string();
+    assert_eq!(input, "struct C;\n");
+    "struct D;".parse().unwrap()
+}
diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs
new file mode 100644 (file)
index 0000000..d83e352
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+// compile-flags:--crate-type rustc-macro
+
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(AToB)]
+pub fn derive1(input: TokenStream) -> TokenStream {
+    println!("input1: {:?}", input.to_string());
+    assert_eq!(input.to_string(), "#[derive(BToC)]\nstruct A;\n");
+    "#[derive(BToC)] struct B;".parse().unwrap()
+}
+
+#[rustc_macro_derive(BToC)]
+pub fn derive2(input: TokenStream) -> TokenStream {
+    assert_eq!(input.to_string(), "struct B;\n");
+    "struct C;".parse().unwrap()
+}
diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs
new file mode 100644 (file)
index 0000000..96aea40
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rustc-macro"]
+#![feature(rustc_macro)]
+#![feature(rustc_macro_lib)]
+#![deny(warnings)]
+
+extern crate rustc_macro;
+
+use rustc_macro::TokenStream;
+
+#[rustc_macro_derive(A)]
+pub fn derive(input: TokenStream) -> TokenStream {
+    let input = input.to_string();
+    assert!(input.contains("struct A;"));
+    r#"
+        struct A;
+
+        impl A {
+            fn a(&self) {
+                panic!("hello");
+            }
+        }
+    "#.parse().unwrap()
+}
+
diff --git a/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs b/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs
new file mode 100644 (file)
index 0000000..ee0d594
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2016 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.
+
+// aux-build:derive-same-struct.rs
+
+#![feature(rustc_macro)]
+
+#[macro_use]
+extern crate derive_same_struct;
+
+#[derive(AToB, BToC)]
+struct A;
+
+fn main() {
+    C;
+}
diff --git a/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs
new file mode 100644 (file)
index 0000000..cc59be2
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2016 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.
+
+// aux-build:expand-with-a-macro.rs
+// ignore-stage1
+
+#![feature(rustc_macro)]
+#![deny(warnings)]
+
+#[macro_use]
+extern crate expand_with_a_macro;
+
+use std::panic;
+
+#[derive(A)]
+struct A;
+
+fn main() {
+    assert!(panic::catch_unwind(|| {
+        A.a();
+    }).is_err());
+}
+
diff --git a/src/test/run-pass-fulldeps/rustc-macro/load-two.rs b/src/test/run-pass-fulldeps/rustc-macro/load-two.rs
new file mode 100644 (file)
index 0000000..1500970
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2016 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.
+
+// aux-build:derive-atob.rs
+// aux-build:derive-ctod.rs
+
+#![feature(rustc_macro)]
+
+#[macro_use]
+extern crate derive_atob;
+#[macro_use]
+extern crate derive_ctod;
+
+#[derive(AToB)]
+struct A;
+
+#[derive(CToD)]
+struct C;
+
+fn main() {
+    B;
+    D;
+}
diff --git a/src/test/run-pass-fulldeps/rustc-macro/smoke.rs b/src/test/run-pass-fulldeps/rustc-macro/smoke.rs
new file mode 100644 (file)
index 0000000..588380f
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2016 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.
+
+// aux-build:derive-a.rs
+// ignore-stage1
+
+#![feature(rustc_macro)]
+
+#[macro_use]
+extern crate derive_a;
+
+#[derive(Debug, PartialEq, A, Eq, Copy, Clone)]
+struct A;
+
+fn main() {
+    A;
+    assert_eq!(A, A);
+    A.clone();
+    let a = A;
+    let _c = a;
+    let _d = a;
+}
index 3dffae99292c61b1c487c8c7d8e1f4d1e18dbffb..517033d58702d60fb01686dd76eb6111636724af 100644 (file)
@@ -11,9 +11,6 @@
 // Regression test for issue #21010: Normalize associated types in
 // various special paths in the `type_is_immediate` function.
 
-
-// pretty-expanded FIXME #23616
-
 pub trait OffsetState: Sized {}
 pub trait Offset {
     type State: OffsetState;
index c026ffc6d318d76e1bcbedef18c823fb4464c47a..3259b1cc0679e516954471b7091ccb3aa209d956 100644 (file)
@@ -13,8 +13,6 @@
 
 // Tests (correct) usage of trait super-builtin-kinds cross-crate.
 
-// pretty-expanded FIXME #23616
-
 extern crate trait_superkinds_in_metadata;
 use trait_superkinds_in_metadata::{RequiresRequiresShareAndSend, RequiresShare};
 use trait_superkinds_in_metadata::RequiresCopy;
index b0630b516407b60f3490ce6d3f2bb920c9bff545..d7c21340afc390977dee417ab2f0b5268bfe705a 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// pretty-expanded FIXME #23616
-
 pub fn main() {
     #[derive(Copy, Clone)]
     enum x { foo }
index 4204d9b5c3eaeb3006c3358e7b5ec6c6a31c2f89..6d0a43997bc47a41890c9f90c336ed1e8a7c749e 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// pretty-expanded FIXME #23616
-
 #[derive(Copy, Clone)]
 struct Test;
 
index 321ed1a3bb283fdcdef5545fc46485d7a3c5de2f..de952436650828a4170e33aa894da126445db2dd 100644 (file)
@@ -10,8 +10,6 @@
 
 // Regression test for #20797.
 
-// pretty-expanded FIXME #23616
-
 #![feature(question_mark)]
 
 use std::default::Default;
index d16655a68554a2b654999f19ddda31c7e3efc848..379715f539039a0089ad4460c52a323861f757d4 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// pretty-expanded FIXME #23616
-
 #![allow(unknown_features)]
 #![feature(box_syntax)]
 
diff --git a/src/test/run-pass/single-derive-attr-with-gate.rs b/src/test/run-pass/single-derive-attr-with-gate.rs
deleted file mode 100644 (file)
index addc56e..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 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.
-
-// pretty-expanded FIXME #23616
-
-#![feature(custom_derive)]
-
-#[derive_Clone]
-struct Test;
-
-pub fn main() {
-    Test.clone();
-}
index 7fa592105c09d4900d14236fe028016c86cf9329..45ac334dc1d768b845754c72555d62fdd55a33ec 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// pretty-expanded FIXME #23616
-
 #![allow(warnings)]
 #![feature(collections)]
 #![feature(drain, enumset, collections_bound, btree_range, vecmap)]