-
Notifications
You must be signed in to change notification settings - Fork 13k
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
How to treat inert attributes on macro invocations? #63221
Comments
Ideally I'd want a common scheme for all macro kinds + a scheme that's more intuitive and/or resistant to mistakes. /// Doc.
mac! {
struct S;
} to translate into /// Doc.
struct S; , so the current approach of throwing the attributes away may be not the best one. |
Alternative 1: Throwing the attributes away.
This alternative seems non-viable for attributes/derives. /// Doc.
#[some_attrs]
#[derive(SomeDerives)]
struct S; and the doc comments must not be lost during expansion in this case. For bang macros this is probably undesirable as well (#63221 (comment)), this leads to users writing code that most likely doesn't do what they expect. |
Alternative 2: Prepending the attributes to the macro output.This alternative basically follows the token-based expansion model described in #61733 (comment). Suppose our macro is derive-like and emit the input item (after perhaps tweaking it slightly) + some additional items like impls. mac! { struct S; }
=>
pub struct S;
impl S { ... } In this case the behavior is pretty reasonable, It's less reasonable if the macro doesn't have a "primary" item, e.g. #[inert]
mac!();
=>
#[inert]
struct U;
struct V;
struct W; , in this case the macro may want to "spread" the attribute across all the produced items. Note that for post-fix semicolons appending them in accordance with the token-based model is almost always the desired behavior that turns the final expression produced by the macro into a non-trailing statement or has no effect. Migrating to this model would be a breaking change for attribute and derive macros, we can estimate the scale of the breakage with crater. |
Alternative 3: Prepending the attributes to the macro input.This is the most flexible alternative - let the macro itself to decide what to do with the attributes. In case of derive-like macros it works somewhat automatically, similarly to the alternative 2. #[inert]
mac! { struct S; }
=>
mac! { #[inert] struct S; }
=>
#[inert]
pub struct S;
impl S { ... } In other cases the macro may implement the spreading semantics or some other semantics itself. Migrating to this model would be a breaking change for fn-like macros, we can estimate the scale of the breakage with crater. /// Doc.
mac! {
struct S;
} is written accidentally, then it's likely that the macro will expect an item and accept mac! {
/// Doc.
struct S;
} as well, so in some cases the change may fix the code rather than break it. We can analyze the breakage and perhaps add some compatibility hacks if necessary (until the next edition or something). |
I tend to agree that alternative 3 seems best here. |
Plausibly relevant: It would be neat if when given |
I think it's worth considering the following fourth approach, not that I necessarily think it's the best one but it is missing above. Alternative 4: Prepending outer attributes as inner#[inert]
mac! {
struct S;
}
=>
mac! {
#![inert]
struct S;
} This is analogous to how Compared to alternative 3, this is less likely to make existing proc macros "work by accident" but it enables macros to define the semantics of outer attributes on their invocation. |
Suggest including unused asm arguments in a comment to avoid error We require all arguments to an `asm!` to be used in the template string, just like format strings. However in some cases (e.g. `black_box`) it may be desirable to have `asm!` arguments that are not used in the template string. Currently this is a hard error rather than a lint since `#[allow]` does not work on macros (rust-lang#63221), so this PR suggests using the unused arguments in an asm comment as a workaround. r? @petrochenkov
For macro_rules! make_fn {
() => {
fn foo() {}
}
}
fn main() {
#[allow(dead_code)] make_fn!();
} In the above code, we'll end up with I think it would be useful to handle attributes equivalently for |
These attributes are currently discarded. This may change in the future (see rust-lang#63221), but for now, placing inert attributes on a macro invocation does nothing, so we should warn users about it. Technically, it's possible for there to be attribute macro on the same macro invocation (or at a higher scope), which inspects the inert attribute. For example: ```rust #[look_for_inline_attr] #[inline] my_macro!() #[look_for_nested_inline] mod foo { #[inline] my_macro!() } ``` However, this would be a very strange thing to do. Anyone running into this can manually suppress the warning.
Warn on inert attributes used on bang macro invocation These attributes are currently discarded. This may change in the future (see rust-lang#63221), but for now, placing inert attributes on a macro invocation does nothing, so we should warn users about it. Technically, it's possible for there to be attribute macro on the same macro invocation (or at a higher scope), which inspects the inert attribute. For example: ```rust #[look_for_inline_attr] #[inline] my_macro!() #[look_for_nested_inline] mod foo { #[inline] my_macro!() } ``` However, this would be a very strange thing to do. Anyone running into this can manually suppress the warning.
Warn on inert attributes used on bang macro invocation These attributes are currently discarded. This may change in the future (see rust-lang#63221), but for now, placing inert attributes on a macro invocation does nothing, so we should warn users about it. Technically, it's possible for there to be attribute macro on the same macro invocation (or at a higher scope), which inspects the inert attribute. For example: ```rust #[look_for_inline_attr] #[inline] my_macro!() #[look_for_nested_inline] mod foo { #[inline] my_macro!() } ``` However, this would be a very strange thing to do. Anyone running into this can manually suppress the warning.
Examples of inert attributes on macro invocations:
How these attributes are treated currently (ad hoc, there's no RFC or anything):
Effectively,
#[inert] #[macro_attr] struct S;
->macro_attr! { #[inert] struct S; }
.Related issues: #61733 (comment).
The text was updated successfully, but these errors were encountered: