mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #35957 - alexcrichton:macros-1.1, r=nrc
rustc: Implement custom derive (macros 1.1) This commit is an implementation of [RFC 1681] which adds support to the compiler for first-class user-define custom `#[derive]` modes with a far more stable API than plugins have today. [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md The main features added by this commit are: * A new `rustc-macro` crate-type. This crate type represents one which will provide custom `derive` implementations and perhaps eventually flower into the implementation of macros 2.0 as well. * A new `rustc_macro` crate in the standard distribution. This crate will provide the runtime interface between macro crates and the compiler. The API here is particularly conservative right now but has quite a bit of room to expand into any manner of APIs required by macro authors. * The ability to load new derive modes through the `#[macro_use]` annotations on other crates. All support added here is gated behind the `rustc_macro` feature gate, both for the library support (the `rustc_macro` crate) as well as the language features. There are a few minor differences from the implementation outlined in the RFC, such as the `rustc_macro` crate being available as a dylib and all symbols are `dlsym`'d directly instead of having a shim compiled. These should only affect the implementation, however, not the public interface. This commit also ended up touching a lot of code related to `#[derive]`, making a few notable changes: * Recognized derive attributes are no longer desugared to `derive_Foo`. Wasn't sure how to keep this behavior and *not* expose it to custom derive. * Derive attributes no longer have access to unstable features by default, they have to opt in on a granular level. * The `derive(Copy,Clone)` optimization is now done through another "obscure attribute" which is just intended to ferry along in the compiler that such an optimization is possible. The `derive(PartialEq,Eq)` optimization was also updated to do something similar. --- One part of this PR which needs to be improved before stabilizing are the errors and exact interfaces here. The error messages are relatively poor quality and there are surprising spects of this such as `#[derive(PartialEq, Eq, MyTrait)]` not working by default. The custom attributes added by the compiler end up becoming unstable again when going through a custom impl. Hopefully though this is enough to start allowing experimentation on crates.io!
This commit is contained in:
commit
a029ea343f
10
mk/crates.mk
10
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
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -475,6 +475,7 @@ pub enum CrateType {
|
||||
CrateTypeRlib,
|
||||
CrateTypeStaticlib,
|
||||
CrateTypeCdylib,
|
||||
CrateTypeRustcMacro,
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash)]
|
||||
@ -962,6 +963,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
|
||||
if sess.opts.debug_assertions {
|
||||
ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
|
||||
}
|
||||
if sess.opts.crate_types.contains(&CrateTypeRustcMacro) {
|
||||
ret.push(attr::mk_word_item(InternedString::new("rustc_macro")));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1547,6 +1551,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
|
||||
"dylib" => CrateTypeDylib,
|
||||
"cdylib" => CrateTypeCdylib,
|
||||
"bin" => CrateTypeExecutable,
|
||||
"rustc-macro" => CrateTypeRustcMacro,
|
||||
_ => {
|
||||
return Err(format!("unknown crate type: `{}`",
|
||||
part));
|
||||
@ -1635,6 +1640,7 @@ impl fmt::Display for CrateType {
|
||||
CrateTypeRlib => "rlib".fmt(f),
|
||||
CrateTypeStaticlib => "staticlib".fmt(f),
|
||||
CrateTypeCdylib => "cdylib".fmt(f),
|
||||
CrateTypeRustcMacro => "rustc-macro".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ pub struct Session {
|
||||
pub entry_fn: RefCell<Option<(NodeId, Span)>>,
|
||||
pub entry_type: Cell<Option<config::EntryFnType>>,
|
||||
pub plugin_registrar_fn: Cell<Option<ast::NodeId>>,
|
||||
pub derive_registrar_fn: Cell<Option<ast::NodeId>>,
|
||||
pub default_sysroot: Option<PathBuf>,
|
||||
// The name of the root source file of the crate, in the local file system.
|
||||
// The path is always expected to be absolute. `None` means that there is no
|
||||
@ -314,6 +315,12 @@ 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(),
|
||||
|
@ -495,6 +495,10 @@ pub struct GlobalCtxt<'tcx> {
|
||||
|
||||
/// Cache for layouts computed from types.
|
||||
pub layout_cache: RefCell<FnvHashMap<Ty<'tcx>, &'tcx Layout>>,
|
||||
|
||||
/// Map from function to the `#[derive]` mode that it's defining. Only used
|
||||
/// by `rustc-macro` crates.
|
||||
pub derive_macros: RefCell<NodeMap<token::InternedString>>,
|
||||
}
|
||||
|
||||
impl<'tcx> GlobalCtxt<'tcx> {
|
||||
@ -756,6 +760,7 @@ 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)
|
||||
}
|
||||
}
|
||||
|
37
src/librustc_driver/derive_registrar.rs
Normal file
37
src/librustc_driver/derive_registrar.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::hir::intravisit::Visitor;
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::hir;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
|
||||
pub fn find(hir_map: &Map) -> Option<ast::NodeId> {
|
||||
let _task = hir_map.dep_graph.in_task(DepNode::PluginRegistrar);
|
||||
let krate = hir_map.krate();
|
||||
|
||||
let mut finder = Finder { registrar: None };
|
||||
krate.visit_all_items(&mut finder);
|
||||
finder.registrar
|
||||
}
|
||||
|
||||
struct Finder {
|
||||
registrar: Option<ast::NodeId>,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for Finder {
|
||||
fn visit_item(&mut self, item: &hir::Item) {
|
||||
if attr::contains_name(&item.attrs, "rustc_derive_registrar") {
|
||||
self.registrar = Some(item.id);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<c
|
||||
Some(ref n) if *n == "staticlib" => {
|
||||
Some(config::CrateTypeStaticlib)
|
||||
}
|
||||
Some(ref n) if *n == "rustc-macro" => {
|
||||
Some(config::CrateTypeRustcMacro)
|
||||
}
|
||||
Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
|
||||
Some(_) => {
|
||||
session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
|
||||
|
@ -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";
|
||||
|
12
src/librustc_macro/Cargo.toml
Normal file
12
src/librustc_macro/Cargo.toml
Normal file
@ -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" }
|
169
src/librustc_macro/lib.rs
Normal file
169
src/librustc_macro/lib.rs
Normal file
@ -0,0 +1,169 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A support library for macro authors when defining new macros.
|
||||
//!
|
||||
//! This library, provided by the standard distribution, provides the types
|
||||
//! consumed in the interfaces of procedurally defined macro definitions.
|
||||
//! Currently the primary use of this crate is to provide the ability to define
|
||||
//! new custom derive modes through `#[rustc_macro_derive]`.
|
||||
//!
|
||||
//! Added recently as part of [RFC 1681] this crate is currently *unstable* and
|
||||
//! requires the `#![feature(rustc_macro_lib)]` directive to use. Eventually,
|
||||
//! though, it is intended for this crate to become stable to use (perhaps under
|
||||
//! a different name).
|
||||
//!
|
||||
//! [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
|
||||
//!
|
||||
//! Note that this crate is intentionally very bare-bones currently. The main
|
||||
//! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
|
||||
//! implementations, indicating that it can only go to and come from a string.
|
||||
//! This functionality is intended to be expanded over time as more surface
|
||||
//! area for macro authors is stabilized.
|
||||
|
||||
#![crate_name = "rustc_macro"]
|
||||
#![unstable(feature = "rustc_macro_lib", issue = "27812")]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#![feature(rustc_private)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(lang_items)]
|
||||
|
||||
extern crate syntax;
|
||||
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::parse;
|
||||
use syntax::ptr::P;
|
||||
|
||||
/// The main type provided by this crate, representing an abstract stream of
|
||||
/// tokens.
|
||||
///
|
||||
/// This is both the input and output of `#[rustc_macro_derive]` definitions.
|
||||
/// Currently it's required to be a list of valid Rust items, but this
|
||||
/// restriction may be lifted in the future.
|
||||
///
|
||||
/// The API of this type is intentionally bare-bones, but it'll be expanded over
|
||||
/// time!
|
||||
pub struct TokenStream {
|
||||
inner: Vec<P<ast::Item>>,
|
||||
}
|
||||
|
||||
/// Error returned from `TokenStream::from_str`.
|
||||
#[derive(Debug)]
|
||||
pub struct LexError {
|
||||
_inner: (),
|
||||
}
|
||||
|
||||
/// Permanently unstable internal implementation details of this crate. This
|
||||
/// should not be used.
|
||||
///
|
||||
/// These methods are used by the rest of the compiler to generate instances of
|
||||
/// `TokenStream` to hand to macro definitions, as well as consume the output.
|
||||
///
|
||||
/// Note that this module is also intentionally separate from the rest of the
|
||||
/// crate. This allows the `#[unstable]` directive below to naturally apply to
|
||||
/// all of the contents.
|
||||
#[unstable(feature = "rustc_macro_internals", issue = "27812")]
|
||||
#[doc(hidden)]
|
||||
pub mod __internal {
|
||||
use std::cell::Cell;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ptr::P;
|
||||
use syntax::parse::ParseSess;
|
||||
use super::TokenStream;
|
||||
|
||||
pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
|
||||
TokenStream { inner: vec![item] }
|
||||
}
|
||||
|
||||
pub fn token_stream_items(stream: TokenStream) -> Vec<P<ast::Item>> {
|
||||
stream.inner
|
||||
}
|
||||
|
||||
pub trait Registry {
|
||||
fn register_custom_derive(&mut self,
|
||||
trait_name: &str,
|
||||
expand: fn(TokenStream) -> TokenStream);
|
||||
}
|
||||
|
||||
// Emulate scoped_thread_local!() here essentially
|
||||
thread_local! {
|
||||
static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _);
|
||||
}
|
||||
|
||||
pub fn set_parse_sess<F, R>(sess: &ParseSess, f: F) -> R
|
||||
where F: FnOnce() -> R
|
||||
{
|
||||
struct Reset { prev: *const ParseSess }
|
||||
|
||||
impl Drop for Reset {
|
||||
fn drop(&mut self) {
|
||||
CURRENT_SESS.with(|p| p.set(self.prev));
|
||||
}
|
||||
}
|
||||
|
||||
CURRENT_SESS.with(|p| {
|
||||
let _reset = Reset { prev: p.get() };
|
||||
p.set(sess);
|
||||
f()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_parse_sess<F, R>(f: F) -> R
|
||||
where F: FnOnce(&ParseSess) -> R
|
||||
{
|
||||
let p = CURRENT_SESS.with(|p| p.get());
|
||||
assert!(!p.is_null());
|
||||
f(unsafe { &*p })
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for TokenStream {
|
||||
type Err = LexError;
|
||||
|
||||
fn from_str(src: &str) -> Result<TokenStream, LexError> {
|
||||
__internal::with_parse_sess(|sess| {
|
||||
let src = src.to_string();
|
||||
let cfg = Vec::new();
|
||||
let name = "rustc-macro source code".to_string();
|
||||
let mut parser = parse::new_parser_from_source_str(sess, cfg, name,
|
||||
src);
|
||||
let mut ret = TokenStream { inner: Vec::new() };
|
||||
loop {
|
||||
match parser.parse_item() {
|
||||
Ok(Some(item)) => ret.inner.push(item),
|
||||
Ok(None) => return Ok(ret),
|
||||
Err(mut err) => {
|
||||
err.cancel();
|
||||
return Err(LexError { _inner: () })
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TokenStream {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for item in self.inner.iter() {
|
||||
let item = syntax::print::pprust::item_to_string(item);
|
||||
try!(f.write_str(&item));
|
||||
try!(f.write_str("\n"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -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" }
|
||||
syntax_ext = { path = "../libsyntax_ext" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
|
@ -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];
|
||||
|
@ -130,18 +130,23 @@ struct ExtensionCrate {
|
||||
metadata: PMDSource,
|
||||
dylib: Option<PathBuf>,
|
||||
target_only: bool,
|
||||
|
||||
ident: String,
|
||||
name: String,
|
||||
span: Span,
|
||||
should_link: bool,
|
||||
}
|
||||
|
||||
enum PMDSource {
|
||||
Registered(Rc<cstore::CrateMetadata>),
|
||||
Owned(MetadataBlob),
|
||||
Owned(loader::Library),
|
||||
}
|
||||
|
||||
impl PMDSource {
|
||||
pub fn as_slice<'a>(&'a self) -> &'a [u8] {
|
||||
match *self {
|
||||
PMDSource::Registered(ref cmd) => cmd.data(),
|
||||
PMDSource::Owned(ref mdb) => mdb.as_slice(),
|
||||
PMDSource::Owned(ref lib) => lib.metadata.as_slice(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -151,6 +156,17 @@ enum LoadResult {
|
||||
Loaded(loader::Library),
|
||||
}
|
||||
|
||||
pub struct Macros {
|
||||
pub macro_rules: Vec<ast::MacroDef>,
|
||||
|
||||
/// An array of pairs where the first element is the name of the custom
|
||||
/// derive (e.g. the trait being derived) and the second element is the
|
||||
/// index of the definition.
|
||||
pub custom_derive_registrar: Option<DefIndex>,
|
||||
pub svh: Svh,
|
||||
pub dylib: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl<'a> CrateReader<'a> {
|
||||
pub fn new(sess: &'a Session,
|
||||
cstore: &'a CStore,
|
||||
@ -281,6 +297,7 @@ impl<'a> CrateReader<'a> {
|
||||
explicitly_linked: bool)
|
||||
-> (ast::CrateNum, Rc<cstore::CrateMetadata>,
|
||||
cstore::CrateSource) {
|
||||
info!("register crate `extern crate {} as {}`", name, ident);
|
||||
self.verify_no_symbol_conflicts(span, &lib.metadata);
|
||||
|
||||
// Claim this crate number and cache it
|
||||
@ -319,6 +336,11 @@ 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::CrateMetadata>, cstore::CrateSource) {
|
||||
info!("resolving crate `extern crate {} as {}`", name, ident);
|
||||
let result = match self.existing_match(name, hash, kind) {
|
||||
Some(cnum) => LoadResult::Previous(cnum),
|
||||
None => {
|
||||
info!("falling back to a load");
|
||||
let mut load_ctxt = loader::Context {
|
||||
sess: self.sess,
|
||||
span: span,
|
||||
@ -412,6 +436,7 @@ 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<ast::MacroDef> {
|
||||
pub fn read_macros(&mut self, item: &ast::Item) -> Macros {
|
||||
let ci = self.extract_crate_info(item).unwrap();
|
||||
let ekrate = self.read_extension_crate(item.span, &ci);
|
||||
|
||||
let source_name = format!("<{} macros>", item.ident);
|
||||
let mut macros = vec![];
|
||||
let mut ret = Macros {
|
||||
macro_rules: Vec::new(),
|
||||
custom_derive_registrar: None,
|
||||
svh: decoder::get_crate_hash(ekrate.metadata.as_slice()),
|
||||
dylib: None,
|
||||
};
|
||||
decoder::each_exported_macro(ekrate.metadata.as_slice(),
|
||||
|name, attrs, span, body| {
|
||||
// NB: Don't use parse::parse_tts_from_source_str because it parses with
|
||||
// quote_depth > 0.
|
||||
let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
|
||||
self.local_crate_config.clone(),
|
||||
source_name.clone(),
|
||||
body);
|
||||
let lo = p.span.lo;
|
||||
let body = match p.parse_all_token_trees() {
|
||||
Ok(body) => body,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
self.sess.abort_if_errors();
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
let local_span = mk_sp(lo, p.last_span.hi);
|
||||
|
||||
// Mark the attrs as used
|
||||
for attr in &attrs {
|
||||
attr::mark_used(attr);
|
||||
|name, attrs, span, body| {
|
||||
// NB: Don't use parse::parse_tts_from_source_str because it parses with
|
||||
// quote_depth > 0.
|
||||
let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
|
||||
self.local_crate_config.clone(),
|
||||
source_name.clone(),
|
||||
body);
|
||||
let lo = p.span.lo;
|
||||
let body = match p.parse_all_token_trees() {
|
||||
Ok(body) => body,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
self.sess.abort_if_errors();
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
let local_span = mk_sp(lo, p.last_span.hi);
|
||||
|
||||
macros.push(ast::MacroDef {
|
||||
ident: ast::Ident::with_empty_ctxt(name),
|
||||
attrs: attrs,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: local_span,
|
||||
imported_from: Some(item.ident),
|
||||
// overridden in plugin/load.rs
|
||||
export: false,
|
||||
use_locally: false,
|
||||
allow_internal_unstable: false,
|
||||
|
||||
body: body,
|
||||
});
|
||||
self.sess.imported_macro_spans.borrow_mut()
|
||||
.insert(local_span, (name.as_str().to_string(), span));
|
||||
true
|
||||
// Mark the attrs as used
|
||||
for attr in &attrs {
|
||||
attr::mark_used(attr);
|
||||
}
|
||||
);
|
||||
macros
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -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<DefIdMap<Option<CachedInlinedItem>>>,
|
||||
pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
|
||||
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
|
||||
pub used_for_derive_macro: RefCell<FnvHashSet<Ident>>,
|
||||
}
|
||||
|
||||
impl CStore {
|
||||
@ -130,6 +131,7 @@ 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 {
|
||||
|
@ -1398,6 +1398,11 @@ pub fn each_exported_macro<F>(data: &[u8], mut f: F) where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_derive_registrar_fn(data: &[u8]) -> Option<DefIndex> {
|
||||
reader::maybe_get_doc(rbml::Doc::new(data), tag_macro_derive_registrar)
|
||||
.map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc)))
|
||||
}
|
||||
|
||||
pub fn get_macro_span(doc: rbml::Doc) -> Span {
|
||||
let lo_doc = reader::get_doc(doc, tag_macro_def_span_lo);
|
||||
let lo = BytePos(reader::doc_as_u32(lo_doc));
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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<token::InternedString, Span>;
|
||||
|
||||
impl<'a> ext::base::MacroLoader for MacroLoader<'a> {
|
||||
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<ast::MacroDef> {
|
||||
fn load_crate(&mut self,
|
||||
extern_crate: &ast::Item,
|
||||
allows_macros: bool) -> Vec<LoadedMacro> {
|
||||
// Parse the attributes relating to macros.
|
||||
let mut import = Some(FnvHashMap()); // None => load all
|
||||
let mut reexport = FnvHashMap();
|
||||
@ -105,7 +116,7 @@ impl<'a> MacroLoader<'a> {
|
||||
allows_macros: bool,
|
||||
import: Option<MacroSelection>,
|
||||
reexport: MacroSelection)
|
||||
-> Vec<ast::MacroDef> {
|
||||
-> Vec<LoadedMacro> {
|
||||
if let Some(sel) = import.as_ref() {
|
||||
if sel.is_empty() && reexport.is_empty() {
|
||||
return Vec::new();
|
||||
@ -118,10 +129,11 @@ 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<LoadedMacro>) {
|
||||
// Make sure the path contains a / or the linker will search for it.
|
||||
let path = macros.dylib.as_ref().unwrap();
|
||||
let path = env::current_dir().unwrap().join(path);
|
||||
let lib = match DynamicLibrary::open(Some(&path)) {
|
||||
Ok(lib) => lib,
|
||||
Err(err) => self.sess.span_fatal(span, &err),
|
||||
};
|
||||
|
||||
let sym = self.sess.generate_derive_registrar_symbol(¯os.svh, index);
|
||||
let registrar = unsafe {
|
||||
let sym = match lib.symbol(&sym) {
|
||||
Ok(f) => f,
|
||||
Err(err) => self.sess.span_fatal(span, &err),
|
||||
};
|
||||
mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
|
||||
};
|
||||
|
||||
struct MyRegistrar<'a>(&'a mut Vec<LoadedMacro>);
|
||||
|
||||
impl<'a> Registry for MyRegistrar<'a> {
|
||||
fn register_custom_derive(&mut self,
|
||||
trait_name: &str,
|
||||
expand: fn(TokenStream) -> TokenStream) {
|
||||
let derive = Box::new(CustomDerive::new(expand));
|
||||
self.0.push(LoadedMacro::CustomDerive(trait_name.to_string(),
|
||||
derive));
|
||||
}
|
||||
}
|
||||
|
||||
registrar(&mut MyRegistrar(ret));
|
||||
|
||||
// Intentionally leak the dynamic library. We can't ever unload it
|
||||
// since the library can make things that will live arbitrarily long.
|
||||
mem::forget(lib);
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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"));
|
||||
}
|
||||
|
||||
|
@ -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<String>,
|
||||
cdylib_exports: Vec<String>
|
||||
exports: HashMap<CrateType, Vec<String>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LinkerInfo {
|
||||
pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
|
||||
reachable: &[String]) -> LinkerInfo {
|
||||
LinkerInfo {
|
||||
dylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeDylib),
|
||||
cdylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeCdylib)
|
||||
exports: scx.sess().crate_types.borrow().iter().map(|&c| {
|
||||
(c, exported_symbols(scx, reachable, c))
|
||||
}).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,7 +244,8 @@ 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<String> {
|
||||
if !scx.sess().crate_types.borrow().contains(&crate_type) {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
// See explanation in GnuLinker::export_symbols, for
|
||||
// why we don't ever need dylib symbols on non-MSVC.
|
||||
if crate_type == CrateType::CrateTypeDylib {
|
||||
if crate_type == CrateType::CrateTypeDylib ||
|
||||
crate_type == CrateType::CrateTypeRustcMacro {
|
||||
if !scx.sess().target.target.options.is_like_msvc {
|
||||
return vec![];
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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<ast::MacroDef>;
|
||||
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool)
|
||||
-> Vec<LoadedMacro>;
|
||||
}
|
||||
|
||||
pub enum LoadedMacro {
|
||||
Def(ast::MacroDef),
|
||||
CustomDerive(String, Box<MultiItemModifier>),
|
||||
}
|
||||
|
||||
pub struct DummyMacroLoader;
|
||||
impl MacroLoader for DummyMacroLoader {
|
||||
fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec<ast::MacroDef> {
|
||||
fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec<LoadedMacro> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
@ -593,6 +599,7 @@ pub struct ExtCtxt<'a> {
|
||||
pub exported_macros: Vec<ast::MacroDef>,
|
||||
|
||||
pub syntax_env: SyntaxEnv,
|
||||
pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
|
||||
pub recursion_count: usize,
|
||||
|
||||
pub filename: Option<String>,
|
||||
@ -616,6 +623,7 @@ 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<MultiItemModifier>,
|
||||
sp: Span) {
|
||||
if !self.ecfg.enable_rustc_macro() {
|
||||
feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic,
|
||||
"rustc_macro",
|
||||
sp,
|
||||
feature_gate::GateIssue::Language,
|
||||
"loading custom derive macro crates \
|
||||
is experimentally supported");
|
||||
}
|
||||
let name = token::intern_and_get_ident(name);
|
||||
if self.derive_modes.insert(name.clone(), ext).is_some() {
|
||||
self.span_err(sp, &format!("cannot shadow existing derive mode `{}`",
|
||||
name));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn struct_span_warn(&self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<u32>)] = &[
|
||||
$((stringify!($feature), $ver, $issue)),+
|
||||
];
|
||||
};
|
||||
|
||||
($((accepted, $feature: ident, $ver: expr, $issue: expr)),+) => {
|
||||
($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
|
||||
/// Those language feature has since been Accepted (it was once Active)
|
||||
const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
|
||||
$((stringify!($feature), $ver, $issue)),+
|
||||
@ -288,7 +288,10 @@ 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)]
|
||||
|
@ -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" }
|
@ -49,7 +49,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
|
||||
ItemKind::Struct(_, Generics { ref ty_params, .. }) |
|
||||
ItemKind::Enum(_, Generics { ref ty_params, .. })
|
||||
if ty_params.is_empty() &&
|
||||
attr::contains_name(&annitem.attrs, "derive_Copy") => {
|
||||
attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") => {
|
||||
|
||||
bounds = vec![Literal(path_std!(cx, core::marker::Copy))];
|
||||
unify_fieldless_variants = true;
|
||||
@ -110,12 +110,12 @@ fn cs_clone(name: &str,
|
||||
Mode::Shallow => cx.std_path(&["clone", "assert_receiver_is_clone"]),
|
||||
Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]),
|
||||
};
|
||||
let subcall = |field: &FieldInfo| {
|
||||
let subcall = |cx: &mut ExtCtxt, field: &FieldInfo| {
|
||||
let args = vec![cx.expr_addr_of(field.span, field.self_.clone())];
|
||||
|
||||
let span = if mode == Mode::Shallow {
|
||||
// set the expn ID so we can call the unstable method
|
||||
Span { expn_id: cx.backtrace(), ..trait_span }
|
||||
super::allow_unstable(cx, field.span, "derive(Clone)")
|
||||
} else {
|
||||
field.span
|
||||
};
|
||||
@ -147,8 +147,10 @@ fn cs_clone(name: &str,
|
||||
|
||||
match mode {
|
||||
Mode::Shallow => {
|
||||
let mut stmts: Vec<_> =
|
||||
all_fields.iter().map(subcall).map(|e| cx.stmt_expr(e)).collect();
|
||||
let mut stmts = all_fields.iter().map(|f| {
|
||||
let call = subcall(cx, f);
|
||||
cx.stmt_expr(call)
|
||||
}).collect::<Vec<_>>();
|
||||
stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span))));
|
||||
cx.expr_block(cx.block(trait_span, stmts))
|
||||
}
|
||||
@ -166,14 +168,15 @@ fn cs_clone(name: &str,
|
||||
name))
|
||||
}
|
||||
};
|
||||
cx.field_imm(field.span, ident, subcall(field))
|
||||
let call = subcall(cx, field);
|
||||
cx.field_imm(field.span, ident, call)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
cx.expr_struct(trait_span, ctor_path, fields)
|
||||
}
|
||||
VariantData::Tuple(..) => {
|
||||
let subcalls = all_fields.iter().map(subcall).collect();
|
||||
let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect();
|
||||
let path = cx.expr_path(ctor_path);
|
||||
cx.expr_call(trait_span, path, subcalls)
|
||||
}
|
||||
|
97
src/libsyntax_ext/deriving/custom.rs
Normal file
97
src/libsyntax_ext/deriving/custom.rs
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::panic;
|
||||
|
||||
use rustc_macro::{TokenStream, __internal};
|
||||
use syntax::ast::{self, ItemKind};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ext::base::*;
|
||||
use syntax::fold::{self, Folder};
|
||||
use errors::FatalError;
|
||||
|
||||
pub struct CustomDerive {
|
||||
inner: fn(TokenStream) -> TokenStream,
|
||||
}
|
||||
|
||||
impl CustomDerive {
|
||||
pub fn new(inner: fn(TokenStream) -> TokenStream) -> CustomDerive {
|
||||
CustomDerive { inner: inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl MultiItemModifier for CustomDerive {
|
||||
fn expand(&self,
|
||||
ecx: &mut ExtCtxt,
|
||||
span: Span,
|
||||
_meta_item: &ast::MetaItem,
|
||||
item: Annotatable)
|
||||
-> Vec<Annotatable> {
|
||||
let item = match item {
|
||||
Annotatable::Item(item) => item,
|
||||
Annotatable::ImplItem(_) |
|
||||
Annotatable::TraitItem(_) => {
|
||||
ecx.span_err(span, "custom derive attributes may only be \
|
||||
applied to struct/enum items");
|
||||
return Vec::new()
|
||||
}
|
||||
};
|
||||
match item.node {
|
||||
ItemKind::Struct(..) |
|
||||
ItemKind::Enum(..) => {}
|
||||
_ => {
|
||||
ecx.span_err(span, "custom derive attributes may only be \
|
||||
applied to struct/enum items");
|
||||
return Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
let input = __internal::new_token_stream(item);
|
||||
let res = __internal::set_parse_sess(&ecx.parse_sess, || {
|
||||
let inner = self.inner;
|
||||
panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input)))
|
||||
});
|
||||
let item = match res {
|
||||
Ok(stream) => __internal::token_stream_items(stream),
|
||||
Err(e) => {
|
||||
let msg = "custom derive attribute panicked";
|
||||
let mut err = ecx.struct_span_fatal(span, msg);
|
||||
if let Some(s) = e.downcast_ref::<String>() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
if let Some(s) = e.downcast_ref::<&'static str>() {
|
||||
err.help(&format!("message: {}", s));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
panic!(FatalError);
|
||||
}
|
||||
};
|
||||
|
||||
// Right now we have no knowledge of spans at all in custom derive
|
||||
// macros, everything is just parsed as a string. Reassign all spans to
|
||||
// the #[derive] attribute for better errors here.
|
||||
item.into_iter().flat_map(|item| {
|
||||
ChangeSpan { span: span }.fold_item(item)
|
||||
}).map(Annotatable::Item).collect()
|
||||
}
|
||||
}
|
||||
|
||||
struct ChangeSpan { span: Span }
|
||||
|
||||
impl Folder for ChangeSpan {
|
||||
fn new_span(&mut self, _sp: Span) -> Span {
|
||||
self.span
|
||||
}
|
||||
|
||||
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||
fold::noop_fold_mac(mac, self)
|
||||
}
|
||||
}
|
@ -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<Annotatable> {
|
||||
debug!("expand_derive: span = {:?}", span);
|
||||
debug!("expand_derive: mitem = {:?}", mitem);
|
||||
debug!("expand_derive: annotatable input = {:?}", annotatable);
|
||||
let annot = annotatable.map_item_or(|item| {
|
||||
item.map(|mut item| {
|
||||
if mitem.value_str().is_some() {
|
||||
cx.span_err(mitem.span, "unexpected value in `derive`");
|
||||
let mut item = match annotatable {
|
||||
Annotatable::Item(item) => item,
|
||||
other => {
|
||||
cx.span_err(span, "`derive` can only be applied to items");
|
||||
return vec![other]
|
||||
}
|
||||
};
|
||||
|
||||
if mitem.value_str().is_some() {
|
||||
cx.span_err(mitem.span, "unexpected value in `derive`");
|
||||
}
|
||||
|
||||
let traits = mitem.meta_item_list().unwrap_or(&[]);
|
||||
if traits.is_empty() {
|
||||
cx.span_warn(mitem.span, "empty trait list in `derive`");
|
||||
}
|
||||
|
||||
// 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
|
||||
});
|
||||
}
|
||||
|
||||
// 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
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
let traits = mitem.meta_item_list().unwrap_or(&[]);
|
||||
if traits.is_empty() {
|
||||
cx.span_warn(mitem.span, "empty trait list in `derive`");
|
||||
// If this is a built-in derive mode, then we expand it immediately
|
||||
// here.
|
||||
if is_builtin_trait(&tname) {
|
||||
let name = intern_and_get_ident(&format!("derive({})", tname));
|
||||
let mitem = cx.meta_word(titem.span, name);
|
||||
|
||||
let span = Span {
|
||||
expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
|
||||
call_site: titem.span,
|
||||
callee: codemap::NameAndSpan {
|
||||
format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
|
||||
span: Some(titem.span),
|
||||
allow_internal_unstable: true,
|
||||
},
|
||||
}),
|
||||
..titem.span
|
||||
};
|
||||
|
||||
let my_item = Annotatable::Item(item);
|
||||
expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| {
|
||||
other_items.push(a);
|
||||
});
|
||||
item = my_item.expect_item();
|
||||
|
||||
// Otherwise if this is a `rustc_macro`-style derive mode, we process it
|
||||
// here. The logic here is to:
|
||||
//
|
||||
// 1. Collect the remaining `#[derive]` annotations into a list. If
|
||||
// there are any left, attach a `#[derive]` attribute to the item
|
||||
// that we're currently expanding with the remaining derive modes.
|
||||
// 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
|
||||
// 3. Expand the current item we're expanding, getting back a list of
|
||||
// items that replace it.
|
||||
// 4. Extend the returned list with the current list of items we've
|
||||
// collected so far.
|
||||
// 5. Return everything!
|
||||
//
|
||||
// If custom derive extensions end up threading through the `#[derive]`
|
||||
// attribute, we'll get called again later on to continue expanding
|
||||
// those modes.
|
||||
} else if let Some(ext) = cx.derive_modes.remove(&tname) {
|
||||
let remaining_derives = iter.cloned().collect::<Vec<_>>();
|
||||
if remaining_derives.len() > 0 {
|
||||
let list = cx.meta_list(titem.span,
|
||||
intern_and_get_ident("derive"),
|
||||
remaining_derives);
|
||||
let attr = cx.attribute(titem.span, list);
|
||||
item = item.map(|mut i| {
|
||||
i.attrs.push(attr);
|
||||
i
|
||||
});
|
||||
}
|
||||
let titem = cx.meta_list_item_word(titem.span, tname.clone());
|
||||
let mitem = cx.meta_list(titem.span,
|
||||
intern_and_get_ident("derive"),
|
||||
vec![titem]);
|
||||
let item = Annotatable::Item(item);
|
||||
let mut items = ext.expand(cx, mitem.span, &mitem, item);
|
||||
items.extend(other_items);
|
||||
cx.derive_modes.insert(tname.clone(), ext);
|
||||
return items
|
||||
|
||||
let mut found_partial_eq = false;
|
||||
let mut eq_span = None;
|
||||
// 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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
// #[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 #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)));
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
280
src/libsyntax_ext/rustc_macro_registrar.rs
Normal file
280
src/libsyntax_ext/rustc_macro_registrar.rs
Normal file
@ -0,0 +1,280 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::mem;
|
||||
|
||||
use errors;
|
||||
use syntax::ast::{self, Ident, NodeId};
|
||||
use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute};
|
||||
use syntax::ext::base::{ExtCtxt, DummyMacroLoader};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::ext::expand::ExpansionConfig;
|
||||
use syntax::parse::ParseSess;
|
||||
use syntax::parse::token::{self, InternedString};
|
||||
use syntax::feature_gate::Features;
|
||||
use syntax::ptr::P;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use syntax::visit::{self, Visitor};
|
||||
|
||||
use deriving;
|
||||
|
||||
struct CustomDerive {
|
||||
trait_name: InternedString,
|
||||
function_name: Ident,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
struct CollectCustomDerives<'a> {
|
||||
derives: Vec<CustomDerive>,
|
||||
in_root: bool,
|
||||
handler: &'a errors::Handler,
|
||||
is_rustc_macro_crate: bool,
|
||||
}
|
||||
|
||||
pub fn modify(sess: &ParseSess,
|
||||
mut krate: ast::Crate,
|
||||
is_rustc_macro_crate: bool,
|
||||
num_crate_types: usize,
|
||||
handler: &errors::Handler,
|
||||
features: &Features) -> ast::Crate {
|
||||
let mut loader = DummyMacroLoader;
|
||||
let mut cx = ExtCtxt::new(sess,
|
||||
Vec::new(),
|
||||
ExpansionConfig::default("rustc_macro".to_string()),
|
||||
&mut loader);
|
||||
|
||||
let mut collect = CollectCustomDerives {
|
||||
derives: Vec::new(),
|
||||
in_root: true,
|
||||
handler: handler,
|
||||
is_rustc_macro_crate: is_rustc_macro_crate,
|
||||
};
|
||||
visit::walk_crate(&mut collect, &krate);
|
||||
|
||||
if !is_rustc_macro_crate {
|
||||
return krate
|
||||
} else if !features.rustc_macro {
|
||||
let mut err = handler.struct_err("the `rustc-macro` crate type is \
|
||||
experimental");
|
||||
err.help("add #![feature(rustc_macro)] to the crate attributes to \
|
||||
enable");
|
||||
err.emit();
|
||||
}
|
||||
|
||||
if num_crate_types > 1 {
|
||||
handler.err("cannot mix `rustc-macro` crate type with others");
|
||||
}
|
||||
|
||||
krate.module.items.push(mk_registrar(&mut cx, &collect.derives));
|
||||
|
||||
if krate.exported_macros.len() > 0 {
|
||||
handler.err("cannot export macro_rules! macros from a `rustc-macro` \
|
||||
crate type currently");
|
||||
}
|
||||
|
||||
return krate
|
||||
}
|
||||
|
||||
impl<'a> CollectCustomDerives<'a> {
|
||||
fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
|
||||
if self.is_rustc_macro_crate &&
|
||||
self.in_root &&
|
||||
*vis == ast::Visibility::Public {
|
||||
self.handler.span_err(sp,
|
||||
"`rustc-macro` crate types cannot \
|
||||
export any items other than functions \
|
||||
tagged with `#[rustc_macro_derive]` \
|
||||
currently");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visitor for CollectCustomDerives<'a> {
|
||||
fn visit_item(&mut self, item: &ast::Item) {
|
||||
// First up, make sure we're checking a bare function. If we're not then
|
||||
// we're just not interested in this item.
|
||||
//
|
||||
// If we find one, try to locate a `#[rustc_macro_derive]` attribute on
|
||||
// it.
|
||||
match item.node {
|
||||
ast::ItemKind::Fn(..) => {}
|
||||
_ => {
|
||||
self.check_not_pub_in_root(&item.vis, item.span);
|
||||
return visit::walk_item(self, item)
|
||||
}
|
||||
}
|
||||
|
||||
let mut attrs = item.attrs.iter()
|
||||
.filter(|a| a.check_name("rustc_macro_derive"));
|
||||
let attr = match attrs.next() {
|
||||
Some(attr) => attr,
|
||||
None => {
|
||||
self.check_not_pub_in_root(&item.vis, item.span);
|
||||
return visit::walk_item(self, item)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(a) = attrs.next() {
|
||||
self.handler.span_err(a.span(), "multiple `#[rustc_macro_derive]` \
|
||||
attributes found");
|
||||
}
|
||||
|
||||
if !self.is_rustc_macro_crate {
|
||||
self.handler.span_err(attr.span(),
|
||||
"the `#[rustc_macro_derive]` attribute is \
|
||||
only usable with crates of the `rustc-macro` \
|
||||
crate type");
|
||||
}
|
||||
|
||||
// Once we've located the `#[rustc_macro_derive]` attribute, verify
|
||||
// that it's of the form `#[rustc_macro_derive(Foo)]`
|
||||
let list = match attr.meta_item_list() {
|
||||
Some(list) => list,
|
||||
None => {
|
||||
self.handler.span_err(attr.span(),
|
||||
"attribute must be of form: \
|
||||
#[rustc_macro_derive(TraitName)]");
|
||||
return
|
||||
}
|
||||
};
|
||||
if list.len() != 1 {
|
||||
self.handler.span_err(attr.span(),
|
||||
"attribute must only have one argument");
|
||||
return
|
||||
}
|
||||
let attr = &list[0];
|
||||
let trait_name = match attr.name() {
|
||||
Some(name) => name,
|
||||
_ => {
|
||||
self.handler.span_err(attr.span(), "not a meta item");
|
||||
return
|
||||
}
|
||||
};
|
||||
if !attr.is_word() {
|
||||
self.handler.span_err(attr.span(), "must only be one word");
|
||||
}
|
||||
|
||||
if deriving::is_builtin_trait(&trait_name) {
|
||||
self.handler.span_err(attr.span(),
|
||||
"cannot override a built-in #[derive] mode");
|
||||
}
|
||||
|
||||
if self.derives.iter().any(|d| d.trait_name == trait_name) {
|
||||
self.handler.span_err(attr.span(),
|
||||
"derive mode defined twice in this crate");
|
||||
}
|
||||
|
||||
if self.in_root {
|
||||
self.derives.push(CustomDerive {
|
||||
span: item.span,
|
||||
trait_name: trait_name,
|
||||
function_name: item.ident,
|
||||
});
|
||||
} else {
|
||||
let msg = "functions tagged with `#[rustc_macro_derive]` must \
|
||||
currently reside in the root of the crate";
|
||||
self.handler.span_err(item.span, msg);
|
||||
}
|
||||
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
|
||||
fn visit_mod(&mut self, m: &ast::Mod, _s: Span, id: NodeId) {
|
||||
let mut prev_in_root = self.in_root;
|
||||
if id != ast::CRATE_NODE_ID {
|
||||
prev_in_root = mem::replace(&mut self.in_root, false);
|
||||
}
|
||||
visit::walk_mod(self, m);
|
||||
self.in_root = prev_in_root;
|
||||
}
|
||||
|
||||
fn visit_mac(&mut self, mac: &ast::Mac) {
|
||||
visit::walk_mac(self, mac)
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a new module which looks like:
|
||||
//
|
||||
// mod $gensym {
|
||||
// extern crate rustc_macro;
|
||||
//
|
||||
// use rustc_macro::__internal::Registry;
|
||||
//
|
||||
// #[plugin_registrar]
|
||||
// fn registrar(registrar: &mut Registry) {
|
||||
// registrar.register_custom_derive($name_trait1, ::$name1);
|
||||
// registrar.register_custom_derive($name_trait2, ::$name2);
|
||||
// // ...
|
||||
// }
|
||||
// }
|
||||
fn mk_registrar(cx: &mut ExtCtxt,
|
||||
custom_derives: &[CustomDerive]) -> P<ast::Item> {
|
||||
let eid = cx.codemap().record_expansion(ExpnInfo {
|
||||
call_site: DUMMY_SP,
|
||||
callee: NameAndSpan {
|
||||
format: MacroAttribute(token::intern("rustc_macro")),
|
||||
span: None,
|
||||
allow_internal_unstable: true,
|
||||
}
|
||||
});
|
||||
let span = Span { expn_id: eid, ..DUMMY_SP };
|
||||
|
||||
let rustc_macro = token::str_to_ident("rustc_macro");
|
||||
let krate = cx.item(span,
|
||||
rustc_macro,
|
||||
Vec::new(),
|
||||
ast::ItemKind::ExternCrate(None));
|
||||
|
||||
let __internal = token::str_to_ident("__internal");
|
||||
let registry = token::str_to_ident("Registry");
|
||||
let registrar = token::str_to_ident("registrar");
|
||||
let register_custom_derive = token::str_to_ident("register_custom_derive");
|
||||
let stmts = custom_derives.iter().map(|cd| {
|
||||
let path = cx.path_global(cd.span, vec![cd.function_name]);
|
||||
let trait_name = cx.expr_str(cd.span, cd.trait_name.clone());
|
||||
(path, trait_name)
|
||||
}).map(|(path, trait_name)| {
|
||||
let registrar = cx.expr_ident(span, registrar);
|
||||
let ufcs_path = cx.path(span, vec![rustc_macro, __internal, registry,
|
||||
register_custom_derive]);
|
||||
cx.expr_call(span,
|
||||
cx.expr_path(ufcs_path),
|
||||
vec![registrar, trait_name, cx.expr_path(path)])
|
||||
}).map(|expr| {
|
||||
cx.stmt_expr(expr)
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let path = cx.path(span, vec![rustc_macro, __internal, registry]);
|
||||
let registrar_path = cx.ty_path(path);
|
||||
let arg_ty = cx.ty_rptr(span, registrar_path, None, ast::Mutability::Mutable);
|
||||
let func = cx.item_fn(span,
|
||||
registrar,
|
||||
vec![cx.arg(span, registrar, arg_ty)],
|
||||
cx.ty(span, ast::TyKind::Tup(Vec::new())),
|
||||
cx.block(span, stmts));
|
||||
|
||||
let derive_registrar = token::intern_and_get_ident("rustc_derive_registrar");
|
||||
let derive_registrar = cx.meta_word(span, derive_registrar);
|
||||
let derive_registrar = cx.attribute(span, derive_registrar);
|
||||
let func = func.map(|mut i| {
|
||||
i.attrs.push(derive_registrar);
|
||||
i.vis = ast::Visibility::Public;
|
||||
i
|
||||
});
|
||||
let module = cx.item_mod(span,
|
||||
span,
|
||||
ast::Ident::with_empty_ctxt(token::gensym("registrar")),
|
||||
Vec::new(),
|
||||
vec![krate, func]);
|
||||
module.map(|mut i| {
|
||||
i.vis = ast::Visibility::Public;
|
||||
i
|
||||
})
|
||||
}
|
10
src/rustc/Cargo.lock
generated
10
src/rustc/Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
33
src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs
Normal file
33
src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:append-impl.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![allow(warnings)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate append_impl;
|
||||
|
||||
trait Append {
|
||||
fn foo(&self);
|
||||
}
|
||||
|
||||
#[derive(PartialEq,
|
||||
Append,
|
||||
Eq)]
|
||||
//~^^ ERROR: the semantics of constant patterns is not yet settled
|
||||
struct A {
|
||||
inner: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
A { inner: 3 }.foo();
|
||||
}
|
25
src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs
Normal file
25
src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
pub mod a { //~ `rustc-macro` crate types cannot export any items
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(B)]
|
||||
pub fn bar(a: TokenStream) -> TokenStream {
|
||||
//~^ ERROR: must currently reside in the root of the crate
|
||||
a
|
||||
}
|
||||
}
|
||||
|
46
src/test/compile-fail-fulldeps/rustc-macro/attribute.rs
Normal file
46
src/test/compile-fail-fulldeps/rustc-macro/attribute.rs
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
#[rustc_macro_derive]
|
||||
//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)]
|
||||
pub fn foo1(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[rustc_macro_derive = "foo"]
|
||||
//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)]
|
||||
pub fn foo2(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[rustc_macro_derive(
|
||||
a = "b"
|
||||
)]
|
||||
//~^^ ERROR: must only be one word
|
||||
pub fn foo3(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[rustc_macro_derive(b, c)]
|
||||
//~^ ERROR: attribute must only have one argument
|
||||
pub fn foo4(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[rustc_macro_derive(d(e))]
|
||||
//~^ ERROR: must only be one word
|
||||
pub fn foo5(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
|
||||
input
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
#![crate_type = "rustc-macro"]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(Append)]
|
||||
pub fn derive_a(input: TokenStream) -> TokenStream {
|
||||
let mut input = input.to_string();
|
||||
input.push_str("
|
||||
impl Append for A {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
");
|
||||
input.parse().unwrap()
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
#![crate_type = "rustc-macro"]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(A)]
|
||||
pub fn derive_a(input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
#![crate_type = "rustc-macro"]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(A)]
|
||||
pub fn derive_a(input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
// force-host
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
#![crate_type = "rustc-macro"]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(A)]
|
||||
pub fn derive_a(_input: TokenStream) -> TokenStream {
|
||||
"struct A { inner }".parse().unwrap()
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
// force-host
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
#![crate_type = "rustc-macro"]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(A)]
|
||||
pub fn derive_a(_input: TokenStream) -> TokenStream {
|
||||
panic!("nope!");
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
#![crate_type = "rustc-macro"]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(Unstable)]
|
||||
pub fn derive(_input: TokenStream) -> TokenStream {
|
||||
|
||||
"
|
||||
#[rustc_foo]
|
||||
fn foo() {}
|
||||
".parse().unwrap()
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
#![crate_type = "rustc-macro"]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(Unstable)]
|
||||
pub fn derive(_input: TokenStream) -> TokenStream {
|
||||
|
||||
"unsafe fn foo() -> u32 { ::std::intrinsics::init() }".parse().unwrap()
|
||||
}
|
16
src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs
Normal file
16
src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-a.rs
|
||||
|
||||
extern crate derive_a;
|
||||
//~^ ERROR: crates of the `rustc-macro` crate type cannot be linked at runtime
|
||||
|
||||
fn main() {}
|
28
src/test/compile-fail-fulldeps/rustc-macro/define-two.rs
Normal file
28
src/test/compile-fail-fulldeps/rustc-macro/define-two.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(A)]
|
||||
pub fn foo(input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[rustc_macro_derive(A)] //~ ERROR: derive mode defined twice in this crate
|
||||
pub fn bar(input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
25
src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs
Normal file
25
src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-bad.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_bad;
|
||||
|
||||
#[derive(
|
||||
A
|
||||
)]
|
||||
//~^^ ERROR: custom derive attribute panicked
|
||||
//~| HELP: called `Result::unwrap()` on an `Err` value: LexError
|
||||
struct A;
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,22 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-a.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![allow(warnings)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_a;
|
||||
|
||||
#[derive_A] //~ ERROR: attributes of the form `#[derive_*]` are reserved for the compiler
|
||||
struct A;
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,25 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-unstable-2.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![allow(warnings)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_unstable_2;
|
||||
|
||||
#[derive(Unstable)]
|
||||
//~^ ERROR: reserved for internal compiler
|
||||
struct A;
|
||||
|
||||
fn main() {
|
||||
foo();
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-unstable.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![allow(warnings)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_unstable;
|
||||
|
||||
#[derive(Unstable)]
|
||||
//~^ ERROR: use of unstable library feature
|
||||
struct A;
|
||||
|
||||
fn main() {
|
||||
unsafe { foo(); }
|
||||
}
|
19
src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs
Normal file
19
src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern: cannot export macro_rules! macros from a `rustc-macro` crate
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! foo {
|
||||
($e:expr) => ($e)
|
||||
}
|
22
src/test/compile-fail-fulldeps/rustc-macro/exports.rs
Normal file
22
src/test/compile-fail-fulldeps/rustc-macro/exports.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![allow(warnings)]
|
||||
|
||||
pub fn a() {} //~ ERROR: cannot export any items
|
||||
pub struct B; //~ ERROR: cannot export any items
|
||||
pub enum C {} //~ ERROR: cannot export any items
|
||||
pub mod d {} //~ ERROR: cannot export any items
|
||||
|
||||
mod e {}
|
||||
struct F;
|
||||
enum G {}
|
||||
fn h() {}
|
13
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs
Normal file
13
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern: the `rustc-macro` crate type is experimental
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
13
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs
Normal file
13
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate rustc_macro; //~ ERROR: use of unstable library feature
|
||||
|
||||
fn main() {}
|
@ -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() {
|
||||
}
|
15
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs
Normal file
15
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-a.rs
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_a;
|
||||
//~^ ERROR: loading custom derive macro crates is experimentally supported
|
12
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs
Normal file
12
src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[cfg(rustc_macro)] //~ ERROR: experimental and subject to change
|
||||
fn foo() {}
|
22
src/test/compile-fail-fulldeps/rustc-macro/import.rs
Normal file
22
src/test/compile-fail-fulldeps/rustc-macro/import.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-a.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![allow(warnings)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_a;
|
||||
|
||||
use derive_a::derive_a;
|
||||
//~^ ERROR: unresolved import `derive_a::derive_a`
|
||||
|
||||
fn main() {}
|
23
src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs
Normal file
23
src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-panic.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_panic;
|
||||
|
||||
#[derive(A)]
|
||||
//~^ ERROR: custom derive attribute panicked
|
||||
//~| HELP: message: nope!
|
||||
struct Foo;
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,21 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
#[rustc_macro_derive(Foo)]
|
||||
//~^ ERROR: only usable with crates of the `rustc-macro` crate type
|
||||
pub fn foo(a: rustc_macro::TokenStream) -> rustc_macro::TokenStream {
|
||||
a
|
||||
}
|
||||
|
||||
fn main() {}
|
22
src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs
Normal file
22
src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(PartialEq)]
|
||||
//~^ ERROR: cannot override a built-in #[derive] mode
|
||||
pub fn foo(input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
21
src/test/compile-fail-fulldeps/rustc-macro/shadow.rs
Normal file
21
src/test/compile-fail-fulldeps/rustc-macro/shadow.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-a.rs
|
||||
// aux-build:derive-a-2.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_a;
|
||||
#[macro_use]
|
||||
extern crate derive_a_2; //~ ERROR: cannot shadow existing derive mode `A`
|
||||
|
||||
fn main() {}
|
24
src/test/compile-fail-fulldeps/rustc-macro/signature.rs
Normal file
24
src/test/compile-fail-fulldeps/rustc-macro/signature.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
#![allow(warnings)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
#[rustc_macro_derive(A)]
|
||||
unsafe extern fn foo(a: i32, b: u32) -> u32 {
|
||||
//~^ ERROR: mismatched types
|
||||
//~| NOTE: expected normal fn, found unsafe fn
|
||||
//~| NOTE: expected type `fn(rustc_macro::TokenStream) -> rustc_macro::TokenStream`
|
||||
//~| NOTE: found type `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
|
||||
loop {}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern: cannot mix `rustc-macro` crate type with others
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![crate_type = "rlib"]
|
@ -0,0 +1,12 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern: cannot mix `rustc-macro` crate type with others
|
||||
// compile-flags: --crate-type rlib --crate-type rustc-macro
|
@ -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() {}
|
||||
|
25
src/test/run-pass-fulldeps/rustc-macro/add-impl.rs
Normal file
25
src/test/run-pass-fulldeps/rustc-macro/add-impl.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:add-impl.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate add_impl;
|
||||
|
||||
#[derive(AddImpl)]
|
||||
struct B;
|
||||
|
||||
fn main() {
|
||||
B.foo();
|
||||
foo();
|
||||
bar::foo();
|
||||
}
|
33
src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs
Normal file
33
src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(AddImpl)]
|
||||
// #[cfg(rustc_macro)]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
(input.to_string() + "
|
||||
impl B {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
fn foo() {}
|
||||
|
||||
mod bar { pub fn foo() {} }
|
||||
").parse().unwrap()
|
||||
}
|
27
src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs
Normal file
27
src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(A)]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
let input = input.to_string();
|
||||
assert!(input.contains("struct A;"));
|
||||
assert!(input.contains("#[derive(Eq, Copy, Clone)]"));
|
||||
"#[derive(Eq, Copy, Clone)] struct A;".parse().unwrap()
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(AToB)]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
let input = input.to_string();
|
||||
assert_eq!(input, "struct A;\n");
|
||||
"struct B;".parse().unwrap()
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(CToD)]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
let input = input.to_string();
|
||||
assert_eq!(input, "struct C;\n");
|
||||
"struct D;".parse().unwrap()
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
// compile-flags:--crate-type rustc-macro
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(AToB)]
|
||||
pub fn derive1(input: TokenStream) -> TokenStream {
|
||||
println!("input1: {:?}", input.to_string());
|
||||
assert_eq!(input.to_string(), "#[derive(BToC)]\nstruct A;\n");
|
||||
"#[derive(BToC)] struct B;".parse().unwrap()
|
||||
}
|
||||
|
||||
#[rustc_macro_derive(BToC)]
|
||||
pub fn derive2(input: TokenStream) -> TokenStream {
|
||||
assert_eq!(input.to_string(), "struct B;\n");
|
||||
"struct C;".parse().unwrap()
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "rustc-macro"]
|
||||
#![feature(rustc_macro)]
|
||||
#![feature(rustc_macro_lib)]
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate rustc_macro;
|
||||
|
||||
use rustc_macro::TokenStream;
|
||||
|
||||
#[rustc_macro_derive(A)]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
let input = input.to_string();
|
||||
assert!(input.contains("struct A;"));
|
||||
r#"
|
||||
struct A;
|
||||
|
||||
impl A {
|
||||
fn a(&self) {
|
||||
panic!("hello");
|
||||
}
|
||||
}
|
||||
"#.parse().unwrap()
|
||||
}
|
||||
|
23
src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs
Normal file
23
src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-same-struct.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_same_struct;
|
||||
|
||||
#[derive(AToB, BToC)]
|
||||
struct A;
|
||||
|
||||
fn main() {
|
||||
C;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:expand-with-a-macro.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
#![deny(warnings)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate expand_with_a_macro;
|
||||
|
||||
use std::panic;
|
||||
|
||||
#[derive(A)]
|
||||
struct A;
|
||||
|
||||
fn main() {
|
||||
assert!(panic::catch_unwind(|| {
|
||||
A.a();
|
||||
}).is_err());
|
||||
}
|
||||
|
30
src/test/run-pass-fulldeps/rustc-macro/load-two.rs
Normal file
30
src/test/run-pass-fulldeps/rustc-macro/load-two.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-atob.rs
|
||||
// aux-build:derive-ctod.rs
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_atob;
|
||||
#[macro_use]
|
||||
extern crate derive_ctod;
|
||||
|
||||
#[derive(AToB)]
|
||||
struct A;
|
||||
|
||||
#[derive(CToD)]
|
||||
struct C;
|
||||
|
||||
fn main() {
|
||||
B;
|
||||
D;
|
||||
}
|
29
src/test/run-pass-fulldeps/rustc-macro/smoke.rs
Normal file
29
src/test/run-pass-fulldeps/rustc-macro/smoke.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-a.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(rustc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_a;
|
||||
|
||||
#[derive(Debug, PartialEq, A, Eq, Copy, Clone)]
|
||||
struct A;
|
||||
|
||||
fn main() {
|
||||
A;
|
||||
assert_eq!(A, A);
|
||||
A.clone();
|
||||
let a = A;
|
||||
let _c = a;
|
||||
let _d = a;
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 }
|
||||
|
@ -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;
|
||||
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
// Regression test for #20797.
|
||||
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
#![feature(question_mark)]
|
||||
|
||||
use std::default::Default;
|
||||
|
@ -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)]
|
||||
|
||||
|
@ -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)]
|
||||
|
Loading…
Reference in New Issue
Block a user