diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index cde16d25412e5..354a0bff74998 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -146,7 +146,7 @@ pub trait AstBuilder { fn expr_lit(&self, sp: Span, lit: ast::Lit_) -> P; fn expr_usize(&self, span: Span, i: usize) -> P; - fn expr_int(&self, sp: Span, i: isize) -> P; + fn expr_isize(&self, sp: Span, i: isize) -> P; fn expr_u8(&self, sp: Span, u: u8) -> P; fn expr_u32(&self, sp: Span, u: u32) -> P; fn expr_bool(&self, sp: Span, value: bool) -> P; @@ -698,7 +698,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn expr_usize(&self, span: Span, i: usize) -> P { self.expr_lit(span, ast::LitInt(i as u64, ast::UnsignedIntLit(ast::TyUs))) } - fn expr_int(&self, sp: Span, i: isize) -> P { + fn expr_isize(&self, sp: Span, i: isize) -> P { self.expr_lit(sp, ast::LitInt(i as u64, ast::SignedIntLit(ast::TyIs, ast::Sign::new(i)))) } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 4c05cd973ff6f..339e535cdcd9f 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -270,7 +270,7 @@ pub struct Substructure<'a> { } /// Summary of the relevant parts of a struct/enum field. -pub struct FieldInfo { +pub struct FieldInfo<'a> { pub span: Span, /// None for tuple structs/normal enum variants, Some for normal /// structs/struct enum variants. @@ -281,6 +281,8 @@ pub struct FieldInfo { /// The expressions corresponding to references to this field in /// the other `Self` arguments. pub other: Vec>, + /// The attributes on the field + pub attrs: &'a [ast::Attribute], } /// Fields for a static method @@ -293,11 +295,11 @@ pub enum StaticFields { /// A summary of the possible sets of fields. pub enum SubstructureFields<'a> { - Struct(Vec), + Struct(Vec>), /// Matching variants of the enum: variant index, ast::Variant, /// fields: the field name is only non-`None` in the case of a struct /// variant. - EnumMatching(usize, &'a ast::Variant, Vec), + EnumMatching(usize, &'a ast::Variant, Vec>), /// Non-matching variants of the enum, but with all state hidden from /// the consequent code. The first component holds `Ident`s for all of @@ -378,7 +380,7 @@ impl<'a> TraitDef<'a> { pub fn expand(&self, cx: &mut ExtCtxt, mitem: &ast::MetaItem, - item: &ast::Item, + item: &'a ast::Item, push: &mut FnMut(P)) { let newitem = match item.node { @@ -609,7 +611,7 @@ impl<'a> TraitDef<'a> { fn expand_struct_def(&self, cx: &mut ExtCtxt, - struct_def: &StructDef, + struct_def: &'a StructDef, type_ident: Ident, generics: &Generics) -> P { let field_tys: Vec> = struct_def.fields.iter() @@ -653,7 +655,7 @@ impl<'a> TraitDef<'a> { fn expand_enum_def(&self, cx: &mut ExtCtxt, - enum_def: &EnumDef, + enum_def: &'a EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, generics: &Generics) -> P { @@ -885,10 +887,10 @@ impl<'a> MethodDef<'a> { /// } /// } /// ``` - fn expand_struct_method_body(&self, + fn expand_struct_method_body<'b>(&self, cx: &mut ExtCtxt, - trait_: &TraitDef, - struct_def: &StructDef, + trait_: &TraitDef<'b>, + struct_def: &'b StructDef, type_ident: Ident, self_args: &[P], nonself_args: &[P]) @@ -914,18 +916,19 @@ impl<'a> MethodDef<'a> { let fields = if !raw_fields.is_empty() { let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter()); let first_field = raw_fields.next().unwrap(); - let mut other_fields: Vec, P)>> + let mut other_fields: Vec> = raw_fields.collect(); - first_field.map(|(span, opt_id, field)| { + first_field.map(|(span, opt_id, field, attrs)| { FieldInfo { span: span, name: opt_id, self_: field, other: other_fields.iter_mut().map(|l| { match l.next().unwrap() { - (_, _, ex) => ex + (_, _, ex, _) => ex } - }).collect() + }).collect(), + attrs: attrs, } }).collect() } else { @@ -999,10 +1002,10 @@ impl<'a> MethodDef<'a> { /// `PartialEq`, and those subcomputations will hopefully be removed /// as their results are unused. The point of `__self_vi` and /// `__arg_1_vi` is for `PartialOrd`; see #15503.) - fn expand_enum_method_body(&self, + fn expand_enum_method_body<'b>(&self, cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, + trait_: &TraitDef<'b>, + enum_def: &'b EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, self_args: Vec>, @@ -1038,11 +1041,11 @@ impl<'a> MethodDef<'a> { /// } /// } /// ``` - fn build_enum_match_tuple( + fn build_enum_match_tuple<'b>( &self, cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, + trait_: &TraitDef<'b>, + enum_def: &'b EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, self_args: Vec>, @@ -1125,7 +1128,7 @@ impl<'a> MethodDef<'a> { // arg fields of the variant for the first self pat. let field_tuples = first_self_pat_idents.into_iter().enumerate() // For each arg field of self, pull out its getter expr ... - .map(|(field_index, (sp, opt_ident, self_getter_expr))| { + .map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| { // ... but FieldInfo also wants getter expr // for matching other arguments of Self type; // so walk across the *other* self_pats_idents @@ -1133,7 +1136,7 @@ impl<'a> MethodDef<'a> { // of them (using `field_index` tracked above). // That is the heart of the transposition. let others = self_pats_idents.iter().map(|fields| { - let (_, _opt_ident, ref other_getter_expr) = + let (_, _opt_ident, ref other_getter_expr, _) = fields[field_index]; // All Self args have same variant, so @@ -1149,6 +1152,7 @@ impl<'a> MethodDef<'a> { name: opt_ident, self_: self_getter_expr, other: others, + attrs: attrs, } }).collect::>(); @@ -1400,10 +1404,12 @@ impl<'a> TraitDef<'a> { fn create_struct_pattern(&self, cx: &mut ExtCtxt, struct_path: ast::Path, - struct_def: &StructDef, + struct_def: &'a StructDef, prefix: &str, mutbl: ast::Mutability) - -> (P, Vec<(Span, Option, P)>) { + -> (P, Vec<(Span, Option, + P, + &'a [ast::Attribute])>) { if struct_def.fields.is_empty() { return (cx.pat_enum(self.span, struct_path, vec![]), vec![]); } @@ -1433,7 +1439,7 @@ impl<'a> TraitDef<'a> { paths.push(codemap::Spanned{span: sp, node: ident}); let val = cx.expr( sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident))))); - ident_expr.push((sp, opt_id, val)); + ident_expr.push((sp, opt_id, val, &struct_field.node.attrs[..])); } let subpats = self.create_subpatterns(cx, paths, mutbl); @@ -1441,7 +1447,8 @@ impl<'a> TraitDef<'a> { // struct_type is definitely not Unknown, since struct_def.fields // must be nonempty to reach here let pattern = if struct_type == Record { - let field_pats = subpats.into_iter().zip(ident_expr.iter()).map(|(pat, &(_, id, _))| { + let field_pats = subpats.into_iter().zip(ident_expr.iter()) + .map(|(pat, &(_, id, _, _))| { // id is guaranteed to be Some codemap::Spanned { span: pat.span, @@ -1459,10 +1466,10 @@ impl<'a> TraitDef<'a> { fn create_enum_variant_pattern(&self, cx: &mut ExtCtxt, enum_ident: ast::Ident, - variant: &ast::Variant, + variant: &'a ast::Variant, prefix: &str, mutbl: ast::Mutability) - -> (P, Vec<(Span, Option, P)>) { + -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]); match variant.node.kind { @@ -1472,7 +1479,7 @@ impl<'a> TraitDef<'a> { } let mut paths = Vec::new(); - let mut ident_expr = Vec::new(); + let mut ident_expr: Vec<(_, _, _, &'a [ast::Attribute])> = Vec::new(); for (i, va) in variant_args.iter().enumerate() { let sp = self.set_expn_info(cx, va.ty.span); let ident = cx.ident_of(&format!("{}_{}", prefix, i)); @@ -1480,7 +1487,7 @@ impl<'a> TraitDef<'a> { paths.push(path1); let expr_path = cx.expr_path(cx.path_ident(sp, ident)); let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path))); - ident_expr.push((sp, None, val)); + ident_expr.push((sp, None, val, &[])); } let subpats = self.create_subpatterns(cx, paths, mutbl); diff --git a/src/test/auxiliary/custom_derive_plugin.rs b/src/test/auxiliary/custom_derive_plugin.rs index 17d3f6a46ef57..78381395dc92c 100644 --- a/src/test/auxiliary/custom_derive_plugin.rs +++ b/src/test/auxiliary/custom_derive_plugin.rs @@ -55,7 +55,7 @@ fn expand(cx: &mut ExtCtxt, ret_ty: Literal(Path::new_local("isize")), attributes: vec![], combine_substructure: combine_substructure(box |cx, span, substr| { - let zero = cx.expr_int(span, 0); + let zero = cx.expr_isize(span, 0); cs_fold(false, |cx, span, subexpr, field, _| { cx.expr_binary(span, ast::BiAdd, subexpr, diff --git a/src/test/auxiliary/custom_derive_plugin_attr.rs b/src/test/auxiliary/custom_derive_plugin_attr.rs new file mode 100644 index 0000000000000..445aa743a77fe --- /dev/null +++ b/src/test/auxiliary/custom_derive_plugin_attr.rs @@ -0,0 +1,87 @@ +// 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 or the MIT license +// , 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::attr::AttrMetaMethods; +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::{Substructure, Struct, EnumMatching}; +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)) { + 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::new(totalsum_substructure)), + }, + ], + }; + + trait_def.expand(cx, mitem, item, push) +} + +// Mostly copied from syntax::ext::deriving::hash +/// Defines how the implementation for `trace()` is to be generated +fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span, + substr: &Substructure) -> P { + let fields = match *substr.fields { + Struct(ref fs) | EnumMatching(_, _, ref fs) => fs, + _ => cx.span_bug(trait_span, "impossible substructure") + }; + + fields.iter().fold(cx.expr_isize(trait_span, 0), |acc, ref item| { + if item.attrs.iter().find(|a| a.check_name("ignore")).is_some() { + acc + } else { + cx.expr_binary(item.span, ast::BiAdd, acc, + cx.expr_method_call(item.span, + item.self_.clone(), + substr.method_ident, + Vec::new())) + } + }) +} diff --git a/src/test/run-pass-fulldeps/derive-totalsum-attr.rs b/src/test/run-pass-fulldeps/derive-totalsum-attr.rs new file mode 100644 index 0000000000000..ef5198b9ae038 --- /dev/null +++ b/src/test/run-pass-fulldeps/derive-totalsum-attr.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:custom_derive_plugin_attr.rs +// ignore-stage1 + +#![feature(plugin, custom_derive, custom_attribute)] +#![plugin(custom_derive_plugin_attr)] + +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, + #[ignore] + nan: NaN, +} + +#[derive(TotalSum)] +struct Bar { + quux: isize, + bleh: isize, + #[ignore] + nan: NaN2 +} + +struct NaN; + +impl TotalSum for NaN { + fn total_sum(&self) -> isize { + panic!(); + } +} + +struct NaN2; + +pub fn main() { + let v = Foo { + seven: Seven, + bar: Bar { + quux: 9, + bleh: 3, + nan: NaN2 + }, + baz: 80, + nan: NaN + }; + assert_eq!(v.total_sum(), 99); +}