diff options
| author | Jana Dönszelmann <jana@donsz.nl> | 2025-08-11 11:46:30 +0200 |
|---|---|---|
| committer | Jana Dönszelmann <jana@donsz.nl> | 2025-08-24 09:14:49 +0200 |
| commit | 4b35cde904c1015df42b2c63244c1db1ed51fff9 (patch) | |
| tree | 244f6f84dd796164a0d9e1be2ce8775f6f498352 | |
| parent | 3bf61444616fc0b9de1e09031f40be0943823fc5 (diff) | |
| download | rust-4b35cde904c1015df42b2c63244c1db1ed51fff9.tar.gz rust-4b35cde904c1015df42b2c63244c1db1ed51fff9.zip | |
Support lints in early attribute parsing
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/interface.rs | 32 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/lints.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/session_diagnostics.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_errors/Cargo.toml | 1 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/lib.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/context.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_session/src/session.rs | 17 | ||||
| -rw-r--r-- | tests/ui/lint/unused/unused_attributes-must_use.fixed | 2 | ||||
| -rw-r--r-- | tests/ui/lint/unused/unused_attributes-must_use.rs | 2 | ||||
| -rw-r--r-- | tests/ui/lint/unused/unused_attributes-must_use.stderr | 63 |
11 files changed, 93 insertions, 45 deletions
diff --git a/Cargo.lock b/Cargo.lock index 89392631127..af206e87c45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3791,7 +3791,6 @@ dependencies = [ "rustc_error_messages", "rustc_fluent_macro", "rustc_hashes", - "rustc_hir_id", "rustc_index", "rustc_lexer", "rustc_lint_defs", diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b4222e41b71..60523c2877c 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -51,6 +51,27 @@ impl<'sess> AttributeParser<'sess, Early> { target_node_id: NodeId, features: Option<&'sess Features>, ) -> Option<Attribute> { + Self::parse_limited_should_emit( + sess, + attrs, + sym, + target_span, + target_node_id, + features, + ShouldEmit::Nothing, + ) + } + + /// Usually you want `parse_limited`, which defaults to no errors. + pub fn parse_limited_should_emit( + sess: &'sess Session, + attrs: &[ast::Attribute], + sym: Symbol, + target_span: Span, + target_node_id: NodeId, + features: Option<&'sess Features>, + should_emit: ShouldEmit, + ) -> Option<Attribute> { let mut parsed = Self::parse_limited_all( sess, attrs, @@ -59,7 +80,7 @@ impl<'sess> AttributeParser<'sess, Early> { target_span, target_node_id, features, - ShouldEmit::Nothing, + should_emit, ); assert!(parsed.len() <= 1); parsed.pop() @@ -84,9 +105,8 @@ impl<'sess> AttributeParser<'sess, Early> { target, OmitDoc::Skip, std::convert::identity, - |_lint| { - // FIXME: Can't emit lints here for now - // This branch can be hit when an attribute produces a warning during early parsing (such as attributes on macro calls) + |lint| { + crate::lints::emit_attribute_lint(&lint, sess); }, ) } @@ -121,8 +141,8 @@ impl<'sess> AttributeParser<'sess, Early> { cx: &mut parser, target_span, target_id: target_node_id, - emit_lint: &mut |_lint| { - panic!("can't emit lints here for now (nothing uses this atm)"); + emit_lint: &mut |lint| { + crate::lints::emit_attribute_lint(&lint, sess); }, }, attr_span: attr.span, diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 7030f28f23c..069478e7f0c 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -1,13 +1,13 @@ use std::borrow::Cow; use rustc_errors::{DiagArgValue, LintEmitter}; +use rustc_hir::Target; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{HirId, Target}; use rustc_span::sym; use crate::session_diagnostics; -pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) { +pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emitter: L) { let AttributeLint { id, span, kind } = lint; match kind { @@ -51,7 +51,7 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emi *id, *span, session_diagnostics::InvalidTargetLint { - name, + name: name.clone(), target: target.plural_name(), applied: DiagArgValue::StrListSepByAnd( applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2192e8f8f83..72bee0ddfbf 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -484,9 +484,9 @@ pub(crate) struct EmptyAttributeList { #[diag(attr_parsing_invalid_target_lint)] #[warning] #[help] -pub(crate) struct InvalidTargetLint<'a> { - pub name: &'a AttrPath, - pub target: &'a str, +pub(crate) struct InvalidTargetLint { + pub name: AttrPath, + pub target: &'static str, pub applied: DiagArgValue, pub only: &'static str, #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index f37b6fb748f..7912b8e6098 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -14,7 +14,6 @@ rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hashes = { path = "../rustc_hashes" } -rustc_hir_id = { path = "../rustc_hir_id" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 38c5716348f..71fc54f0d33 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -61,7 +61,6 @@ pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display, }; use rustc_hashes::Hash128; -use rustc_hir_id::HirId; pub use rustc_lint_defs::{Applicability, listify, pluralize}; use rustc_lint_defs::{Lint, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; @@ -110,13 +109,14 @@ rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); /// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`. /// Always the `TyCtxt`. pub trait LintEmitter: Copy { + type Id: Copy; #[track_caller] fn emit_node_span_lint( self, lint: &'static Lint, - hir_id: HirId, + hir_id: Self::Id, span: impl Into<MultiSpan>, - decorator: impl for<'a> LintDiagnostic<'a, ()>, + decorator: impl for<'a> LintDiagnostic<'a, ()> + DynSend + 'static, ); } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c215e44a965..4990a85466e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1421,6 +1421,8 @@ pub struct TyCtxt<'tcx> { } impl<'tcx> LintEmitter for TyCtxt<'tcx> { + type Id = HirId; + fn emit_node_span_lint( self, lint: &'static Lint, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index bb7ffa2a85d..96767d05439 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -7,6 +7,7 @@ use std::sync::atomic::AtomicBool; use std::{env, fmt, io}; use rand::{RngCore, rng}; +use rustc_ast::NodeId; use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; @@ -22,7 +23,7 @@ use rustc_errors::timings::TimingSectionHandler; use rustc_errors::translation::Translator; use rustc_errors::{ Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort, - TerminalUrl, fallback_fluent_bundle, + LintEmitter, TerminalUrl, fallback_fluent_bundle, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -223,6 +224,20 @@ pub struct Session { pub invocation_temp: Option<String>, } +impl LintEmitter for &'_ Session { + type Id = NodeId; + + fn emit_node_span_lint( + self, + lint: &'static rustc_lint_defs::Lint, + node_id: Self::Id, + span: impl Into<rustc_errors::MultiSpan>, + decorator: impl for<'a> rustc_errors::LintDiagnostic<'a, ()> + DynSend + 'static, + ) { + self.psess.buffer_lint(lint, span, node_id, decorator); + } +} + #[derive(Clone, Copy)] pub enum CodegenUnits { /// Specified by the user. In this case we try fairly hard to produce the diff --git a/tests/ui/lint/unused/unused_attributes-must_use.fixed b/tests/ui/lint/unused/unused_attributes-must_use.fixed index 2e800cbff3f..6bc63c8ee5b 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.fixed +++ b/tests/ui/lint/unused/unused_attributes-must_use.fixed @@ -66,6 +66,8 @@ extern "Rust" { } //~ ERROR unused attribute +//~^ ERROR `#[must_use]` attribute cannot be used on macro calls +//~| WARN this was previously accepted by the compiler but is being phased out global_asm!(""); //~ ERROR attribute cannot be used on diff --git a/tests/ui/lint/unused/unused_attributes-must_use.rs b/tests/ui/lint/unused/unused_attributes-must_use.rs index c41c6c1d706..3c0d76e619f 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.rs +++ b/tests/ui/lint/unused/unused_attributes-must_use.rs @@ -66,6 +66,8 @@ extern "Rust" { } #[must_use] //~ ERROR unused attribute +//~^ ERROR `#[must_use]` attribute cannot be used on macro calls +//~| WARN this was previously accepted by the compiler but is being phased out global_asm!(""); #[must_use] //~ ERROR attribute cannot be used on diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 03baea3a004..231d799057c 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -1,20 +1,29 @@ -error: unused attribute `must_use` +error: `#[must_use]` attribute cannot be used on macro calls --> $DIR/unused_attributes-must_use.rs:68:1 | LL | #[must_use] | ^^^^^^^^^^^ | -note: the built-in attribute `must_use` will be ignored, since it's applied to the macro invocation `global_asm` - --> $DIR/unused_attributes-must_use.rs:69:1 - | -LL | global_asm!(""); - | ^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[must_use]` can be applied to functions, data types, unions, and traits note: the lint level is defined here --> $DIR/unused_attributes-must_use.rs:4:9 | LL | #![deny(unused_attributes, unused_must_use)] | ^^^^^^^^^^^^^^^^^ +error: unused attribute `must_use` + --> $DIR/unused_attributes-must_use.rs:68:1 + | +LL | #[must_use] + | ^^^^^^^^^^^ + | +note: the built-in attribute `must_use` will be ignored, since it's applied to the macro invocation `global_asm` + --> $DIR/unused_attributes-must_use.rs:71:1 + | +LL | global_asm!(""); + | ^^^^^^^^^^ + error: `#[must_use]` attribute cannot be used on extern crates --> $DIR/unused_attributes-must_use.rs:7:1 | @@ -88,7 +97,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on type aliases - --> $DIR/unused_attributes-must_use.rs:71:1 + --> $DIR/unused_attributes-must_use.rs:73:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -97,7 +106,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on function params - --> $DIR/unused_attributes-must_use.rs:75:8 + --> $DIR/unused_attributes-must_use.rs:77:8 | LL | fn qux<#[must_use] T>(_: T) {} | ^^^^^^^^^^^ @@ -106,7 +115,7 @@ LL | fn qux<#[must_use] T>(_: T) {} = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on associated consts - --> $DIR/unused_attributes-must_use.rs:80:5 + --> $DIR/unused_attributes-must_use.rs:82:5 | LL | #[must_use] | ^^^^^^^^^^^ @@ -115,7 +124,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on associated types - --> $DIR/unused_attributes-must_use.rs:83:5 + --> $DIR/unused_attributes-must_use.rs:85:5 | LL | #[must_use] | ^^^^^^^^^^^ @@ -124,7 +133,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on trait impl blocks - --> $DIR/unused_attributes-must_use.rs:93:1 + --> $DIR/unused_attributes-must_use.rs:95:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -133,7 +142,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on trait methods in impl blocks - --> $DIR/unused_attributes-must_use.rs:98:5 + --> $DIR/unused_attributes-must_use.rs:100:5 | LL | #[must_use] | ^^^^^^^^^^^ @@ -142,7 +151,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to data types, functions, unions, required trait methods, provided trait methods, inherent methods, foreign functions, and traits error: `#[must_use]` attribute cannot be used on trait aliases - --> $DIR/unused_attributes-must_use.rs:105:1 + --> $DIR/unused_attributes-must_use.rs:107:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -151,7 +160,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on macro defs - --> $DIR/unused_attributes-must_use.rs:109:1 + --> $DIR/unused_attributes-must_use.rs:111:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -160,7 +169,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on statements - --> $DIR/unused_attributes-must_use.rs:118:5 + --> $DIR/unused_attributes-must_use.rs:120:5 | LL | #[must_use] | ^^^^^^^^^^^ @@ -169,7 +178,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on closures - --> $DIR/unused_attributes-must_use.rs:123:13 + --> $DIR/unused_attributes-must_use.rs:125:13 | LL | let x = #[must_use] | ^^^^^^^^^^^ @@ -178,7 +187,7 @@ LL | let x = #[must_use] = help: `#[must_use]` can be applied to methods, data types, functions, unions, foreign functions, and traits error: `#[must_use]` attribute cannot be used on match arms - --> $DIR/unused_attributes-must_use.rs:146:9 + --> $DIR/unused_attributes-must_use.rs:148:9 | LL | #[must_use] | ^^^^^^^^^^^ @@ -187,7 +196,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on struct fields - --> $DIR/unused_attributes-must_use.rs:155:28 + --> $DIR/unused_attributes-must_use.rs:157:28 | LL | let s = PatternField { #[must_use] foo: 123 }; | ^^^^^^^^^^^ @@ -196,7 +205,7 @@ LL | let s = PatternField { #[must_use] foo: 123 }; = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on pattern fields - --> $DIR/unused_attributes-must_use.rs:157:24 + --> $DIR/unused_attributes-must_use.rs:159:24 | LL | let PatternField { #[must_use] foo } = s; | ^^^^^^^^^^^ @@ -205,7 +214,7 @@ LL | let PatternField { #[must_use] foo } = s; = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: unused `X` that must be used - --> $DIR/unused_attributes-must_use.rs:128:5 + --> $DIR/unused_attributes-must_use.rs:130:5 | LL | X; | ^ @@ -221,7 +230,7 @@ LL | let _ = X; | +++++++ error: unused `Y` that must be used - --> $DIR/unused_attributes-must_use.rs:129:5 + --> $DIR/unused_attributes-must_use.rs:131:5 | LL | Y::Z; | ^^^^ @@ -232,7 +241,7 @@ LL | let _ = Y::Z; | +++++++ error: unused `U` that must be used - --> $DIR/unused_attributes-must_use.rs:130:5 + --> $DIR/unused_attributes-must_use.rs:132:5 | LL | U { unit: () }; | ^^^^^^^^^^^^^^ @@ -243,7 +252,7 @@ LL | let _ = U { unit: () }; | +++++++ error: unused return value of `U::method` that must be used - --> $DIR/unused_attributes-must_use.rs:131:5 + --> $DIR/unused_attributes-must_use.rs:133:5 | LL | U::method(); | ^^^^^^^^^^^ @@ -254,7 +263,7 @@ LL | let _ = U::method(); | +++++++ error: unused return value of `foo` that must be used - --> $DIR/unused_attributes-must_use.rs:132:5 + --> $DIR/unused_attributes-must_use.rs:134:5 | LL | foo(); | ^^^^^ @@ -265,7 +274,7 @@ LL | let _ = foo(); | +++++++ error: unused return value of `foreign_foo` that must be used - --> $DIR/unused_attributes-must_use.rs:135:9 + --> $DIR/unused_attributes-must_use.rs:137:9 | LL | foreign_foo(); | ^^^^^^^^^^^^^ @@ -276,7 +285,7 @@ LL | let _ = foreign_foo(); | +++++++ error: unused return value of `Use::get_four` that must be used - --> $DIR/unused_attributes-must_use.rs:143:5 + --> $DIR/unused_attributes-must_use.rs:145:5 | LL | ().get_four(); | ^^^^^^^^^^^^^ @@ -286,5 +295,5 @@ help: use `let _ = ...` to ignore the resulting value LL | let _ = ().get_four(); | +++++++ -error: aborting due to 29 previous errors +error: aborting due to 30 previous errors |
