Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to see derive attributes anymore #40574

Closed
iddm opened this issue Mar 16, 2017 · 9 comments
Closed

Unable to see derive attributes anymore #40574

iddm opened this issue Mar 16, 2017 · 9 comments
Assignees

Comments

@iddm
Copy link

iddm commented Mar 16, 2017

I have made a procedural macro which implements a trait with some functions for a enums. This the whole code:

#[proc_macro_derive(StateMachine, attributes(state_transitions))]
pub fn fxsm(input: TokenStream) -> TokenStream {
    // Construct a string representation of the type definition
    let s = input.to_string();

    // Parse the string representation
    let ast = syn::parse_derive_input(&s).unwrap();

    // Build the impl
    let gen = impl_fsm(&ast);

    // Return the generated impl
    gen.parse().unwrap()
}

fn impl_fsm(ast: &syn::DeriveInput) -> Tokens {
    if let syn::Body::Enum(ref variants) = ast.body {
        if let Some(ref a) = ast.attrs.iter().find(|a| a.name() == "derive") {
            if let syn::MetaItem::List(_, ref nested) = a.value {
                if derives(nested, "Copy") {
                    return gen_for_copyable(&ast.ident,
                                            &variants,
                                            &ast.generics);
                } else if derives(nested, "Clone") {
                    return gen_for_clonable(&ast.ident,
                                            &variants,
                                            &ast.generics);
                } else {
                    panic!("Unable to produce State Machine code on a enum which does not drive Copy nor Clone traits.");
                }
            } else {
                panic!("Unable to produce State Machine code on a enum which does not drive Copy nor Clone traits.");
            }
        } else {
            panic!("How were you able to call me without derive!?!?");
        }
    } else {
        panic!("State Machine must be derived on a enum.");
    }
}

This code worked perfectly like 2 weeks ago but now I have tried to compile it and it can't find any attribute on this struct! As you can see, I try to see what derives does the enum have but now this list is empty! What happened?

Original issue was posted here
@dtolnay told that is was changed here

So how do I fix this?

@sgrif
Copy link
Contributor

sgrif commented Mar 16, 2017

Just to pile on, I also was planning to take advantage of the ability to see other derives, which was possible when the feature was stabilized. #39572 (comment) seems like a much more flexible (and backwards compatible) solution.

@iddm
Copy link
Author

iddm commented Mar 17, 2017

@sgrif I don't quite understand what does this comment say. Could you re-explain it to me please?
Or @jseyfried, could you explain again how to check derives now please?

@jseyfried
Copy link
Contributor

jseyfried commented Mar 17, 2017

@sgrif Well, it was only possible to see other builtin derives reliably, but point taken.

@vityafx As described in #39572 (comment), the input to a derive procedural macro never has any #[derive] attributes today, so you cannot check what #[derive]s were applied to the item.

The rationale here is that a derive procedural macro sees the item after it is expanded, so that e.g. #[derive(Copy)] already turned into an impl Copy ... item. Note that #[cfg]s are also processed/expanded before applying derive procedural macros:

#[derive(MyProcMacro)]
struct S(#[cfg(any())] i32);
//^ The input to `MyProcMacro` here is `struct S();`

That being said, I personally don't have a strong preference between the current behavior and the alternative described in #39572 (comment).

cc @nrc @alexcrichton

@jseyfried jseyfried self-assigned this Mar 17, 2017
@iddm
Copy link
Author

iddm commented Mar 17, 2017

@jseyfried okay, so how do I generate different code for structs/enums based on condition does it derive Copy or Clone?

@jseyfried
Copy link
Contributor

jseyfried commented Mar 17, 2017

@vityafx You can't, since:

you cannot check what #[derive]s were applied to the item.

In particular, this:

#[derive(Clone)]
#[derive(MyProcMacro)]
struct S;

always behaves exactly the same as this:

#[derive(MyProcMacro)]
struct S;

impl S {
    fn clone(&self) -> Self { /* appropriate manual implementation here */ }
}

I actually think this is a benefit of the current behavior, since it means you can always refactor #[derive(Clone)] to a manual impl of Clone without worrying about the other derives.

@iddm
Copy link
Author

iddm commented Mar 17, 2017

That's correct and good. But if I remember correctly I also do not have an ability to check what trait implementation the struct/enum has, am I right?

@jseyfried
Copy link
Contributor

jseyfried commented Mar 17, 2017

@vityafx

I also do not have an ability to check what trait implementation the struct/enum has

Right, the compiler doesn't know what traits the struct/enum implements until long after procedural macros are expanded.

It might be feasible for the compiler to compute this information earlier and make it available to procedural macros, but that would entail major architectural changes.

@iddm
Copy link
Author

iddm commented Mar 17, 2017

@jseyfried So, finalizing the discussion, - how can I generate the code for struct/enums then? If I can not know does it Copy or Clone ? I have checked this earlier and provided needed implementation.. But what can I do now?

@jseyfried
Copy link
Contributor

@vityafx Copy implies Clone, so the code you generate for struct/enums that implement Clone should automatically work with all struct/enums that implement Copy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants