# wg-macros open discussion 2023-12-15 Possible topics: - https://internals.rust-lang.org/t/how-can-we-improve-proc-macro-without-dependencies/19996 - https://internals.rust-lang.org/t/pre-rfc-sandboxed-deterministic-reproducible-efficient-wasm-compilation-of-proc-macros/19359 - https://internals.rust-lang.org/t/what-are-the-use-cases-for-macros-which-define-macros/908 - https://internals.rust-lang.org/t/pre-rfc-extend-macros-1-1-to-support-foo-style-macros/3921 - PR: https://github.com/rust-lang/rust/issues/118580 Present: Eric Holk, Vincenzo Palazzo, Trevor Gross, Daniel H.M. ## How can we improve `proc_macro` without dependencies? Blog: https://internals.rust-lang.org/t/how-can-we-improve-proc-macro-without-dependencies/19996/1 Zulip: https://rust-lang.zulipchat.com/#narrow/stream/404510-wg-macros/topic/Proc.20macro.20simplification **Trevor**: Writing proc macros without `syn` is not fun. Proposal here is to add a simple parse API that would cover a lot of cases `syn` is currently used for, but still works well with `syn` when more power is needed. **Vincenzo**: https://github.com/rsmicro/kproc-macros ```rust /// Default fn my_macro(ts: TokenStream) -> TokenStream; /// Proposed fn my_macro(ts: TokenStream) -> Result<TokenStream, ParserError>; ``` Lukas points out this doesn't work well for rust-analyzer / IDE support. [Original comment](https://rust-lang.zulipchat.com/#narrow/stream/404510-wg-macros/topic/Proc.20macro.20simplification/near/406918659) **Daniel**: Real-world robust macros use `Result` everywhere and unwrap at the top level into a `TokenStream` describing the error. We need to remember there are both `#[derive]` style macros and function-like macros. For items, we can emit them as a syntax error. `#[tokio::main]` emits tokens unchanged on error which lets rustc recover from the error better. If a macro generates `impl Foo`, on error we should make an `impl Foo` so we don't get as many subsequent errors. An explicit `Error` type may not actually help. We could add a flag to the `Error` to automatically re-emit the input which helps diagnostics. This is harder for function-like macros **Trevor**: Rather than an `Error` type, maybe we can hook into the diagnostic API? ```rust let name: Ident = p.parse() .or_diag_error("you need to provide a name") .emit_then(Ident::from("name_placeholder")); ``` For Rust Analyzer, just having the token stream may not help. **Daniel**: The distinction between attribute macros and function-like macros is important. Can we add signatures to macros? This takes a function and output an item, for example. Parsing API could have good diagnostics built in. **Trevor**: Not sure the distincton between function and attribute macros is so important. Function macros can still expand into items. On error, we want to generate expanded code as best we can and emit a diagnostic. If you slightly mis-type something, you want to keep the skeleton mostly the same so you don't get unrelated errors elsewhere. **Daniel**: Some restrictions though -- attribute macros can only go on items. current pattern of returning a token stream that happens to have a `compile_error!` invocation is the worst option since you lose the input / and the info for IDEs of there being an error. A lot of macros, especially attribute macros, work on input that looks like Rust, which is why emitting unchanged on error tends to work well. To illustrate, two kinds of bang macros: - ```rust foo! { hello Earth // ^^^^^ // proc-macro errored: expected `World` } ``` - Here, the IDE cannot guess anything/have a fallback - ```rust bar! { fn foo(v: &mut Vec<u8>) { let x = v.iter().flat_ma // ^ // proc-macro errored: expected `;` } } ``` - Here, the IDE should be able to provide feedback/suggestions (_e.g._, completion) - **How could we make our (bang) proc-macros convey this info/distinction?** With attribute and derive macros, we only have `bar!` kind of macros, so it's easy for IDEs to "recover" (_e.g._, if `Error` returned / if `.diagnostic_err()` raised). **Vincenzo**: Let's investigate and explore more! **Eric**: Writing good error messages is hard. Look at how much code in rustc is to generate messages. Even using crates like `miette` need a lot of care to generate a high quality message. So we need to give the right tools to macro writers, but we likely won't be able to automatically generate error messages at the level we want. ## Pre-RFC: Sandboxed, deterministic, reproducible, efficient Wasm compilation of proc macros https://internals.rust-lang.org/t/pre-rfc-sandboxed-deterministic-reproducible-efficient-wasm-compilation-of-proc-macros/19359 Eric: Need to define threat model. Skeptical of pulling a whole new compiler/runtime into rustc. This is a lot of extra attack surface. Sandboxing usually needs OS mechanisms, so can we use these OS sandboxing tools directly? Wasm has value for compile-once-run-anywhere though. Daniel: Agreed, we should define the benefits we want. Could easily get caught up in bikeshedding. Driving this RFC will require leadership. One possibility could be to punt on the sandboxing/security aspect of it for a first PoC. Eric: dtolnay has likely thought through these threat model questions; I'm speaking from a place of ignorance. Need to read pre-RFC. Trevor: we should have a look at dtolnay's reference implementation. We will follow up in a Zulip thread. ## Provide a way for custom derives to know if they were invoked via `#[derive_const]` https://github.com/rust-lang/rust/pull/118580 Follow up async on Zulip. ## Meeting Schedule Let's take a break for the holidays and meet again on 2023-01-12.