diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index 1825c3d347e..0085182d1ac 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -11,7 +11,7 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr}; +use syntax::ast::{MetaItem, Expr, VariantData}; use syntax::codemap::Span; use syntax::ext::base::{ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; @@ -66,14 +66,17 @@ fn cs_clone( cx.expr_call_global(field.span, fn_path.clone(), args) }; + let vdata; match *substr.fields { - Struct(ref af) => { + Struct(vdata_, ref af) => { ctor_path = cx.path(trait_span, vec![substr.type_ident]); all_fields = af; + vdata = vdata_; } EnumMatching(_, variant, ref af) => { ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.name]); all_fields = af; + vdata = &variant.node.data; }, EnumNonMatchingCollapsed (..) => { cx.span_bug(trait_span, @@ -86,30 +89,29 @@ fn cs_clone( } } - if !all_fields.is_empty() && all_fields[0].name.is_none() { - // enum-like - let subcalls = all_fields.iter().map(subcall).collect(); - let path = cx.expr_path(ctor_path); - cx.expr_call(trait_span, path, subcalls) - } else { - // struct-like - let fields = all_fields.iter().map(|field| { - let ident = match field.name { - Some(i) => i, - None => { - cx.span_bug(trait_span, - &format!("unnamed field in normal struct in \ - `derive({})`", name)) - } - }; - cx.field_imm(field.span, ident, subcall(field)) - }).collect::>(); + match *vdata { + VariantData::Struct(..) => { + let fields = all_fields.iter().map(|field| { + let ident = match field.name { + Some(i) => i, + None => { + cx.span_bug(trait_span, + &format!("unnamed field in normal struct in \ + `derive({})`", name)) + } + }; + cx.field_imm(field.span, ident, subcall(field)) + }).collect::>(); - if fields.is_empty() { - // no fields, so construct like `None` - cx.expr_path(ctor_path) - } else { cx.expr_struct(trait_span, ctor_path, fields) } + VariantData::Tuple(..) => { + let subcalls = all_fields.iter().map(subcall).collect(); + let path = cx.expr_path(ctor_path); + cx.expr_call(trait_span, path, subcalls) + } + VariantData::Unit(..) => { + cx.expr_path(ctor_path) + } } } diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index 6439e9aa498..109f2ad4025 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -62,7 +62,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, // or fmt.debug_tuple().field(&)....build() // based on the "shape". let ident = match *substr.fields { - Struct(_) => substr.type_ident, + Struct(..) => substr.type_ident, EnumMatching(_, v, _) => v.node.name, EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") @@ -76,11 +76,16 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, let builder_expr = cx.expr_ident(span, builder.clone()); let fmt = substr.nonself_args[0].clone(); + let is_struct = match *substr.fields { + Struct(vdata, _) => vdata, + EnumMatching(_, v, _) => &v.node.data, + _ => unreachable!() + }.is_struct(); let stmts = match *substr.fields { - Struct(ref fields) | EnumMatching(_, _, ref fields) => { + Struct(_, ref fields) | EnumMatching(_, _, ref fields) => { let mut stmts = vec![]; - if fields.is_empty() || fields[0].name.is_none() { + if !is_struct { // tuple struct/"normal" variant let expr = cx.expr_method_call(span, fmt, diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 614a6381962..8262a04e9ce 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -179,7 +179,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, let encode = cx.ident_of("encode"); return match *substr.fields { - Struct(ref fields) => { + Struct(_, ref fields) => { let emit_struct_field = cx.ident_of("emit_struct_field"); let mut stmts = Vec::new(); for (i, &FieldInfo { diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index bdba49f2f29..c0237a5d29a 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -300,7 +300,7 @@ pub enum StaticFields { /// A summary of the possible sets of fields. pub enum SubstructureFields<'a> { - Struct(Vec>), + Struct(&'a ast::VariantData, 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. @@ -981,7 +981,7 @@ impl<'a> MethodDef<'a> { type_ident, self_args, nonself_args, - &Struct(fields)); + &Struct(struct_def, fields)); // make a series of nested matches, to destructure the // structs. This is actually right-to-left, but it shouldn't @@ -1460,8 +1460,9 @@ impl<'a> TraitDef<'a> { fields in generic `derive`"), // named fields (_, false) => Named(named_idents), - // tuple structs (includes empty structs) - (_, _) => Unnamed(just_spans) + // empty structs + _ if struct_def.is_struct() => Named(named_idents), + _ => Unnamed(just_spans), } } @@ -1486,7 +1487,11 @@ impl<'a> TraitDef<'a> { P, &'a [ast::Attribute])>) { if struct_def.fields().is_empty() { - return (cx.pat_enum(self.span, struct_path, vec![]), vec![]); + if struct_def.is_struct() { + return (cx.pat_struct(self.span, struct_path, vec![]), vec![]); + } else { + return (cx.pat_enum(self.span, struct_path, vec![]), vec![]); + } } let mut paths = Vec::new(); @@ -1521,7 +1526,7 @@ 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 pattern = if struct_def.is_struct() { let field_pats = subpats.into_iter().zip(&ident_expr) .map(|(pat, &(_, id, _, _))| { // id is guaranteed to be Some @@ -1566,7 +1571,7 @@ pub fn cs_fold(use_foldl: bool, F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P, { match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { + EnumMatching(_, _, ref all_fields) | Struct(_, ref all_fields) => { if use_foldl { all_fields.iter().fold(base, |old, field| { f(cx, @@ -1612,7 +1617,7 @@ pub fn cs_same_method(f: F, F: FnOnce(&mut ExtCtxt, Span, Vec>) -> P, { match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { + EnumMatching(_, _, ref all_fields) | Struct(_, ref all_fields) => { // call self_n.method(other_1_n, other_2_n, ...) let called = all_fields.iter().map(|field| { cx.expr_method_call(field.span, diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index 371ba732b48..bf8aa8fb23d 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -76,7 +76,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) let mut stmts = Vec::new(); let fields = match *substr.fields { - Struct(ref fs) => fs, + Struct(_, ref fs) => fs, EnumMatching(index, variant, ref fs) => { // Determine the discriminant. We will feed this value to the byte // iteration function. diff --git a/src/test/auxiliary/custom_derive_plugin_attr.rs b/src/test/auxiliary/custom_derive_plugin_attr.rs index ba216289fd4..2878674f0ea 100644 --- a/src/test/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/auxiliary/custom_derive_plugin_attr.rs @@ -73,7 +73,7 @@ fn expand(cx: &mut ExtCtxt, fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { let fields = match *substr.fields { - Struct(ref fs) | EnumMatching(_, _, ref fs) => fs, + Struct(_, ref fs) | EnumMatching(_, _, ref fs) => fs, _ => cx.span_bug(trait_span, "impossible substructure") }; diff --git a/src/test/run-pass/empty-struct-braces-derive.rs b/src/test/run-pass/empty-struct-braces-derive.rs new file mode 100644 index 00000000000..e54a8245d0b --- /dev/null +++ b/src/test/run-pass/empty-struct-braces-derive.rs @@ -0,0 +1,45 @@ +// 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. + +// `#[derive(Trait)]` works for empty structs/variants with braces + +#![feature(braced_empty_structs)] +#![feature(rustc_private)] + +extern crate serialize as rustc_serialize; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, + Default, Debug, RustcEncodable, RustcDecodable)] +struct S {} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, + Debug, RustcEncodable, RustcDecodable)] +enum E { + V {}, + U, +} + +fn main() { + let s = S {}; + let s1 = s; + let s2 = s.clone(); + assert_eq!(s, s1); + assert_eq!(s, s2); + assert!(!(s < s1)); + assert_eq!(format!("{:?}", s), "S"); + + let e = E::V {}; + let e1 = e; + let e2 = e.clone(); + assert_eq!(e, e1); + assert_eq!(e, e2); + assert!(!(e < e1)); + assert_eq!(format!("{:?}", e), "V"); +}