Make #[derive(Anything)] into sugar for #[derive_Anything]
This is a hack, but I don't think we can do much better as long as `derive` is
running at the syntax expansion phase.
If the custom_derive feature gate is enabled, this works with user-defined
traits and syntax extensions. Without the gate, you can't use e.g. #[derive_Clone]
directly, so this does not change the stable language.
This commit also cleans up the deriving code somewhat, and forbids some
previously-meaningless attribute syntax. For this reason it's technically a
[breaking-change]
This commit is contained in:
@@ -2429,6 +2429,10 @@ The currently implemented features of the reference compiler are:
|
|||||||
so that new attributes can be added in a bacwards compatible
|
so that new attributes can be added in a bacwards compatible
|
||||||
manner (RFC 572).
|
manner (RFC 572).
|
||||||
|
|
||||||
|
* `custom_derive` - Allows the use of `#[derive(Foo,Bar)]` as sugar for
|
||||||
|
`#[derive_Foo] #[derive_Bar]`, which can be user-defined syntax
|
||||||
|
extensions.
|
||||||
|
|
||||||
* `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
|
* `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
|
||||||
are inherently unstable and no promise about them is made.
|
are inherently unstable and no promise about them is made.
|
||||||
|
|
||||||
|
|||||||
@@ -491,10 +491,8 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
|
|||||||
syntax_expanders.insert(intern("log_syntax"),
|
syntax_expanders.insert(intern("log_syntax"),
|
||||||
builtin_normal_expander(
|
builtin_normal_expander(
|
||||||
ext::log_syntax::expand_syntax_ext));
|
ext::log_syntax::expand_syntax_ext));
|
||||||
syntax_expanders.insert(intern("derive"),
|
|
||||||
Decorator(Box::new(ext::deriving::expand_meta_derive)));
|
ext::deriving::register_all(&mut syntax_expanders);
|
||||||
syntax_expanders.insert(intern("deriving"),
|
|
||||||
Decorator(Box::new(ext::deriving::expand_deprecated_deriving)));
|
|
||||||
|
|
||||||
if ecfg.enable_quotes() {
|
if ecfg.enable_quotes() {
|
||||||
// Quasi-quoting expanders
|
// Quasi-quoting expanders
|
||||||
|
|||||||
@@ -8,47 +8,34 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use ast::{MetaItem, MetaWord, Item};
|
use ast::{MetaItem, Item};
|
||||||
use codemap::Span;
|
use codemap::Span;
|
||||||
use ext::base::ExtCtxt;
|
use ext::base::ExtCtxt;
|
||||||
use ext::deriving::generic::*;
|
use ext::deriving::generic::*;
|
||||||
use ext::deriving::generic::ty::*;
|
use ext::deriving::generic::ty::*;
|
||||||
use ptr::P;
|
use ptr::P;
|
||||||
|
|
||||||
pub fn expand_deriving_bound<F>(cx: &mut ExtCtxt,
|
pub fn expand_deriving_unsafe_bound<F>(cx: &mut ExtCtxt,
|
||||||
|
span: Span,
|
||||||
|
_: &MetaItem,
|
||||||
|
_: &Item,
|
||||||
|
_: F) where
|
||||||
|
F: FnOnce(P<Item>),
|
||||||
|
{
|
||||||
|
cx.span_err(span, "this unsafe trait should be implemented explicitly");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand_deriving_copy<F>(cx: &mut ExtCtxt,
|
||||||
span: Span,
|
span: Span,
|
||||||
mitem: &MetaItem,
|
mitem: &MetaItem,
|
||||||
item: &Item,
|
item: &Item,
|
||||||
push: F) where
|
push: F) where
|
||||||
F: FnOnce(P<Item>),
|
F: FnOnce(P<Item>),
|
||||||
{
|
{
|
||||||
let name = match mitem.node {
|
|
||||||
MetaWord(ref tname) => {
|
|
||||||
match &tname[..] {
|
|
||||||
"Copy" => "Copy",
|
|
||||||
"Send" | "Sync" => {
|
|
||||||
return cx.span_err(span,
|
|
||||||
&format!("{} is an unsafe trait and it \
|
|
||||||
should be implemented explicitly",
|
|
||||||
*tname))
|
|
||||||
}
|
|
||||||
ref tname => {
|
|
||||||
cx.span_bug(span,
|
|
||||||
&format!("expected built-in trait name but \
|
|
||||||
found {}", *tname))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
return cx.span_err(span, "unexpected value in deriving, expected \
|
|
||||||
a trait")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let path = Path::new(vec![
|
let path = Path::new(vec![
|
||||||
if cx.use_std { "std" } else { "core" },
|
if cx.use_std { "std" } else { "core" },
|
||||||
"marker",
|
"marker",
|
||||||
name
|
"Copy",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let trait_def = TraitDef {
|
let trait_def = TraitDef {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
@@ -13,9 +13,13 @@
|
|||||||
//! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
|
//! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
|
||||||
//! the standard library, and "std" is the core library.
|
//! the standard library, and "std" is the core library.
|
||||||
|
|
||||||
use ast::{Item, MetaItem, MetaList, MetaNameValue, MetaWord};
|
use ast::{Item, MetaItem, MetaWord};
|
||||||
use ext::base::ExtCtxt;
|
use attr::AttrMetaMethods;
|
||||||
|
use ext::base::{ExtCtxt, SyntaxEnv, Decorator, ItemDecorator, Modifier};
|
||||||
|
use ext::build::AstBuilder;
|
||||||
|
use feature_gate;
|
||||||
use codemap::Span;
|
use codemap::Span;
|
||||||
|
use parse::token::{intern, intern_and_get_ident};
|
||||||
use ptr::P;
|
use ptr::P;
|
||||||
|
|
||||||
macro_rules! pathvec {
|
macro_rules! pathvec {
|
||||||
@@ -74,7 +78,7 @@ pub mod totalord;
|
|||||||
|
|
||||||
pub mod generic;
|
pub mod generic;
|
||||||
|
|
||||||
pub fn expand_deprecated_deriving(cx: &mut ExtCtxt,
|
fn expand_deprecated_deriving(cx: &mut ExtCtxt,
|
||||||
span: Span,
|
span: Span,
|
||||||
_: &MetaItem,
|
_: &MetaItem,
|
||||||
_: &Item,
|
_: &Item,
|
||||||
@@ -82,93 +86,125 @@ pub fn expand_deprecated_deriving(cx: &mut ExtCtxt,
|
|||||||
cx.span_err(span, "`deriving` has been renamed to `derive`");
|
cx.span_err(span, "`deriving` has been renamed to `derive`");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_meta_derive(cx: &mut ExtCtxt,
|
fn expand_derive(cx: &mut ExtCtxt,
|
||||||
_span: Span,
|
_: Span,
|
||||||
|
mitem: &MetaItem,
|
||||||
|
item: P<Item>) -> P<Item> {
|
||||||
|
item.map(|mut item| {
|
||||||
|
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`");
|
||||||
|
}
|
||||||
|
|
||||||
|
for titem in traits.iter().rev() {
|
||||||
|
let tname = match titem.node {
|
||||||
|
MetaWord(ref tname) => tname,
|
||||||
|
_ => {
|
||||||
|
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::EXPLAIN_CUSTOM_DERIVE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
|
||||||
|
item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
|
||||||
|
intern_and_get_ident(&format!("derive_{}", tname)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
item
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! derive_traits {
|
||||||
|
($( $name:expr => $func:path, )*) => {
|
||||||
|
pub fn register_all(env: &mut SyntaxEnv) {
|
||||||
|
// Define the #[derive_*] extensions.
|
||||||
|
$({
|
||||||
|
struct DeriveExtension;
|
||||||
|
|
||||||
|
impl ItemDecorator for DeriveExtension {
|
||||||
|
fn expand(&self,
|
||||||
|
ecx: &mut ExtCtxt,
|
||||||
|
sp: Span,
|
||||||
mitem: &MetaItem,
|
mitem: &MetaItem,
|
||||||
item: &Item,
|
item: &Item,
|
||||||
push: &mut FnMut(P<Item>)) {
|
push: &mut FnMut(P<Item>)) {
|
||||||
match mitem.node {
|
warn_if_deprecated(ecx, sp, $name);
|
||||||
MetaNameValue(_, ref l) => {
|
$func(ecx, sp, mitem, item, |i| push(i));
|
||||||
cx.span_err(l.span, "unexpected value in `derive`");
|
|
||||||
}
|
|
||||||
MetaWord(_) => {
|
|
||||||
cx.span_warn(mitem.span, "empty trait list in `derive`");
|
|
||||||
}
|
|
||||||
MetaList(_, ref titems) if titems.len() == 0 => {
|
|
||||||
cx.span_warn(mitem.span, "empty trait list in `derive`");
|
|
||||||
}
|
|
||||||
MetaList(_, ref titems) => {
|
|
||||||
for titem in titems.iter().rev() {
|
|
||||||
match titem.node {
|
|
||||||
MetaNameValue(ref tname, _) |
|
|
||||||
MetaList(ref tname, _) |
|
|
||||||
MetaWord(ref tname) => {
|
|
||||||
macro_rules! expand {
|
|
||||||
($func:path) => ($func(cx, titem.span, &**titem, item,
|
|
||||||
|i| push(i)))
|
|
||||||
}
|
|
||||||
|
|
||||||
match &tname[..] {
|
|
||||||
"Clone" => expand!(clone::expand_deriving_clone),
|
|
||||||
|
|
||||||
"Hash" => expand!(hash::expand_deriving_hash),
|
|
||||||
|
|
||||||
"RustcEncodable" => {
|
|
||||||
expand!(encodable::expand_deriving_rustc_encodable)
|
|
||||||
}
|
|
||||||
"RustcDecodable" => {
|
|
||||||
expand!(decodable::expand_deriving_rustc_decodable)
|
|
||||||
}
|
|
||||||
"Encodable" => {
|
|
||||||
cx.span_warn(titem.span,
|
|
||||||
"derive(Encodable) is deprecated \
|
|
||||||
in favor of derive(RustcEncodable)");
|
|
||||||
|
|
||||||
expand!(encodable::expand_deriving_encodable)
|
|
||||||
}
|
|
||||||
"Decodable" => {
|
|
||||||
cx.span_warn(titem.span,
|
|
||||||
"derive(Decodable) is deprecated \
|
|
||||||
in favor of derive(RustcDecodable)");
|
|
||||||
|
|
||||||
expand!(decodable::expand_deriving_decodable)
|
|
||||||
}
|
|
||||||
|
|
||||||
"PartialEq" => expand!(eq::expand_deriving_eq),
|
|
||||||
"Eq" => expand!(totaleq::expand_deriving_totaleq),
|
|
||||||
"PartialOrd" => expand!(ord::expand_deriving_ord),
|
|
||||||
"Ord" => expand!(totalord::expand_deriving_totalord),
|
|
||||||
|
|
||||||
"Rand" => expand!(rand::expand_deriving_rand),
|
|
||||||
|
|
||||||
"Show" => {
|
|
||||||
cx.span_warn(titem.span,
|
|
||||||
"derive(Show) is deprecated \
|
|
||||||
in favor of derive(Debug)");
|
|
||||||
|
|
||||||
expand!(show::expand_deriving_show)
|
|
||||||
},
|
|
||||||
|
|
||||||
"Debug" => expand!(show::expand_deriving_show),
|
|
||||||
|
|
||||||
"Default" => expand!(default::expand_deriving_default),
|
|
||||||
|
|
||||||
"FromPrimitive" => expand!(primitive::expand_deriving_from_primitive),
|
|
||||||
|
|
||||||
"Send" => expand!(bounds::expand_deriving_bound),
|
|
||||||
"Sync" => expand!(bounds::expand_deriving_bound),
|
|
||||||
"Copy" => expand!(bounds::expand_deriving_bound),
|
|
||||||
|
|
||||||
ref tname => {
|
|
||||||
cx.span_err(titem.span,
|
|
||||||
&format!("unknown `derive` \
|
|
||||||
trait: `{}`",
|
|
||||||
*tname));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env.insert(intern(concat!("derive_", $name)),
|
||||||
|
Decorator(Box::new(DeriveExtension)));
|
||||||
|
})*
|
||||||
|
|
||||||
|
env.insert(intern("derive"),
|
||||||
|
Modifier(Box::new(expand_derive)));
|
||||||
|
env.insert(intern("deriving"),
|
||||||
|
Decorator(Box::new(expand_deprecated_deriving)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_builtin_trait(name: &str) -> bool {
|
||||||
|
match name {
|
||||||
|
$( $name )|* => true,
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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" => eq::expand_deriving_eq,
|
||||||
|
"Eq" => totaleq::expand_deriving_totaleq,
|
||||||
|
"PartialOrd" => ord::expand_deriving_ord,
|
||||||
|
"Ord" => totalord::expand_deriving_totalord,
|
||||||
|
|
||||||
|
"Rand" => rand::expand_deriving_rand,
|
||||||
|
|
||||||
|
"Debug" => show::expand_deriving_show,
|
||||||
|
|
||||||
|
"Default" => default::expand_deriving_default,
|
||||||
|
|
||||||
|
"FromPrimitive" => primitive::expand_deriving_from_primitive,
|
||||||
|
|
||||||
|
"Send" => bounds::expand_deriving_unsafe_bound,
|
||||||
|
"Sync" => bounds::expand_deriving_unsafe_bound,
|
||||||
|
"Copy" => bounds::expand_deriving_copy,
|
||||||
|
|
||||||
|
// deprecated
|
||||||
|
"Show" => show::expand_deriving_show,
|
||||||
|
"Encodable" => encodable::expand_deriving_encodable,
|
||||||
|
"Decodable" => decodable::expand_deriving_decodable,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] // because `name` is a compile-time constant
|
||||||
|
fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
|
||||||
|
if let Some(replacement) = match name {
|
||||||
|
"Show" => Some("Debug"),
|
||||||
|
"Encodable" => Some("RustcEncodable"),
|
||||||
|
"Decodable" => Some("RustcDecodable"),
|
||||||
|
_ => None,
|
||||||
|
} {
|
||||||
|
ecx.span_warn(sp, &format!("derive({}) is deprecated in favor of derive({})",
|
||||||
|
name, replacement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1476,6 +1476,7 @@ impl<'feat> ExpansionConfig<'feat> {
|
|||||||
fn enable_concat_idents = allow_concat_idents,
|
fn enable_concat_idents = allow_concat_idents,
|
||||||
fn enable_trace_macros = allow_trace_macros,
|
fn enable_trace_macros = allow_trace_macros,
|
||||||
fn enable_allow_internal_unstable = allow_internal_unstable,
|
fn enable_allow_internal_unstable = allow_internal_unstable,
|
||||||
|
fn enable_custom_derive = allow_custom_derive,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,10 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
|
|||||||
// Allows the use of custom attributes; RFC 572
|
// Allows the use of custom attributes; RFC 572
|
||||||
("custom_attribute", "1.0.0", Active),
|
("custom_attribute", "1.0.0", Active),
|
||||||
|
|
||||||
|
// Allows the use of #[derive(Anything)] as sugar for
|
||||||
|
// #[derive_Anything].
|
||||||
|
("custom_derive", "1.0.0", Active),
|
||||||
|
|
||||||
// Allows the use of rustc_* attributes; RFC 572
|
// Allows the use of rustc_* attributes; RFC 572
|
||||||
("rustc_attrs", "1.0.0", Active),
|
("rustc_attrs", "1.0.0", Active),
|
||||||
|
|
||||||
@@ -319,6 +323,7 @@ pub struct Features {
|
|||||||
pub allow_concat_idents: bool,
|
pub allow_concat_idents: bool,
|
||||||
pub allow_trace_macros: bool,
|
pub allow_trace_macros: bool,
|
||||||
pub allow_internal_unstable: bool,
|
pub allow_internal_unstable: bool,
|
||||||
|
pub allow_custom_derive: bool,
|
||||||
pub old_orphan_check: bool,
|
pub old_orphan_check: bool,
|
||||||
pub simd_ffi: bool,
|
pub simd_ffi: bool,
|
||||||
pub unmarked_api: bool,
|
pub unmarked_api: bool,
|
||||||
@@ -340,6 +345,7 @@ impl Features {
|
|||||||
allow_concat_idents: false,
|
allow_concat_idents: false,
|
||||||
allow_trace_macros: false,
|
allow_trace_macros: false,
|
||||||
allow_internal_unstable: false,
|
allow_internal_unstable: false,
|
||||||
|
allow_custom_derive: false,
|
||||||
old_orphan_check: false,
|
old_orphan_check: false,
|
||||||
simd_ffi: false,
|
simd_ffi: false,
|
||||||
unmarked_api: false,
|
unmarked_api: false,
|
||||||
@@ -391,6 +397,10 @@ impl<'a> Context<'a> {
|
|||||||
"unless otherwise specified, attributes \
|
"unless otherwise specified, attributes \
|
||||||
with the prefix `rustc_` \
|
with the prefix `rustc_` \
|
||||||
are reserved for internal compiler diagnostics");
|
are reserved for internal compiler diagnostics");
|
||||||
|
} else if name.starts_with("derive_") {
|
||||||
|
self.gate_feature("custom_derive", attr.span,
|
||||||
|
"attributes of the form `#[derive_*]` are reserved
|
||||||
|
for the compiler");
|
||||||
} else {
|
} else {
|
||||||
self.gate_feature("custom_attribute", attr.span,
|
self.gate_feature("custom_attribute", attr.span,
|
||||||
format!("The attribute `{}` is currently \
|
format!("The attribute `{}` is currently \
|
||||||
@@ -432,6 +442,9 @@ pub const EXPLAIN_TRACE_MACROS: &'static str =
|
|||||||
pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
|
pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
|
||||||
"allow_internal_unstable side-steps feature gating and stability checks";
|
"allow_internal_unstable side-steps feature gating and stability checks";
|
||||||
|
|
||||||
|
pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
|
||||||
|
"`#[derive]` for custom traits is not stable enough for use and is subject to change";
|
||||||
|
|
||||||
struct MacroVisitor<'a> {
|
struct MacroVisitor<'a> {
|
||||||
context: &'a Context<'a>
|
context: &'a Context<'a>
|
||||||
}
|
}
|
||||||
@@ -780,6 +793,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
|
|||||||
allow_concat_idents: cx.has_feature("concat_idents"),
|
allow_concat_idents: cx.has_feature("concat_idents"),
|
||||||
allow_trace_macros: cx.has_feature("trace_macros"),
|
allow_trace_macros: cx.has_feature("trace_macros"),
|
||||||
allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
|
allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
|
||||||
|
allow_custom_derive: cx.has_feature("custom_derive"),
|
||||||
old_orphan_check: cx.has_feature("old_orphan_check"),
|
old_orphan_check: cx.has_feature("old_orphan_check"),
|
||||||
simd_ffi: cx.has_feature("simd_ffi"),
|
simd_ffi: cx.has_feature("simd_ffi"),
|
||||||
unmarked_api: cx.has_feature("unmarked_api"),
|
unmarked_api: cx.has_feature("unmarked_api"),
|
||||||
|
|||||||
74
src/test/auxiliary/custom_derive_plugin.rs
Normal file
74
src/test/auxiliary/custom_derive_plugin.rs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// force-host
|
||||||
|
|
||||||
|
#![feature(plugin_registrar)]
|
||||||
|
#![feature(box_syntax)]
|
||||||
|
#![feature(rustc_private)]
|
||||||
|
|
||||||
|
extern crate syntax;
|
||||||
|
extern crate rustc;
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
|
use syntax::codemap::Span;
|
||||||
|
use syntax::ext::base::{Decorator, ExtCtxt};
|
||||||
|
use syntax::ext::build::AstBuilder;
|
||||||
|
use syntax::ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure};
|
||||||
|
use syntax::ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
|
||||||
|
use syntax::parse::token;
|
||||||
|
use syntax::ptr::P;
|
||||||
|
use rustc::plugin::Registry;
|
||||||
|
|
||||||
|
#[plugin_registrar]
|
||||||
|
pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
|
reg.register_syntax_extension(
|
||||||
|
token::intern("derive_TotalSum"),
|
||||||
|
Decorator(box expand));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand(cx: &mut ExtCtxt,
|
||||||
|
span: Span,
|
||||||
|
mitem: &ast::MetaItem,
|
||||||
|
item: &ast::Item,
|
||||||
|
push: &mut FnMut(P<ast::Item>)) {
|
||||||
|
let trait_def = TraitDef {
|
||||||
|
span: span,
|
||||||
|
attributes: vec![],
|
||||||
|
path: Path::new(vec!["TotalSum"]),
|
||||||
|
additional_bounds: vec![],
|
||||||
|
generics: LifetimeBounds::empty(),
|
||||||
|
associated_types: vec![],
|
||||||
|
methods: vec![
|
||||||
|
MethodDef {
|
||||||
|
name: "total_sum",
|
||||||
|
generics: LifetimeBounds::empty(),
|
||||||
|
explicit_self: borrowed_explicit_self(),
|
||||||
|
args: vec![],
|
||||||
|
ret_ty: Literal(Path::new_local("isize")),
|
||||||
|
attributes: vec![],
|
||||||
|
combine_substructure: combine_substructure(box |cx, span, substr| {
|
||||||
|
let zero = cx.expr_int(span, 0);
|
||||||
|
cs_fold(false,
|
||||||
|
|cx, span, subexpr, field, _| {
|
||||||
|
cx.expr_binary(span, ast::BiAdd, subexpr,
|
||||||
|
cx.expr_method_call(span, field,
|
||||||
|
token::str_to_ident("total_sum"), vec![]))
|
||||||
|
},
|
||||||
|
zero,
|
||||||
|
box |cx, span, _, _| { cx.span_bug(span, "wtf??"); },
|
||||||
|
cx, span, substr)
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
trait_def.expand(cx, mitem, item, |i| push(i))
|
||||||
|
}
|
||||||
@@ -8,12 +8,12 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#[derive(Copy(Bad))]
|
#[derive(Send)]
|
||||||
//~^ ERROR unexpected value in deriving, expected a trait
|
//~^ ERROR this unsafe trait should be implemented explicitly
|
||||||
struct Test;
|
struct Test;
|
||||||
|
|
||||||
#[derive(Sync)]
|
#[derive(Sync)]
|
||||||
//~^ ERROR Sync is an unsafe trait and it should be implemented explicitly
|
//~^ ERROR this unsafe trait should be implemented explicitly
|
||||||
struct Test1;
|
struct Test1;
|
||||||
|
|
||||||
pub fn main() {}
|
pub fn main() {}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#[derive(Eqr)] //~ ERROR unknown `derive` trait: `Eqr`
|
#[derive(Eqr)]
|
||||||
|
//~^ ERROR `#[derive]` for custom traits is not stable enough for use and is subject to change
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
pub fn main() {}
|
pub fn main() {}
|
||||||
|
|||||||
25
src/test/compile-fail/malformed-derive-entry.rs
Normal file
25
src/test/compile-fail/malformed-derive-entry.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[derive(Copy(Bad))]
|
||||||
|
//~^ ERROR malformed `derive` entry
|
||||||
|
struct Test1;
|
||||||
|
|
||||||
|
#[derive(Copy="bad")]
|
||||||
|
//~^ ERROR malformed `derive` entry
|
||||||
|
struct Test2;
|
||||||
|
|
||||||
|
#[derive()]
|
||||||
|
//~^ WARNING empty trait list
|
||||||
|
struct Test3;
|
||||||
|
|
||||||
|
#[derive]
|
||||||
|
//~^ WARNING empty trait list
|
||||||
|
struct Test4;
|
||||||
15
src/test/compile-fail/single-derive-attr.rs
Normal file
15
src/test/compile-fail/single-derive-attr.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[derive_Clone]
|
||||||
|
//~^ ERROR attributes of the form `#[derive_*]` are reserved
|
||||||
|
struct Test;
|
||||||
|
|
||||||
|
pub fn main() {}
|
||||||
59
src/test/run-pass-fulldeps/derive-totalsum.rs
Normal file
59
src/test/run-pass-fulldeps/derive-totalsum.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// aux-build:custom_derive_plugin.rs
|
||||||
|
// ignore-stage1
|
||||||
|
|
||||||
|
#![feature(plugin, custom_derive)]
|
||||||
|
#![plugin(custom_derive_plugin)]
|
||||||
|
|
||||||
|
trait TotalSum {
|
||||||
|
fn total_sum(&self) -> isize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TotalSum for isize {
|
||||||
|
fn total_sum(&self) -> isize {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Seven;
|
||||||
|
|
||||||
|
impl TotalSum for Seven {
|
||||||
|
fn total_sum(&self) -> isize {
|
||||||
|
7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(TotalSum)]
|
||||||
|
struct Foo {
|
||||||
|
seven: Seven,
|
||||||
|
bar: Bar,
|
||||||
|
baz: isize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(TotalSum)]
|
||||||
|
struct Bar {
|
||||||
|
quux: isize,
|
||||||
|
bleh: isize,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let v = Foo {
|
||||||
|
seven: Seven,
|
||||||
|
bar: Bar {
|
||||||
|
quux: 9,
|
||||||
|
bleh: 3,
|
||||||
|
},
|
||||||
|
baz: 80,
|
||||||
|
};
|
||||||
|
assert_eq!(v.total_sum(), 99);
|
||||||
|
}
|
||||||
15
src/test/run-pass/deprecated-derive.rs
Normal file
15
src/test/run-pass/deprecated-derive.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[derive(Show)]
|
||||||
|
//~^ WARNING derive(Show) is deprecated
|
||||||
|
struct Test1;
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
18
src/test/run-pass/single-derive-attr-with-gate.rs
Normal file
18
src/test/run-pass/single-derive-attr-with-gate.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(custom_derive)]
|
||||||
|
|
||||||
|
#[derive_Clone]
|
||||||
|
struct Test;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
Test.clone();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user