Skip to content

Commit b1d2f2c

Browse files
committed
Auto merge of #140717 - mejrs:diagnostic_lints, r=oli-obk
Split up the `unknown_or_malformed_diagnostic_attributes` lint This splits up the lint into the following lint group: - `unknown_diagnostic_attributes` - triggers if the attribute is unknown to the current compiler - `misplaced_diagnostic_attributes` - triggers if the attribute exists but it is not placed on the item kind it's meant for - `malformed_diagnostic_attributes` - triggers if the attribute's syntax or options are invalid - `malformed_diagnostic_format_literals` - triggers if the format string literal is invalid, for example if it has unpaired curly braces or invalid parameters - this pr doesn't create it, but future lints for things like deprecations can also go here. This PR does not start emitting lints in places that previously did not. ## Motivation I want to have finer control over what `unknown_or_malformed_diagnostic_attributes` does I have a project with fairly low msrv that is/will have a lower msrv than future diagnostic attributes. So lints will be emitted when I or others compile it on a lower msrv. At this time, there are two options to silence these lints: - `#[allow(unknown_or_malformed_diagnostic_attributes)]` - this risks diagnostic regressions if I (or others) mess up using the attribute, or if the attribute's syntax ever changes. - write a build script to detect the compiler version and emit cfgs, and then conditionally enable the attribute: ```rust #[cfg_attr(rust_version_99, diagnostic::new_attr_in_rust_99(thing = ..))]` struct Foo; ``` or conditionally `allow` the lint: ```rust // lib.rs #![cfg_attr(not(current_rust), allow(unknown_or_malformed_diagnostic_attributes))] ``` I like to avoid using build scripts if I can, so the following works much better for me. That is what this PR will let me do in the future: ```rust #[allow(unknown_diagnostic_attribute, reason = "attribute came out in rust 1.99 but msrv is 1.70")] #[diagnostic::new_attr_in_rust_99(thing = ..)]` struct Foo;
2 parents 288e94c + a7bf5c4 commit b1d2f2c

25 files changed

+157
-59
lines changed

compiler/rustc_lint/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,14 @@ fn register_builtins(store: &mut LintStore) {
339339

340340
add_lint_group!("deprecated_safe", DEPRECATED_SAFE_2024);
341341

342+
add_lint_group!(
343+
"unknown_or_malformed_diagnostic_attributes",
344+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
345+
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
346+
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
347+
UNKNOWN_DIAGNOSTIC_ATTRIBUTES
348+
);
349+
342350
// Register renamed and removed lints.
343351
store.register_renamed("single_use_lifetime", "single_use_lifetimes");
344352
store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths");

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 89 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ declare_lint_pass! {
6363
LOSSY_PROVENANCE_CASTS,
6464
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
6565
MACRO_USE_EXTERN_CRATE,
66+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
67+
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
6668
META_VARIABLE_MISUSE,
69+
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
6770
MISSING_ABI,
6871
MISSING_UNSAFE_ON_EXTERN,
6972
MUST_NOT_SUSPEND,
@@ -112,8 +115,8 @@ declare_lint_pass! {
112115
UNFULFILLED_LINT_EXPECTATIONS,
113116
UNINHABITED_STATIC,
114117
UNKNOWN_CRATE_TYPES,
118+
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
115119
UNKNOWN_LINTS,
116-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
117120
UNNAMEABLE_TEST_ITEMS,
118121
UNNAMEABLE_TYPES,
119122
UNREACHABLE_CODE,
@@ -4284,31 +4287,105 @@ declare_lint! {
42844287
}
42854288

42864289
declare_lint! {
4287-
/// The `unknown_or_malformed_diagnostic_attributes` lint detects unrecognized or otherwise malformed
4288-
/// diagnostic attributes.
4290+
/// The `malformed_diagnostic_attributes` lint detects malformed diagnostic attributes.
42894291
///
42904292
/// ### Example
42914293
///
42924294
/// ```rust
4293-
/// #![feature(diagnostic_namespace)]
4294-
/// #[diagnostic::does_not_exist]
4295-
/// struct Foo;
4295+
/// #[diagnostic::do_not_recommend(message = "message")]
4296+
/// trait Trait {}
42964297
/// ```
42974298
///
42984299
/// {{produces}}
42994300
///
4301+
/// ### Explanation
4302+
///
4303+
/// It is usually a mistake to use options or syntax that is not supported. Check the spelling,
4304+
/// and check the diagnostic attribute listing for the correct name and syntax. Also consider if
4305+
/// you are using an old version of the compiler; perhaps the option or syntax is only available
4306+
/// in a newer version. See the [reference] for a list of diagnostic attributes and the syntax
4307+
/// of each.
4308+
///
4309+
/// [reference]: https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#the-diagnostic-tool-attribute-namespace
4310+
pub MALFORMED_DIAGNOSTIC_ATTRIBUTES,
4311+
Warn,
4312+
"detects malformed diagnostic attributes",
4313+
}
4314+
4315+
declare_lint! {
4316+
/// The `misplaced_diagnostic_attributes` lint detects wrongly placed diagnostic attributes.
4317+
///
4318+
/// ### Example
4319+
///
4320+
/// ```rust
4321+
/// #[diagnostic::do_not_recommend]
4322+
/// struct NotUserFacing;
4323+
/// ```
4324+
///
4325+
/// {{produces}}
43004326
///
43014327
/// ### Explanation
43024328
///
4303-
/// It is usually a mistake to specify a diagnostic attribute that does not exist. Check
4304-
/// the spelling, and check the diagnostic attribute listing for the correct name. Also
4305-
/// consider if you are using an old version of the compiler, and the attribute
4306-
/// is only available in a newer version.
4307-
pub UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
4329+
/// It is usually a mistake to specify a diagnostic attribute on an item it is not meant for.
4330+
/// For example, `#[diagnostic::do_not_recommend]` can only be placed on trait implementations,
4331+
/// and does nothing if placed elsewhere. See the [reference] for a list of diagnostic
4332+
/// attributes and their correct positions.
4333+
///
4334+
/// [reference]: https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#the-diagnostic-tool-attribute-namespace
4335+
pub MISPLACED_DIAGNOSTIC_ATTRIBUTES,
43084336
Warn,
4309-
"unrecognized or malformed diagnostic attribute",
4337+
"detects diagnostic attributes that are placed on the wrong item",
43104338
}
43114339

4340+
declare_lint! {
4341+
/// The `unknown_diagnostic_attributes` lint detects unknown diagnostic attributes.
4342+
///
4343+
/// ### Example
4344+
///
4345+
/// ```rust
4346+
/// #[diagnostic::does_not_exist]
4347+
/// struct Thing;
4348+
/// ```
4349+
///
4350+
/// {{produces}}
4351+
///
4352+
/// ### Explanation
4353+
///
4354+
/// It is usually a mistake to specify a diagnostic attribute that does not exist. Check the
4355+
/// spelling, and check the diagnostic attribute listing for the correct name. Also consider if
4356+
/// you are using an old version of the compiler and the attribute is only available in a newer
4357+
/// version. See the [reference] for the list of diagnostic attributes.
4358+
///
4359+
/// [reference]: https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#the-diagnostic-tool-attribute-namespace
4360+
pub UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
4361+
Warn,
4362+
"detects unknown diagnostic attributes",
4363+
}
4364+
4365+
declare_lint! {
4366+
/// The `malformed_diagnostic_format_literals` lint detects malformed diagnostic format
4367+
/// literals.
4368+
///
4369+
/// ### Example
4370+
///
4371+
/// ```rust
4372+
/// #[diagnostic::on_unimplemented(message = "{Self}} does not implement `Trait`")]
4373+
/// trait Trait {}
4374+
/// ```
4375+
///
4376+
/// {{produces}}
4377+
///
4378+
/// ### Explanation
4379+
///
4380+
/// The `#[diagnostic::on_unimplemented]` attribute accepts string literal values that are
4381+
/// similar to `format!`'s string literal. See the [reference] for details on what is permitted
4382+
/// in this string literal.
4383+
///
4384+
/// [reference]: https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#the-diagnostic-tool-attribute-namespace
4385+
pub MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
4386+
Warn,
4387+
"detects diagnostic attribute with malformed diagnostic format literals",
4388+
}
43124389
declare_lint! {
43134390
/// The `ambiguous_glob_imports` lint detects glob imports that should report ambiguity
43144391
/// errors, but previously didn't do that due to rustc bugs.

compiler/rustc_passes/src/check_attr.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use rustc_session::config::CrateType;
3333
use rustc_session::lint;
3434
use rustc_session::lint::builtin::{
3535
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
36-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
36+
MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
3737
};
3838
use rustc_session::parse::feature_err;
3939
use rustc_span::edition::Edition;
@@ -460,7 +460,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
460460
);
461461
}
462462

463-
/// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl.
463+
/// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl and that it has no
464+
/// arguments.
464465
fn check_do_not_recommend(
465466
&self,
466467
attr_span: Span,
@@ -477,15 +478,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
477478
)
478479
{
479480
self.tcx.emit_node_span_lint(
480-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
481+
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
481482
hir_id,
482483
attr_span,
483484
errors::IncorrectDoNotRecommendLocation,
484485
);
485486
}
486487
if !attr.is_word() {
487488
self.tcx.emit_node_span_lint(
488-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
489+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
489490
hir_id,
490491
attr_span,
491492
errors::DoNotRecommendDoesNotExpectArgs,
@@ -497,7 +498,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
497498
fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) {
498499
if !matches!(target, Target::Trait) {
499500
self.tcx.emit_node_span_lint(
500-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
501+
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
501502
hir_id,
502503
attr_span,
503504
DiagnosticOnUnimplementedOnlyForTraits,

compiler/rustc_resolve/src/macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_middle::middle::stability;
2424
use rustc_middle::ty::{RegisteredTools, TyCtxt, Visibility};
2525
use rustc_session::lint::BuiltinLintDiag;
2626
use rustc_session::lint::builtin::{
27-
LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
27+
LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
2828
UNUSED_MACRO_RULES, UNUSED_MACROS,
2929
};
3030
use rustc_session::parse::feature_err;
@@ -689,7 +689,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
689689
);
690690

691691
self.tcx.sess.psess.buffer_lint(
692-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
692+
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
693693
attribute.span(),
694694
node_id,
695695
BuiltinLintDiag::UnknownDiagnosticAttribute { span: attribute.span(), typo_name },

compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use rustc_macros::LintDiagnostic;
1111
use rustc_middle::bug;
1212
use rustc_middle::ty::print::PrintTraitRefExt;
1313
use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt};
14-
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
14+
use rustc_session::lint::builtin::{
15+
MALFORMED_DIAGNOSTIC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
16+
};
1517
use rustc_span::{Span, Symbol, sym};
1618
use tracing::{debug, info};
1719

@@ -382,7 +384,7 @@ impl IgnoredDiagnosticOption {
382384
if let (Some(new_item), Some(old_item)) = (new, old) {
383385
if let Some(item_def_id) = item_def_id.as_local() {
384386
tcx.emit_node_span_lint(
385-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
387+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
386388
tcx.local_def_id_to_hir_id(item_def_id),
387389
new_item,
388390
IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name },
@@ -533,7 +535,7 @@ impl<'tcx> OnUnimplementedDirective {
533535
if is_diagnostic_namespace_variant {
534536
if let Some(def_id) = item_def_id.as_local() {
535537
tcx.emit_node_span_lint(
536-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
538+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
537539
tcx.local_def_id_to_hir_id(def_id),
538540
vec![item.span()],
539541
MalformedOnUnimplementedAttrLint::new(item.span()),
@@ -689,7 +691,7 @@ impl<'tcx> OnUnimplementedDirective {
689691

690692
if let Some(item_def_id) = item_def_id.as_local() {
691693
tcx.emit_node_span_lint(
692-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
694+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
693695
tcx.local_def_id_to_hir_id(item_def_id),
694696
report_span,
695697
MalformedOnUnimplementedAttrLint::new(report_span),
@@ -702,7 +704,7 @@ impl<'tcx> OnUnimplementedDirective {
702704
Attribute::Unparsed(p) if !matches!(p.args, AttrArgs::Empty) => {
703705
if let Some(item_def_id) = item_def_id.as_local() {
704706
tcx.emit_node_span_lint(
705-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
707+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
706708
tcx.local_def_id_to_hir_id(item_def_id),
707709
attr.span(),
708710
MalformedOnUnimplementedAttrLint::new(attr.span()),
@@ -712,7 +714,7 @@ impl<'tcx> OnUnimplementedDirective {
712714
_ => {
713715
if let Some(item_def_id) = item_def_id.as_local() {
714716
tcx.emit_node_span_lint(
715-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
717+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
716718
tcx.local_def_id_to_hir_id(item_def_id),
717719
attr.span(),
718720
MissingOptionsForOnUnimplementedAttr,
@@ -859,7 +861,7 @@ impl<'tcx> OnUnimplementedFormatString {
859861
if self.is_diagnostic_namespace_variant {
860862
if let Some(trait_def_id) = trait_def_id.as_local() {
861863
tcx.emit_node_span_lint(
862-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
864+
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
863865
tcx.local_def_id_to_hir_id(trait_def_id),
864866
self.span,
865867
WrappedParserError { description: e.description, label: e.label },

compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
77
use rustc_parse_format::{
88
Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position,
99
};
10-
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
10+
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_FORMAT_LITERALS;
1111
use rustc_span::def_id::DefId;
1212
use rustc_span::{InnerSpan, Span, Symbol, kw, sym};
1313

@@ -69,7 +69,7 @@ impl FormatWarning {
6969
let this = tcx.item_ident(item_def_id);
7070
if let Some(item_def_id) = item_def_id.as_local() {
7171
tcx.emit_node_span_lint(
72-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
72+
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
7373
tcx.local_def_id_to_hir_id(item_def_id),
7474
span,
7575
UnknownFormatParameterForOnUnimplementedAttr {
@@ -82,7 +82,7 @@ impl FormatWarning {
8282
FormatWarning::PositionalArgument { span, .. } => {
8383
if let Some(item_def_id) = item_def_id.as_local() {
8484
tcx.emit_node_span_lint(
85-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
85+
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
8686
tcx.local_def_id_to_hir_id(item_def_id),
8787
span,
8888
DisallowedPositionalArgument,
@@ -92,7 +92,7 @@ impl FormatWarning {
9292
FormatWarning::InvalidSpecifier { span, .. } => {
9393
if let Some(item_def_id) = item_def_id.as_local() {
9494
tcx.emit_node_span_lint(
95-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
95+
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
9696
tcx.local_def_id_to_hir_id(item_def_id),
9797
span,
9898
InvalidFormatSpecifier,

src/tools/lint-docs/src/groups.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
2626
"Lints that detect identifiers which will be come keywords in later editions",
2727
),
2828
("deprecated-safe", "Lints for functions which were erroneously marked as safe in the past"),
29+
(
30+
"unknown-or-malformed-diagnostic-attributes",
31+
"detects unknown or malformed diagnostic attributes",
32+
),
2933
];
3034

3135
type LintGroups = BTreeMap<String, BTreeSet<String>>;

tests/ui/attributes/malformed-attrs.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
594594
LL | #[diagnostic::do_not_recommend()]
595595
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
596596
|
597-
= note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
597+
= note: `#[warn(malformed_diagnostic_attributes)]` on by default
598598

599599
warning: missing options for `on_unimplemented` attribute
600600
--> $DIR/malformed-attrs.rs:138:1

tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ note: the lint level is defined here
99
|
1010
LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= note: `#[deny(unknown_diagnostic_attributes)]` implied by `#[deny(unknown_or_malformed_diagnostic_attributes)]`
1213

1314
error: aborting due to 1 previous error
1415

tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
44
LL | #[diagnostic::do_not_recommend(not_accepted)]
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
7+
= note: `#[warn(malformed_diagnostic_attributes)]` on by default
88

99
warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
1010
--> $DIR/does_not_acccept_args.rs:15:1

0 commit comments

Comments
 (0)