# Pre-RFC: Implementation-defined Lints

**URL:** <https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870>\
**Category:** language design\
**Created:** [January 20, 2021, 1:09pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870 "2021-01-20T13:09:03Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![InfernoDeity](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infernodeity/32/7588_2.png) [@InfernoDeity](https://internals.rust-lang.org/u/InfernoDeity)\
**Post date:** [January 20, 2021, 1:09pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/1 "2021-01-20T13:09:04Z")

</div>

Reading through the documentation on lints, it seems like really isn't an opening for lints defined by the implementation that are accepted by other implementations (even if they do not support such lints). As someone working on an alternative implementation of rust, I would like to propose such a mechanism, for implementations to define lints beyond those which are a part of the core language. This mechanism is "implementation-defined" lints, which extends [tool lints](https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#tool-lint-attributes)

A lint name of the form `IDENTIFIER::SimplePath` is an implementation-defined lint. An implementation shall accept any lint of this form, and issue no diagnostic for an unrecongized lint in this form, except that it may issue an implementation-defined warn-by-default lint if an unrecognized lint name occurs within the tool-name chosen below. The lints of this form that are recognized and their meanings are _implementation-defined_. An implementation should choose a tool-name that all lints recognized by it are defined within, and may accept variants on that namespace with the same meaning (for example, if an implementation accepts implementation-defined lints with the `foo` namespace, it could also accept ` __foo` and `__ foo__`).

This (Pre-)RFC recommends the use of the `rustc` namespace by the rustc compiler. Whether or not it accepts variants of this namespace is not specified. All existing lints for rustc should be categorized as core language and implementation-defined, and the latter should be renamed to this form and have it's original form deprecated. This (Pre-)RFC does not provide any recommendations for how existing lints are categorized. A future RFC is recommended to define this split, and the former category shall become mandatory for implementations to be implemented. Implementations should accept, and may issue a lint, for attributes in the second category.

For compatibility with existing tool lints, the `clippy` namespace is reserved for use with the tool `clippy`, and continues to operate as specified in [RFC 2103](https://rust-lang.github.io/rfcs/2103-tool-attributes.html) and [RFC 2476](https://rust-lang.github.io/rfcs/2476-clippy-uno.html) as well as any others I have not mentioned to this effect. Future tools that make use of tool lints should use the mechanism prescribed here.

Open Question: This Pre-RFC only seeks to extend lints, but it may be useful similarily extend attributes. One note is that attributes may have effects beyond changing a lint level, and the policy for lint level changes is that lints are minor changes. It is possible that use of (undefined) attributes of this form may be sufficient to "opt-in" to breaking changes from future compiler versions and use in alternative implementations.

---

<div class="post-metadata">

**Author:** ![jyn514](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jyn514/32/13245_2.png) [@jyn514](https://internals.rust-lang.org/u/jyn514)\
**Post date:** [January 20, 2021, 2:49pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/2 "2021-01-20T14:49:49Z")

</div>

Note that the rustc:: prefix is already used for internal lints, so it would have to be renamed to rustc\_internal or something. But that's not a big deal, all the internal lints are unstable anyway.

---

<div class="post-metadata">

**Author:** ![jyn514](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jyn514/32/13245_2.png) [@jyn514](https://internals.rust-lang.org/u/jyn514)\
**Post date:** [January 20, 2021, 2:52pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/3 "2021-01-20T14:52:26Z")

</div>

Also note that rustdoc lints are about to become tool lints: [Make rustdoc lints a tool lint instead of built-in by jyn514 · Pull Request #80527 · rust-lang/rust · GitHub](https://github.com/rust-lang/rust/pull/80527#issuecomment-762304423). So I guess under your scheme they'd have to be reserved too? I don't understand the difference between an "implemention defined lint" and a normal tool lint.

---

<div class="post-metadata">

**Author:** ![InfernoDeity](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infernodeity/32/7588_2.png) [@InfernoDeity](https://internals.rust-lang.org/u/InfernoDeity)\
**Post date:** [January 20, 2021, 3:07pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/4 "2021-01-20T15:07:45Z")

</div>

> [@jyn514](#):
>
> I don't understand that the difference between an "implemention defined lint" and a normal tool lint.

I'm not sure if there is a semantic difference, actually. It's basically a "don't use this tool-name" unless you are this tool, or provide something identical to it (which is already . The reason why I reserved clippy was because if there was a difference between the existing scheme and this one (other than removing the "unknown tool name" error), I wanted to not break code that already used clippy. I could probably look into it in more depth, but otherwise, `rustdoc` probably could be likewise reserved and fall under the existing 2103 rules. If there isn't a difference, RFC 2476 would almost certainly count as sufficient documentation for the former, and I'm sure something equivalent exists for the latter, and they could simply fall under these rules.

> [@jyn514](#):
>
> Note that the rustc:: prefix is already used for internal lints, so it would have to be renamed to rustc\_internal or something. But that's not a big deal, all the internal lints are unstable anyway

Unstable lints may pose an issue to this. While I think that requiring a feature to enable it could fall under implementation-defined meanings, it would cause a disparity between implementations, where one implmentation accepts but ignores them, and then rustc errors unless you enable a feature (whereas for any other lint under these rules, an error would only occur for `deny` and `forbid`, so the behaviour may be suprising). One possibly would be making an exception, and reserving certain names as ill-formed unless accepted, but I'd rather not specify an exception for just rustc. I am open to suggestions in that regard.

---

<div class="post-metadata">

**Author:** ![jyn514](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jyn514/32/13245_2.png) [@jyn514](https://internals.rust-lang.org/u/jyn514)\
**Post date:** [January 20, 2021, 6:00pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/5 "2021-01-20T18:00:07Z")

</div>

If there is no difference between tool lints and implementation lints, I'm not quite sure what you're suggesting. Is the point to separate "core language" lints from lints related to the current implementation, by putting them in different namespaces? I don't know if that makes sense to do - for example, the warning for `[].into_iter()` only exists because we want to add `impl IntoIterator for [T; N]` at some point, but it's not implemented yet. It's both a language and implementation lint.

I also think any changes here will be a lot of churn, and I'm not sure what benefit they bring.

---

<div class="post-metadata">

**Author:** ![InfernoDeity](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infernodeity/32/7588_2.png) [@InfernoDeity](https://internals.rust-lang.org/u/InfernoDeity)\
**Post date:** [January 20, 2021, 6:22pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/6 "2021-01-20T18:22:07Z")

</div>

> [@jyn514](#):
>
> If there is no difference between tool lints and implementation lints, I'm not quite sure what you're suggesting. Is the point to separate "core language" lints from lints related to the current implementation, by putting them in different namespaces?

The goal is to allow different implementations of rust to provide additional lints that can be manipulated by user crates without having to worry about whether the particular implementation is in-use. A particular example I had was [https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=996ad6894fee3b3796fcfa78d92cf8d0](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=996ad6894fee3b3796fcfa78d92cf8d0), which uses the `lccc::pedantic` lint from the implementation I am working on ([lccc](https://github.com/LightningCreations/lccc)). Currently, this would only be "valid" code when built in lccc (on rustc, this gives an unknown tool error, on lccc, this would trigger the `lccc::rust_union_layout` and `lccc::pointer_interconversion` lints). Additionally, a goal is to decide the lints implemented in rustc that should are considered part of the "core language", that is, something that all implementations should provide, and not simply a lint that rustc does provide.

> [@jyn514](#):
>
> I don't know if that makes sense to do - for example, the warning for `[].into_iter()` only exists because we want to add `impl IntoIterator for [T; N]` at some point, but it's not implemented yet. It's both a language and implementation lint.

For a lint like this, I would assume it would be a core language lint, but is triggered because of the implementation (for example, using an attribute, or a stability flag. I don't know what this particular lint is off the top of my head). It would be similar to the `incomplete_features` lint, which should be core language, but different implementations would apply it for different features (or, if it doesn't support unstable features, for example, `stable` rustc, it wouldn't apply it at all).

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [January 20, 2021, 8:36pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/7 "2021-01-20T20:36:13Z")

</div>

> [@InfernoDeity](#):
>
> it seems like really isn't an opening for lints defined by the implementation that are accepted by other implementations

Honestly, I think essentially all lints should be considered quality-of-implementation questions, not part of the core language. Given that changing lints is a "minor change" anyway...

---

<div class="post-metadata">

**Author:** ![InfernoDeity](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infernodeity/32/7588_2.png) [@InfernoDeity](https://internals.rust-lang.org/u/InfernoDeity)\
**Post date:** [January 20, 2021, 9:13pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/8 "2021-01-20T21:13:48Z")

</div>

> [@scottmcm](#):
>
> I think essentially all lints should be considered quality-of-implementation questions, not part of the core language

If that's a good way to go, then it should be, however I'd still recommend the use of namespaced lints for this. I did just check, and simply using `deny(pedantic)` does not error (it does warn though, which makes it incompatible with `deny(warnings)`. Seems interesting, though). Though, I believe that adding a lint is a question for the Lang Team, not the Compiler Team, so it seems to me like that would make it a question of the core language.

---

<div class="post-metadata">

**Author:** ![jyn514](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jyn514/32/13245_2.png) [@jyn514](https://internals.rust-lang.org/u/jyn514)\
**Post date:** [January 21, 2021, 12:54am UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/9 "2021-01-21T00:54:28Z")

</div>

> A particular example I had was [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=996ad6894fee3b3796fcfa78d92cf8d0), which uses the `lccc::pedantic` lint from the implementation I am working on ([lccc](https://github.com/LightningCreations/lccc)). Currently, this would only be "valid" code when built in lccc (on rustc, this gives an unknown tool error, on lccc, this would trigger the `lccc::rust_union_layout` and `lccc::pointer_interconversion` lints)

It sounds like what you actually need is a way to register tool lints. I think @flip1995 mentioned something like this that's opt-in, but I can't find it documented anywhere. I think having `#[register_tool("lccc")]` or something would be a better approach than splitting up the existing lints, though.That would be pretty easy to implement, just add a check here: [https://github.com/rust-lang/rust/blob/a1a13b2bc4fa6370b9501135d97c5fe0bc401894/compiler/rustc\_lint/src/levels.rs#L244](https://github.com/rust-lang/rust/blob/a1a13b2bc4fa6370b9501135d97c5fe0bc401894/compiler/rustc_lint/src/levels.rs#L244)

---

<div class="post-metadata">

**Author:** ![flip1995](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/flip1995/32/7662_2.png) [@flip1995](https://internals.rust-lang.org/u/flip1995)\
**Post date:** [January 21, 2021, 11:34am UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/10 "2021-01-21T11:34:16Z")

</div>

Yeah, what you asking for is exactly what tool lints are for. This is already an accepted feature and implemented in the compiler. Currently the tool lint feature can only be used (by implementer) by Clippy and soon rustdoc, because of a a hard coded whitelist. This was also the case for tool attributes when those were first implemented and then was removed once the first non-official tool wanted to use tool attributes.

If you want to use tool lints attributes, the only thing that currently blocks you is that hard coded whitelist, which causes the unknown tool error. The only reason why this whitelist is still there is that no one complained about it. If you're willing to put some work into this (mostly writing tests and making sure existing tools don't break), I'm supporting removing this whitelist and open up tool lints for everyone.

---

<div class="post-metadata">

**Author:** ![InfernoDeity](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infernodeity/32/7588_2.png) [@InfernoDeity](https://internals.rust-lang.org/u/InfernoDeity)\
**Post date:** [January 21, 2021, 3:37pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/11 "2021-01-21T15:37:54Z")

</div>

> [@flip1995](#):
>
> Yeah, what you asking for is exactly what tool lints are for. This is already an accepted feature and implemented in the compiler. Currently the tool lint feature can only be used (by implementer) by Clippy and soon rustdoc, because of a a hard coded whitelist

Yeah, the proposal seeks to remove the whitelist. The split of lints was so that rustc lints can also participate the same way without being warned (or denied) about by implementations that don't understand a particular lint. The issue I raised works both, ways. For example, an implementation that does not have unstable features may not include the `stable_features` lint. In such an implementation, naming this lint explicitly would cause a compile-time error when used with `deny(warnings)` as it would trip `unknown_lints`.

---

<div class="post-metadata">

**Author:** ![jyn514](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jyn514/32/13245_2.png) [@jyn514](https://internals.rust-lang.org/u/jyn514)\
**Post date:** [January 21, 2021, 4:27pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/12 "2021-01-21T16:27:46Z")

</div>

Using deny(warnings) is a bad idea in general, though, it will break any time a new lint is added on nightly (which is why the stability guarantees explicitly don't cover it). Docs.rs uses --cap-lints warn for exactly this reason.

---

<div class="post-metadata">

**Author:** ![flip1995](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/flip1995/32/7662_2.png) [@flip1995](https://internals.rust-lang.org/u/flip1995)\
**Post date:** [January 21, 2021, 5:08pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/13 "2021-01-21T17:08:44Z")

</div>

> Yeah, the proposal seeks to remove the whitelist.

I'm good with that. If you want to address this in rustc, I'm happy to mentor this work.

> In such an implementation, naming this lint explicitly would cause a compile-time error when used with `deny(warnings)` as it would trip `unknown_lints`.

Just that I understand you correctly: Are you proposing that there shouldn't be any "unscoped" lints and that `rustc` lints should be used with the `rustc::` prefix? If that is the case, then I'm afraid that this will never happen. According to the Rust reference there are [Lint check attributes](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#lint-check-attributes) where the name is unscoped. It is not specified how a Rust compiler treats unknown lints. `rustc` made the decision, that it will warn on unknown lints. If you're implementing a compiler it is up to you how to deal with unknown lints. If you also warn on them and don't implement all of the lints of `rustc`, than you will run into the problem, you're having. But you could also just ignore unknown lints, or keep a list of known rustc lints, that aren't in your compiler.

On the other hand, if you want to add lints to your compiler, that aren't in `rustc`, you can either use tool lints (given the whitelist is gone), to prevent rustc to warn on your lints, or you can just use normal lints and be fine with `rustc` triggering `unknown_lints` on them. In the later case, users of your compiler, that also want to use `rustc` will have to add lints with `#[cfg_attr(feature = "lccc", warn(your_own_lint)]` (this is how Clippy did it before tool lints).

---

<div class="post-metadata">

**Author:** ![InfernoDeity](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infernodeity/32/7588_2.png) [@InfernoDeity](https://internals.rust-lang.org/u/InfernoDeity)\
**Post date:** [January 21, 2021, 7:51pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/14 "2021-01-21T19:51:56Z")

</div>

> [@flip1995](#):
>
> If you want to address this in rustc, I'm happy to mentor this work

I'd prefer bringing the proposal to the stage it needs to be brought. I'm trying to avoid the rustc source code while working on lccc.

> [@flip1995](#):
>
> If you're implementing a compiler it is up to you how to deal with unknown lints. If you also warn on them and don't implement all of the lints of `rustc` , than you will run into the problem, you're having. But you could also just ignore unknown lints, or keep a list of known rustc lints, that aren't in your compiler

This sort of sounds like a "if you don't have a lint we do, it's your problem, but if you do have a lint we don't, it's also your problem." Keeping a list for rustc is fairly simple, there's a documented one, and I wouldn't need to update it nightly (since the goal is, when finished, it will be compatible with latest stable rustc after 2 weeks). The problem comes when there are several implementations, each deciding how to deal with lints. The idea here was to provide a consistent mechanism for all implementations to use.

In any case, would something like this be better:

> [@](#):
>
> - A lint name of the form `IDENTIFIER::SimplePath` is an implementation-specific lint. An implementation shall document the lints of this form which it recognize. Otherwise, the implementation shall accept but ignore any lints of this form, except that it may issue a warn-by-default lint for any lints with any implementation-defined prefix. It is recommended that implementations define lints only in a specific chosen prefix.
> - A lint name of the form `IDENTIFIER` is a standard lint. The lints of this form which the compiler accepts are implementation-defined, but shall at least include the item `warnings`. If a lint that is not accepted is used by the program, the result is implementation-defined.

In any case, both forms should be documented as implementation-defined. However, lints of the latter form should really be deprecated, or simply accepted. In any case, code using any unscoped lints would be inherently non-portable, whereas those using the scoped forms would not. That was the idea with the split. That the people who defined the lints would decide which ones are common enough that they should be left unscoped, so all implementations should accept them, and the rest moved to the scoped system where implementations can (and should) simply ignore them.

> [@flip1995](#):
>
> `#[cfg_attr(feature = "lccc", warn(your_own_lint)]`

A while back, I proposed `cfg(has_rustc = "<whatever>")` (which, in retrospect, is a very poor name, something like `cfg(rust_vendor = "<whatever>")` would have been better), where the "whatever" was implementation defined. However it did not get very far for a few reasons, so it would have to be detected manually by the package. This seems reasonable for things like unstable features, however, having to detect this for a lint is a bit excessive.

---

<div class="post-metadata">

**Author:** ![flip1995](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/flip1995/32/7662_2.png) [@flip1995](https://internals.rust-lang.org/u/flip1995)\
**Post date:** [January 21, 2021, 8:39pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/15 "2021-01-21T20:39:10Z")

</div>

> I'd prefer bringing the proposal to the stage it needs to be brought

I don't see a proposal here. What you describe are tool lints. `rustc` lints won't be renamed. I mean you can try, but something that exists for over 5 years like this in the language will not change. Especially not, if it complicates things.

> This sort of sounds like a "if you don't have a lint we do, it's your problem, but if you do have a lint we don't, it's also your problem."

Not at all. It isn't the responsibility of `rustc` to take care of what other compilers do. It is also not the responsibility of your compiler to take care of things `rustc` does. But I admit that it may be interpreted like this, but this is because `rustc` was the first compiler (and currently the only one).

If your compiler has the requirement, that it has to conform to lints implemented in another compiler, this is on your compiler. The alternative would be that every Rust compiler would have to know about every other Rust compiler and know about all lints they implement or don't implement.

`rustc` is conform with The Rust Reference. You could propose to change the reference, but I doubt that this will be successful.

> A lint name of the form `IDENTIFIER` is a standard lint.

And who says what a standard lint is? Let's say lccc and rustc agree on a standard set. What if a 3rd compiler is implemented and it decides to not implement any lints. Would the list then be updated? Or does the 3rd compiler have to deal with those lints in another way?

Also: Aren't standard lints just errors? (philosophical question)

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [April 21, 2021, 8:39pm UTC](https://internals.rust-lang.org/t/pre-rfc-implementation-defined-lints/13870/16 "2021-04-21T20:39:11Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
