about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-02-22 21:24:32 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-02-22 21:24:32 +0300
commit4e8e607d8469a8882944233e4bb3ee45d2a6435a (patch)
tree1383d1f4a4e8982ea73c7165a169ba0fa53912a2 /src
parent98a59cf57e02b6e6a5a3bd74eb47b1422eaacc53 (diff)
downloadrust-4e8e607d8469a8882944233e4bb3ee45d2a6435a.tar.gz
rust-4e8e607d8469a8882944233e4bb3ee45d2a6435a.zip
Fix #[derive] for empty structs with braces
Diffstat (limited to 'src')
-rw-r--r--src/libsyntax_ext/deriving/clone.rs50
-rw-r--r--src/libsyntax_ext/deriving/debug.rs11
-rw-r--r--src/libsyntax_ext/deriving/encodable.rs2
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs21
-rw-r--r--src/libsyntax_ext/deriving/hash.rs2
-rw-r--r--src/test/auxiliary/custom_derive_plugin_attr.rs2
-rw-r--r--src/test/run-pass/empty-struct-braces-derive.rs45
7 files changed, 95 insertions, 38 deletions
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::<Vec<_>>();
+    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::<Vec<_>>();
 
-        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(<name>).field(&<fieldval>)....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<FieldInfo<'a>>),
+    Struct(&'a ast::VariantData, Vec<FieldInfo<'a>>),
     /// 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<Expr>,
                                                    &'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<F>(use_foldl: bool,
     F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
 {
     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,
     F: FnOnce(&mut ExtCtxt, Span, Vec<P<Expr>>) -> P<Expr>,
 {
     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<ast::Expr> {
     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 <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(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");
+}