Rollup merge of #36384 - petrochenkov:derclone, r=alexcrichton
Improve shallow `Clone` deriving `Copy` unions now support `#[derive(Clone)]`. Less code is generated for `#[derive(Clone, Copy)]`. + Unions now support `#[derive(Eq)]`. Less code is generated for `#[derive(Eq)]`. --- Example of code reduction: ``` enum E { A { a: u8, b: u16 }, B { c: [u8; 100] }, } ``` Before: ``` fn clone(&self) -> E { match (&*self,) { (&E::A { a: ref __self_0, b: ref __self_1 },) => { ::std::clone::assert_receiver_is_clone(&(*__self_0)); ::std::clone::assert_receiver_is_clone(&(*__self_1)); *self } (&E::B { c: ref __self_0 },) => { ::std::clone::assert_receiver_is_clone(&(*__self_0)); *self } } } ``` After: ``` fn clone(&self) -> E { { let _: ::std::clone::AssertParamIsClone<u8>; let _: ::std::clone::AssertParamIsClone<u16>; let _: ::std::clone::AssertParamIsClone<[u8; 100]>; *self } } ``` All the matches are removed, bound assertions are more lightweight. `let _: Checker<CheckMe>;`, unlike `checker(&check_me);`, doesn't have to be translated by rustc_trans and then inlined by LLVM, it doesn't even exist in MIR, this means faster compilation. --- Union impls are generated like this: ``` union U { a: u8, b: u16, c: [u8; 100], } ``` ``` fn clone(&self) -> U { { let _: ::std::clone::AssertParamIsCopy<Self>; *self } } ``` Fixes https://github.com/rust-lang/rust/issues/36043 cc @durka r? @alexcrichton
This commit is contained in:
commit
726850170d
@ -113,10 +113,23 @@ pub trait Clone : Sized {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(aburka): this method is used solely by #[derive] to
|
||||
// assert that every component of a type implements Clone.
|
||||
// FIXME(aburka): these structs are used solely by #[derive] to
|
||||
// assert that every component of a type implements Clone or Copy.
|
||||
//
|
||||
// This should never be called by user code.
|
||||
// These structs should never appear in user code.
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsClone<T: Clone + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
#[cfg(stage0)]
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
|
@ -129,7 +129,7 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
|
||||
/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has
|
||||
/// no extra methods, it is only informing the compiler that this is an
|
||||
/// equivalence relation rather than a partial equivalence relation. Note that
|
||||
/// the `derive` strategy requires all fields are `PartialEq`, which isn't
|
||||
/// the `derive` strategy requires all fields are `Eq`, which isn't
|
||||
/// always desired.
|
||||
///
|
||||
/// ## How can I implement `Eq`?
|
||||
@ -165,6 +165,17 @@ pub trait Eq: PartialEq<Self> {
|
||||
fn assert_receiver_is_total_eq(&self) {}
|
||||
}
|
||||
|
||||
// FIXME: this struct is used solely by #[derive] to
|
||||
// assert that every component of a type implements Eq.
|
||||
//
|
||||
// This struct should never appear in user code.
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "derive_eq",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsEq<T: Eq + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
|
||||
/// An `Ordering` is the result of a comparison between two values.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -97,6 +97,7 @@ pub trait AstBuilder {
|
||||
typ: P<ast::Ty>,
|
||||
ex: P<ast::Expr>)
|
||||
-> P<ast::Stmt>;
|
||||
fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt;
|
||||
fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt;
|
||||
|
||||
// blocks
|
||||
@ -577,6 +578,23 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
// Generate `let _: Type;`, usually used for type assertions.
|
||||
fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
|
||||
let local = P(ast::Local {
|
||||
pat: self.pat_wild(span),
|
||||
ty: Some(ty),
|
||||
init: None,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: span,
|
||||
attrs: ast::ThinVec::new(),
|
||||
});
|
||||
ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::StmtKind::Local(local),
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
|
||||
fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt {
|
||||
ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
|
@ -11,20 +11,14 @@
|
||||
use deriving::generic::*;
|
||||
use deriving::generic::ty::*;
|
||||
|
||||
use syntax::ast::{Expr, Generics, ItemKind, MetaItem, VariantData};
|
||||
use syntax::ast::{self, Expr, Generics, ItemKind, MetaItem, VariantData};
|
||||
use syntax::attr;
|
||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::parse::token::{keywords, InternedString};
|
||||
use syntax::ptr::P;
|
||||
use syntax_pos::Span;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Mode {
|
||||
Deep,
|
||||
Shallow,
|
||||
}
|
||||
|
||||
pub fn expand_deriving_clone(cx: &mut ExtCtxt,
|
||||
span: Span,
|
||||
mitem: &MetaItem,
|
||||
@ -40,29 +34,38 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
|
||||
// if we used the short form with generics, we'd have to bound the generics with
|
||||
// Clone + Copy, and then there'd be no Clone impl at all if the user fills in something
|
||||
// that is Clone but not Copy. and until specialization we can't write both impls.
|
||||
// - the item is a union with Copy fields
|
||||
// Unions with generic parameters still can derive Clone because they require Copy
|
||||
// for deriving, Clone alone is not enough.
|
||||
// Whever Clone is implemented for fields is irrelevant so we don't assert it.
|
||||
let bounds;
|
||||
let unify_fieldless_variants;
|
||||
let substructure;
|
||||
let is_shallow;
|
||||
match *item {
|
||||
Annotatable::Item(ref annitem) => {
|
||||
match annitem.node {
|
||||
ItemKind::Struct(_, Generics { ref ty_params, .. }) |
|
||||
ItemKind::Enum(_, Generics { ref ty_params, .. })
|
||||
if ty_params.is_empty() &&
|
||||
attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") => {
|
||||
|
||||
bounds = vec![Literal(path_std!(cx, core::marker::Copy))];
|
||||
unify_fieldless_variants = true;
|
||||
if attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") &&
|
||||
ty_params.is_empty() => {
|
||||
bounds = vec![];
|
||||
is_shallow = true;
|
||||
substructure = combine_substructure(Box::new(|c, s, sub| {
|
||||
cs_clone("Clone", c, s, sub, Mode::Shallow)
|
||||
cs_clone_shallow("Clone", c, s, sub, false)
|
||||
}));
|
||||
}
|
||||
ItemKind::Union(..) => {
|
||||
bounds = vec![Literal(path_std!(cx, core::marker::Copy))];
|
||||
is_shallow = true;
|
||||
substructure = combine_substructure(Box::new(|c, s, sub| {
|
||||
cs_clone_shallow("Clone", c, s, sub, true)
|
||||
}));
|
||||
}
|
||||
|
||||
_ => {
|
||||
bounds = vec![];
|
||||
unify_fieldless_variants = false;
|
||||
is_shallow = false;
|
||||
substructure = combine_substructure(Box::new(|c, s, sub| {
|
||||
cs_clone("Clone", c, s, sub, Mode::Deep)
|
||||
cs_clone("Clone", c, s, sub)
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -80,7 +83,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
|
||||
additional_bounds: bounds,
|
||||
generics: LifetimeBounds::empty(),
|
||||
is_unsafe: false,
|
||||
supports_unions: false,
|
||||
supports_unions: true,
|
||||
methods: vec![MethodDef {
|
||||
name: "clone",
|
||||
generics: LifetimeBounds::empty(),
|
||||
@ -89,37 +92,72 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
|
||||
ret_ty: Self_,
|
||||
attributes: attrs,
|
||||
is_unsafe: false,
|
||||
unify_fieldless_variants: unify_fieldless_variants,
|
||||
unify_fieldless_variants: false,
|
||||
combine_substructure: substructure,
|
||||
}],
|
||||
associated_types: Vec::new(),
|
||||
};
|
||||
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
trait_def.expand_ext(cx, mitem, item, push, is_shallow)
|
||||
}
|
||||
|
||||
fn cs_clone_shallow(name: &str,
|
||||
cx: &mut ExtCtxt,
|
||||
trait_span: Span,
|
||||
substr: &Substructure,
|
||||
is_union: bool)
|
||||
-> P<Expr> {
|
||||
fn assert_ty_bounds(cx: &mut ExtCtxt, stmts: &mut Vec<ast::Stmt>,
|
||||
ty: P<ast::Ty>, span: Span, helper_name: &str) {
|
||||
// Generate statement `let _: helper_name<ty>;`,
|
||||
// set the expn ID so we can use the unstable struct.
|
||||
let span = super::allow_unstable(cx, span, "derive(Clone)");
|
||||
let assert_path = cx.path_all(span, true,
|
||||
cx.std_path(&["clone", helper_name]),
|
||||
vec![], vec![ty], vec![]);
|
||||
stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
|
||||
}
|
||||
fn process_variant(cx: &mut ExtCtxt, stmts: &mut Vec<ast::Stmt>, variant: &VariantData) {
|
||||
for field in variant.fields() {
|
||||
// let _: AssertParamIsClone<FieldTy>;
|
||||
assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsClone");
|
||||
}
|
||||
}
|
||||
|
||||
let mut stmts = Vec::new();
|
||||
if is_union {
|
||||
// let _: AssertParamIsCopy<Self>;
|
||||
let self_ty = cx.ty_path(cx.path_ident(trait_span, keywords::SelfType.ident()));
|
||||
assert_ty_bounds(cx, &mut stmts, self_ty, trait_span, "AssertParamIsCopy");
|
||||
} else {
|
||||
match *substr.fields {
|
||||
StaticStruct(vdata, ..) => {
|
||||
process_variant(cx, &mut stmts, vdata);
|
||||
}
|
||||
StaticEnum(enum_def, ..) => {
|
||||
for variant in &enum_def.variants {
|
||||
process_variant(cx, &mut stmts, &variant.node.data);
|
||||
}
|
||||
}
|
||||
_ => cx.span_bug(trait_span, &format!("unexpected substructure in \
|
||||
shallow `derive({})`", name))
|
||||
}
|
||||
}
|
||||
stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span))));
|
||||
cx.expr_block(cx.block(trait_span, stmts))
|
||||
}
|
||||
|
||||
fn cs_clone(name: &str,
|
||||
cx: &mut ExtCtxt,
|
||||
trait_span: Span,
|
||||
substr: &Substructure,
|
||||
mode: Mode)
|
||||
substr: &Substructure)
|
||||
-> P<Expr> {
|
||||
let ctor_path;
|
||||
let all_fields;
|
||||
let fn_path = match mode {
|
||||
Mode::Shallow => cx.std_path(&["clone", "assert_receiver_is_clone"]),
|
||||
Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]),
|
||||
};
|
||||
let fn_path = cx.std_path(&["clone", "Clone", "clone"]);
|
||||
let subcall = |cx: &mut ExtCtxt, field: &FieldInfo| {
|
||||
let args = vec![cx.expr_addr_of(field.span, field.self_.clone())];
|
||||
|
||||
let span = if mode == Mode::Shallow {
|
||||
// set the expn ID so we can call the unstable method
|
||||
super::allow_unstable(cx, field.span, "derive(Clone)")
|
||||
} else {
|
||||
field.span
|
||||
};
|
||||
cx.expr_call_global(span, fn_path.clone(), args)
|
||||
cx.expr_call_global(field.span, fn_path.clone(), args)
|
||||
};
|
||||
|
||||
let vdata;
|
||||
@ -145,43 +183,31 @@ fn cs_clone(name: &str,
|
||||
}
|
||||
}
|
||||
|
||||
match mode {
|
||||
Mode::Shallow => {
|
||||
let mut stmts = all_fields.iter().map(|f| {
|
||||
let call = subcall(cx, f);
|
||||
cx.stmt_expr(call)
|
||||
}).collect::<Vec<_>>();
|
||||
stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span))));
|
||||
cx.expr_block(cx.block(trait_span, stmts))
|
||||
}
|
||||
Mode::Deep => {
|
||||
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))
|
||||
}
|
||||
};
|
||||
let call = subcall(cx, field);
|
||||
cx.field_imm(field.span, ident, call)
|
||||
})
|
||||
.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))
|
||||
}
|
||||
};
|
||||
let call = subcall(cx, field);
|
||||
cx.field_imm(field.span, ident, call)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
cx.expr_struct(trait_span, ctor_path, fields)
|
||||
}
|
||||
VariantData::Tuple(..) => {
|
||||
let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect();
|
||||
let path = cx.expr_path(ctor_path);
|
||||
cx.expr_call(trait_span, path, subcalls)
|
||||
}
|
||||
VariantData::Unit(..) => cx.expr_path(ctor_path),
|
||||
}
|
||||
cx.expr_struct(trait_span, ctor_path, fields)
|
||||
}
|
||||
VariantData::Tuple(..) => {
|
||||
let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect();
|
||||
let path = cx.expr_path(ctor_path);
|
||||
cx.expr_call(trait_span, path, subcalls)
|
||||
}
|
||||
VariantData::Unit(..) => cx.expr_path(ctor_path),
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
use deriving::generic::*;
|
||||
use deriving::generic::ty::*;
|
||||
|
||||
use syntax::ast::{Expr, MetaItem};
|
||||
use syntax::ast::{self, Expr, MetaItem};
|
||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::parse::token::InternedString;
|
||||
@ -23,22 +23,6 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
|
||||
mitem: &MetaItem,
|
||||
item: &Annotatable,
|
||||
push: &mut FnMut(Annotatable)) {
|
||||
fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
|
||||
cs_same_method(|cx, span, exprs| {
|
||||
// create `a.<method>(); b.<method>(); c.<method>(); ...`
|
||||
// (where method is `assert_receiver_is_total_eq`)
|
||||
let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect();
|
||||
let block = cx.block(span, stmts);
|
||||
cx.expr_block(block)
|
||||
},
|
||||
Box::new(|cx, sp, _, _| {
|
||||
cx.span_bug(sp, "non matching enums in derive(Eq)?")
|
||||
}),
|
||||
cx,
|
||||
span,
|
||||
substr)
|
||||
}
|
||||
|
||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||
let hidden = cx.meta_list_item_word(span, InternedString::new("hidden"));
|
||||
let doc = cx.meta_list(span, InternedString::new("doc"), vec![hidden]);
|
||||
@ -50,7 +34,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
|
||||
additional_bounds: Vec::new(),
|
||||
generics: LifetimeBounds::empty(),
|
||||
is_unsafe: false,
|
||||
supports_unions: false,
|
||||
supports_unions: true,
|
||||
methods: vec![MethodDef {
|
||||
name: "assert_receiver_is_total_eq",
|
||||
generics: LifetimeBounds::empty(),
|
||||
@ -66,5 +50,38 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
|
||||
}],
|
||||
associated_types: Vec::new(),
|
||||
};
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
trait_def.expand_ext(cx, mitem, item, push, true)
|
||||
}
|
||||
|
||||
fn cs_total_eq_assert(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
|
||||
fn assert_ty_bounds(cx: &mut ExtCtxt, stmts: &mut Vec<ast::Stmt>,
|
||||
ty: P<ast::Ty>, span: Span, helper_name: &str) {
|
||||
// Generate statement `let _: helper_name<ty>;`,
|
||||
// set the expn ID so we can use the unstable struct.
|
||||
let span = super::allow_unstable(cx, span, "derive(Eq)");
|
||||
let assert_path = cx.path_all(span, true,
|
||||
cx.std_path(&["cmp", helper_name]),
|
||||
vec![], vec![ty], vec![]);
|
||||
stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
|
||||
}
|
||||
fn process_variant(cx: &mut ExtCtxt, stmts: &mut Vec<ast::Stmt>, variant: &ast::VariantData) {
|
||||
for field in variant.fields() {
|
||||
// let _: AssertParamIsEq<FieldTy>;
|
||||
assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsEq");
|
||||
}
|
||||
}
|
||||
|
||||
let mut stmts = Vec::new();
|
||||
match *substr.fields {
|
||||
StaticStruct(vdata, ..) => {
|
||||
process_variant(cx, &mut stmts, vdata);
|
||||
}
|
||||
StaticEnum(enum_def, ..) => {
|
||||
for variant in &enum_def.variants {
|
||||
process_variant(cx, &mut stmts, &variant.node.data);
|
||||
}
|
||||
}
|
||||
_ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`")
|
||||
}
|
||||
cx.expr_block(cx.block(trait_span, stmts))
|
||||
}
|
||||
|
@ -401,18 +401,29 @@ impl<'a> TraitDef<'a> {
|
||||
mitem: &ast::MetaItem,
|
||||
item: &'a Annotatable,
|
||||
push: &mut FnMut(Annotatable)) {
|
||||
self.expand_ext(cx, mitem, item, push, false);
|
||||
}
|
||||
|
||||
pub fn expand_ext(&self,
|
||||
cx: &mut ExtCtxt,
|
||||
mitem: &ast::MetaItem,
|
||||
item: &'a Annotatable,
|
||||
push: &mut FnMut(Annotatable),
|
||||
from_scratch: bool) {
|
||||
match *item {
|
||||
Annotatable::Item(ref item) => {
|
||||
let newitem = match item.node {
|
||||
ast::ItemKind::Struct(ref struct_def, ref generics) => {
|
||||
self.expand_struct_def(cx, &struct_def, item.ident, generics)
|
||||
self.expand_struct_def(cx, &struct_def, item.ident, generics, from_scratch)
|
||||
}
|
||||
ast::ItemKind::Enum(ref enum_def, ref generics) => {
|
||||
self.expand_enum_def(cx, enum_def, &item.attrs, item.ident, generics)
|
||||
self.expand_enum_def(cx, enum_def, &item.attrs,
|
||||
item.ident, generics, from_scratch)
|
||||
}
|
||||
ast::ItemKind::Union(ref struct_def, ref generics) => {
|
||||
if self.supports_unions {
|
||||
self.expand_struct_def(cx, &struct_def, item.ident, generics)
|
||||
self.expand_struct_def(cx, &struct_def, item.ident,
|
||||
generics, from_scratch)
|
||||
} else {
|
||||
cx.span_err(mitem.span,
|
||||
"this trait cannot be derived for unions");
|
||||
@ -661,7 +672,8 @@ impl<'a> TraitDef<'a> {
|
||||
cx: &mut ExtCtxt,
|
||||
struct_def: &'a VariantData,
|
||||
type_ident: Ident,
|
||||
generics: &Generics)
|
||||
generics: &Generics,
|
||||
from_scratch: bool)
|
||||
-> P<ast::Item> {
|
||||
let field_tys: Vec<P<ast::Ty>> = struct_def.fields()
|
||||
.iter()
|
||||
@ -674,7 +686,7 @@ impl<'a> TraitDef<'a> {
|
||||
let (explicit_self, self_args, nonself_args, tys) =
|
||||
method_def.split_self_nonself_args(cx, self, type_ident, generics);
|
||||
|
||||
let body = if method_def.is_static() {
|
||||
let body = if from_scratch || method_def.is_static() {
|
||||
method_def.expand_static_struct_method_body(cx,
|
||||
self,
|
||||
struct_def,
|
||||
@ -709,7 +721,8 @@ impl<'a> TraitDef<'a> {
|
||||
enum_def: &'a EnumDef,
|
||||
type_attrs: &[ast::Attribute],
|
||||
type_ident: Ident,
|
||||
generics: &Generics)
|
||||
generics: &Generics,
|
||||
from_scratch: bool)
|
||||
-> P<ast::Item> {
|
||||
let mut field_tys = Vec::new();
|
||||
|
||||
@ -727,7 +740,7 @@ impl<'a> TraitDef<'a> {
|
||||
let (explicit_self, self_args, nonself_args, tys) =
|
||||
method_def.split_self_nonself_args(cx, self, type_ident, generics);
|
||||
|
||||
let body = if method_def.is_static() {
|
||||
let body = if from_scratch || method_def.is_static() {
|
||||
method_def.expand_static_enum_method_body(cx,
|
||||
self,
|
||||
enum_def,
|
||||
|
@ -18,16 +18,12 @@ struct S {
|
||||
b: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
union U {
|
||||
s: S,
|
||||
c: u32,
|
||||
}
|
||||
|
||||
impl Clone for U {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
impl Copy for U {}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
{
|
||||
|
@ -12,16 +12,12 @@
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
union U {
|
||||
a: u8,
|
||||
b: u64,
|
||||
}
|
||||
|
||||
impl Clone for U {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
impl Copy for U {}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut u = U { b: 0 };
|
||||
|
@ -10,16 +10,16 @@
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
#[derive(Clone)]
|
||||
union U {
|
||||
a: u8
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
union W {
|
||||
a: String
|
||||
}
|
||||
|
||||
impl Clone for U { fn clone(&self) { panic!(); } }
|
||||
impl Clone for W { fn clone(&self) { panic!(); } }
|
||||
impl Copy for U {} // OK
|
||||
impl Copy for W {} //~ ERROR the trait `Copy` may not be implemented for this type
|
||||
|
||||
|
41
src/test/compile-fail/union/union-derive-clone.rs
Normal file
41
src/test/compile-fail/union/union-derive-clone.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
#[derive(Clone)] //~ ERROR the trait bound `U1: std::marker::Copy` is not satisfied
|
||||
union U1 {
|
||||
a: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
union U2 {
|
||||
a: u8, // OK
|
||||
}
|
||||
|
||||
impl Copy for U2 {}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
union U3 {
|
||||
a: u8, // OK
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
union U4<T> {
|
||||
a: T, // OK
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct CloneNoCopy;
|
||||
|
||||
fn main() {
|
||||
let u = U4 { a: CloneNoCopy };
|
||||
let w = u.clone(); //~ ERROR no method named `clone` found for type `U4<CloneNoCopy>`
|
||||
}
|
30
src/test/compile-fail/union/union-derive-eq.rs
Normal file
30
src/test/compile-fail/union/union-derive-eq.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
#[derive(Eq)] // OK
|
||||
union U1 {
|
||||
a: u8,
|
||||
}
|
||||
|
||||
impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } }
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct PartialEqNotEq;
|
||||
|
||||
#[derive(Eq)]
|
||||
union U2 {
|
||||
a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: std::cmp::Eq` is not satisfied
|
||||
}
|
||||
|
||||
impl PartialEq for U2 { fn eq(&self, rhs: &Self) -> bool { true } }
|
||||
|
||||
fn main() {}
|
@ -13,9 +13,7 @@
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
#[derive(
|
||||
Clone, //~ ERROR this trait cannot be derived for unions
|
||||
PartialEq, //~ ERROR this trait cannot be derived for unions
|
||||
Eq, //~ ERROR this trait cannot be derived for unions
|
||||
PartialOrd, //~ ERROR this trait cannot be derived for unions
|
||||
Ord, //~ ERROR this trait cannot be derived for unions
|
||||
Hash, //~ ERROR this trait cannot be derived for unions
|
||||
|
@ -10,14 +10,14 @@
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
#[derive(Copy)]
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
struct LARGE_INTEGER_U {
|
||||
LowPart: u32,
|
||||
HighPart: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy)]
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
union LARGE_INTEGER {
|
||||
__unnamed__: LARGE_INTEGER_U,
|
||||
@ -25,9 +25,6 @@ union LARGE_INTEGER {
|
||||
QuadPart: u64,
|
||||
}
|
||||
|
||||
impl Clone for LARGE_INTEGER_U { fn clone(&self) -> Self { *self } }
|
||||
impl Clone for LARGE_INTEGER { fn clone(&self) -> Self { *self } }
|
||||
|
||||
#[link(name = "rust_test_helpers")]
|
||||
extern "C" {
|
||||
fn increment_all_parts(_: LARGE_INTEGER) -> LARGE_INTEGER;
|
||||
|
@ -14,18 +14,34 @@
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
Eq,
|
||||
)]
|
||||
union U {
|
||||
a: u8,
|
||||
b: u16,
|
||||
}
|
||||
|
||||
impl Clone for U {
|
||||
fn clone(&self) -> Self { *self }
|
||||
impl PartialEq for U { fn eq(&self, rhs: &Self) -> bool { true } }
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Eq
|
||||
)]
|
||||
union W<T> {
|
||||
a: T,
|
||||
}
|
||||
|
||||
impl<T> PartialEq for W<T> { fn eq(&self, rhs: &Self) -> bool { true } }
|
||||
|
||||
fn main() {
|
||||
let u = U { b: 0 };
|
||||
let u1 = u;
|
||||
let u2 = u.clone();
|
||||
assert!(u1 == u2);
|
||||
|
||||
let w = W { a: 0 };
|
||||
let w1 = w.clone();
|
||||
assert!(w == w1);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user