Skip to content

Commit 3263316

Browse files
committed
Auto merge of #31822 - petrochenkov:derive, r=alexcrichton
Fixes #29548
2 parents be7196a + a3f3c4a commit 3263316

File tree

7 files changed

+92
-40
lines changed

7 files changed

+92
-40
lines changed

src/libsyntax_ext/deriving/clone.rs

+26-24
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use deriving::generic::*;
1212
use deriving::generic::ty::*;
1313

14-
use syntax::ast::{MetaItem, Expr};
14+
use syntax::ast::{MetaItem, Expr, VariantData};
1515
use syntax::codemap::Span;
1616
use syntax::ext::base::{ExtCtxt, Annotatable};
1717
use syntax::ext::build::AstBuilder;
@@ -66,14 +66,17 @@ fn cs_clone(
6666
cx.expr_call_global(field.span, fn_path.clone(), args)
6767
};
6868

69+
let vdata;
6970
match *substr.fields {
70-
Struct(ref af) => {
71+
Struct(vdata_, ref af) => {
7172
ctor_path = cx.path(trait_span, vec![substr.type_ident]);
7273
all_fields = af;
74+
vdata = vdata_;
7375
}
7476
EnumMatching(_, variant, ref af) => {
7577
ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.name]);
7678
all_fields = af;
79+
vdata = &variant.node.data;
7780
},
7881
EnumNonMatchingCollapsed (..) => {
7982
cx.span_bug(trait_span,
@@ -86,30 +89,29 @@ fn cs_clone(
8689
}
8790
}
8891

89-
if !all_fields.is_empty() && all_fields[0].name.is_none() {
90-
// enum-like
91-
let subcalls = all_fields.iter().map(subcall).collect();
92-
let path = cx.expr_path(ctor_path);
93-
cx.expr_call(trait_span, path, subcalls)
94-
} else {
95-
// struct-like
96-
let fields = all_fields.iter().map(|field| {
97-
let ident = match field.name {
98-
Some(i) => i,
99-
None => {
100-
cx.span_bug(trait_span,
101-
&format!("unnamed field in normal struct in \
102-
`derive({})`", name))
103-
}
104-
};
105-
cx.field_imm(field.span, ident, subcall(field))
106-
}).collect::<Vec<_>>();
92+
match *vdata {
93+
VariantData::Struct(..) => {
94+
let fields = all_fields.iter().map(|field| {
95+
let ident = match field.name {
96+
Some(i) => i,
97+
None => {
98+
cx.span_bug(trait_span,
99+
&format!("unnamed field in normal struct in \
100+
`derive({})`", name))
101+
}
102+
};
103+
cx.field_imm(field.span, ident, subcall(field))
104+
}).collect::<Vec<_>>();
107105

108-
if fields.is_empty() {
109-
// no fields, so construct like `None`
110-
cx.expr_path(ctor_path)
111-
} else {
112106
cx.expr_struct(trait_span, ctor_path, fields)
113107
}
108+
VariantData::Tuple(..) => {
109+
let subcalls = all_fields.iter().map(subcall).collect();
110+
let path = cx.expr_path(ctor_path);
111+
cx.expr_call(trait_span, path, subcalls)
112+
}
113+
VariantData::Unit(..) => {
114+
cx.expr_path(ctor_path)
115+
}
114116
}
115117
}

src/libsyntax_ext/deriving/debug.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
6161
// build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
6262
// or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
6363
// based on the "shape".
64-
let ident = match *substr.fields {
65-
Struct(_) => substr.type_ident,
66-
EnumMatching(_, v, _) => v.node.name,
64+
let (ident, is_struct) = match *substr.fields {
65+
Struct(vdata, _) => (substr.type_ident, vdata.is_struct()),
66+
EnumMatching(_, v, _) => (v.node.name, v.node.data.is_struct()),
6767
EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
6868
cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
6969
}
@@ -78,9 +78,9 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
7878
let fmt = substr.nonself_args[0].clone();
7979

8080
let stmts = match *substr.fields {
81-
Struct(ref fields) | EnumMatching(_, _, ref fields) => {
81+
Struct(_, ref fields) | EnumMatching(_, _, ref fields) => {
8282
let mut stmts = vec![];
83-
if fields.is_empty() || fields[0].name.is_none() {
83+
if !is_struct {
8484
// tuple struct/"normal" variant
8585
let expr = cx.expr_method_call(span,
8686
fmt,

src/libsyntax_ext/deriving/encodable.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
179179
let encode = cx.ident_of("encode");
180180

181181
return match *substr.fields {
182-
Struct(ref fields) => {
182+
Struct(_, ref fields) => {
183183
let emit_struct_field = cx.ident_of("emit_struct_field");
184184
let mut stmts = Vec::new();
185185
for (i, &FieldInfo {

src/libsyntax_ext/deriving/generic/mod.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ pub enum StaticFields {
300300

301301
/// A summary of the possible sets of fields.
302302
pub enum SubstructureFields<'a> {
303-
Struct(Vec<FieldInfo<'a>>),
303+
Struct(&'a ast::VariantData, Vec<FieldInfo<'a>>),
304304
/// Matching variants of the enum: variant index, ast::Variant,
305305
/// fields: the field name is only non-`None` in the case of a struct
306306
/// variant.
@@ -981,7 +981,7 @@ impl<'a> MethodDef<'a> {
981981
type_ident,
982982
self_args,
983983
nonself_args,
984-
&Struct(fields));
984+
&Struct(struct_def, fields));
985985

986986
// make a series of nested matches, to destructure the
987987
// structs. This is actually right-to-left, but it shouldn't
@@ -1460,8 +1460,9 @@ impl<'a> TraitDef<'a> {
14601460
fields in generic `derive`"),
14611461
// named fields
14621462
(_, false) => Named(named_idents),
1463-
// tuple structs (includes empty structs)
1464-
(_, _) => Unnamed(just_spans)
1463+
// empty structs
1464+
_ if struct_def.is_struct() => Named(named_idents),
1465+
_ => Unnamed(just_spans),
14651466
}
14661467
}
14671468

@@ -1486,7 +1487,11 @@ impl<'a> TraitDef<'a> {
14861487
P<Expr>,
14871488
&'a [ast::Attribute])>) {
14881489
if struct_def.fields().is_empty() {
1489-
return (cx.pat_enum(self.span, struct_path, vec![]), vec![]);
1490+
if struct_def.is_struct() {
1491+
return (cx.pat_struct(self.span, struct_path, vec![]), vec![]);
1492+
} else {
1493+
return (cx.pat_enum(self.span, struct_path, vec![]), vec![]);
1494+
}
14901495
}
14911496

14921497
let mut paths = Vec::new();
@@ -1521,7 +1526,7 @@ impl<'a> TraitDef<'a> {
15211526

15221527
// struct_type is definitely not Unknown, since struct_def.fields
15231528
// must be nonempty to reach here
1524-
let pattern = if struct_type == Record {
1529+
let pattern = if struct_def.is_struct() {
15251530
let field_pats = subpats.into_iter().zip(&ident_expr)
15261531
.map(|(pat, &(_, id, _, _))| {
15271532
// id is guaranteed to be Some
@@ -1566,7 +1571,7 @@ pub fn cs_fold<F>(use_foldl: bool,
15661571
F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
15671572
{
15681573
match *substructure.fields {
1569-
EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1574+
EnumMatching(_, _, ref all_fields) | Struct(_, ref all_fields) => {
15701575
if use_foldl {
15711576
all_fields.iter().fold(base, |old, field| {
15721577
f(cx,
@@ -1612,7 +1617,7 @@ pub fn cs_same_method<F>(f: F,
16121617
F: FnOnce(&mut ExtCtxt, Span, Vec<P<Expr>>) -> P<Expr>,
16131618
{
16141619
match *substructure.fields {
1615-
EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1620+
EnumMatching(_, _, ref all_fields) | Struct(_, ref all_fields) => {
16161621
// call self_n.method(other_1_n, other_2_n, ...)
16171622
let called = all_fields.iter().map(|field| {
16181623
cx.expr_method_call(field.span,

src/libsyntax_ext/deriving/hash.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
7676
let mut stmts = Vec::new();
7777

7878
let fields = match *substr.fields {
79-
Struct(ref fs) => fs,
79+
Struct(_, ref fs) => fs,
8080
EnumMatching(index, variant, ref fs) => {
8181
// Determine the discriminant. We will feed this value to the byte
8282
// iteration function.

src/test/auxiliary/custom_derive_plugin_attr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ fn expand(cx: &mut ExtCtxt,
7373
fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span,
7474
substr: &Substructure) -> P<ast::Expr> {
7575
let fields = match *substr.fields {
76-
Struct(ref fs) | EnumMatching(_, _, ref fs) => fs,
76+
Struct(_, ref fs) | EnumMatching(_, _, ref fs) => fs,
7777
_ => cx.span_bug(trait_span, "impossible substructure")
7878
};
7979

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// `#[derive(Trait)]` works for empty structs/variants with braces
12+
13+
#![feature(braced_empty_structs)]
14+
#![feature(rustc_private)]
15+
16+
extern crate serialize as rustc_serialize;
17+
18+
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
19+
Default, Debug, RustcEncodable, RustcDecodable)]
20+
struct S {}
21+
22+
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
23+
Debug, RustcEncodable, RustcDecodable)]
24+
enum E {
25+
V {},
26+
U,
27+
}
28+
29+
fn main() {
30+
let s = S {};
31+
let s1 = s;
32+
let s2 = s.clone();
33+
assert_eq!(s, s1);
34+
assert_eq!(s, s2);
35+
assert!(!(s < s1));
36+
assert_eq!(format!("{:?}", s), "S");
37+
38+
let e = E::V {};
39+
let e1 = e;
40+
let e2 = e.clone();
41+
assert_eq!(e, e1);
42+
assert_eq!(e, e2);
43+
assert!(!(e < e1));
44+
assert_eq!(format!("{:?}", e), "V");
45+
}

0 commit comments

Comments
 (0)