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

wasm_bindgen(skip) in cfg_attr #2703

Open
mBornand opened this issue Oct 18, 2021 · 11 comments · May be fixed by #4351
Open

wasm_bindgen(skip) in cfg_attr #2703

mBornand opened this issue Oct 18, 2021 · 11 comments · May be fixed by #4351

Comments

@mBornand
Copy link
Contributor

Hello
I tried to use #[cfg_attr(feature = "wasm-bindgen", wasm_bindgen(skip))] but I get this:

99 |     #[cfg_attr(feature = "wasm-bindgen", wasm_bindgen(skip))]
   |                                          ^^^^^^^^^^^^ not a non-macro attribute

But it works for other macros like derive. Is this a bug or does a workaround exist?

@alexcrichton
Copy link
Contributor

Sorry I'm not sure why this would be happening.

@mBornand
Copy link
Contributor Author

This is an example:

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct Test1 {
    #[wasm_bindgen(skip)]
    pub s: Option<String>,
}

#[wasm_bindgen]
pub struct Test2 {
    #[cfg_attr(feature = "wasm-bindgen", wasm_bindgen(skip))]
    pub s: Option<String>,
}

pub struct Test3 {
    #[wasm_bindgen(skip)]
    pub s: Option<String>,
}

It produces this error:

error: expected non-macro attribute, found attribute macro `wasm_bindgen`
  --> src/lib.rs:11:42
   |
11 |     #[cfg_attr(feature = "wasm-bindgen", wasm_bindgen(skip))]
   |                                          ^^^^^^^^^^^^ not a non-macro attribute

error: expected non-macro attribute, found attribute macro `wasm_bindgen`
  --> src/lib.rs:16:7
   |
16 |     #[wasm_bindgen(skip)]
   |       ^^^^^^^^^^^^ not a non-macro attribute

error[E0277]: the trait bound `String: std::marker::Copy` is not satisfied
  --> src/lib.rs:12:12
   |
12 |     pub s: Option<String>,
   |            ^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `String`
   |
   = note: required because of the requirements on the impl of `std::marker::Copy` for `Option<String>`

Test2 or Test3 alone also produces an error.

@alexcrichton
Copy link
Contributor

The error on Test3 is expected because there's no attribute on the struct itself, the error on Test2 is probably because the cfg_attr would be processed after the outer procedural macro. I think you may be able to fix this by placing #[cfg_attr] on the outer wasm_bindgen attribute as well, but that's just a guess.

@mBornand
Copy link
Contributor Author

use wasm_bindgen::prelude::*;

#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen)]
pub struct Test2 {
    #[cfg_attr(feature = "wasm-bindgen", wasm_bindgen(skip))]
    pub s: Option<String>,
}

fails the same way.
I think the problems is in crates/macro-support/src/parser.rs in the function find on line 172.
It looks only for wasm_bindgen and my guess is that cfg_attr is not evaluated yet.

@mBornand
Copy link
Contributor Author

I found a solution.

#![feature(cfg_eval)]
use wasm_bindgen::prelude::*;

#[cfg_eval]
#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen)]
pub struct Test2 {
    #[cfg_attr(feature = "wasm-bindgen", wasm_bindgen(skip))]
    pub s: Option<String>,
}

It works. But in some way it should be the responsibility of the wasm_bindgen macro to do this.

@mBornand mBornand closed this as completed Aug 1, 2022
@FabianHummel
Copy link

I also have this issue but have not found a fix for it yet. When I try the supposed solution from above I just get syntax errors about expected symbols in this #![feature(cfg_eval)] line.

#![feature(cfg_eval)] // syntax error here
use wasm_bindgen::prelude::*;

#[cfg_eval]
#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen)]
pub struct Test2 {
    #[cfg_attr(feature = "wasm-bindgen", wasm_bindgen(skip))]
    pub s: Option<String>,
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
pub struct MyStruct {
    #[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen(skip))]
    pub my_field: String,
image image

@daxpedda
Copy link
Collaborator

I do not believe that there is something wasm-bindgen can do here. While it is possible for wasm-bindgen to parse #[cfg_attr(...)] attributes, we can't evaluate them, this is just a limitation of how proc-macros work in Rust.

I'm unfamiliar with cfg_eval, so I can't assist there.

@FabianHummel
Copy link

FabianHummel commented Nov 15, 2024

it's fine. i guess I'll just wait and see what the future has to offer. In the meantime, this is my workaround:

#[cfg(target_arch = "wasm32")]
#[wasm_bindgen::prelude::wasm_bindgen]
pub struct MyStruct {
    #[wasm_bindgen::prelude::wasm_bindgen(skip)]
    pub my_field: String,
}

#[cfg(not(target_arch = "wasm32"))]
pub struct MyStruct {
    pub my_field: String,
}

a bit cumbersome, but it works.

@fl0rek
Copy link

fl0rek commented Dec 6, 2024

I believe I found a fix which doesn't require cfg_eval, thus can be used on stable (which motivated me to look into it). It uses similar two-step expansion pattern used to allow cfg_attr in impl blocks: #1208. It is also inspired by the discussion on a similar problem in bon crate: elastio/bon#124.

Overview:

  • During #[wasm_bindgen] attribute macro expansion on struct, instead of generating ast for Program, it puts a #[derive(BindgenedStruct)] on it and preserves all the wasm_bindgen atributes as-is.
  • When #[derive(BindgenedStruct)] is expanded, cfg_attr are already evaluated, so macro can just processes the leftover attributes and generate the glue code required, as it's done now. Attributes are then automatically removed by the compiler, since macro is defined as #[proc_macro_derive(BindgenedStruct, attributes(wasm_bindgen))].

BindgenedStruct is a placeholder, internal-use name.

I think I have a POC working with tests passing and would be happy to work on getting it to a PR state.

@daxpedda
Copy link
Collaborator

daxpedda commented Dec 6, 2024

That sounds workable indeed. I'm hoping the implementation can be actually lightweight.

Happy to review a PR! Would need a good testsuite though!

@fl0rek fl0rek linked a pull request Dec 11, 2024 that will close this issue
@fl0rek
Copy link

fl0rek commented Dec 13, 2024

Opened #4351 with proposed fix

@daxpedda daxpedda reopened this Dec 15, 2024
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

Successfully merging a pull request may close this issue.

5 participants