-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
The #[diagnostic]
attribute namespace
#3368
Changes from 2 commits
b9bf6ad
74958a3
30f575c
a9fc409
6e9038b
cecccb4
c6b8f65
cb8f2fc
4b112aa
0d519ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,32 +71,50 @@ I expect the new attributes to be documented on the existing [Diagnostics](https | |
|
||
This RFC proposes to introduce a new `#[diagnostic]` attribute namespace. This namespace is supposed to contain different attributes, which allow users to hint the compiler to emit specific error messages in certain cases like type mismatches, unsatisfied trait bounds or similar situations. By collecting such attributes in a common namespace it is easier for users to find useful attributes and it is easier for the language team to establish a set of common rules for these attributes. | ||
|
||
Attributes in this namespace are generally expected to be formed like: | ||
```rust | ||
#[diagnostic::attribute(option)] | ||
``` | ||
where several `option` entries can appear in the same attribute. `option` is expected to be a valid attribute argument in this position. Attributes in this namespace are versioned. Any incompatible change to an existing stable attribute in this namespace requires bumping the version of the diagnostic attribute namespace. Crates using these attributes must specify the expected version of the diagnostic namespace via a `#![diagnostic::v{version_number}]` crate top-level attribute. If multiple such attributes are present the compiler will choose the highest version number and ignore the rest. The compiler is encouraged to provide a lint for outdated versions of the diagnostic attribute namespace. This mechanism exists so that a third party crate can provide a shim implementation of the corresponding attributes to translate between different versions of the diagnostic attribute namespace on different rust versions. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think I'm comfortable with adding a new versioning scheme for a subset of the language. Or at least, I don't understand the motivation at all. Why can't we use editions to evolve the attributes?
What purpose does this serve? Supporting newer versions on old compilers? How would it work? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
because we want to remove old versions from the compiler entirely. Editions must be supported until the heat death of the universe.
a crates.io crate could check the compiler version and change what attribute they generate, even if the crate's input attribute syntax is stable across compiler versions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For context: This versioning scheme was proposed by @joshtriplett. I personally would be fine with specifying that the compiler is not allowed to change the semantic of a certain attribute/option + it is allowed to ignore a certain attribute/option. If necessary that alone would allow to replace the a certain option by another one by just choosing a differently named option. |
||
|
||
Any attribute in this namespace may: | ||
|
||
* Hint the compiler to emit a specific error message in a specific situation | ||
* Only affect the messages emitted by a compiler in case of a failed compilation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like warnings should be fine to support from this namespace too. |
||
|
||
Any attribute in this namespace is not allowed to: | ||
|
||
* Change the result of the compilation, which means applying such an attribute should never cause an error as long as they are syntactically valid | ||
* pass-through information from the source of the diagnostic in a way that users can rely on. E.g. Such an attribute should not allow users to keep the compilation successful and dump information about `extern` blocks to generate C header files | ||
|
||
The compiler is allowed to: | ||
|
||
* Ignore the provided hints | ||
* Use only parts of the provided hints, for example for the proposed `#[diagnostic::on_unimplemented]` only use the `message` option | ||
* Change this behaviour at any time | ||
* Ignore the hints provided by: | ||
+ A specific attribute | ||
+ A specific option | ||
* Change the set of supported attributes and options at any time | ||
* Provide warning lints for malformed or otherwise not accepted attributes | ||
|
||
The compiler must: | ||
The compiler must not: | ||
|
||
* Verify that the attribute is syntactically correct, which means: | ||
+ Its one of the accepted attributes | ||
+ It only contains the allowed options | ||
+ Any provided option follows the defined syntax | ||
* Follow the described semantics if the attribute is not ignored. | ||
* Change the semantic of an attribute or option, these kind of change requires a bump of the diagnostic attribute space version number | ||
* Emit an hard error on malformed attribute, although emitting lints is fine | ||
|
||
Adding a new attribute or option to the `#[diagnostic]` namespace is a decision of the compiler team. The envisioned procedure for this is as following: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would the new attribute option be in the language reference/spec? Is the compiler team comfortable reasoning about how this might affect other (maybe hypothetical) compilers? Put another way, is the justification for bypassing T-lang approval essentially that: it doesn't affect semantics of programs, including whether they compile, and that alternate compilers can ignore it? It seems partially justified also by the alternative versioning scheme ("we'll just bump the version if we mess something up"), which I have concerns about (comment below). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
rustc can ignore them, they are effectively a new kind of comments from the lang perspective, even if we as compiler developers will want to give users a reliable experience. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The original proposal (before opening this RFC) was to introduce a Now this RFC tries to specify the namespace in such a way that supporting anything in that namespace should be optional for other compilers. So if these attributes do not fit their model, they are free to ignore these attributes (or ignore certain options only). Otherwise the main argument for "bypassing" approval from the language team is to prevent spamming the team with otherwise trivial changes. Again that was something that was proposed by @joshtriplett . |
||
|
||
1. The new attribute lands on nightly without a feature gate. It gets ignored on stable/beta until its explicitly activated there. | ||
2. The time as nightly only attribute is used to verify that: | ||
* The attribute solves a real problem | ||
* The implemented syntax matches the expectations | ||
3. To enable a certain attribute in stable release the following steps are required: | ||
* The attribute is documented in the rust reference | ||
* T-lang is informed | ||
* T-compiler performs a FCP, where a simple majority (>50%) accepts the attribute | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leave a comment saying that the usual concern rules still apply, everyone can raise a concern. |
||
|
||
|
||
## The `#[diagnostic::on_unimplemented]` attribute | ||
|
||
This section describes the syntax of the `on_unimplemented` attribute and additionally how it is supposed to work. Implementing the later part is optional as outlined in the previous section. Any syntax not explicitly described in this section must be rejected as invalid according to the general rules of the `#[diagnostic]` attribute namespace. | ||
This section describes the syntax of the `on_unimplemented` attribute and additionally how it is supposed to work. The specification of this attribute is partially provided as example and motivation for the `#[diagnostic]` attribute namespace. In addition it is provided to give this RFC a | ||
|
||
```rust | ||
#[diagnostic::on_unimplemented( | ||
|
@@ -116,7 +134,7 @@ In addition the `on_unimplemented` attribute provides mechanisms to specify for | |
|
||
The `any` and `all` options allow to combine multiple filter options. The `any` option matches if one of the supplied filter options evaluates to `true`, the `all` option requires that all supplied filter options evaluate to true. `not` allows to negate a given filter option. It evaluates to `true` if the inner filter option evaluates to `false`. These options can be nested to construct complex filters. | ||
|
||
The `on_unimplemented` attribute can be applied multiple times to the same trait definition. Multiple attributes are evaluated in order. The first matching instance for each of the `message`/`label`/`note` options is emitted. | ||
The `on_unimplemented` attribute can be applied multiple times to the same trait definition. Multiple attributes are evaluated in order. The first matching instance for each of the `message`/`label`/`note` options is emitted. The compiler may lint against ignored variants as this is the case for `match` arms for example. | ||
```rust | ||
#[diagnostic::on_unimplemented( | ||
if(Self = std::string::String), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we ever had where clause equality syntax, do we think it would look like this? Does anyone in @rust-lang/lang know? I mostly want there to be sharing of existing work on possible syntax ideas, for a higher probability of convergence in the long term. I especially don't want to block the RFC on finalizing syntax for a nonexistent feature ;) |
||
|
@@ -164,6 +182,10 @@ Another drawback is that crates might hint lower quality error messages than the | |
|
||
This proposal tries to improve error messages generated by rustc. It would give crate authors a tool to influence what error message is emitted in a certain situation, as they might sometimes want to provide specific details on certain error conditions. Not implementing this proposal would result in the current status quo. Currently the compiler always shows a "general" error message, even if it would be helpful to show additional details. | ||
|
||
There are alternatives for the naming of the `#[diagnostic]` namespace: | ||
|
||
* Use a `#[rustc]` namespace for these attributes. This would signifies that these are rustc specific extensions. We likely want to encourage other rust implementations to utilise these information as well, therefore a more general attribute namespace seems to be a better solution. | ||
|
||
There are alternative designs for the proposed `on_unimplemented` attribute: | ||
|
||
* The `on()` based filtering might be replaceable by placing the attribute on negative trait impls. This would turn a filter like | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. That should be address in cb8f2fc |
||
|
@@ -196,17 +218,6 @@ Notably all of the listed similar features are unofficial language extensions. | |
|
||
Clarify the procedure of various potential changes prior stabilisation of the attribute namespace: | ||
|
||
* Process of adding a new attribute to the `#[diagnostics]` attribute macro namespace | ||
+ Requires a RFC? (t-lang seems to prefer that?) | ||
+ Requires a language/compiler MCP? | ||
+ Just a PR to the compiler? | ||
* Process of extending an existing attribute by adding more options | ||
+ Requires a RFC? | ||
+ Requires a language/compiler MCP? | ||
+ Just a PR to the compiler? | ||
* Process of removing support for specific options or an entire attribute from rustc | ||
+ Requires a compiler MCP? | ||
+ Just a PR to the compiler? | ||
* Exact syntax of the `on_unimplemented` attribute | ||
+ Can `Self` be accepted in that position or do we need another name? | ||
+ Is `if()` a valid identifier in the proposed position? | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Today I was thinking about how to design a macro api, and I realized a (niche) downside of this versioning approach. It won't work (out of the box) when I want to insert it in my user's code and I own neither the trait nor the struct.
For example, say an user writes the following code:
I'd really like to make this expand to:
Is there a good workaround for this? Or will this cause the compiler to throw a "please enable diagnostics version 12 for diagnostics on negative impls" error to my user?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that per attr versioning selection (a convention of accepting a specific field?) would need to be provided to cater to attribute proc macros, as you correctly point out :-/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could hygiene pick the macro crate's attribute version instead of the user crate's version? Regular macros would have the same issue.