Skip to content
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

Stabilize lint_reasons in rustc (RFC 2383) #99063

Closed
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ declare_features! (
(accepted, item_like_imports, "1.15.0", Some(35120), None),
/// Allows `if/while p && let q = r && ...` chains.
(accepted, let_chains, "1.64.0", Some(53667), None),
/// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
(accepted, lint_reasons, "1.64.0", Some(54503), None),
/// Allows `break {expr}` with a value inside `loop`s.
(accepted, loop_break_value, "1.19.0", Some(37339), None),
/// Allows use of `?` as the Kleene "at most one" operator in macros.
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,6 @@ declare_features! (
(active, let_else, "1.56.0", Some(87335), None),
/// Allows `#[link(..., cfg(..))]`.
(active, link_cfg, "1.14.0", Some(37406), None),
/// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
(active, lint_reasons, "1.31.0", Some(54503), None),
/// Give access to additional metadata about declarative macro meta-variables.
(active, macro_metavar_expr, "1.61.0", Some(83527), None),
/// Allows `#[marker]` on certain traits allowing overlapping implementations.
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(
allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
),
gated!(
expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk,
lint_reasons, experimental!(expect)
ungated!(
expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
),
ungated!(
forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_lint/src/expect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,13 @@ use rustc_hir::HirId;
use rustc_middle::ty::query::Providers;
use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
use rustc_session::lint::LintExpectationId;
use rustc_span::symbol::sym;
use rustc_span::Symbol;

pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_expectations, ..*providers };
}

fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
if !tcx.sess.features_untracked().enabled(sym::lint_reasons) {
return;
}

let fulfilled_expectations = tcx.sess.diagnostic().steal_fulfilled_expectation_ids();
let lint_expectations = &tcx.lint_levels(()).lint_expectations;

Expand Down
11 changes: 1 addition & 10 deletions compiler/rustc_lint/src/levels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rustc_session::lint::{
builtin::{self, FORBIDDEN_LINT_GROUPS, SINGLE_USE_LIFETIMES, UNFULFILLED_LINT_EXPECTATIONS},
Level, Lint, LintExpectationId, LintId,
};
use rustc_session::parse::{add_feature_diagnostics, feature_err};
use rustc_session::parse::add_feature_diagnostics;
use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
Expand Down Expand Up @@ -306,15 +306,6 @@ impl<'s> LintLevelsBuilder<'s> {
ast::MetaItemKind::NameValue(ref name_value) => {
if item.path == sym::reason {
if let ast::LitKind::Str(rationale, _) = name_value.kind {
if !self.sess.features_untracked().lint_reasons {
feature_err(
&self.sess.parse_sess,
sym::lint_reasons,
item.span,
"lint reasons are experimental",
)
.emit();
}
reason = Some(rationale);
} else {
bad_attr(name_value.span)
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,8 +503,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
/// #![feature(lint_reasons)]
///
/// #[expect(unused_variables)]
/// let x = 10;
/// println!("{}", x);
Expand All @@ -530,8 +528,7 @@ declare_lint! {
/// [#54503]: https://github.com/rust-lang/rust/issues/54503
pub UNFULFILLED_LINT_EXPECTATIONS,
Warn,
"unfulfilled lint expectation",
@feature_gate = rustc_span::sym::lint_reasons;
"unfulfilled lint expectation"
}

declare_lint! {
Expand Down
64 changes: 59 additions & 5 deletions src/doc/rustc/src/lints/levels.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# Lint Levels

In `rustc`, lints are divided into five *levels*:
In `rustc`, lints are divided into six *levels*:

1. allow
2. warn
3. force-warn
4. deny
5. forbid
2. expect
3. warn
4. force-warn
5. deny
6. forbid

Each lint has a default level (explained in the lint listing later in this
chapter), and the compiler has a default warning level. First, let's explain
Expand All @@ -33,6 +34,41 @@ But this code violates the `missing_docs` lint.
These lints exist mostly to be manually turned on via configuration, as we'll
talk about later in this section.

## expect

Sometimes, it can be helpful to suppress lints, but at the same time ensure that
the code in question still emits them. The 'expect' level does exactly this, with
it a lint can be expected. If the lint in question is not an emitted, a new lint
`unfulfilled_lint_expectation` at the attribute notifying you that the expectation,
is no longer fulfilled.
xFrednet marked this conversation as resolved.
Show resolved Hide resolved

```rust
fn main() {
#[expect(unused_variables)]
let unused = "Everyone ignores me";

#[expect(unused_variables)]
let used = "I'm usefull";
flip1995 marked this conversation as resolved.
Show resolved Hide resolved
println!("The `used` value is equal to: {:?}", used);
}
```

This will produce the following warning:

```txt
warning: this lint expectation is unfulfilled
--> src/main.rs:7:14
|
7 | #[expect(unused_variables)]
| ^^^^^^^^^^^^^^^^
|
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
```

This level can only be defined via the `#[expect]` attribute and not via the
console. Lints with the special 'force-warn' lint will still be emitted as usual.
The fulfillment of expectations is still tracked.
xFrednet marked this conversation as resolved.
Show resolved Hide resolved

## warn

The 'warn' lint level will produce a warning if you violate the lint. For example,
Expand Down Expand Up @@ -240,6 +276,24 @@ And use multiple attributes together:
pub fn foo() {}
```

All lint attributes support an additional `reason` parameter, to give context why
a certain attribute was added. This reason will be displayed as part of the lint
message, if the lint is emitted at the defined level.

```rust
use std::path::PathBuf;

pub fn get_path() -> PathBuf {
#[allow(unused_mut, reason = "this is only modified on some platforms")]
let mut file_name = PathBuf::from("git");

#[cfg(target_os = "windows")]
file_name.set_extension("exe");

file_name
}
```

### Capping lints

`rustc` supports a flag, `--cap-lints LEVEL` that sets the "lint cap level."
Expand Down
1 change: 0 additions & 1 deletion src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// check-pass
#![feature(lint_reasons)]

//! This file tests the `#[expect]` attribute implementation for tool lints. The same
//! file is used to test clippy and rustdoc. Any changes to this file should be synced
Expand Down
8 changes: 4 additions & 4 deletions src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
warning: this lint expectation is unfulfilled
--> $DIR/expect-tool-lint-rfc-2383.rs:16:11
--> $DIR/expect-tool-lint-rfc-2383.rs:15:11
|
LL | #![expect(rustdoc::missing_crate_level_docs)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unfulfilled_lint_expectations)]` on by default

warning: this lint expectation is unfulfilled
--> $DIR/expect-tool-lint-rfc-2383.rs:71:14
--> $DIR/expect-tool-lint-rfc-2383.rs:70:14
|
LL | #[expect(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: this lint expectation is unfulfilled
--> $DIR/expect-tool-lint-rfc-2383.rs:76:14
--> $DIR/expect-tool-lint-rfc-2383.rs:75:14
|
LL | #[expect(rustdoc::invalid_html_tags)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: this lint expectation is unfulfilled
--> $DIR/expect-tool-lint-rfc-2383.rs:81:14
--> $DIR/expect-tool-lint-rfc-2383.rs:80:14
|
LL | #[expect(rustdoc::bare_urls)]
| ^^^^^^^^^^^^^^^^^^
Expand Down
2 changes: 0 additions & 2 deletions src/test/ui/empty/empty-attributes.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![feature(lint_reasons)]

#![deny(unused_attributes)]
#![allow()] //~ ERROR unused attribute
#![expect()] //~ ERROR unused attribute
Expand Down
18 changes: 9 additions & 9 deletions src/test/ui/empty/empty-attributes.stderr
Original file line number Diff line number Diff line change
@@ -1,66 +1,66 @@
error: unused attribute
--> $DIR/empty-attributes.rs:11:1
--> $DIR/empty-attributes.rs:9:1
|
LL | #[repr()]
| ^^^^^^^^^ help: remove this attribute
|
note: the lint level is defined here
--> $DIR/empty-attributes.rs:3:9
--> $DIR/empty-attributes.rs:1:9
|
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
= note: attribute `repr` with an empty list has no effect

error: unused attribute
--> $DIR/empty-attributes.rs:14:1
--> $DIR/empty-attributes.rs:12:1
|
LL | #[target_feature()]
| ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
= note: attribute `target_feature` with an empty list has no effect

error: unused attribute
--> $DIR/empty-attributes.rs:4:1
--> $DIR/empty-attributes.rs:2:1
|
LL | #![allow()]
| ^^^^^^^^^^^ help: remove this attribute
|
= note: attribute `allow` with an empty list has no effect

error: unused attribute
--> $DIR/empty-attributes.rs:5:1
--> $DIR/empty-attributes.rs:3:1
|
LL | #![expect()]
| ^^^^^^^^^^^^ help: remove this attribute
|
= note: attribute `expect` with an empty list has no effect

error: unused attribute
--> $DIR/empty-attributes.rs:6:1
--> $DIR/empty-attributes.rs:4:1
|
LL | #![warn()]
| ^^^^^^^^^^ help: remove this attribute
|
= note: attribute `warn` with an empty list has no effect

error: unused attribute
--> $DIR/empty-attributes.rs:7:1
--> $DIR/empty-attributes.rs:5:1
|
LL | #![deny()]
| ^^^^^^^^^^ help: remove this attribute
|
= note: attribute `deny` with an empty list has no effect

error: unused attribute
--> $DIR/empty-attributes.rs:8:1
--> $DIR/empty-attributes.rs:6:1
|
LL | #![forbid()]
| ^^^^^^^^^^^^ help: remove this attribute
|
= note: attribute `forbid` with an empty list has no effect

error: unused attribute
--> $DIR/empty-attributes.rs:9:1
--> $DIR/empty-attributes.rs:7:1
|
LL | #![feature()]
| ^^^^^^^^^^^^^ help: remove this attribute
Expand Down
5 changes: 0 additions & 5 deletions src/test/ui/feature-gates/feature-gate-lint-reasons.rs

This file was deleted.

21 changes: 0 additions & 21 deletions src/test/ui/feature-gates/feature-gate-lint-reasons.stderr

This file was deleted.

2 changes: 0 additions & 2 deletions src/test/ui/lint/empty-lint-attributes.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![feature(lint_reasons)]

// check-pass

// Empty (and reason-only) lint attributes are legal—although we may want to
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// check-pass
#![feature(lint_reasons)]

#[expect(drop_bounds)]
fn trigger_rustc_lints<T: Drop>() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// check-pass

#![feature(lint_reasons)]

#![warn(unused)]

// This expect attribute should catch all lint triggers
Expand Down
2 changes: 0 additions & 2 deletions src/test/ui/lint/rfc-2383-lint-reason/crate_level_expect.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// check-pass

#![feature(lint_reasons)]

#![warn(unused)]

#![expect(unused_mut)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
warning: this lint expectation is unfulfilled
--> $DIR/crate_level_expect.rs:7:11
--> $DIR/crate_level_expect.rs:5:11
|
LL | #![expect(unused_mut)]
| ^^^^^^^^^^
Expand Down
2 changes: 0 additions & 2 deletions src/test/ui/lint/rfc-2383-lint-reason/expect_inside_macro.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// check-pass

#![feature(lint_reasons)]

#![warn(unused)]

macro_rules! expect_inside_macro {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// check-pass

#![feature(lint_reasons)]

#![warn(unused_variables)]

macro_rules! trigger_unused_variables_macro {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
warning: unused variable: `x`
--> $DIR/expect_lint_from_macro.rs:9:13
--> $DIR/expect_lint_from_macro.rs:7:13
|
LL | let x = 0;
| ^ help: if this is intentional, prefix it with an underscore: `_x`
Expand All @@ -8,14 +8,14 @@ LL | trigger_unused_variables_macro!();
| --------------------------------- in this macro invocation
|
note: the lint level is defined here
--> $DIR/expect_lint_from_macro.rs:5:9
--> $DIR/expect_lint_from_macro.rs:3:9
|
LL | #![warn(unused_variables)]
| ^^^^^^^^^^^^^^^^
= note: this warning originates in the macro `trigger_unused_variables_macro` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: unused variable: `x`
--> $DIR/expect_lint_from_macro.rs:9:13
--> $DIR/expect_lint_from_macro.rs:7:13
|
LL | let x = 0;
| ^ help: if this is intentional, prefix it with an underscore: `_x`
Expand Down
Loading