Expand derives manually where allowed

This commit is contained in:
David Tolnay 2020-11-27 11:46:16 -08:00
parent 652cb50e33
commit 4a0c53a7b0
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
6 changed files with 45 additions and 40 deletions

View File

@ -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),*)]));
}
}
}

View File

@ -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(ffi: Module, apis: &[Api], types: &Types) -> TokenStream {
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 @@ fn expand_struct(strct: &Struct) -> TokenStream {
quote!(#vis #field)
});
quote! {
let mut expanded = quote! {
#doc
#derives
#[repr(C)]
pub struct #ident {
#(#fields,)*
@ -148,7 +145,37 @@ fn expand_struct(strct: &Struct) -> TokenStream {
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 @@ fn expand_enum(enm: &Enum) -> TokenStream {
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 @@ fn expand_enum(enm: &Enum) -> TokenStream {
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
}
}
}
}

View File

@ -10,7 +10,6 @@
extern crate proc_macro;
mod derive;
mod expand;
mod syntax;
mod type_id;

View File

@ -15,12 +15,3 @@ impl Derive {
}
}
}
impl AsRef<str> for Derive {
fn as_ref(&self) -> &str {
match self {
Derive::Clone => "Clone",
Derive::Copy => "Copy",
}
}
}

View File

@ -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 Array {
}
}
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);

View File

@ -7,4 +7,4 @@ error[E0119]: conflicting implementations of trait `std::clone::Clone` for type
| 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)