Require a LintId for all proc-macro warnings · Issue #524 · rust-lang/libs-team (original) (raw)
Proposal
Problem statement
This proposal is designed as the minimal LintId integration that unblocks stabilization of a proc-macro warning API (rust-lang/rust#54140). Per rust-lang/rust#54140 (comment), macro-generated warnings should be associated with a namespaced identifier which can be used for setting lint level at the call site, and for rendering rustdoc documentation about the lints emitted by a macro.
Motivating examples or use cases
- https://github.com/openvm-org/openvm/blob/ab01b0cdf95e18b3ac8f790838a1e467303454b7/extensions/algebra/moduli-setup/src/lib.rs#L69
- https://github.com/diesel-rs/diesel/blob/94d5a0d4f918770fc6d6802382a0c133b29e2ba6/diesel_derives/src/deprecated/mod.rs
Solution sketch
Add a proc_macro::LintId
type with Copy
, Clone
, and Debug
impl. Add a 4th proc-macro attribute #[proc_macro_warning]
for declaring a unique LintId at the crate root of a proc-macro crate. Update/rearrange existing Diagnostic
functions in the proc_macro crate to require passing a LintId
when creating a warning.
// from the openvm use case:
use proc_macro::{LintId, TokenStream};
#[proc_macro_warning] pub static limbs_too_small: LintId;
#[proc_macro]
pub fn moduli_declare(input: TokenStream) -> TokenStream {
...
if limbs < 32 {
limbs = 32;
proc_macro::warning(limbs_too_small, "limbs
has been set to 32 because it was too small");
// or: proc_macro::Diagnostic::warning(limbs_too_small, "`limbs` has been set to 32 because it was too small")
// .note("this is going to be changed once we support more flexible reads")
// .emit()
}
...
}
Within the same proc macro crate, the static (limbs_too_small
) exists in the value namespace. Downstream of the proc macro crate, the same static exists in the macro namespace for the purpose of re-exports. The use of 2 namespaces in such a way is identical to how all proc macro items already work.
Alternatives
The 10 comments under rust-lang/rust#54140 (comment) explore a variety of designs.
- No statically declared lint names. Proc macro can pass a runtime value for the lint name. Downside: you have only informed the compiler about the existence of a particular lint name if that lint is ever triggered. This means no ability to report
unknown_lints
on a typo like#![deny(openvm_macros::limbs_too_smal)]
, and worse rustdoc. - No lint names. Lint level will be controllable only at the level of an entire proc macro crate's lints:
#![deny(diesel_derives::warnings)]
- No lint names. Lint level will be controllable using the path of whichever macro produced them:
#![deny(diesel_derives::Selectable::warnings)]
- No lint names. Lint level will be controllable universally for all macro-generated warnings:
#![deny(warning_from_proc_macro)]
Future work
The following enhancements would not need to block stabilization of a diagnostics API in proc_macro once LintId
exists.
- Support
allow
/warn
/deny
lint level system in the code which calls the proc macro. - Integrate with
unknown_lints
lint. If a user writesdeny(foo::ambiguous_thing)
whenfoo
is not a proc macro crate declaring aambiguous_thing
lint id, nor is this resolved as a re-export of such a lint id, this needs to triggerunknown_lints
. - Render rustdoc documentation for lint ids.
- Mechanism for a proc macro crate to set a default level for each of its lints. By default they are warn-by-default, but some lints might be better as allow-by-default or deny-by-default.
- A style lint that enforces a case convention for lint ids (snake_case).
- Rust-analyzer will want to provide autocomplete for proc macro lint ids inside
allow
/warn
/deny
.
What happens now?
This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
Possible responses
The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):
- We think this problem seems worth solving, and the standard library might be the right place to solve it.
- We think that this probably doesn't belong in the standard library.
Second, if there's a concrete solution:
- We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
- We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.