Auto merge of #23137 - kmcallister:derive-sugar, r=sfackler

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.

To make this effective, we now check gated attributes both before and after macro expansion. This uncovered a number of tests that were missing feature gates.

This PR also cleans up the deriving code somewhat, and forbids some previously-meaningless attribute syntax. For this reason it's technically a

    [breaking-change]

r? @sfackler
This commit is contained in:
bors 2015-03-07 18:39:17 +00:00
commit 668c647408
24 changed files with 468 additions and 205 deletions

View file

@ -2429,6 +2429,10 @@ The currently implemented features of the reference compiler are:
so that new attributes can be added in a bacwards compatible
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
are inherently unstable and no promise about them is made.

View file

@ -491,10 +491,8 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
syntax_expanders.insert(intern("log_syntax"),
builtin_normal_expander(
ext::log_syntax::expand_syntax_ext));
syntax_expanders.insert(intern("derive"),
Decorator(Box::new(ext::deriving::expand_meta_derive)));
syntax_expanders.insert(intern("deriving"),
Decorator(Box::new(ext::deriving::expand_deprecated_deriving)));
ext::deriving::register_all(&mut syntax_expanders);
if ecfg.enable_quotes() {
// Quasi-quoting expanders

View file

@ -8,47 +8,34 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{MetaItem, MetaWord, Item};
use ast::{MetaItem, Item};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
use ptr::P;
pub fn expand_deriving_bound<F>(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: F) where
pub fn expand_deriving_unsafe_bound<F>(cx: &mut ExtCtxt,
span: Span,
_: &MetaItem,
_: &Item,
_: F) where
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")
}
};
cx.span_err(span, "this unsafe trait should be implemented explicitly");
}
pub fn expand_deriving_copy<F>(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: F) where
F: FnOnce(P<Item>),
{
let path = Path::new(vec![
if cx.use_std { "std" } else { "core" },
"marker",
name
"Copy",
]);
let trait_def = TraitDef {

View file

@ -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
// http://rust-lang.org/COPYRIGHT.
//
@ -13,9 +13,13 @@
//! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
//! the standard library, and "std" is the core library.
use ast::{Item, MetaItem, MetaList, MetaNameValue, MetaWord};
use ext::base::ExtCtxt;
use ast::{Item, MetaItem, MetaWord};
use attr::AttrMetaMethods;
use ext::base::{ExtCtxt, SyntaxEnv, Decorator, ItemDecorator, Modifier};
use ext::build::AstBuilder;
use feature_gate;
use codemap::Span;
use parse::token::{intern, intern_and_get_ident};
use ptr::P;
macro_rules! pathvec {
@ -74,101 +78,133 @@ pub mod totalord;
pub mod generic;
pub fn expand_deprecated_deriving(cx: &mut ExtCtxt,
span: Span,
_: &MetaItem,
_: &Item,
_: &mut FnMut(P<Item>)) {
fn expand_deprecated_deriving(cx: &mut ExtCtxt,
span: Span,
_: &MetaItem,
_: &Item,
_: &mut FnMut(P<Item>)) {
cx.span_err(span, "`deriving` has been renamed to `derive`");
}
pub fn expand_meta_derive(cx: &mut ExtCtxt,
_span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>)) {
match mitem.node {
MetaNameValue(_, ref l) => {
cx.span_err(l.span, "unexpected value in `derive`");
fn expand_derive(cx: &mut ExtCtxt,
_: 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`");
}
MetaWord(_) => {
let traits = mitem.meta_item_list().unwrap_or(&[]);
if traits.is_empty() {
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`");
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)))));
}
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),
item
})
}
"Hash" => expand!(hash::expand_deriving_hash),
macro_rules! derive_traits {
($( $name:expr => $func:path, )*) => {
pub fn register_all(env: &mut SyntaxEnv) {
// Define the #[derive_*] extensions.
$({
struct DeriveExtension;
"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));
}
};
impl ItemDecorator for DeriveExtension {
fn expand(&self,
ecx: &mut ExtCtxt,
sp: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>)) {
warn_if_deprecated(ecx, sp, $name);
$func(ecx, sp, mitem, item, |i| push(i));
}
}
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));
}
}

View file

@ -1447,6 +1447,19 @@ pub struct ExpansionConfig<'feat> {
pub recursion_limit: usize,
}
macro_rules! feature_tests {
($( fn $getter:ident = $field:ident, )*) => {
$(
pub fn $getter(&self) -> bool {
match self.features {
Some(&Features { $field: true, .. }) => true,
_ => false,
}
}
)*
}
}
impl<'feat> ExpansionConfig<'feat> {
pub fn default(crate_name: String) -> ExpansionConfig<'static> {
ExpansionConfig {
@ -1456,46 +1469,14 @@ impl<'feat> ExpansionConfig<'feat> {
}
}
pub fn enable_quotes(&self) -> bool {
match self.features {
Some(&Features { allow_quote: true, .. }) => true,
_ => false,
}
}
pub fn enable_asm(&self) -> bool {
match self.features {
Some(&Features { allow_asm: true, .. }) => true,
_ => false,
}
}
pub fn enable_log_syntax(&self) -> bool {
match self.features {
Some(&Features { allow_log_syntax: true, .. }) => true,
_ => false,
}
}
pub fn enable_concat_idents(&self) -> bool {
match self.features {
Some(&Features { allow_concat_idents: true, .. }) => true,
_ => false,
}
}
pub fn enable_trace_macros(&self) -> bool {
match self.features {
Some(&Features { allow_trace_macros: true, .. }) => true,
_ => false,
}
}
pub fn enable_allow_internal_unstable(&self) -> bool {
match self.features {
Some(&Features { allow_internal_unstable: true, .. }) => true,
_ => false
}
feature_tests! {
fn enable_quotes = allow_quote,
fn enable_asm = allow_asm,
fn enable_log_syntax = allow_log_syntax,
fn enable_concat_idents = allow_concat_idents,
fn enable_trace_macros = allow_trace_macros,
fn enable_allow_internal_unstable = allow_internal_unstable,
fn enable_custom_derive = allow_custom_derive,
}
}

View file

@ -137,6 +137,10 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
// Allows the use of custom attributes; RFC 572
("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
("rustc_attrs", "1.0.0", Active),
@ -196,6 +200,7 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
("no_mangle", Normal),
("no_link", Normal),
("derive", Normal),
("deriving", Normal), // deprecation err in expansion
("should_fail", Normal),
("should_panic", Normal),
("ignore", Normal),
@ -235,6 +240,9 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
"the `#[rustc_move_fragments]` attribute \
is an experimental feature")),
("allow_internal_unstable", Gated("allow_internal_unstable",
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
// FIXME: #14408 whitelist docs since rustdoc looks at them
("doc", Whitelisted),
@ -315,6 +323,7 @@ pub struct Features {
pub allow_concat_idents: bool,
pub allow_trace_macros: bool,
pub allow_internal_unstable: bool,
pub allow_custom_derive: bool,
pub old_orphan_check: bool,
pub simd_ffi: bool,
pub unmarked_api: bool,
@ -336,6 +345,7 @@ impl Features {
allow_concat_idents: false,
allow_trace_macros: false,
allow_internal_unstable: false,
allow_custom_derive: false,
old_orphan_check: false,
simd_ffi: false,
unmarked_api: false,
@ -369,6 +379,37 @@ impl<'a> Context<'a> {
fn has_feature(&self, feature: &str) -> bool {
self.features.iter().any(|&n| n == feature)
}
fn check_attribute(&self, attr: &ast::Attribute) {
debug!("check_attribute(attr = {:?})", attr);
let name = &*attr.name();
for &(n, ty) in KNOWN_ATTRIBUTES {
if n == name {
if let Gated(gate, desc) = ty {
self.gate_feature(gate, attr.span, desc);
}
debug!("check_attribute: {:?} is known, {:?}", name, ty);
return;
}
}
if name.starts_with("rustc_") {
self.gate_feature("rustc_attrs", attr.span,
"unless otherwise specified, attributes \
with the prefix `rustc_` \
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 {
self.gate_feature("custom_attribute", attr.span,
format!("The attribute `{}` is currently \
unknown to the the compiler and \
may have meaning \
added to it in the future",
name).as_slice());
}
}
}
pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain: &str) {
@ -401,6 +442,9 @@ pub const EXPLAIN_TRACE_MACROS: &'static str =
pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
"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> {
context: &'a Context<'a>
}
@ -436,10 +480,7 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
}
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
if attr.name() == "allow_internal_unstable" {
self.context.gate_feature("allow_internal_unstable", attr.span,
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)
}
self.context.check_attribute(attr);
}
}
@ -456,6 +497,12 @@ impl<'a> PostExpansionVisitor<'a> {
}
impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
if !self.context.cm.span_allows_unstable(attr.span) {
self.context.check_attribute(attr);
}
}
fn visit_name(&mut self, sp: Span, name: ast::Name) {
if !token::get_name(name).is_ascii() {
self.gate_feature("non_ascii_idents", sp,
@ -556,12 +603,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
}
fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
if attr::contains_name(&i.attrs, "linkage") {
self.gate_feature("linkage", i.span,
"the `linkage` attribute is experimental \
and not portable across platforms")
}
let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
"link_name") {
Some(val) => val.starts_with("llvm."),
@ -636,33 +677,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
visit::walk_expr(self, e);
}
fn visit_attribute(&mut self, attr: &ast::Attribute) {
debug!("visit_attribute(attr = {:?})", attr);
let name = &*attr.name();
for &(n, ty) in KNOWN_ATTRIBUTES {
if n == name {
if let Gated(gate, desc) = ty {
self.gate_feature(gate, attr.span, desc);
}
debug!("visit_attribute: {:?} is known, {:?}", name, ty);
return;
}
}
if name.starts_with("rustc_") {
self.gate_feature("rustc_attrs", attr.span,
"unless otherwise specified, attributes \
with the prefix `rustc_` \
are reserved for internal compiler diagnostics");
} else {
self.gate_feature("custom_attribute", attr.span,
format!("The attribute `{}` is currently \
unknown to the the compiler and \
may have meaning \
added to it in the future",
name).as_slice());
}
}
fn visit_pat(&mut self, pattern: &ast::Pat) {
match pattern.node {
ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
@ -779,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_trace_macros: cx.has_feature("trace_macros"),
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"),
simd_ffi: cx.has_feature("simd_ffi"),
unmarked_api: cx.has_feature("unmarked_api"),

View 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))
}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(custom_attribute)]
#[phase(blah)]
//~^ ERROR #[phase] is deprecated
extern crate foo;

View file

@ -8,12 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[derive(Copy(Bad))]
//~^ ERROR unexpected value in deriving, expected a trait
#[derive(Send)]
//~^ ERROR this unsafe trait should be implemented explicitly
struct Test;
#[derive(Sync)]
//~^ ERROR Sync is an unsafe trait and it should be implemented explicitly
//~^ ERROR this unsafe trait should be implemented explicitly
struct Test1;
pub fn main() {}

View file

@ -8,7 +8,8 @@
// option. This file may not be copied, modified, or distributed
// 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;
pub fn main() {}

View file

@ -8,9 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[lang="foo"] //~ ERROR language items are subject to change
trait Foo {}
extern "rust-intrinsic" { //~ ERROR intrinsics are subject to change
fn bar();
}
@ -20,4 +17,3 @@ extern "rust-intrinsic" fn baz() { //~ ERROR intrinsics are subject to change
fn main() {
}

View file

@ -0,0 +1,15 @@
// Copyright 2014 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.
#[lang="foo"] //~ ERROR language items are subject to change
trait Foo {}
fn main() {
}

View file

@ -11,5 +11,4 @@
extern {
#[linkage = "extern_weak"] static foo: isize;
//~^ ERROR: the `linkage` attribute is experimental and not portable
//~^^ ERROR: the `linkage` attribute is experimental and not portable
}

View 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;

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(plugin)]
#![plugin] //~ ERROR malformed plugin attribute
fn main() {}

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(plugin)]
#![plugin="bleh"] //~ ERROR malformed plugin attribute
fn main() {}

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(plugin)]
#![plugin(foo="bleh")] //~ ERROR malformed plugin attribute
fn main() {}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(plugin)]
#[plugin] //~ ERROR #[plugin] on `extern crate` is deprecated
//~^ HELP use a crate attribute instead, i.e. #![plugin(std)]
extern crate std;

View 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.
#[rustc_attribute_should_be_reserved] //~ ERROR attributes with the prefix `rustc_` are reserved
macro_rules! foo {
() => (());
}
fn main() {
foo!();
}

View 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() {}

View 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);
}

View file

@ -11,7 +11,7 @@
// aux-build:macro_crate_test.rs
// ignore-stage1
#![feature(plugin)]
#![feature(plugin, custom_attribute)]
#![plugin(macro_crate_test)]
#[macro_use] #[no_link]

View 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() { }

View 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();
}