1. Symptoms
When the Rust compiler encounters code that attempts to deny or allow a lint attribute that has been removed from the compiler, it produces error E0636. This error manifests during the compilation phase and prevents the code from building successfully.
The compiler output typically displays the error along with the specific lint name that is no longer recognized:
error[E0636]: this lint attribute has been removed
|
= help: the lint `old_lint_name` has been removed
= note: see issue #12345 for more information
--> src/main.rs:3:10
|
3 | #[deny(old_lint_name)]
| ^^^^^^^^^^^^^^^ removed lint
In some cases, the error may also appear when using #[allow] instead of #[deny] on the deprecated lint. The compiler treats both deny and allow directives equally when the underlying lint has been removed, since the directive itself cannot be processed without a valid lint to target.
You might encounter this error after upgrading your Rust toolchain to a newer version, particularly when migrating code that was written against an older Rust release. Lint attributes that were once valid become problematic when the Rust team determines that the lint is no longer necessary, was a false positive, or has been superseded by a better diagnostic mechanism.
2. Root Cause
Error E0636 arises from a fundamental mismatch between the lint attributes present in your source code and the current state of the Rust compiler’s lint registry. The Rust compiler maintains an internal registry of lints that it knows how to recognize and process. When a lint is deemed unnecessary, harmful, or redundant, the Rust team removes it from this registry entirely.
The removal of lints can occur for several reasons. First, the lint may have been addressing a pattern that the language itself evolved to handle differently, making the lint obsolete. Second, the lint might have been generating excessive false positives that frustrated developers more than it helped them. Third, the lint could have been replaced by a more precise or configurable alternative that provides better diagnostics.
When you write #[deny(lint_name)] or #[allow(lint_name)] in your code, the compiler attempts to look up the specified lint in its registry. If the lint has been removed, this lookup fails, and the compiler cannot proceed with the attribute application. The error message explicitly states that the lint attribute has been removed, guiding developers toward understanding that the lint itself no longer exists rather than being merely unstable or deprecated.
This situation commonly occurs during Rust toolchain upgrades. Code that compiled successfully on Rust 1.50 may fail to compile on Rust 1.70 if the codebase contained attributes targeting a lint that was removed between those versions. The compiler is conservative in these situations because applying a deny or allow directive to a non-existent lint could mask real issues or create confusion about what restrictions are actually in effect.
3. Step-by-Step Fix
The fix for E0636 requires removing or updating the lint attribute that references the removed lint. The exact approach depends on what the removed lint was intended to accomplish and whether an alternative lint or language feature now handles the same concern.
Before:
#![deny(raw_pointer_derive)]
struct MyStruct {
data: i32,
}
fn main() {
println!("This code uses a removed lint attribute");
}
After:
// Removed the denied lint attribute entirely
// The lint was deemed unnecessary by the Rust team
struct MyStruct {
data: i32,
}
fn main() {
println!("Code compiles without the obsolete lint attribute");
}
Step 1: Identify the removed lint
Read the error message carefully to identify the exact name of the lint that has been removed. The error output includes the lint name in the message and provides a link to the relevant issue or pull request that explains the removal rationale.
Step 2: Research the removal reason
Search the Rust changelog or the linked issue to understand why the lint was removed. This helps determine whether you need to replace it with an alternative lint, change your code pattern, or simply remove the attribute.
Step 3: Remove or replace the attribute
If the lint is no longer relevant (which is often the case), simply remove the #[deny(lint_name)] or #[allow(lint_name)] attribute from your code. If a replacement lint exists, update the attribute to use the new lint name.
Before:
#![allow(unused_imports)]
#[deny(superstellar)]
mod old_module {
use std::collections::HashMap;
}
After:
#![allow(unused_imports)]
// Removed #[deny(superstellar)] as the lint was removed
// If concerned about specific issues, use relevant current lints
mod old_module {
use std::collections::HashMap;
}
Step 4: Verify in Cargo.toml for crate-level lints
Check your Cargo.toml file for any [lints.rust] or [lints] sections that might define the removed lint. Crate-level lint configuration also needs updating when lints are removed.
Before:
[lints.rust]
superstellar = "deny"
After:
[lints.rust]
# Removed: stellar = "deny"
# The stellar lint was removed in Rust 1.70
4. Verification
After removing or updating the lint attribute, recompile your project to verify the fix resolves the error. Use cargo build or cargo check to trigger a fresh compilation and confirm that E0636 no longer appears in the output.
cargo build
A successful verification produces output showing no errors:
Compiling my-project v0.1.0 (path/to/my-project)
Finished dev [unoptimized + debuginfo] target(s) in 0.52s
If the removed lint was enforcing a coding standard in your project, consider adding a CI check that verifies the code continues to follow the intended patterns through alternative means. You might use clippy with specific rules or implement custom lints through procedural macros if strict enforcement is necessary.
Run your test suite to ensure that removing the lint attribute does not introduce regressions:
cargo test
Check that all tests pass after the change. If tests fail, investigate whether the removed lint was catching a genuine issue that requires a different solution, such as refactoring the affected code or enabling a replacement lint.
5. Common Pitfalls
One frequent mistake is blindly removing lint attributes without investigating whether the underlying concern they addressed still applies. When a lint is removed, the Rust team generally determines that the lint was more harmful than helpful, but this does not mean the code patterns it flagged were necessarily acceptable. Take time to review the code affected by the removed lint to ensure no genuine issues remain.
Another pitfall involves global lint attributes in lib.rs or main.rs files that target multiple removed lints. If your project has been using several deprecated lints, you may encounter E0636 multiple times in a single compilation. Address each occurrence systematically rather than stopping at the first error, as the compiler stops at the first error by default and additional issues may exist.
Be cautious when copying lint configurations from online examples or outdated tutorials. Lint configurations that were valid in older Rust versions may reference lints that have since been removed. Always verify that lint names in your configuration match current lints in the Rust lint registry.
When maintaining crates that support multiple Rust versions, consider using conditional compilation or version-specific attributes to manage removed lints gracefully. However, in most cases, simply removing the attribute for all supported versions is appropriate if the lint was genuinely unnecessary.
Finally, avoid the temptation to suppress E0636 itself using #[allow(E0636)]. This error exists to inform you of outdated configuration that should be cleaned up. Suppressing it masks the problem rather than solving it and may cause confusion for future maintainers who encounter unexplained suppressions in the codebase.
6. Related Errors
E0600: Ambiguous import, x could refer to a locally defined item
This error occurs when an import is ambiguous and could refer to multiple possible targets. Unlike E0636 which concerns removed lint attributes, E0600 relates to import resolution and typically requires qualifying the import with a module path or renaming the import to disambiguate.
E0658: x is not yet stable as a lint
This error appears when attempting to use a lint that exists but is not yet stable. Unlike E0636, which targets lints that have been removed entirely, E0658 indicates the lint exists but cannot be used without enabling a nightly feature or reaching a future stable release. The distinction matters because E0658 lints may become available in the future, whereas E0636 lints are permanently removed.
E0733: async fn in trait is unstable
This error concerns async function stability in traits rather than lint attributes. While unrelated to lint removal, it shares a similar structure where a feature cannot be used in the current context. Understanding this pattern helps recognize when Rust features or attributes are unavailable due to stability constraints versus complete removal from the compiler.