rust/src/libsyntax_ext/deriving/mod.rs

194 lines
6.2 KiB
Rust
Raw Normal View History

//! The compiler code necessary to implement the `#[derive]` extensions.
2018-02-27 16:11:14 +00:00
use rustc_data_structures::sync::Lrc;
use syntax::ast::{self, MetaItem};
use syntax::edition::Edition;
use syntax::ext::base::{Annotatable, ExtCtxt, Resolver, MultiItemModifier};
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use syntax::ext::build::AstBuilder;
2017-03-17 04:04:41 +00:00
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::ptr::P;
use syntax::symbol::{Symbol, sym};
use syntax_pos::Span;
2014-05-16 07:16:13 +00:00
macro path_local($x:ident) {
generic::ty::Path::new_local(stringify!($x))
2014-09-07 20:58:41 +00:00
}
macro pathvec_std($cx:expr, $($rest:ident)::+) {{
vec![ $( stringify!($rest) ),+ ]
}}
macro path_std($($x:tt)*) {
generic::ty::Path::new( pathvec_std!( $($x)* ) )
}
pub mod bounds;
pub mod clone;
pub mod encodable;
pub mod decodable;
pub mod hash;
2015-10-18 16:03:42 +00:00
pub mod debug;
pub mod default;
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! syntax-[breaking-change]
2016-08-23 00:07:11 +00:00
pub mod custom;
#[path="cmp/partial_eq.rs"]
pub mod partial_eq;
#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/partial_ord.rs"]
pub mod partial_ord;
#[path="cmp/ord.rs"]
pub mod ord;
pub mod generic;
struct BuiltinDerive(
fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable))
);
impl MultiItemModifier for BuiltinDerive {
fn expand(&self,
ecx: &mut ExtCtxt<'_>,
span: Span,
meta_item: &MetaItem,
item: Annotatable)
-> Vec<Annotatable> {
let mut items = Vec::new();
(self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
items
}
}
macro_rules! derive_traits {
($( $name:expr => $func:path, )+) => {
pub fn is_builtin_trait(name: ast::Name) -> bool {
match &*name.as_str() {
$( $name )|+ => true,
_ => false,
}
}
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! syntax-[breaking-change]
2016-08-23 00:07:11 +00:00
pub fn register_builtin_derives(resolver: &mut dyn Resolver, edition: Edition) {
let allow_internal_unstable = Some([
sym::rustc_attrs,
Symbol::intern("derive_clone_copy"),
Symbol::intern("derive_eq"),
Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
][..].into());
$(
resolver.add_builtin(
ast::Ident::with_empty_ctxt(Symbol::intern($name)),
Lrc::new(SyntaxExtension {
allow_internal_unstable: allow_internal_unstable.clone(),
..SyntaxExtension::default(
SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($func))),
edition,
)
}),
);
)*
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! syntax-[breaking-change]
2016-08-23 00:07:11 +00:00
}
}
}
derive_traits! {
"Clone" => clone::expand_deriving_clone,
"Hash" => hash::expand_deriving_hash,
"RustcEncodable" => encodable::expand_deriving_rustc_encodable,
"RustcDecodable" => decodable::expand_deriving_rustc_decodable,
"PartialEq" => partial_eq::expand_deriving_partial_eq,
"Eq" => eq::expand_deriving_eq,
"PartialOrd" => partial_ord::expand_deriving_partial_ord,
"Ord" => ord::expand_deriving_ord,
2015-10-18 16:03:42 +00:00
"Debug" => debug::expand_deriving_debug,
"Default" => default::expand_deriving_default,
"Send" => bounds::expand_deriving_unsafe_bound,
"Sync" => bounds::expand_deriving_unsafe_bound,
"Copy" => bounds::expand_deriving_copy,
// deprecated
"Encodable" => encodable::expand_deriving_encodable,
"Decodable" => decodable::expand_deriving_decodable,
}
#[inline] // because `name` is a compile-time constant
2019-02-04 12:49:54 +00:00
fn warn_if_deprecated(ecx: &mut ExtCtxt<'_>, sp: Span, name: &str) {
if let Some(replacement) = match name {
"Encodable" => Some("RustcEncodable"),
"Decodable" => Some("RustcDecodable"),
_ => None,
} {
ecx.span_warn(sp,
&format!("derive({}) is deprecated in favor of derive({})",
name,
replacement));
}
}
/// Construct a name for the inner type parameter that can't collide with any type parameters of
/// the item. This is achieved by starting with a base and then concatenating the names of all
/// other type parameters.
// FIXME(aburka): use real hygiene when that becomes possible
fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
let mut typaram = String::from(base);
if let Annotatable::Item(ref item) = *item {
match item.node {
ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) |
ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => {
2018-05-26 18:16:21 +00:00
for param in params {
match param.kind {
2018-05-27 19:07:09 +00:00
ast::GenericParamKind::Type { .. } => {
2018-05-26 18:16:21 +00:00
typaram.push_str(&param.ident.as_str());
}
_ => {}
}
}
}
_ => {}
}
}
typaram
}
/// Constructs an expression that calls an intrinsic
2019-02-04 12:49:54 +00:00
fn call_intrinsic(cx: &ExtCtxt<'_>,
mut span: Span,
intrinsic: &str,
args: Vec<P<ast::Expr>>)
-> P<ast::Expr> {
let intrinsic_allowed_via_allow_internal_unstable = cx
.current_expansion.mark.expn_info().unwrap()
.allow_internal_unstable.map_or(false, |features| features.iter().any(|&s|
s == sym::core_intrinsics
));
if intrinsic_allowed_via_allow_internal_unstable {
2017-07-31 20:04:34 +00:00
span = span.with_ctxt(cx.backtrace());
2017-03-17 04:04:41 +00:00
} else { // Avoid instability errors with user defined curstom derives, cc #36316
let mut info = cx.current_expansion.mark.expn_info().unwrap();
info.allow_internal_unstable = Some(vec![sym::core_intrinsics].into());
2017-03-22 08:39:51 +00:00
let mark = Mark::fresh(Mark::root());
2017-03-17 04:04:41 +00:00
mark.set_expn_info(info);
2017-07-31 20:04:34 +00:00
span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
2017-03-17 04:04:41 +00:00
}
let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]);
let call = cx.expr_call_global(span, path, args);
cx.expr_block(P(ast::Block {
2016-06-23 09:51:18 +00:00
stmts: vec![cx.stmt_expr(call)],
id: ast::DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
span,
}))
}