Skip to content

Commit 9017b97

Browse files
committed
Improve the warning messages for the #[diagnostic::on_unimplemented]
This commit improves warnings emitted for malformed on unimplemented attributes by: * Improving the span of the warnings * Adding a label message to them * Separating the messages for missing and unexpected options * Adding a help message that says which options are supported
1 parent 020d008 commit 9017b97

File tree

5 files changed

+126
-27
lines changed

5 files changed

+126
-27
lines changed

compiler/rustc_trait_selection/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-claus
2828
.label = invalid on-clause here
2929
3030
trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute
31+
.help = only `message`, `note` and `label` are allowed as options
32+
.label = invalid option found here
33+
34+
trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute
35+
.help = at least one of the `message`, `note` and `label` options are expected
3136
3237
trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc ->
3338
[none] {""}

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

+47-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use super::{ObligationCauseCode, PredicateObligation};
22
use crate::infer::error_reporting::TypeErrCtxt;
3+
use rustc_ast::AttrArgs;
4+
use rustc_ast::AttrArgsEq;
5+
use rustc_ast::AttrKind;
36
use rustc_ast::{Attribute, MetaItem, NestedMetaItem};
47
use rustc_attr as attr;
58
use rustc_data_structures::fx::FxHashMap;
@@ -342,7 +345,22 @@ pub enum AppendConstMessage {
342345

343346
#[derive(LintDiagnostic)]
344347
#[diag(trait_selection_malformed_on_unimplemented_attr)]
345-
pub struct NoValueInOnUnimplementedLint;
348+
#[help]
349+
pub struct MalformedOnUnimplementedAttrLint {
350+
#[label]
351+
pub span: Span,
352+
}
353+
354+
impl MalformedOnUnimplementedAttrLint {
355+
fn new(span: Span) -> Self {
356+
Self { span }
357+
}
358+
}
359+
360+
#[derive(LintDiagnostic)]
361+
#[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
362+
#[help]
363+
pub struct MissingOptionsForOnUnimplementedAttr;
346364

347365
impl<'tcx> OnUnimplementedDirective {
348366
fn parse(
@@ -453,7 +471,7 @@ impl<'tcx> OnUnimplementedDirective {
453471
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
454472
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
455473
vec![item.span()],
456-
NoValueInOnUnimplementedLint,
474+
MalformedOnUnimplementedAttrLint::new(item.span()),
457475
);
458476
} else {
459477
// nothing found
@@ -530,21 +548,40 @@ impl<'tcx> OnUnimplementedDirective {
530548
append_const_msg: None,
531549
}))
532550
} else {
551+
let item = attr.get_normal_item();
552+
let report_span = match &item.args {
553+
AttrArgs::Empty => item.path.span,
554+
AttrArgs::Delimited(args) => args.dspan.entire(),
555+
AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => eq_span.to(expr.span),
556+
AttrArgs::Eq(span, AttrArgsEq::Hir(expr)) => span.to(expr.span),
557+
};
558+
533559
tcx.emit_spanned_lint(
534560
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
535561
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
536-
attr.span,
537-
NoValueInOnUnimplementedLint,
562+
report_span,
563+
MalformedOnUnimplementedAttrLint::new(report_span),
538564
);
539565
Ok(None)
540566
}
541567
} else if is_diagnostic_namespace_variant {
542-
tcx.emit_spanned_lint(
543-
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
544-
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
545-
attr.span,
546-
NoValueInOnUnimplementedLint,
547-
);
568+
match &attr.kind {
569+
AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => {
570+
tcx.emit_spanned_lint(
571+
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
572+
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
573+
attr.span,
574+
MalformedOnUnimplementedAttrLint::new(attr.span),
575+
);
576+
}
577+
_ => tcx.emit_spanned_lint(
578+
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
579+
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
580+
attr.span,
581+
MissingOptionsForOnUnimplementedAttr,
582+
),
583+
};
584+
548585
Ok(None)
549586
} else {
550587
let reported =

tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs

+8
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@ trait Boom {}
2323
//~^WARN malformed `on_unimplemented` attribute
2424
trait Doom {}
2525

26+
#[diagnostic::on_unimplemented]
27+
//~^WARN missing options for `on_unimplemented` attribute
28+
//~|WARN missing options for `on_unimplemented` attribute
29+
trait Whatever {}
30+
2631
fn take_foo(_: impl Foo) {}
2732
fn take_baz(_: impl Baz) {}
2833
fn take_boom(_: impl Boom) {}
34+
fn take_whatever(_: impl Whatever) {}
2935

3036
fn main() {
3137
take_foo(1_i32);
@@ -34,4 +40,6 @@ fn main() {
3440
//~^ERROR Boom
3541
take_boom(1_i32);
3642
//~^ERROR Boom
43+
take_whatever(1_i32);
44+
//~^ERROR the trait bound `i32: Whatever` is not satisfied
3745
}

tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr

+62-15
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,53 @@ warning: malformed `on_unimplemented` attribute
1010
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
1111
|
1212
LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
13-
| ^^^^^^^^^^^^^^^^^^^
13+
| ^^^^^^^^^^^^^^^^^^^ invalid option found here
14+
|
15+
= help: only `message`, `note` and `label` are allowed as options
1416

1517
warning: malformed `on_unimplemented` attribute
1618
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
1719
|
1820
LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
19-
| ^^^^^^^^^^^^^^^^^^^
21+
| ^^^^^^^^^^^^^^^^^^^ invalid option found here
22+
|
23+
= help: only `message`, `note` and `label` are allowed as options
2024

2125
warning: malformed `on_unimplemented` attribute
2226
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
2327
|
2428
LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
25-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
30+
|
31+
= help: only `message`, `note` and `label` are allowed as options
2632

2733
warning: malformed `on_unimplemented` attribute
28-
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:1
34+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32
2935
|
3036
LL | #[diagnostic::on_unimplemented = "boom"]
31-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
37+
| ^^^^^^^^ invalid option found here
38+
|
39+
= help: only `message`, `note` and `label` are allowed as options
40+
41+
warning: missing options for `on_unimplemented` attribute
42+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
43+
|
44+
LL | #[diagnostic::on_unimplemented]
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
46+
|
47+
= help: at least one of the `message`, `note` and `label` options are expected
3248

3349
warning: malformed `on_unimplemented` attribute
3450
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
3551
|
3652
LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
37-
| ^^^^^^^^^^^^^^^^^^^
53+
| ^^^^^^^^^^^^^^^^^^^ invalid option found here
3854
|
55+
= help: only `message`, `note` and `label` are allowed as options
3956
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
4057

4158
error[E0277]: the trait bound `i32: Foo` is not satisfied
42-
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:14
59+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:14
4360
|
4461
LL | take_foo(1_i32);
4562
| -------- ^^^^^ the trait `Foo` is not implemented for `i32`
@@ -52,7 +69,7 @@ help: this trait has no implementations, consider adding one
5269
LL | trait Foo {}
5370
| ^^^^^^^^^
5471
note: required by a bound in `take_foo`
55-
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:21
72+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:21
5673
|
5774
LL | fn take_foo(_: impl Foo) {}
5875
| ^^^ required by this bound in `take_foo`
@@ -61,12 +78,13 @@ warning: malformed `on_unimplemented` attribute
6178
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
6279
|
6380
LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
64-
| ^^^^^^^^^^^^^^^^^^^
81+
| ^^^^^^^^^^^^^^^^^^^ invalid option found here
6582
|
83+
= help: only `message`, `note` and `label` are allowed as options
6684
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
6785

6886
error[E0277]: Boom
69-
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:14
87+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:14
7088
|
7189
LL | take_baz(1_i32);
7290
| -------- ^^^^^ the trait `Baz` is not implemented for `i32`
@@ -79,7 +97,7 @@ help: this trait has no implementations, consider adding one
7997
LL | trait Baz {}
8098
| ^^^^^^^^^
8199
note: required by a bound in `take_baz`
82-
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:21
100+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:21
83101
|
84102
LL | fn take_baz(_: impl Baz) {}
85103
| ^^^ required by this bound in `take_baz`
@@ -88,12 +106,13 @@ warning: malformed `on_unimplemented` attribute
88106
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
89107
|
90108
LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
91-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
109+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
92110
|
111+
= help: only `message`, `note` and `label` are allowed as options
93112
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
94113

95114
error[E0277]: Boom
96-
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:15
115+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:15
97116
|
98117
LL | take_boom(1_i32);
99118
| --------- ^^^^^ the trait `Boom` is not implemented for `i32`
@@ -106,11 +125,39 @@ help: this trait has no implementations, consider adding one
106125
LL | trait Boom {}
107126
| ^^^^^^^^^^
108127
note: required by a bound in `take_boom`
109-
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:28:22
128+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:22
110129
|
111130
LL | fn take_boom(_: impl Boom) {}
112131
| ^^^^ required by this bound in `take_boom`
113132

114-
error: aborting due to 3 previous errors; 8 warnings emitted
133+
warning: missing options for `on_unimplemented` attribute
134+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
135+
|
136+
LL | #[diagnostic::on_unimplemented]
137+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
138+
|
139+
= help: at least one of the `message`, `note` and `label` options are expected
140+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
141+
142+
error[E0277]: the trait bound `i32: Whatever` is not satisfied
143+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:19
144+
|
145+
LL | take_whatever(1_i32);
146+
| ------------- ^^^^^ the trait `Whatever` is not implemented for `i32`
147+
| |
148+
| required by a bound introduced by this call
149+
|
150+
help: this trait has no implementations, consider adding one
151+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1
152+
|
153+
LL | trait Whatever {}
154+
| ^^^^^^^^^^^^^^
155+
note: required by a bound in `take_whatever`
156+
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:26
157+
|
158+
LL | fn take_whatever(_: impl Whatever) {}
159+
| ^^^^^^^^ required by this bound in `take_whatever`
160+
161+
error: aborting due to 4 previous errors; 10 warnings emitted
115162

116163
For more information about this error, try `rustc --explain E0277`.

tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ LL | | if(Self = ()),
88
... |
99
LL | | note = "not used yet"
1010
LL | | )]
11-
| |__^
11+
| |__^ invalid option found here
1212
|
13+
= help: only `message`, `note` and `label` are allowed as options
1314
= note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
1415

1516
warning: malformed `on_unimplemented` attribute
@@ -22,8 +23,9 @@ LL | | if(Self = ()),
2223
... |
2324
LL | | note = "not used yet"
2425
LL | | )]
25-
| |__^
26+
| |__^ invalid option found here
2627
|
28+
= help: only `message`, `note` and `label` are allowed as options
2729
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
2830

2931
error[E0277]: fallback!!

0 commit comments

Comments
 (0)