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
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
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
}
}
- // 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();
// 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,
let needs_check = sess.crate_types.borrow().iter().any(|kind| {
match *kind {
config::CrateTypeDylib |
+ config::CrateTypeRustcMacro |
config::CrateTypeCdylib |
config::CrateTypeExecutable |
config::CrateTypeStaticlib => true,
CrateTypeRlib,
CrateTypeStaticlib,
CrateTypeCdylib,
+ CrateTypeRustcMacro,
}
#[derive(Clone, Hash)]
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;
}
"dylib" => CrateTypeDylib,
"cdylib" => CrateTypeCdylib,
"bin" => CrateTypeExecutable,
+ "rustc-macro" => CrateTypeRustcMacro,
_ => {
return Err(format!("unknown crate type: `{}`",
part));
CrateTypeRlib => "rlib".fmt(f),
CrateTypeStaticlib => "staticlib".fmt(f),
CrateTypeCdylib => "cdylib".fmt(f),
+ CrateTypeRustcMacro => "rustc-macro".fmt(f),
}
}
}
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
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,
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(),
/// 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> {
crate_name: token::intern_and_get_ident(crate_name),
data_layout: data_layout,
layout_cache: RefCell::new(FnvHashMap()),
+ derive_macros: RefCell::new(NodeMap()),
}, f)
}
}
--- /dev/null
+// 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);
+ }
+ }
+}
use syntax;
use syntax_ext;
+use derive_registrar;
+
#[derive(Clone)]
pub struct Resolutions {
pub def_map: DefMap,
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);
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",
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,
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";
--- /dev/null
+[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" }
--- /dev/null
+// 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(())
+ }
+}
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" }
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];
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(),
}
}
}
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,
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
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,
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,
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);
}
});
}
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;
}
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)
}
};
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
match *ct {
config::CrateTypeExecutable => need_exe_alloc = true,
config::CrateTypeDylib |
+ config::CrateTypeRustcMacro |
config::CrateTypeCdylib |
config::CrateTypeStaticlib => need_lib_alloc = true,
config::CrateTypeRlib => {}
}
}
+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,
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,
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;
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 {
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()),
}
}
{
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 {
}
}
+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));
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;
/// 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);
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,
// 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.
#![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;
//! 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> {
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();
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();
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() {
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, ¯os, index, &mut ret);
+ }
+
if let Some(sel) = import.as_ref() {
for (name, span) in sel {
if !seen.contains(&name) {
}
}
- 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(¯os.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);
}
}
self.llvm_passes.push(name.to_owned());
}
-
/// Register an attribute with an attribute type.
///
/// Registered attributes will bypass the `custom_attribute` feature gate.
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
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);
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")
});
// 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"));
}
// 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(),
}
}
// 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
}
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}};")?;
};
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(())
// 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(())
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![];
}
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.
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;
}
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()
}
}
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>,
exported_macros: Vec::new(),
loader: loader,
syntax_env: env,
+ derive_modes: HashMap::new(),
recursion_count: 0,
filename: None,
}
}
+ 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)
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,
}
});
// 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);
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,
}
}
}
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,
}
};
- ($((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)),+
(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! (
(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! (
(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)
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),
("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)]
[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
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;
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
};
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))
}
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)
}
--- /dev/null
+// 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)
+ }
+}
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;
pub mod hash;
pub mod debug;
pub mod default;
+pub mod custom;
#[path="cmp/partial_eq.rs"]
pub mod partial_eq;
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),
+ }
+ }
}
}
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)]
#[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};
mod log_syntax;
mod trace_macros;
+pub mod rustc_macro_registrar;
+
// for custom_derive
pub mod deriving;
--- /dev/null
+// 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
+ })
+}
"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"
"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",
]
"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",
]
--- /dev/null
+// 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();
+}
--- /dev/null
+// 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
+ }
+}
+
--- /dev/null
+// 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
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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()
+}
+
--- /dev/null
+// 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!");
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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();
+}
--- /dev/null
+// 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(); }
+}
--- /dev/null
+// 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)
+}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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"]
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {
+}
--- /dev/null
+// 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
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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 {}
+}
--- /dev/null
+// 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"]
--- /dev/null
+// 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
macro_rules! foo (
() => (
- #[derive_Clone] //~ WARN attributes of the form
+ #[derive_Clone] //~ ERROR attributes of the form
struct T;
);
);
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() {}
--- /dev/null
+// 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();
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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()
+}
+
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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());
+}
+
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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;
+}
// 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;
// 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;
// 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 }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// pretty-expanded FIXME #23616
-
#[derive(Copy, Clone)]
struct Test;
// Regression test for #20797.
-// pretty-expanded FIXME #23616
-
#![feature(question_mark)]
use std::default::Default;
// 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)]
+++ /dev/null
-// 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();
-}
// 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)]