diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 9261c0162c7a5..f9ca842c02099 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use ast; use ast::{MetaItem, Expr}; use codemap::Span; use ext::base::{ExtCtxt, Annotatable}; @@ -38,11 +39,23 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, explicit_self: borrowed_explicit_self(), args: Vec::new(), ret_ty: Self_, - attributes: attrs, + attributes: attrs.clone(), is_unsafe: false, combine_substructure: combine_substructure(Box::new(|c, s, sub| { cs_clone("Clone", c, s, sub) })), + }, + MethodDef { + name: "clone_from", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_mut_explicit_self(), + args: vec![borrowed_self()], + ret_ty: nil_ty(), + attributes: attrs, + is_unsafe: false, + combine_substructure: combine_substructure(Box::new(|c, s, sub| { + cs_clone_from("Clone", c, s, sub) + })), } ), associated_types: Vec::new(), @@ -111,3 +124,30 @@ fn cs_clone( } } } + +fn cs_clone_from( + name: &str, + cx: &mut ExtCtxt, span: Span, + substr: &Substructure) -> P { + + let fn_path = cx.std_path(&["clone", "Clone", "clone_from"]); + cs_call_global( + |cx, span, exprs| { + cx.expr_block(cx.block(span, exprs.into_iter().map(|expr| { + cx.stmt_expr(expr) + }).collect(), None)) + }, + Box::new(|cx, span, (self_args, _), _non_self_args| { + if self_args.len() != 2 { + cx.span_bug(span, &format!("not exactly 2 arguments in `derive({})`", name)) + } else { + let clone_path = cx.std_path(&["clone", "Clone", "clone"]); + let args = vec![cx.expr_addr_of(span, self_args[1].clone())]; + + let rhs = cx.expr_call_global(span, clone_path, args); + let lhs = self_args[0].clone(); + cx.expr(span, ast::ExprAssign(lhs, rhs)) + } + }), + cx, span, substr, fn_path, ast::MutMutable) +} diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index f8f63e94ee574..a9c1ced860ee0 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -155,7 +155,7 @@ //! //! ```{.text} //! EnumNonMatchingCollapsed( -//! vec![, ], +//! vec![, ], //! &[, ], //! &[, ]) //! ``` @@ -203,7 +203,6 @@ use ext::build::AstBuilder; use codemap::{self, DUMMY_SP}; use codemap::Span; use diagnostic::SpanHandler; -use fold::MoveMap; use owned_slice::OwnedSlice; use parse::token::InternedString; use parse::token::special_idents; @@ -267,7 +266,7 @@ pub struct Substructure<'a> { /// ident of the method pub method_ident: Ident, /// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments - pub self_args: &'a [P], + pub self_args: &'a [(P, ast::Mutability)], /// verbatim access to any other arguments pub nonself_args: &'a [P], pub fields: &'a SubstructureFields<'a> @@ -311,7 +310,7 @@ pub enum SubstructureFields<'a> { /// variants for the enum itself, and the third component is a list of /// `Ident`s bound to the variant index values for each of the actual /// input `Self` arguments. - EnumNonMatchingCollapsed(Vec, &'a [P], &'a [Ident]), + EnumNonMatchingCollapsed(Vec>, &'a [P], &'a [Ident]), /// A static method where `Self` is a struct. StaticStruct(&'a ast::StructDef, StaticFields), @@ -332,7 +331,7 @@ pub type CombineSubstructureFunc<'a> = /// holding the variant index value for each of the `Self` arguments. The /// last argument is all the non-`Self` args of the method being derived. pub type EnumNonMatchCollapsedFunc<'a> = - Box]) -> P + 'a>; + Box], &[Ident]), &[P]) -> P + 'a>; pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) -> RefCell> { @@ -764,7 +763,7 @@ impl<'a> MethodDef<'a> { cx: &mut ExtCtxt, trait_: &TraitDef, type_ident: Ident, - self_args: &[P], + self_args: &[(P, ast::Mutability)], nonself_args: &[P], fields: &SubstructureFields) -> P { @@ -798,7 +797,8 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef, type_ident: Ident, generics: &Generics) - -> (ast::ExplicitSelf, Vec>, Vec>, Vec<(Ident, P)>) { + -> (ast::ExplicitSelf, Vec<(P, ast::Mutability)>, + Vec>, Vec<(Ident, P)>) { let mut self_args = Vec::new(); let mut nonself_args = Vec::new(); @@ -807,10 +807,10 @@ impl<'a> MethodDef<'a> { let ast_explicit_self = match self.explicit_self { Some(ref self_ptr) => { - let (self_expr, explicit_self) = + let (self_expr, mutability, explicit_self) = ty::get_explicit_self(cx, trait_.span, self_ptr); - self_args.push(self_expr); + self_args.push((self_expr, mutability)); nonstatic = true; explicit_self @@ -829,10 +829,13 @@ impl<'a> MethodDef<'a> { // for static methods, just treat any Self // arguments as a normal arg Self_ if nonstatic => { - self_args.push(arg_expr); + self_args.push((arg_expr, ast::MutImmutable)); } - Ptr(ref ty, _) if **ty == Self_ && nonstatic => { - self_args.push(cx.expr_deref(trait_.span, arg_expr)) + Ptr(ref ty, ref ty_ptr) if **ty == Self_ && nonstatic => { + let mutability = match ty_ptr { + &ty::Borrowed(_, m) | &ty::Raw(m) => m + }; + self_args.push((cx.expr_deref(trait_.span, arg_expr), mutability)) } _ => { nonself_args.push(arg_expr); @@ -921,7 +924,7 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'b>, struct_def: &'b StructDef, type_ident: Ident, - self_args: &[P], + self_args: &[(P, ast::Mutability)], nonself_args: &[P]) -> P { @@ -936,7 +939,7 @@ impl<'a> MethodDef<'a> { struct_def, &format!("__self_{}", i), - ast::MutImmutable); + self_args[i].1); patterns.push(pat); raw_fields.push(ident_expr); } @@ -978,7 +981,7 @@ impl<'a> MethodDef<'a> { // make a series of nested matches, to destructure the // structs. This is actually right-to-left, but it shouldn't // matter. - for (arg_expr, pat) in self_args.iter().zip(patterns) { + for (&(ref arg_expr, _), ref pat) in self_args.iter().zip(patterns) { body = cx.expr_match(trait_.span, arg_expr.clone(), vec!( cx.arm(trait_.span, vec!(pat.clone()), body) )) } @@ -990,7 +993,7 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef, struct_def: &StructDef, type_ident: Ident, - self_args: &[P], + self_args: &[(P, ast::Mutability)], nonself_args: &[P]) -> P { let summary = trait_.summarise_struct(cx, struct_def); @@ -1037,7 +1040,7 @@ impl<'a> MethodDef<'a> { enum_def: &'b EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, - self_args: Vec>, + self_args: Vec<(P, ast::Mutability)>, nonself_args: &[P]) -> P { self.build_enum_match_tuple( @@ -1087,31 +1090,27 @@ impl<'a> MethodDef<'a> { enum_def: &'b EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, - self_args: Vec>, + self_args: Vec<(P, ast::Mutability)>, nonself_args: &[P]) -> P { let sp = trait_.span; let variants = &enum_def.variants; let self_arg_names = self_args.iter().enumerate() - .map(|(arg_count, _self_arg)| { + .map(|(arg_count, &(_, mutability))| { if arg_count == 0 { - "__self".to_string() + ("__self".to_string(), mutability) } else { - format!("__arg_{}", arg_count) + (format!("__arg_{}", arg_count-1), mutability) } }) - .collect::>(); - - let self_arg_idents = self_arg_names.iter() - .map(|name|cx.ident_of(&name[..])) - .collect::>(); + .collect::>(); // The `vi_idents` will be bound, solely in the catch-all, to // a series of let statements mapping each self_arg to an int // value corresponding to its discriminant. let vi_idents: Vec = self_arg_names.iter() - .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); + .map(|&(ref name, _)| { let vi_suffix = format!("{}_vi", &name[..]); cx.ident_of(&vi_suffix[..]) }) .collect::>(); @@ -1119,7 +1118,10 @@ impl<'a> MethodDef<'a> { // delegated expression that handles the catch-all case, // using `__variants_tuple` to drive logic if necessary. let catch_all_substructure = EnumNonMatchingCollapsed( - self_arg_idents, &variants[..], &vi_idents[..]); + self_args.iter().map(|&(ref expr, _)| { + expr.clone() + }).collect(), &variants[..], &vi_idents[..] + ); // These arms are of the form: // (Variant1, Variant1, ...) => Body1 @@ -1128,12 +1130,12 @@ impl<'a> MethodDef<'a> { // where each tuple has length = self_args.len() let mut match_arms: Vec = variants.iter().enumerate() .map(|(index, variant)| { - let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &str| { + let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &(String, ast::Mutability)| { let (p, idents) = trait_.create_enum_variant_pattern(cx, type_ident, &**variant, - self_arg_name, - ast::MutImmutable); - (cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents) + &self_arg_name.0[..], + self_arg_name.1); + (cx.pat(sp, ast::PatRegion(p, self_arg_name.1)), idents) }; // A single arm has form (&VariantK, &VariantK, ...) => BodyK @@ -1146,7 +1148,7 @@ impl<'a> MethodDef<'a> { idents }; for self_arg_name in &self_arg_names[1..] { - let (p, idents) = mk_self_pat(cx, &self_arg_name[..]); + let (p, idents) = mk_self_pat(cx, self_arg_name); subpats.push(p); self_pats_idents.push(idents); } @@ -1251,7 +1253,7 @@ impl<'a> MethodDef<'a> { find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs); let mut first_ident = None; - for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { + for (&ident, &(ref self_arg, _)) in vi_idents.iter().zip(&self_args) { let path = cx.std_path(&["intrinsics", "discriminant_value"]); let call = cx.expr_call_global( sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]); @@ -1303,7 +1305,9 @@ impl<'a> MethodDef<'a> { // them when they are fed as r-values into a tuple // expression; here add a layer of borrowing, turning // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. - let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); + let borrowed_self_args = self_args.into_iter().map(|(self_arg, mutability)| { + cs_addr_of(cx, sp, self_arg, mutability) + }).collect(); let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); //Lastly we create an expression which branches on all discriminants being equal @@ -1381,7 +1385,9 @@ impl<'a> MethodDef<'a> { // them when they are fed as r-values into a tuple // expression; here add a layer of borrowing, turning // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. - let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); + let borrowed_self_args = self_args.into_iter().map(|(self_arg, mutability)| { + cs_addr_of(cx, sp, self_arg, mutability) + }).collect(); let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); cx.expr_match(sp, match_arg, match_arms) } @@ -1392,7 +1398,7 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef, enum_def: &EnumDef, type_ident: Ident, - self_args: &[P], + self_args: &[(P, ast::Mutability)], nonself_args: &[P]) -> P { let summary = enum_def.variants.iter().map(|v| { @@ -1659,6 +1665,51 @@ pub fn cs_same_method(f: F, } } +/// Call a global function on all the fields, and then +/// process the collected results. i.e. +/// +/// ``` +/// f(cx, span, vec![path::method(self_1, __arg_1_1, __arg_2_1), +/// path::method(self_2, __arg_1_2, __arg_2_2)]) +/// ``` +#[inline] +pub fn cs_call_global(f: F, + mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, + cx: &mut ExtCtxt, + trait_span: Span, + substructure: &Substructure, + path: Vec, + mutability: ast::Mutability) + -> P where + F: FnOnce(&mut ExtCtxt, Span, Vec>) -> P, +{ + match *substructure.fields { + EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { + // call path::method(self_n, other_1_n, other_2_n, ...) + let called = all_fields.iter().map(|field| { + // Start with self_n + let mut args = vec![cs_addr_of(cx, field.span, field.self_.clone(), mutability)]; + // Extend with other_n_m + args.extend(field.other.iter().map(|e| { + cx.expr_addr_of(field.span, e.clone()) + })); + + cx.expr_call_global(field.span, + path.clone(), + args) + }).collect(); + + f(cx, trait_span, called) + }, + EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => + enum_nonmatch_f(cx, trait_span, (&all_self_args[..], tuple), + substructure.nonself_args), + StaticEnum(..) | StaticStruct(..) => { + cx.span_bug(trait_span, "static function in `derive`") + } + } +} + /// Fold together the results of calling the derived method on all the /// fields. `use_foldl` controls whether this is done left-to-right /// (`true`) or right-to-left (`false`). @@ -1728,3 +1779,12 @@ pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc, enum_nonmatch_f, cx, span, substructure) } + +/// Mutably/immutabily take the address of an expression +#[inline] +pub fn cs_addr_of(cx: &mut ExtCtxt, span: Span, expr: P, mutbl: ast::Mutability) -> P { + match mutbl { + ast::MutImmutable => cx.expr_addr_of(span, expr), + ast::MutMutable => cx.expr_mut_addr_of(span, expr), + } +} diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index 9e8e68c0b8cce..7afd5132d4054 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -100,17 +100,29 @@ pub enum Ty<'a> { pub fn borrowed_ptrty<'r>() -> PtrTy<'r> { Borrowed(None, ast::MutImmutable) } +pub fn borrowed_mut_ptrty<'r>() -> PtrTy<'r> { + Borrowed(None, ast::MutMutable) +} pub fn borrowed<'r>(ty: Box>) -> Ty<'r> { Ptr(ty, borrowed_ptrty()) } +pub fn borrowed_mut<'r>(ty: Box>) -> Ty<'r> { + Ptr(ty, borrowed_mut_ptrty()) +} pub fn borrowed_explicit_self<'r>() -> Option>> { Some(Some(borrowed_ptrty())) } +pub fn borrowed_mut_explicit_self<'r>() -> Option>> { + Some(Some(borrowed_mut_ptrty())) +} pub fn borrowed_self<'r>() -> Ty<'r> { borrowed(Box::new(Self_)) } +pub fn borrowed_mut_self<'r>() -> Ty<'r> { + borrowed_mut(Box::new(Self_)) +} pub fn nil_ty<'r>() -> Ty<'r> { Tuple(Vec::new()) @@ -258,26 +270,28 @@ impl<'a> LifetimeBounds<'a> { } pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option) - -> (P, ast::ExplicitSelf) { + -> (P, ast::Mutability, ast::ExplicitSelf) { // this constructs a fresh `self` path, which will match the fresh `self` binding // created below. let self_path = cx.expr_self(span); match *self_ptr { None => { - (self_path, respan(span, ast::SelfValue(special_idents::self_))) + (self_path, ast::MutImmutable, respan(span, ast::SelfValue(special_idents::self_))) } Some(ref ptr) => { + let mutability; let self_ty = respan( span, match *ptr { Borrowed(ref lt, mutbl) => { + mutability = mutbl; let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name)); ast::SelfRegion(lt, mutbl, special_idents::self_) } Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition") }); let self_expr = cx.expr_deref(span, self_path); - (self_expr, self_ty) + (self_expr, mutability, self_ty) } } } diff --git a/src/test/compile-fail/deriving-no-inner-impl-error-message.rs b/src/test/compile-fail/deriving-no-inner-impl-error-message.rs index ac63cc27da1ee..c5cc2881a49c2 100644 --- a/src/test/compile-fail/deriving-no-inner-impl-error-message.rs +++ b/src/test/compile-fail/deriving-no-inner-impl-error-message.rs @@ -17,8 +17,8 @@ struct E { } #[derive(Clone)] struct C { - x: NoCloneOrEq - //~^ ERROR the trait `core::clone::Clone` is not implemented for the type `NoCloneOrEq` + x: NoCloneOrEq //~ ERROR the trait `core::clone::Clone` is not implemented for the type + //~^ ERROR the trait `core::clone::Clone` is not implemented for the type `NoCloneOrEq` } diff --git a/src/test/compile-fail/deriving-span-Clone-enum-struct-variant.rs b/src/test/compile-fail/deriving-span-Clone-enum-struct-variant.rs index 9badb5b262dfe..cfc15c1cd3ab7 100644 --- a/src/test/compile-fail/deriving-span-Clone-enum-struct-variant.rs +++ b/src/test/compile-fail/deriving-span-Clone-enum-struct-variant.rs @@ -18,7 +18,8 @@ struct Error; #[derive(Clone)] enum Enum { A { - x: Error //~ ERROR + x: Error //~ ERROR the trait `core::clone::Clone` is not implemented for the type `Error` + //~^ ERROR the trait `core::clone::Clone` is not implemented for the type `Error` } } diff --git a/src/test/compile-fail/deriving-span-Clone-enum.rs b/src/test/compile-fail/deriving-span-Clone-enum.rs index 6b71610778c19..a9d9db70eafb4 100644 --- a/src/test/compile-fail/deriving-span-Clone-enum.rs +++ b/src/test/compile-fail/deriving-span-Clone-enum.rs @@ -18,7 +18,8 @@ struct Error; #[derive(Clone)] enum Enum { A( - Error //~ ERROR + Error //~ ERROR the trait `core::clone::Clone` is not implemented for the type `Error` + //~^ ERROR the trait `core::clone::Clone` is not implemented for the type `Error` ) } diff --git a/src/test/compile-fail/deriving-span-Clone-struct.rs b/src/test/compile-fail/deriving-span-Clone-struct.rs index 845da771de826..171f1934ed552 100644 --- a/src/test/compile-fail/deriving-span-Clone-struct.rs +++ b/src/test/compile-fail/deriving-span-Clone-struct.rs @@ -17,7 +17,8 @@ struct Error; #[derive(Clone)] struct Struct { - x: Error //~ ERROR + x: Error //~ ERROR the trait `core::clone::Clone` is not implemented for the type `Error` + //~^ ERROR the trait `core::clone::Clone` is not implemented for the type `Error` } fn main() {} diff --git a/src/test/compile-fail/deriving-span-Clone-tuple-struct.rs b/src/test/compile-fail/deriving-span-Clone-tuple-struct.rs index 698e5a79bef29..326d79c12e3d0 100644 --- a/src/test/compile-fail/deriving-span-Clone-tuple-struct.rs +++ b/src/test/compile-fail/deriving-span-Clone-tuple-struct.rs @@ -17,7 +17,8 @@ struct Error; #[derive(Clone)] struct Struct( - Error //~ ERROR + Error //~ ERROR the trait `core::clone::Clone` is not implemented for the type `Error` + //~^ ERROR the trait `core::clone::Clone` is not implemented for the type `Error` ); fn main() {} diff --git a/src/test/run-pass/deriving-clone-enum.rs b/src/test/run-pass/deriving-clone-enum.rs index 22daffc48699a..e3efc04fe8473 100644 --- a/src/test/run-pass/deriving-clone-enum.rs +++ b/src/test/run-pass/deriving-clone-enum.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +// no-pretty-expanded FIXME #15189 #[derive(Clone)] enum E { @@ -18,5 +18,10 @@ enum E { } pub fn main() { - let _ = E::A.clone(); + let mut foo = E::A.clone(); + + // Test both code-paths of clone_from (same variant/different variant) + foo.clone_from(&E::A); + foo.clone_from(&E::B(())); + foo.clone_from(&E::B(())); } diff --git a/src/test/run-pass/deriving-clone-generic-enum.rs b/src/test/run-pass/deriving-clone-generic-enum.rs index 8a07bad696188..f8e0f6444fbba 100644 --- a/src/test/run-pass/deriving-clone-generic-enum.rs +++ b/src/test/run-pass/deriving-clone-generic-enum.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +// no-pretty-expanded FIXME #15189 #[derive(Clone)] enum E { @@ -18,5 +18,10 @@ enum E { } pub fn main() { - let _ = E::A::(1).clone(); + let mut foo = E::A::(1).clone(); + + // Test both code-paths of clone_from (same variant/different variant) + foo.clone_from(&E::A(32)); + foo.clone_from(&E::B(1, 2)); + foo.clone_from(&E::B(3, 4)); } diff --git a/src/test/run-pass/deriving-clone-generic-struct.rs b/src/test/run-pass/deriving-clone-generic-struct.rs index d80f14c36945b..37e44fb1e147b 100644 --- a/src/test/run-pass/deriving-clone-generic-struct.rs +++ b/src/test/run-pass/deriving-clone-generic-struct.rs @@ -18,5 +18,6 @@ struct S { } pub fn main() { - let _ = S { foo: (), bar: (), baz: 1 }.clone(); + let mut foo = S { foo: (), bar: (), baz: 1 }.clone(); + foo.clone_from(&S { foo: (), bar: (), baz: 31 }); } diff --git a/src/test/run-pass/deriving-clone-generic-tuple-struct.rs b/src/test/run-pass/deriving-clone-generic-tuple-struct.rs index f2f2ec3de7600..4068e58367b17 100644 --- a/src/test/run-pass/deriving-clone-generic-tuple-struct.rs +++ b/src/test/run-pass/deriving-clone-generic-tuple-struct.rs @@ -14,5 +14,6 @@ struct S(T, ()); pub fn main() { - let _ = S(1, ()).clone(); + let mut foo = S(1, ()).clone(); + foo.clone_from(&S(32, ())); } diff --git a/src/test/run-pass/issue-13281.rs b/src/test/run-pass/issue-13281.rs new file mode 100644 index 0000000000000..e08937d126f80 --- /dev/null +++ b/src/test/run-pass/issue-13281.rs @@ -0,0 +1,52 @@ +// Copyright 2013 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. + +struct ForceCloneFrom; +struct ForceClone; + +impl Clone for ForceCloneFrom { + fn clone(&self) -> Self { + // Ensure `clone_from` is called + assert!(false); + ForceCloneFrom + } + fn clone_from(&mut self, _: &Self) { + } +} + +impl Clone for ForceClone { + fn clone(&self) -> Self { + ForceClone + } + fn clone_from(&mut self, _: &Self) { + // Ensure `clone` is called + assert!(false); + } +} + +#[derive(Clone)] +enum E { + A(ForceCloneFrom), + B(ForceClone), +} + +pub fn main() { + let mut a = E::A(ForceCloneFrom); + let b = E::A(ForceCloneFrom); + let c = E::B(ForceClone); + + // This should use `clone_from` internally because they are + // the same variant + a.clone_from(&b); + + // This should use `clone` internally because they are different + // variants + a.clone_from(&c); +} diff --git a/src/test/run-pass/issue-3121.rs b/src/test/run-pass/issue-3121.rs index 777e5bf7a6ded..682c1518b2a61 100644 --- a/src/test/run-pass/issue-3121.rs +++ b/src/test/run-pass/issue-3121.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +// no-pretty-expanded FIXME #15189 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index 8160fe56fd0b2..fd0e4b43b9c50 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +// no-pretty-expanded FIXME #15189 #![allow(warnings)] #![feature(collections)]