diff --git a/mk/crates.mk b/mk/crates.mk index a915d07384f3c..06ad07de136b1 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -59,7 +59,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_platform_intrinsics rustc_errors \ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ - rustc_const_eval rustc_const_math rustc_incremental + rustc_const_eval rustc_const_math rustc_incremental rustc_macro HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \ flate arena graphviz rbml log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator @@ -99,7 +99,7 @@ DEPS_term := std DEPS_test := std getopts term native:rust_test_helpers DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos -DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros +DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro DEPS_proc_macro := syntax syntax_pos rustc_plugin log DEPS_syntax_pos := serialize @@ -118,11 +118,13 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo rustc_trans rustc_privacy rustc_lint rustc_plugin \ rustc_metadata syntax_ext proc_macro \ rustc_passes rustc_save_analysis rustc_const_eval \ - rustc_incremental syntax_pos rustc_errors + rustc_incremental syntax_pos rustc_errors rustc_macro DEPS_rustc_errors := log libc serialize syntax_pos DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags -DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math +DEPS_rustc_macro := std syntax +DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math \ + rustc_macro syntax_ext DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index cf6905ecf439a..7822fe2536f1f 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -139,8 +139,13 @@ fn calculate_type(sess: &session::Session, } } - // Everything else falls through below - config::CrateTypeExecutable | config::CrateTypeDylib => {}, + // Everything else falls through below. This will happen either with the + // `-C prefer-dynamic` or because we're a rustc-macro crate. Note that + // rustc-macro crates are required to be dylibs, and they're currently + // required to link to libsyntax as well. + config::CrateTypeExecutable | + config::CrateTypeDylib | + config::CrateTypeRustcMacro => {}, } let mut formats = FnvHashMap(); diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index e29a7cf9d6846..1f9738556d925 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -138,7 +138,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Creates a new reachability computation context. fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> { let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { - *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib + *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || + *ty == config::CrateTypeRustcMacro }); ReachableContext { tcx: tcx, diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 6fb1b16705fe4..c2f275e6deaf8 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -70,6 +70,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) { let needs_check = sess.crate_types.borrow().iter().any(|kind| { match *kind { config::CrateTypeDylib | + config::CrateTypeRustcMacro | config::CrateTypeCdylib | config::CrateTypeExecutable | config::CrateTypeStaticlib => true, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 562dce6a1b129..a2f926aa92c52 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -475,6 +475,7 @@ pub enum CrateType { CrateTypeRlib, CrateTypeStaticlib, CrateTypeCdylib, + CrateTypeRustcMacro, } #[derive(Clone, Hash)] @@ -962,6 +963,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { if sess.opts.debug_assertions { ret.push(attr::mk_word_item(InternedString::new("debug_assertions"))); } + if sess.opts.crate_types.contains(&CrateTypeRustcMacro) { + ret.push(attr::mk_word_item(InternedString::new("rustc_macro"))); + } return ret; } @@ -1547,6 +1551,7 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result CrateTypeDylib, "cdylib" => CrateTypeCdylib, "bin" => CrateTypeExecutable, + "rustc-macro" => CrateTypeRustcMacro, _ => { return Err(format!("unknown crate type: `{}`", part)); @@ -1635,6 +1640,7 @@ impl fmt::Display for CrateType { CrateTypeRlib => "rlib".fmt(f), CrateTypeStaticlib => "staticlib".fmt(f), CrateTypeCdylib => "cdylib".fmt(f), + CrateTypeRustcMacro => "rustc-macro".fmt(f), } } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 338c656379959..ee2837e7bf1ab 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -62,6 +62,7 @@ pub struct Session { pub entry_fn: RefCell>, pub entry_type: Cell>, pub plugin_registrar_fn: Cell>, + pub derive_registrar_fn: Cell>, pub default_sysroot: Option, // The name of the root source file of the crate, in the local file system. // The path is always expected to be absolute. `None` means that there is no @@ -314,6 +315,12 @@ impl Session { format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize()) } + pub fn generate_derive_registrar_symbol(&self, + svh: &Svh, + index: DefIndex) -> String { + format!("__rustc_derive_registrar__{}_{}", svh, index.as_usize()) + } + pub fn sysroot<'a>(&'a self) -> &'a Path { match self.opts.maybe_sysroot { Some (ref sysroot) => sysroot, @@ -501,6 +508,7 @@ pub fn build_session_(sopts: config::Options, entry_fn: RefCell::new(None), entry_type: Cell::new(None), plugin_registrar_fn: Cell::new(None), + derive_registrar_fn: Cell::new(None), default_sysroot: default_sysroot, local_crate_source_file: local_crate_source_file, working_dir: env::current_dir().unwrap(), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e048e618e84d6..725bbf6adfd42 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -495,6 +495,10 @@ pub struct GlobalCtxt<'tcx> { /// Cache for layouts computed from types. pub layout_cache: RefCell, &'tcx Layout>>, + + /// Map from function to the `#[derive]` mode that it's defining. Only used + /// by `rustc-macro` crates. + pub derive_macros: RefCell>, } impl<'tcx> GlobalCtxt<'tcx> { @@ -756,6 +760,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, '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) } } diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs new file mode 100644 index 0000000000000..ea7621e16e7b7 --- /dev/null +++ b/src/librustc_driver/derive_registrar.rs @@ -0,0 +1,37 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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 { + 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, +} + +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); + } + } +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 94092be4922b5..47a0399b63283 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -55,6 +55,8 @@ use syntax::util::node_count::NodeCounter; use syntax; use syntax_ext; +use derive_registrar; + #[derive(Clone)] pub struct Resolutions { pub def_map: DefMap, @@ -696,6 +698,18 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, sess.diagnostic()) }); + krate = time(time_passes, "maybe creating a macro crate", || { + let crate_types = sess.crate_types.borrow(); + let is_rustc_macro_crate = crate_types.contains(&config::CrateTypeRustcMacro); + let num_crate_types = crate_types.len(); + syntax_ext::rustc_macro_registrar::modify(&sess.parse_sess, + krate, + is_rustc_macro_crate, + num_crate_types, + sess.diagnostic(), + &sess.features.borrow()) + }); + let resolver_arenas = Resolver::arenas(); let mut resolver = Resolver::new(sess, make_glob_map, &resolver_arenas); @@ -838,6 +852,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, sess.plugin_registrar_fn.set(time(time_passes, "looking for plugin registrar", || { plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map) })); + sess.derive_registrar_fn.set(derive_registrar::find(&hir_map)); let region_map = time(time_passes, "region resolution", @@ -1171,6 +1186,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { 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, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index efadf1ff488df..6616e9579e818 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -107,7 +107,7 @@ pub mod test; pub mod driver; pub mod pretty; pub mod target_features; - +mod derive_registrar; const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\ md#bug-reports"; diff --git a/src/librustc_macro/Cargo.toml b/src/librustc_macro/Cargo.toml new file mode 100644 index 0000000000000..6b3ee21d9aceb --- /dev/null +++ b/src/librustc_macro/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_macro" +version = "0.0.0" + +[lib] +name = "rustc_macro" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +syntax = { path = "../libsyntax" } diff --git a/src/librustc_macro/lib.rs b/src/librustc_macro/lib.rs new file mode 100644 index 0000000000000..c2a2cc2ecd64d --- /dev/null +++ b/src/librustc_macro/lib.rs @@ -0,0 +1,169 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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>, +} + +/// 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) -> TokenStream { + TokenStream { inner: vec![item] } + } + + pub fn token_stream_items(stream: TokenStream) -> Vec> { + 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(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: 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 { + __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(()) + } +} diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 2d3302c2eef3a..d70510896b96e 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -19,6 +19,8 @@ rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } +rustc_macro = { path = "../librustc_macro" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_ext = { path = "../libsyntax_ext" } +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 85cf41e42a273..1e6c74bef8da5 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -234,6 +234,8 @@ pub fn rustc_version() -> String { pub const tag_panic_strategy: usize = 0x114; +pub const tag_macro_derive_registrar: usize = 0x115; + // NB: increment this if you change the format of metadata such that // rustc_version can't be found. pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2]; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 7e1f3ea618c97..2524348dc1a96 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -130,18 +130,23 @@ struct ExtensionCrate { metadata: PMDSource, dylib: Option, target_only: bool, + + ident: String, + name: String, + span: Span, + should_link: bool, } enum PMDSource { Registered(Rc), - Owned(MetadataBlob), + Owned(loader::Library), } impl PMDSource { pub fn as_slice<'a>(&'a self) -> &'a [u8] { match *self { PMDSource::Registered(ref cmd) => cmd.data(), - PMDSource::Owned(ref mdb) => mdb.as_slice(), + PMDSource::Owned(ref lib) => lib.metadata.as_slice(), } } } @@ -151,6 +156,17 @@ enum LoadResult { Loaded(loader::Library), } +pub struct Macros { + pub macro_rules: Vec, + + /// 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, + pub svh: Svh, + pub dylib: Option, +} + impl<'a> CrateReader<'a> { pub fn new(sess: &'a Session, cstore: &'a CStore, @@ -281,6 +297,7 @@ impl<'a> CrateReader<'a> { explicitly_linked: bool) -> (ast::CrateNum, Rc, cstore::CrateSource) { + info!("register crate `extern crate {} as {}`", name, ident); self.verify_no_symbol_conflicts(span, &lib.metadata); // Claim this crate number and cache it @@ -319,6 +336,11 @@ impl<'a> CrateReader<'a> { explicitly_linked: Cell::new(explicitly_linked), }); + if decoder::get_derive_registrar_fn(cmeta.data.as_slice()).is_some() { + self.sess.span_err(span, "crates of the `rustc-macro` crate type \ + cannot be linked at runtime"); + } + let source = cstore::CrateSource { dylib: dylib, rlib: rlib, @@ -349,9 +371,11 @@ impl<'a> CrateReader<'a> { kind: PathKind, explicitly_linked: bool) -> (ast::CrateNum, Rc, cstore::CrateSource) { + info!("resolving crate `extern crate {} as {}`", name, ident); let result = match self.existing_match(name, hash, kind) { Some(cnum) => LoadResult::Previous(cnum), None => { + info!("falling back to a load"); let mut load_ctxt = loader::Context { sess: self.sess, span: span, @@ -412,6 +436,7 @@ impl<'a> CrateReader<'a> { self.cstore.iter_crate_data(|cnum, data| { if data.name() == meta_name && meta_hash == data.hash() { assert!(loader.hash.is_none()); + info!("load success, going to previous cnum: {}", cnum); result = LoadResult::Previous(cnum); } }); @@ -483,6 +508,8 @@ impl<'a> CrateReader<'a> { } fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate { + info!("read extension crate {} `extern crate {} as {}` linked={}", + info.id, info.name, info.ident, info.should_link); let target_triple = &self.sess.opts.target_triple[..]; let is_cross = target_triple != config::host_triple(); let mut should_link = info.should_link && !is_cross; @@ -533,16 +560,7 @@ impl<'a> CrateReader<'a> { } LoadResult::Loaded(library) => { let dylib = library.dylib.clone(); - let metadata = if should_link { - // Register crate now to avoid double-reading metadata - let (_, cmd, _) = self.register_crate(&None, &info.ident, - &info.name, span, - library, true); - PMDSource::Registered(cmd) - } else { - // Not registering the crate; just hold on to the metadata - PMDSource::Owned(library.metadata) - }; + let metadata = PMDSource::Owned(library); (dylib, metadata) } }; @@ -551,59 +569,97 @@ impl<'a> CrateReader<'a> { 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 { + pub fn read_macros(&mut self, item: &ast::Item) -> Macros { let ci = self.extract_crate_info(item).unwrap(); let ekrate = self.read_extension_crate(item.span, &ci); let source_name = format!("<{} macros>", item.ident); - let mut macros = vec![]; + let mut ret = Macros { + macro_rules: Vec::new(), + custom_derive_registrar: None, + svh: decoder::get_crate_hash(ekrate.metadata.as_slice()), + dylib: None, + }; decoder::each_exported_macro(ekrate.metadata.as_slice(), - |name, attrs, span, body| { - // NB: Don't use parse::parse_tts_from_source_str because it parses with - // quote_depth > 0. - let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, - self.local_crate_config.clone(), - source_name.clone(), - body); - let lo = p.span.lo; - let body = match p.parse_all_token_trees() { - Ok(body) => body, - Err(mut err) => { - err.emit(); - self.sess.abort_if_errors(); - unreachable!(); - } - }; - let local_span = mk_sp(lo, p.last_span.hi); - - // Mark the attrs as used - for attr in &attrs { - attr::mark_used(attr); + |name, attrs, span, body| { + // NB: Don't use parse::parse_tts_from_source_str because it parses with + // quote_depth > 0. + let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, + self.local_crate_config.clone(), + source_name.clone(), + body); + let lo = p.span.lo; + let body = match p.parse_all_token_trees() { + Ok(body) => body, + Err(mut err) => { + err.emit(); + self.sess.abort_if_errors(); + unreachable!(); } + }; + let local_span = mk_sp(lo, p.last_span.hi); - macros.push(ast::MacroDef { - ident: ast::Ident::with_empty_ctxt(name), - attrs: attrs, - id: ast::DUMMY_NODE_ID, - span: local_span, - imported_from: Some(item.ident), - // overridden in plugin/load.rs - export: false, - use_locally: false, - allow_internal_unstable: false, - - body: body, - }); - self.sess.imported_macro_spans.borrow_mut() - .insert(local_span, (name.as_str().to_string(), span)); - true + // Mark the attrs as used + for attr in &attrs { + attr::mark_used(attr); + } + + ret.macro_rules.push(ast::MacroDef { + ident: ast::Ident::with_empty_ctxt(name), + attrs: attrs, + id: ast::DUMMY_NODE_ID, + span: local_span, + imported_from: Some(item.ident), + // overridden in plugin/load.rs + export: false, + use_locally: false, + allow_internal_unstable: false, + + body: body, + }); + self.sess.imported_macro_spans.borrow_mut() + .insert(local_span, (name.as_str().to_string(), span)); + true + }); + + match decoder::get_derive_registrar_fn(ekrate.metadata.as_slice()) { + Some(id) => ret.custom_derive_registrar = Some(id), + + // If this crate is not a rustc-macro crate then we might be able to + // register it with the local crate store to prevent loading the + // metadata twice. + // + // If it's a rustc-macro crate, though, then we definitely don't + // want to register it with the local crate store as we're just + // going to use it as we would a plugin. + None => { + ekrate.register(self); + return ret } - ); - macros + } + + self.cstore.add_used_for_derive_macros(item); + ret.dylib = ekrate.dylib.clone(); + if ret.dylib.is_none() { + span_bug!(item.span, "rustc-macro crate not dylib"); + } + + if ekrate.target_only { + let message = format!("rustc-macro crate is not available for \ + triple `{}` (only found {})", + config::host_triple(), + self.sess.opts.target_triple); + self.sess.span_fatal(item.span, &message); + } + + return ret } /// Look for a plugin registrar. Returns library path, crate @@ -774,6 +830,7 @@ impl<'a> CrateReader<'a> { match *ct { config::CrateTypeExecutable => need_exe_alloc = true, config::CrateTypeDylib | + config::CrateTypeRustcMacro | config::CrateTypeCdylib | config::CrateTypeStaticlib => need_lib_alloc = true, config::CrateTypeRlib => {} @@ -858,6 +915,27 @@ impl<'a> CrateReader<'a> { } } +impl ExtensionCrate { + fn register(self, creader: &mut CrateReader) { + if !self.should_link { + return + } + + let library = match self.metadata { + PMDSource::Owned(lib) => lib, + PMDSource::Registered(_) => return, + }; + + // Register crate now to avoid double-reading metadata + creader.register_crate(&None, + &self.ident, + &self.name, + self.span, + library, + true); + } +} + impl<'a> LocalCrateReader<'a> { fn new(sess: &'a Session, cstore: &'a CStore, @@ -906,11 +984,25 @@ impl<'a> LocalCrateReader<'a> { 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, diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index d786cc5ba0eb7..952d7008d0f27 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -28,13 +28,13 @@ use rustc::hir::svh::Svh; use rustc::middle::cstore::ExternCrate; use rustc::session::config::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; -use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; +use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet}; use std::cell::{RefCell, Ref, Cell}; use std::rc::Rc; use std::path::PathBuf; use flate::Bytes; -use syntax::ast; +use syntax::ast::{self, Ident}; use syntax::attr; use syntax::codemap; use syntax_pos; @@ -115,6 +115,7 @@ pub struct CStore { pub inlined_item_cache: RefCell>>, pub defid_for_inlined_node: RefCell>, pub visible_parent_map: RefCell>, + pub used_for_derive_macro: RefCell>, } impl CStore { @@ -130,6 +131,7 @@ 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()), } } @@ -286,6 +288,14 @@ impl CStore { { 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 { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 7117cdb731cf3..9a13be8ade52a 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1398,6 +1398,11 @@ pub fn each_exported_macro(data: &[u8], mut f: F) where } } +pub fn get_derive_registrar_fn(data: &[u8]) -> Option { + 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)); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index b3ac678d7120d..bb4cf70bd3b3e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -31,7 +31,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::svh::Svh; use rustc::mir::mir_map::MirMap; -use rustc::session::config::{self, PanicStrategy}; +use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; use rustc_serialize::Encodable; @@ -1567,7 +1567,8 @@ fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) { /// Serialize the text of the exported macros fn encode_macro_defs(rbml_w: &mut Encoder, - krate: &hir::Crate) { + krate: &hir::Crate, + tcx: TyCtxt) { rbml_w.start_tag(tag_macro_defs); for def in &krate.exported_macros { rbml_w.start_tag(tag_macro_def); @@ -1585,6 +1586,12 @@ fn encode_macro_defs(rbml_w: &mut Encoder, rbml_w.end_tag(); } rbml_w.end_tag(); + + if tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro) { + let id = tcx.sess.derive_registrar_fn.get().unwrap(); + let did = tcx.map.local_def_id(id); + rbml_w.wr_tagged_u32(tag_macro_derive_registrar, did.index.as_u32()); + } } fn encode_struct_field_attrs(ecx: &EncodeContext, @@ -1882,7 +1889,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, // 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. diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index a96fa8a006d89..a3afb9d84bd30 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -19,11 +19,13 @@ #![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; @@ -33,12 +35,14 @@ extern crate flate; 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; diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index fa31b6f4c7224..22691975050e5 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -10,16 +10,25 @@ //! Used by `rustc` when loading a crate with exported macros. -use creader::CrateReader; +use std::collections::HashSet; +use std::env; +use std::mem; + +use creader::{CrateReader, Macros}; use cstore::CStore; +use rustc::hir::def_id::DefIndex; use rustc::session::Session; -use rustc::util::nodemap::{FnvHashSet, FnvHashMap}; - -use syntax::parse::token; +use rustc::util::nodemap::FnvHashMap; +use rustc_back::dynamic_lib::DynamicLibrary; +use rustc_macro::TokenStream; +use rustc_macro::__internal::Registry; use syntax::ast; use syntax::attr; +use syntax::ext::base::LoadedMacro; use syntax::ext; +use syntax::parse::token; +use syntax_ext::deriving::custom::CustomDerive; use syntax_pos::Span; pub struct MacroLoader<'a> { @@ -47,7 +56,9 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) { pub type MacroSelection = FnvHashMap; impl<'a> ext::base::MacroLoader for MacroLoader<'a> { - fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { + fn load_crate(&mut self, + extern_crate: &ast::Item, + allows_macros: bool) -> Vec { // Parse the attributes relating to macros. let mut import = Some(FnvHashMap()); // None => load all let mut reexport = FnvHashMap(); @@ -105,7 +116,7 @@ impl<'a> MacroLoader<'a> { allows_macros: bool, import: Option, reexport: MacroSelection) - -> Vec { + -> Vec { if let Some(sel) = import.as_ref() { if sel.is_empty() && reexport.is_empty() { return Vec::new(); @@ -118,10 +129,11 @@ impl<'a> MacroLoader<'a> { return Vec::new(); } - let mut macros = Vec::new(); - let mut seen = FnvHashSet(); + let mut macros = self.reader.read_macros(vi); + let mut ret = Vec::new(); + let mut seen = HashSet::new(); - for mut def in self.reader.read_exported_macros(vi) { + for mut def in macros.macro_rules.drain(..) { let name = def.ident.name.as_str(); def.use_locally = match import.as_ref() { @@ -132,10 +144,29 @@ impl<'a> MacroLoader<'a> { 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) { @@ -152,6 +183,54 @@ impl<'a> MacroLoader<'a> { } } - 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) { + // 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); + + 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); } } diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 5ae6584aed425..6db821b2cd8d1 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -156,7 +156,6 @@ impl<'a> Registry<'a> { self.llvm_passes.push(name.to_owned()); } - /// Register an attribute with an attribute type. /// /// Registered attributes will bypass the `custom_attribute` feature gate. diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index b21785c27dae5..b970c63a22433 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -238,6 +238,7 @@ pub fn invalid_output_for_target(sess: &Session, match (sess.target.target.options.dynamic_linking, sess.target.target.options.executables, crate_type) { (false, _, config::CrateTypeCdylib) | + (false, _, config::CrateTypeRustcMacro) | (false, _, config::CrateTypeDylib) => true, (_, false, config::CrateTypeExecutable) => true, _ => false @@ -261,6 +262,7 @@ pub fn filename_for_input(sess: &Session, outputs.out_directory.join(&format!("lib{}.rlib", libname)) } config::CrateTypeCdylib | + config::CrateTypeRustcMacro | config::CrateTypeDylib => { let (prefix, suffix) = (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix); @@ -291,7 +293,8 @@ pub fn each_linked_rlib(sess: &Session, let fmts = sess.dependency_formats.borrow(); let fmts = fmts.get(&config::CrateTypeExecutable) .or_else(|| fmts.get(&config::CrateTypeStaticlib)) - .or_else(|| fmts.get(&config::CrateTypeCdylib)); + .or_else(|| fmts.get(&config::CrateTypeCdylib)) + .or_else(|| fmts.get(&config::CrateTypeRustcMacro)); let fmts = fmts.unwrap_or_else(|| { bug!("could not find formats for rlibs") }); @@ -738,7 +741,8 @@ fn link_args(cmd: &mut Linker, // When linking a dynamic library, we put the metadata into a section of the // executable. This metadata is in a separate object file from the main // object file, so we link that in here. - if crate_type == config::CrateTypeDylib { + if crate_type == config::CrateTypeDylib || + crate_type == config::CrateTypeRustcMacro { cmd.add_object(&outputs.with_extension("metadata.o")); } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index f2d5b128d2705..58cad5c117f93 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::HashMap; use std::ffi::OsString; use std::fs::{self, File}; -use std::io::{self, BufWriter}; use std::io::prelude::*; +use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; use std::process::Command; @@ -28,16 +29,16 @@ use syntax::ast; /// 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, - cdylib_exports: Vec + exports: HashMap>, } impl<'a, 'tcx> LinkerInfo { pub fn new(scx: &SharedCrateContext<'a, 'tcx>, reachable: &[String]) -> LinkerInfo { LinkerInfo { - dylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeDylib), - cdylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeCdylib) + exports: scx.sess().crate_types.borrow().iter().map(|&c| { + (c, exported_symbols(scx, reachable, c)) + }).collect(), } } @@ -243,7 +244,8 @@ impl<'a> Linker for GnuLinker<'a> { // exported symbols to ensure we don't expose any more. The object files // have far more public symbols than we actually want to export, so we // hide them all here. - if crate_type == CrateType::CrateTypeDylib { + if crate_type == CrateType::CrateTypeDylib || + crate_type == CrateType::CrateTypeRustcMacro { return } @@ -254,7 +256,7 @@ impl<'a> Linker for GnuLinker<'a> { let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); writeln!(f, "{{\n global:")?; - for sym in &self.info.cdylib_exports { + for sym in self.info.exports[&crate_type].iter() { writeln!(f, " {};", sym)?; } writeln!(f, "\n local:\n *;\n}};")?; @@ -274,7 +276,7 @@ impl<'a> Linker for GnuLinker<'a> { }; let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); - for sym in &self.info.cdylib_exports { + for sym in self.info.exports[&crate_type].iter() { writeln!(f, "{}{}", prefix, sym)?; } Ok(()) @@ -427,12 +429,7 @@ impl<'a> Linker for MsvcLinker<'a> { // straight to exports. writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - let symbols = if crate_type == CrateType::CrateTypeCdylib { - &self.info.cdylib_exports - } else { - &self.info.dylib_exports - }; - for symbol in symbols { + for symbol in self.info.exports[&crate_type].iter() { writeln!(f, " {}", symbol)?; } Ok(()) @@ -450,13 +447,10 @@ fn exported_symbols(scx: &SharedCrateContext, reachable: &[String], crate_type: CrateType) -> Vec { - 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![]; } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 9b02cbe6721f3..143275fa7117b 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -188,6 +188,11 @@ impl<'a, 'tcx> Instance<'tcx> { 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. diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 43e190f5deb81..3b1c01319c492 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -27,10 +27,10 @@ use ptr::P; use util::small_vector::SmallVector; use util::lev_distance::find_best_match_for_name; use fold::Folder; +use feature_gate; use std::collections::{HashMap, HashSet}; use std::rc::Rc; -use std::default::Default; use tokenstream; @@ -568,12 +568,18 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) } pub trait MacroLoader { - fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) + -> Vec; +} + +pub enum LoadedMacro { + Def(ast::MacroDef), + CustomDerive(String, Box), } pub struct DummyMacroLoader; impl MacroLoader for DummyMacroLoader { - fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec { + fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec { Vec::new() } } @@ -593,6 +599,7 @@ pub struct ExtCtxt<'a> { pub exported_macros: Vec, pub syntax_env: SyntaxEnv, + pub derive_modes: HashMap>, pub recursion_count: usize, pub filename: Option, @@ -616,6 +623,7 @@ impl<'a> ExtCtxt<'a> { exported_macros: Vec::new(), loader: loader, syntax_env: env, + derive_modes: HashMap::new(), recursion_count: 0, filename: None, @@ -714,6 +722,25 @@ impl<'a> ExtCtxt<'a> { } } + pub fn insert_custom_derive(&mut self, + name: &str, + ext: Box, + 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) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 15ebf95d62393..d06b77a5b0549 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -440,8 +440,7 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVe callee: NameAndSpan { format: MacroAttribute(intern(&attr.name())), span: Some(attr.span), - // attributes can do whatever they like, for now - allow_internal_unstable: true, + allow_internal_unstable: false, } }); @@ -538,7 +537,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // We need to error on `#[macro_use] extern crate` when it isn't at the // crate root, because `$crate` won't work properly. for def in self.cx.loader.load_crate(item, self.at_crate_root) { - self.cx.insert_macro(def); + match def { + LoadedMacro::Def(def) => self.cx.insert_macro(def), + LoadedMacro::CustomDerive(name, ext) => { + self.cx.insert_custom_derive(&name, ext, item.span); + } + } } } else { let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false); @@ -688,6 +692,7 @@ impl<'feat> ExpansionConfig<'feat> { 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, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 02c44c3a56d7e..683d5277359e8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -47,7 +47,7 @@ macro_rules! setter { } macro_rules! declare_features { - ($((active, $feature: ident, $ver: expr, $issue: expr)),+) => { + ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => { /// Represents active features that are currently being implemented or /// currently being considered for addition/removal. const ACTIVE_FEATURES: &'static [(&'static str, &'static str, @@ -75,14 +75,14 @@ macro_rules! declare_features { } }; - ($((removed, $feature: ident, $ver: expr, $issue: expr)),+) => { + ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => { /// Represents features which has since been removed (it was once Active) const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option)] = &[ $((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)] = &[ $((stringify!($feature), $ver, $issue)),+ @@ -288,7 +288,10 @@ declare_features! ( (active, abi_sysv64, "1.13.0", Some(36167)), // Use the import semantics from RFC 1560. - (active, item_like_imports, "1.13.0", Some(35120)) + (active, item_like_imports, "1.13.0", Some(35120)), + + // Macros 1.1 + (active, rustc_macro, "1.13.0", Some(35900)), ); declare_features! ( @@ -302,7 +305,6 @@ 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! ( @@ -330,7 +332,7 @@ 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) @@ -543,6 +545,15 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat is an experimental feature", cfg_fn!(linked_from))), + ("rustc_macro_derive", Normal, Gated("rustc_macro", + "the `#[rustc_macro_derive]` attribute \ + is an experimental feature", + cfg_fn!(rustc_macro))), + + ("rustc_copy_clone_marker", Whitelisted, Gated("rustc_attrs", + "internal implementation detail", + cfg_fn!(rustc_attrs))), + // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted, Ungated), @@ -616,6 +627,7 @@ const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)), ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), + ("rustc_macro", "rustc_macro", cfg_fn!(rustc_macro)), ]; #[derive(Debug, Eq, PartialEq)] diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 040c6c8ebff26..6910e6400d4f8 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["dylib"] [dependencies] fmt_macros = { path = "../libfmt_macros" } log = { path = "../liblog" } +rustc_errors = { path = "../librustc_errors" } +rustc_macro = { path = "../librustc_macro" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_errors = { path = "../librustc_errors" } \ No newline at end of file diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index f1a3a1f41b14e..c7afaaf4796a4 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -49,7 +49,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, ItemKind::Struct(_, Generics { ref ty_params, .. }) | ItemKind::Enum(_, Generics { ref ty_params, .. }) if ty_params.is_empty() && - attr::contains_name(&annitem.attrs, "derive_Copy") => { + attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") => { bounds = vec![Literal(path_std!(cx, core::marker::Copy))]; unify_fieldless_variants = true; @@ -110,12 +110,12 @@ fn cs_clone(name: &str, Mode::Shallow => cx.std_path(&["clone", "assert_receiver_is_clone"]), Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]), }; - let subcall = |field: &FieldInfo| { + let subcall = |cx: &mut ExtCtxt, field: &FieldInfo| { let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; let span = if mode == Mode::Shallow { // set the expn ID so we can call the unstable method - Span { expn_id: cx.backtrace(), ..trait_span } + super::allow_unstable(cx, field.span, "derive(Clone)") } else { field.span }; @@ -147,8 +147,10 @@ fn cs_clone(name: &str, match mode { Mode::Shallow => { - let mut stmts: Vec<_> = - all_fields.iter().map(subcall).map(|e| cx.stmt_expr(e)).collect(); + let mut stmts = all_fields.iter().map(|f| { + let call = subcall(cx, f); + cx.stmt_expr(call) + }).collect::>(); stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span)))); cx.expr_block(cx.block(trait_span, stmts)) } @@ -166,14 +168,15 @@ fn cs_clone(name: &str, name)) } }; - cx.field_imm(field.span, ident, subcall(field)) + let call = subcall(cx, field); + cx.field_imm(field.span, ident, call) }) .collect::>(); cx.expr_struct(trait_span, ctor_path, fields) } VariantData::Tuple(..) => { - let subcalls = all_fields.iter().map(subcall).collect(); + let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect(); let path = cx.expr_path(ctor_path); cx.expr_call(trait_span, path, subcalls) } diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs new file mode 100644 index 0000000000000..1f9c24a0dcd69 --- /dev/null +++ b/src/libsyntax_ext/deriving/custom.rs @@ -0,0 +1,97 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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 { + 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::() { + 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) + } +} diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 81085122e875b..5582166c12e9c 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -12,7 +12,7 @@ use syntax::ast::{self, MetaItem}; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; -use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; +use syntax::ext::base::MultiModifier; use syntax::ext::build::AstBuilder; use syntax::feature_gate; use syntax::codemap; @@ -61,6 +61,7 @@ pub mod decodable; pub mod hash; pub mod debug; pub mod default; +pub mod custom; #[path="cmp/partial_eq.rs"] pub mod partial_eq; @@ -74,156 +75,201 @@ pub mod ord; 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 { 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::>(); + 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), + } + } } } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 3aa62339b477e..4bae9ec5a1a1f 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -19,6 +19,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] +#![feature(rustc_macro_lib)] +#![feature(rustc_macro_internals)] #![feature(rustc_private)] #![feature(staged_api)] @@ -28,6 +30,7 @@ extern crate log; #[macro_use] extern crate syntax; extern crate syntax_pos; +extern crate rustc_macro; extern crate rustc_errors as errors; use syntax::ext::base::{MacroExpanderFn, NormalTT}; @@ -44,6 +47,8 @@ mod format; mod log_syntax; mod trace_macros; +pub mod rustc_macro_registrar; + // for custom_derive pub mod deriving; diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs new file mode 100644 index 0000000000000..7693e2416f4b0 --- /dev/null +++ b/src/libsyntax_ext/rustc_macro_registrar.rs @@ -0,0 +1,280 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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, + 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 { + 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::>(); + + 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 + }) +} diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index fde2f83e220f9..3377fc43d8a60 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -214,6 +214,13 @@ dependencies = [ "rustc_bitflags 0.0.0", ] +[[package]] +name = "rustc_macro" +version = "0.0.0" +dependencies = [ + "syntax 0.0.0", +] + [[package]] name = "rustc_metadata" version = "0.0.0" @@ -228,8 +235,10 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_llvm 0.0.0", + "rustc_macro 0.0.0", "serialize 0.0.0", "syntax 0.0.0", + "syntax_ext 0.0.0", "syntax_pos 0.0.0", ] @@ -400,6 +409,7 @@ dependencies = [ "fmt_macros 0.0.0", "log 0.0.0", "rustc_errors 0.0.0", + "rustc_macro 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs new file mode 100644 index 0000000000000..fa0b5763803ff --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs @@ -0,0 +1,33 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:append-impl.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate append_impl; + +trait Append { + fn foo(&self); +} + +#[derive(PartialEq, + Append, + Eq)] +//~^^ ERROR: the semantics of constant patterns is not yet settled +struct A { + inner: u32, +} + +fn main() { + A { inner: 3 }.foo(); +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs b/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs new file mode 100644 index 0000000000000..46724523d1c70 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +pub mod a { //~ `rustc-macro` crate types cannot export any items + use rustc_macro::TokenStream; + + #[rustc_macro_derive(B)] + pub fn bar(a: TokenStream) -> TokenStream { + //~^ ERROR: must currently reside in the root of the crate + a + } +} + diff --git a/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs b/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs new file mode 100644 index 0000000000000..7740238aeacc9 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs @@ -0,0 +1,46 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +#[rustc_macro_derive] +//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)] +pub fn foo1(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive = "foo"] +//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)] +pub fn foo2(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive( + a = "b" +)] +//~^^ ERROR: must only be one word +pub fn foo3(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive(b, c)] +//~^ ERROR: attribute must only have one argument +pub fn foo4(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive(d(e))] +//~^ ERROR: must only be one word +pub fn foo5(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs new file mode 100644 index 0000000000000..c3d295e02c163 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(Append)] +pub fn derive_a(input: TokenStream) -> TokenStream { + let mut input = input.to_string(); + input.push_str(" + impl Append for A { + fn foo(&self) {} + } + "); + input.parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs new file mode 100644 index 0000000000000..ff00a9d96a30a --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs new file mode 100644 index 0000000000000..ff00a9d96a30a --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs new file mode 100644 index 0000000000000..5dd42d28b7be1 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic +// force-host + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(_input: TokenStream) -> TokenStream { + "struct A { inner }".parse().unwrap() +} + diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs new file mode 100644 index 0000000000000..d867082ed5e52 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic +// force-host + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(_input: TokenStream) -> TokenStream { + panic!("nope!"); +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs new file mode 100644 index 0000000000000..9eebad897564a --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(Unstable)] +pub fn derive(_input: TokenStream) -> TokenStream { + + " + #[rustc_foo] + fn foo() {} + ".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs new file mode 100644 index 0000000000000..f4a1ec9970067 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(Unstable)] +pub fn derive(_input: TokenStream) -> TokenStream { + + "unsafe fn foo() -> u32 { ::std::intrinsics::init() }".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs b/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs new file mode 100644 index 0000000000000..1f135330a9995 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-a.rs + +extern crate derive_a; +//~^ ERROR: crates of the `rustc-macro` crate type cannot be linked at runtime + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs b/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs new file mode 100644 index 0000000000000..e4f21dc23840b --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn foo(input: TokenStream) -> TokenStream { + input +} + +#[rustc_macro_derive(A)] //~ ERROR: derive mode defined twice in this crate +pub fn bar(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs b/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs new file mode 100644 index 0000000000000..f3a73af299357 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-bad.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_bad; + +#[derive( + A +)] +//~^^ ERROR: custom derive attribute panicked +//~| HELP: called `Result::unwrap()` on an `Err` value: LexError +struct A; + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs b/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs new file mode 100644 index 0000000000000..a46d79f517f7d --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-a.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_a; + +#[derive_A] //~ ERROR: attributes of the form `#[derive_*]` are reserved for the compiler +struct A; + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs new file mode 100644 index 0000000000000..29b9fd228094a --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-unstable-2.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_unstable_2; + +#[derive(Unstable)] +//~^ ERROR: reserved for internal compiler +struct A; + +fn main() { + foo(); +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs new file mode 100644 index 0000000000000..874081760f662 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-unstable.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_unstable; + +#[derive(Unstable)] +//~^ ERROR: use of unstable library feature +struct A; + +fn main() { + unsafe { foo(); } +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs b/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs new file mode 100644 index 0000000000000..759f3d32e16e6 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: cannot export macro_rules! macros from a `rustc-macro` crate + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +#[macro_export] +macro_rules! foo { + ($e:expr) => ($e) +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/exports.rs b/src/test/compile-fail-fulldeps/rustc-macro/exports.rs new file mode 100644 index 0000000000000..e985356dc5844 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/exports.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rustc-macro"] +#![allow(warnings)] + +pub fn a() {} //~ ERROR: cannot export any items +pub struct B; //~ ERROR: cannot export any items +pub enum C {} //~ ERROR: cannot export any items +pub mod d {} //~ ERROR: cannot export any items + +mod e {} +struct F; +enum G {} +fn h() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs new file mode 100644 index 0000000000000..86afc08cae861 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: the `rustc-macro` crate type is experimental + +#![crate_type = "rustc-macro"] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs new file mode 100644 index 0000000000000..1a19f6046d9e1 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate rustc_macro; //~ ERROR: use of unstable library feature + +fn main() {} diff --git a/src/test/run-pass/single-derive-attr-with-gate.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs similarity index 68% rename from src/test/run-pass/single-derive-attr-with-gate.rs rename to src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs index addc56e9c4210..9f47f07bd023d 100644 --- a/src/test/run-pass/single-derive-attr-with-gate.rs +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,13 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +#![crate_type = "rustc-macro"] -#![feature(custom_derive)] - -#[derive_Clone] -struct Test; - -pub fn main() { - Test.clone(); +#[rustc_macro_derive(Foo)] //~ ERROR: is an experimental feature +pub fn foo() { } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs new file mode 100644 index 0000000000000..0fdd13bc30cce --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-a.rs + +#[macro_use] +extern crate derive_a; +//~^ ERROR: loading custom derive macro crates is experimentally supported diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs new file mode 100644 index 0000000000000..e44b29a170517 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs @@ -0,0 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(rustc_macro)] //~ ERROR: experimental and subject to change +fn foo() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/import.rs b/src/test/compile-fail-fulldeps/rustc-macro/import.rs new file mode 100644 index 0000000000000..c1d0823cb6b84 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/import.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-a.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_a; + +use derive_a::derive_a; +//~^ ERROR: unresolved import `derive_a::derive_a` + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs b/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs new file mode 100644 index 0000000000000..0d08d27c38e46 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-panic.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_panic; + +#[derive(A)] +//~^ ERROR: custom derive attribute panicked +//~| HELP: message: nope! +struct Foo; + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs b/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs new file mode 100644 index 0000000000000..cdc50acea9262 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_macro)] + +extern crate rustc_macro; + +#[rustc_macro_derive(Foo)] +//~^ ERROR: only usable with crates of the `rustc-macro` crate type +pub fn foo(a: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + a +} + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs b/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs new file mode 100644 index 0000000000000..1353a234b4836 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(PartialEq)] +//~^ ERROR: cannot override a built-in #[derive] mode +pub fn foo(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs b/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs new file mode 100644 index 0000000000000..33330ed8f6a05 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-a.rs +// aux-build:derive-a-2.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_a; +#[macro_use] +extern crate derive_a_2; //~ ERROR: cannot shadow existing derive mode `A` + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/signature.rs b/src/test/compile-fail-fulldeps/rustc-macro/signature.rs new file mode 100644 index 0000000000000..9662cc69e1e14 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/signature.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![allow(warnings)] + +extern crate rustc_macro; + +#[rustc_macro_derive(A)] +unsafe extern fn foo(a: i32, b: u32) -> u32 { + //~^ ERROR: mismatched types + //~| NOTE: expected normal fn, found unsafe fn + //~| NOTE: expected type `fn(rustc_macro::TokenStream) -> rustc_macro::TokenStream` + //~| NOTE: found type `unsafe extern "C" fn(i32, u32) -> u32 {foo}` + loop {} +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs new file mode 100644 index 0000000000000..35f6149ad4946 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: cannot mix `rustc-macro` crate type with others + +#![crate_type = "rustc-macro"] +#![crate_type = "rlib"] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs new file mode 100644 index 0000000000000..ec95e3e4685be --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs @@ -0,0 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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 diff --git a/src/test/compile-fail/issue-32655.rs b/src/test/compile-fail/issue-32655.rs index edd7fe4a1e588..25ecd5d08626d 100644 --- a/src/test/compile-fail/issue-32655.rs +++ b/src/test/compile-fail/issue-32655.rs @@ -13,7 +13,7 @@ macro_rules! foo ( () => ( - #[derive_Clone] //~ WARN attributes of the form + #[derive_Clone] //~ ERROR attributes of the form struct T; ); ); @@ -25,9 +25,8 @@ macro_rules! bar ( foo!(); bar!( - #[derive_Clone] //~ WARN attributes of the form + #[derive_Clone] //~ ERROR attributes of the form struct S; ); -#[rustc_error] -fn main() {} //~ ERROR compilation successful +fn main() {} diff --git a/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs b/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs new file mode 100644 index 0000000000000..226c082564ae4 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:add-impl.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate add_impl; + +#[derive(AddImpl)] +struct B; + +fn main() { + B.foo(); + foo(); + bar::foo(); +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs new file mode 100644 index 0000000000000..8aab423af0a3b --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs @@ -0,0 +1,33 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(AddImpl)] +// #[cfg(rustc_macro)] +pub fn derive(input: TokenStream) -> TokenStream { + (input.to_string() + " + impl B { + fn foo(&self) {} + } + + fn foo() {} + + mod bar { pub fn foo() {} } + ").parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs new file mode 100644 index 0000000000000..4dd6ad88b757c --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert!(input.contains("struct A;")); + assert!(input.contains("#[derive(Eq, Copy, Clone)]")); + "#[derive(Eq, Copy, Clone)] struct A;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs new file mode 100644 index 0000000000000..5b85e2b2a7c4b --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(AToB)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert_eq!(input, "struct A;\n"); + "struct B;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs new file mode 100644 index 0000000000000..54f8dff509ab0 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(CToD)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert_eq!(input, "struct C;\n"); + "struct D;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs new file mode 100644 index 0000000000000..d83e352e3b175 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs @@ -0,0 +1,32 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic +// compile-flags:--crate-type rustc-macro + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(AToB)] +pub fn derive1(input: TokenStream) -> TokenStream { + println!("input1: {:?}", input.to_string()); + assert_eq!(input.to_string(), "#[derive(BToC)]\nstruct A;\n"); + "#[derive(BToC)] struct B;".parse().unwrap() +} + +#[rustc_macro_derive(BToC)] +pub fn derive2(input: TokenStream) -> TokenStream { + assert_eq!(input.to_string(), "struct B;\n"); + "struct C;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs new file mode 100644 index 0000000000000..96aea407e6e74 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs @@ -0,0 +1,36 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![deny(warnings)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert!(input.contains("struct A;")); + r#" + struct A; + + impl A { + fn a(&self) { + panic!("hello"); + } + } + "#.parse().unwrap() +} + diff --git a/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs b/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs new file mode 100644 index 0000000000000..ee0d594564883 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-same-struct.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_same_struct; + +#[derive(AToB, BToC)] +struct A; + +fn main() { + C; +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs new file mode 100644 index 0000000000000..cc59be2d75df3 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:expand-with-a-macro.rs +// ignore-stage1 + +#![feature(rustc_macro)] +#![deny(warnings)] + +#[macro_use] +extern crate expand_with_a_macro; + +use std::panic; + +#[derive(A)] +struct A; + +fn main() { + assert!(panic::catch_unwind(|| { + A.a(); + }).is_err()); +} + diff --git a/src/test/run-pass-fulldeps/rustc-macro/load-two.rs b/src/test/run-pass-fulldeps/rustc-macro/load-two.rs new file mode 100644 index 0000000000000..1500970f02dad --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/load-two.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-atob.rs +// aux-build:derive-ctod.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_atob; +#[macro_use] +extern crate derive_ctod; + +#[derive(AToB)] +struct A; + +#[derive(CToD)] +struct C; + +fn main() { + B; + D; +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/smoke.rs b/src/test/run-pass-fulldeps/rustc-macro/smoke.rs new file mode 100644 index 0000000000000..588380f1140c9 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/smoke.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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; +} diff --git a/src/test/run-pass/associated-types-normalize-unifield-struct.rs b/src/test/run-pass/associated-types-normalize-unifield-struct.rs index 3dffae99292c6..517033d58702d 100644 --- a/src/test/run-pass/associated-types-normalize-unifield-struct.rs +++ b/src/test/run-pass/associated-types-normalize-unifield-struct.rs @@ -11,9 +11,6 @@ // Regression test for issue #21010: Normalize associated types in // various special paths in the `type_is_immediate` function. - -// pretty-expanded FIXME #23616 - pub trait OffsetState: Sized {} pub trait Offset { type State: OffsetState; diff --git a/src/test/run-pass/builtin-superkinds-in-metadata.rs b/src/test/run-pass/builtin-superkinds-in-metadata.rs index c026ffc6d318d..3259b1cc0679e 100644 --- a/src/test/run-pass/builtin-superkinds-in-metadata.rs +++ b/src/test/run-pass/builtin-superkinds-in-metadata.rs @@ -13,8 +13,6 @@ // Tests (correct) usage of trait super-builtin-kinds cross-crate. -// pretty-expanded FIXME #23616 - extern crate trait_superkinds_in_metadata; use trait_superkinds_in_metadata::{RequiresRequiresShareAndSend, RequiresShare}; use trait_superkinds_in_metadata::RequiresCopy; diff --git a/src/test/run-pass/coherence-impl-in-fn.rs b/src/test/run-pass/coherence-impl-in-fn.rs index b0630b516407b..d7c21340afc39 100644 --- a/src/test/run-pass/coherence-impl-in-fn.rs +++ b/src/test/run-pass/coherence-impl-in-fn.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - pub fn main() { #[derive(Copy, Clone)] enum x { foo } diff --git a/src/test/run-pass/deriving-bounds.rs b/src/test/run-pass/deriving-bounds.rs index 4204d9b5c3eae..6d0a43997bc47 100644 --- a/src/test/run-pass/deriving-bounds.rs +++ b/src/test/run-pass/deriving-bounds.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #[derive(Copy, Clone)] struct Test; diff --git a/src/test/run-pass/issue-20797.rs b/src/test/run-pass/issue-20797.rs index 321ed1a3bb283..de95243665082 100644 --- a/src/test/run-pass/issue-20797.rs +++ b/src/test/run-pass/issue-20797.rs @@ -10,8 +10,6 @@ // Regression test for #20797. -// pretty-expanded FIXME #23616 - #![feature(question_mark)] use std::default::Default; diff --git a/src/test/run-pass/issue-2288.rs b/src/test/run-pass/issue-2288.rs index d16655a68554a..379715f539039 100644 --- a/src/test/run-pass/issue-2288.rs +++ b/src/test/run-pass/issue-2288.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index 7fa592105c09d..45ac334dc1d76 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #![allow(warnings)] #![feature(collections)] #![feature(drain, enumset, collections_bound, btree_range, vecmap)]