Expand derives manually where allowed
diff --git a/macro/src/derive.rs b/macro/src/derive.rs
deleted file mode 100644
index 1abc5da..0000000
--- a/macro/src/derive.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-use crate::syntax::Derive;
-use proc_macro2::TokenStream;
-use quote::{quote, ToTokens};
-
-pub struct DeriveAttribute<'a>(pub &'a [Derive]);
-
-impl<'a> ToTokens for DeriveAttribute<'a> {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        if !self.0.is_empty() {
-            let derives = self.0;
-            tokens.extend(quote!(#[derive(#(#derives),*)]));
-        }
-    }
-}
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index c735483..92551e6 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -1,11 +1,10 @@
-use crate::derive::DeriveAttribute;
 use crate::syntax::atom::Atom::{self, *};
 use crate::syntax::file::Module;
 use crate::syntax::report::Errors;
 use crate::syntax::symbol::Symbol;
 use crate::syntax::{
-    self, check, mangle, Api, Enum, ExternFn, ExternType, Impl, Pair, ResolvableName, Signature,
-    Struct, Type, TypeAlias, Types,
+    self, check, mangle, Api, Derive, Enum, ExternFn, ExternType, Impl, Pair, ResolvableName,
+    Signature, Struct, Type, TypeAlias, Types,
 };
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::{format_ident, quote, quote_spanned, ToTokens};
@@ -127,7 +126,6 @@
 fn expand_struct(strct: &Struct) -> TokenStream {
     let ident = &strct.name.rust;
     let doc = &strct.doc;
-    let derives = DeriveAttribute(&strct.derives);
     let type_id = type_id(&strct.name);
     let fields = strct.fields.iter().map(|field| {
         // This span on the pub makes "private type in public interface" errors
@@ -136,9 +134,8 @@
         quote!(#vis #field)
     });
 
-    quote! {
+    let mut expanded = quote! {
         #doc
-        #derives
         #[repr(C)]
         pub struct #ident {
             #(#fields,)*
@@ -148,7 +145,37 @@
             type Id = #type_id;
             type Kind = ::cxx::kind::Trivial;
         }
+    };
+
+    let is_copy = strct.derives.contains(&Derive::Copy);
+    for derive in &strct.derives {
+        match derive {
+            Derive::Copy => {
+                expanded.extend(quote! {
+                    impl ::std::marker::Copy for #ident {}
+                });
+            }
+            Derive::Clone => {
+                let body = if is_copy {
+                    quote!(*self)
+                } else {
+                    let fields = strct.fields.iter().map(|field| &field.ident);
+                    quote!(#ident {
+                        #(#fields: ::std::clone::Clone::clone(&self.#fields),)*
+                    })
+                };
+                expanded.extend(quote! {
+                    impl ::std::clone::Clone for #ident {
+                        fn clone(&self) -> Self {
+                            #body
+                        }
+                    }
+                });
+            }
+        }
     }
+
+    expanded
 }
 
 fn expand_enum(enm: &Enum) -> TokenStream {
@@ -166,7 +193,7 @@
 
     quote! {
         #doc
-        #[derive(Copy, Clone, PartialEq, Eq)]
+        #[derive(PartialEq, Eq)] // required to be derived in order to be usable in patterns
         #[repr(transparent)]
         pub struct #ident {
             pub repr: #repr,
@@ -181,6 +208,14 @@
             type Id = #type_id;
             type Kind = ::cxx::kind::Trivial;
         }
+
+        impl ::std::marker::Copy for #ident {}
+
+        impl ::std::clone::Clone for #ident {
+            fn clone(&self) -> Self {
+                *self
+            }
+        }
     }
 }
 
diff --git a/macro/src/lib.rs b/macro/src/lib.rs
index 1de7e6c..6285451 100644
--- a/macro/src/lib.rs
+++ b/macro/src/lib.rs
@@ -10,7 +10,6 @@
 
 extern crate proc_macro;
 
-mod derive;
 mod expand;
 mod syntax;
 mod type_id;
diff --git a/syntax/derive.rs b/syntax/derive.rs
index 435aa20..855e80f 100644
--- a/syntax/derive.rs
+++ b/syntax/derive.rs
@@ -15,12 +15,3 @@
         }
     }
 }
-
-impl AsRef<str> for Derive {
-    fn as_ref(&self) -> &str {
-        match self {
-            Derive::Clone => "Clone",
-            Derive::Copy => "Copy",
-        }
-    }
-}
diff --git a/syntax/tokens.rs b/syntax/tokens.rs
index d450f73..29899a9 100644
--- a/syntax/tokens.rs
+++ b/syntax/tokens.rs
@@ -1,7 +1,7 @@
 use crate::syntax::atom::Atom::*;
 use crate::syntax::{
-    Array, Atom, Derive, Enum, ExternFn, ExternType, Impl, Receiver, Ref, ResolvableName,
-    Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var,
+    Array, Atom, Enum, ExternFn, ExternType, Impl, Receiver, Ref, ResolvableName, Signature,
+    SliceRef, Struct, Ty1, Type, TypeAlias, Var,
 };
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::{quote_spanned, ToTokens};
@@ -93,12 +93,6 @@
     }
 }
 
-impl ToTokens for Derive {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        Ident::new(self.as_ref(), Span::call_site()).to_tokens(tokens);
-    }
-}
-
 impl ToTokens for Atom {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         Ident::new(self.as_ref(), Span::call_site()).to_tokens(tokens);
diff --git a/tests/ui/derive_duplicate.stderr b/tests/ui/derive_duplicate.stderr
index e0450e2..0d5de2c 100644
--- a/tests/ui/derive_duplicate.stderr
+++ b/tests/ui/derive_duplicate.stderr
@@ -7,4 +7,4 @@
   | first implementation here
   | conflicting implementation for `ffi::Struct`
   |
-  = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)