Skip to content

Commit 6712c02

Browse files
committed
assert_clone in shallow #[derive(Copy,Clone)]
1 parent 0cf4bc5 commit 6712c02

File tree

16 files changed

+114
-69
lines changed

16 files changed

+114
-69
lines changed

src/libcore/clone.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ pub trait Clone : Sized {
7575
}
7676
}
7777

78+
// FIXME(aburka): this method is used solely by #[deriving] to
79+
// assert that every component of a type implements Clone.
80+
//
81+
// This should never be called by user code.
82+
#[doc(hidden)]
83+
#[inline(always)]
84+
#[stable(feature = "rust1", since = "1.0.0")]
85+
pub fn assert_receiver_is_clone<T: Clone + ?Sized>(_: &T) {}
86+
7887
#[stable(feature = "rust1", since = "1.0.0")]
7988
impl<'a, T: ?Sized> Clone for &'a T {
8089
/// Returns a shallow copy of the reference.

src/libsyntax_ext/deriving/clone.rs

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ use syntax::ext::build::AstBuilder;
1919
use syntax::parse::token::InternedString;
2020
use syntax::ptr::P;
2121

22+
enum Mode { Assert, Clone }
23+
2224
pub fn expand_deriving_clone(cx: &mut ExtCtxt,
2325
span: Span,
2426
mitem: &MetaItem,
@@ -39,25 +41,30 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
3941
let substructure;
4042
let nested_match;
4143
match *item {
42-
Annotatable::Item(ref item) => {
43-
match item.node {
44+
Annotatable::Item(ref annitem) => {
45+
match annitem.node {
4446
ItemKind::Struct(_, Generics { ref ty_params, .. }) |
4547
ItemKind::Enum(_, Generics { ref ty_params, .. })
46-
if ty_params.is_empty() && attr::contains_name(&item.attrs, "derive_Copy") => {
48+
if ty_params.is_empty()
49+
&& attr::contains_name(&annitem.attrs, "derive_Copy") => {
4750

4851
bounds = vec![Literal(path_std!(cx, core::marker::Copy))];
49-
substructure = combine_substructure(Box::new(|c, s, _| {
50-
cs_shallow_clone(c, s)
52+
substructure = combine_substructure(Box::new(|c, s, sub| {
53+
cs_deep_clone("Clone", c, s, sub, Mode::Assert)
5154
}));
52-
nested_match = false;
55+
nested_match = enclose(|c, s, sub| {
56+
let inner = cs_shallow_clone(c, s);
57+
c.expr_block(c.block_all(s, vec![c.stmt_expr(sub)], Some(inner)))
58+
//^ FIXME(aburka): this generates an extra set of {} braces
59+
});
5360
}
5461

5562
_ => {
5663
bounds = vec![];
5764
substructure = combine_substructure(Box::new(|c, s, sub| {
58-
cs_deep_clone("Clone", c, s, sub)
65+
cs_deep_clone("Clone", c, s, sub, Mode::Clone)
5966
}));
60-
nested_match = true;
67+
nested_match = None;
6168
}
6269
}
6370
}
@@ -101,10 +108,14 @@ fn cs_shallow_clone(cx: &mut ExtCtxt, trait_span: Span) -> P<Expr> {
101108
fn cs_deep_clone(
102109
name: &str,
103110
cx: &mut ExtCtxt, trait_span: Span,
104-
substr: &Substructure) -> P<Expr> {
111+
substr: &Substructure,
112+
mode: Mode) -> P<Expr> {
105113
let ctor_path;
106114
let all_fields;
107-
let fn_path = cx.std_path(&["clone", "Clone", "clone"]);
115+
let fn_path = match mode {
116+
Mode::Assert => cx.std_path(&["clone", "assert_receiver_is_clone"]),
117+
Mode::Clone => cx.std_path(&["clone", "Clone", "clone"]),
118+
};
108119
let subcall = |field: &FieldInfo| {
109120
let args = vec![cx.expr_addr_of(field.span, field.self_.clone())];
110121

@@ -134,29 +145,41 @@ fn cs_deep_clone(
134145
}
135146
}
136147

137-
match *vdata {
138-
VariantData::Struct(..) => {
139-
let fields = all_fields.iter().map(|field| {
140-
let ident = match field.name {
141-
Some(i) => i,
142-
None => {
143-
cx.span_bug(trait_span,
144-
&format!("unnamed field in normal struct in \
145-
`derive({})`", name))
146-
}
147-
};
148-
cx.field_imm(field.span, ident, subcall(field))
149-
}).collect::<Vec<_>>();
150-
151-
cx.expr_struct(trait_span, ctor_path, fields)
148+
match mode {
149+
Mode::Assert => {
150+
cx.expr_block(cx.block(trait_span,
151+
all_fields.iter()
152+
.map(subcall)
153+
.map(|e| cx.stmt_expr(e))
154+
.collect(),
155+
None))
152156
}
153-
VariantData::Tuple(..) => {
154-
let subcalls = all_fields.iter().map(subcall).collect();
155-
let path = cx.expr_path(ctor_path);
156-
cx.expr_call(trait_span, path, subcalls)
157-
}
158-
VariantData::Unit(..) => {
159-
cx.expr_path(ctor_path)
157+
Mode::Clone => {
158+
match *vdata {
159+
VariantData::Struct(..) => {
160+
let fields = all_fields.iter().map(|field| {
161+
let ident = match field.name {
162+
Some(i) => i,
163+
None => {
164+
cx.span_bug(trait_span,
165+
&format!("unnamed field in normal struct in \
166+
`derive({})`", name))
167+
}
168+
};
169+
cx.field_imm(field.span, ident, subcall(field))
170+
}).collect::<Vec<_>>();
171+
172+
cx.expr_struct(trait_span, ctor_path, fields)
173+
}
174+
VariantData::Tuple(..) => {
175+
let subcalls = all_fields.iter().map(subcall).collect();
176+
let path = cx.expr_path(ctor_path);
177+
cx.expr_call(trait_span, path, subcalls)
178+
}
179+
VariantData::Unit(..) => {
180+
cx.expr_path(ctor_path)
181+
}
182+
}
160183
}
161184
}
162185
}

src/libsyntax_ext/deriving/cmp/eq.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
5858
name: "assert_receiver_is_total_eq",
5959
generics: LifetimeBounds::empty(),
6060
explicit_self: borrowed_explicit_self(),
61-
nested_match: true,
61+
nested_match: None,
6262
args: vec!(),
6363
ret_ty: nil_ty(),
6464
attributes: attrs,

src/libsyntax_ext/deriving/cmp/ord.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
3838
name: "cmp",
3939
generics: LifetimeBounds::empty(),
4040
explicit_self: borrowed_explicit_self(),
41-
nested_match: true,
41+
nested_match: None,
4242
args: vec!(borrowed_self()),
4343
ret_ty: Literal(path_std!(cx, core::cmp::Ordering)),
4444
attributes: attrs,

src/libsyntax_ext/deriving/cmp/partial_eq.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
6969
name: $name,
7070
generics: LifetimeBounds::empty(),
7171
explicit_self: borrowed_explicit_self(),
72-
nested_match: true,
72+
nested_match: None,
7373
args: vec!(borrowed_self()),
7474
ret_ty: Literal(path_local!(bool)),
7575
attributes: attrs,

src/libsyntax_ext/deriving/cmp/partial_ord.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
3434
name: $name,
3535
generics: LifetimeBounds::empty(),
3636
explicit_self: borrowed_explicit_self(),
37-
nested_match: true,
37+
nested_match: None,
3838
args: vec!(borrowed_self()),
3939
ret_ty: Literal(path_local!(bool)),
4040
attributes: attrs,
@@ -59,7 +59,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
5959
name: "partial_cmp",
6060
generics: LifetimeBounds::empty(),
6161
explicit_self: borrowed_explicit_self(),
62-
nested_match: true,
62+
nested_match: None,
6363
args: vec![borrowed_self()],
6464
ret_ty: ret_ty,
6565
attributes: attrs,

src/libsyntax_ext/deriving/debug.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt,
4141
name: "fmt",
4242
generics: LifetimeBounds::empty(),
4343
explicit_self: borrowed_explicit_self(),
44-
nested_match: true,
44+
nested_match: None,
4545
args: vec!(fmtr),
4646
ret_ty: Literal(path_std!(cx, core::fmt::Result)),
4747
attributes: Vec::new(),

src/libsyntax_ext/deriving/decodable.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
7373
vec![Path::new_(vec!(krate, "Decoder"), None, vec!(), true)])]
7474
},
7575
explicit_self: None,
76-
nested_match: true,
76+
nested_match: None,
7777
args: vec!(Ptr(Box::new(Literal(Path::new_local(typaram))),
7878
Borrowed(None, Mutability::Mutable))),
7979
ret_ty: Literal(Path::new_(

src/libsyntax_ext/deriving/default.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
3838
name: "default",
3939
generics: LifetimeBounds::empty(),
4040
explicit_self: None,
41-
nested_match: true,
41+
nested_match: None,
4242
args: Vec::new(),
4343
ret_ty: Self_,
4444
attributes: attrs,

src/libsyntax_ext/deriving/encodable.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt,
149149
vec![Path::new_(vec![krate, "Encoder"], None, vec!(), true)])]
150150
},
151151
explicit_self: borrowed_explicit_self(),
152-
nested_match: true,
152+
nested_match: None,
153153
args: vec!(Ptr(Box::new(Literal(Path::new_local(typaram))),
154154
Borrowed(None, Mutability::Mutable))),
155155
ret_ty: Literal(Path::new_(

0 commit comments

Comments
 (0)