Skip to content

Commit 5eb76fa

Browse files
authored
Rollup merge of #117205 - weiznich:multiple_notes_for_on_unimplemented, r=compiler-errors
Allows `#[diagnostic::on_unimplemented]` attributes to have multiple notes This commit extends the `#[diagnostic::on_unimplemented]` (and `#[rustc_on_unimplemented]`) attributes to allow multiple `note` options. This enables emitting multiple notes for custom error messages. For now I've opted to not change any of the existing usages of `#[rustc_on_unimplemented]` and just updated the relevant compile tests. r? `@compiler-errors` I'm happy to adjust any of the existing changed location to emit the old error message if that's desired.
2 parents 098bb37 + 160b179 commit 5eb76fa

File tree

9 files changed

+111
-23
lines changed

9 files changed

+111
-23
lines changed

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

+17-15
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ pub struct OnUnimplementedDirective {
319319
pub subcommands: Vec<OnUnimplementedDirective>,
320320
pub message: Option<OnUnimplementedFormatString>,
321321
pub label: Option<OnUnimplementedFormatString>,
322-
pub note: Option<OnUnimplementedFormatString>,
322+
pub notes: Vec<OnUnimplementedFormatString>,
323323
pub parent_label: Option<OnUnimplementedFormatString>,
324324
pub append_const_msg: Option<AppendConstMessage>,
325325
}
@@ -329,7 +329,7 @@ pub struct OnUnimplementedDirective {
329329
pub struct OnUnimplementedNote {
330330
pub message: Option<String>,
331331
pub label: Option<String>,
332-
pub note: Option<String>,
332+
pub notes: Vec<String>,
333333
pub parent_label: Option<String>,
334334
// If none, should fall back to a generic message
335335
pub append_const_msg: Option<AppendConstMessage>,
@@ -399,7 +399,7 @@ impl<'tcx> OnUnimplementedDirective {
399399

400400
let mut message = None;
401401
let mut label = None;
402-
let mut note = None;
402+
let mut notes = Vec::new();
403403
let mut parent_label = None;
404404
let mut subcommands = vec![];
405405
let mut append_const_msg = None;
@@ -415,10 +415,12 @@ impl<'tcx> OnUnimplementedDirective {
415415
label = parse_value(label_)?;
416416
continue;
417417
}
418-
} else if item.has_name(sym::note) && note.is_none() {
418+
} else if item.has_name(sym::note) {
419419
if let Some(note_) = item.value_str() {
420-
note = parse_value(note_)?;
421-
continue;
420+
if let Some(note) = parse_value(note_)? {
421+
notes.push(note);
422+
continue;
423+
}
422424
}
423425
} else if item.has_name(sym::parent_label)
424426
&& parent_label.is_none()
@@ -432,7 +434,7 @@ impl<'tcx> OnUnimplementedDirective {
432434
&& is_root
433435
&& message.is_none()
434436
&& label.is_none()
435-
&& note.is_none()
437+
&& notes.is_empty()
436438
&& !is_diagnostic_namespace_variant
437439
// FIXME(diagnostic_namespace): disallow filters for now
438440
{
@@ -487,7 +489,7 @@ impl<'tcx> OnUnimplementedDirective {
487489
subcommands,
488490
message,
489491
label,
490-
note,
492+
notes,
491493
parent_label,
492494
append_const_msg,
493495
}))
@@ -505,12 +507,14 @@ impl<'tcx> OnUnimplementedDirective {
505507
if let Some(aggr) = aggr {
506508
let mut subcommands = aggr.subcommands;
507509
subcommands.extend(directive.subcommands);
510+
let mut notes = aggr.notes;
511+
notes.extend(directive.notes);
508512
Ok(Some(Self {
509513
condition: aggr.condition.or(directive.condition),
510514
subcommands,
511515
message: aggr.message.or(directive.message),
512516
label: aggr.label.or(directive.label),
513-
note: aggr.note.or(directive.note),
517+
notes,
514518
parent_label: aggr.parent_label.or(directive.parent_label),
515519
append_const_msg: aggr.append_const_msg.or(directive.append_const_msg),
516520
}))
@@ -543,7 +547,7 @@ impl<'tcx> OnUnimplementedDirective {
543547
value,
544548
attr.span,
545549
)?),
546-
note: None,
550+
notes: Vec::new(),
547551
parent_label: None,
548552
append_const_msg: None,
549553
}))
@@ -600,7 +604,7 @@ impl<'tcx> OnUnimplementedDirective {
600604
) -> OnUnimplementedNote {
601605
let mut message = None;
602606
let mut label = None;
603-
let mut note = None;
607+
let mut notes = Vec::new();
604608
let mut parent_label = None;
605609
let mut append_const_msg = None;
606610
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
@@ -637,9 +641,7 @@ impl<'tcx> OnUnimplementedDirective {
637641
label = Some(label_.clone());
638642
}
639643

640-
if let Some(ref note_) = command.note {
641-
note = Some(note_.clone());
642-
}
644+
notes.extend(command.notes.clone());
643645

644646
if let Some(ref parent_label_) = command.parent_label {
645647
parent_label = Some(parent_label_.clone());
@@ -651,7 +653,7 @@ impl<'tcx> OnUnimplementedDirective {
651653
OnUnimplementedNote {
652654
label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
653655
message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
654-
note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
656+
notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, &options_map)).collect(),
655657
parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
656658
append_const_msg,
657659
}

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -445,29 +445,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
445445
let OnUnimplementedNote {
446446
message,
447447
label,
448-
note,
448+
notes,
449449
parent_label,
450450
append_const_msg,
451451
} = self.on_unimplemented_note(trait_ref, &obligation);
452452
let have_alt_message = message.is_some() || label.is_some();
453453
let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
454454
let is_unsize =
455455
Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
456-
let (message, note, append_const_msg) = if is_try_conversion {
456+
let (message, notes, append_const_msg) = if is_try_conversion {
457457
(
458458
Some(format!(
459459
"`?` couldn't convert the error to `{}`",
460460
trait_ref.skip_binder().self_ty(),
461461
)),
462-
Some(
462+
vec![
463463
"the question mark operation (`?`) implicitly performs a \
464464
conversion on the error value using the `From` trait"
465465
.to_owned(),
466-
),
466+
],
467467
Some(AppendConstMessage::Default),
468468
)
469469
} else {
470-
(message, note, append_const_msg)
470+
(message, notes, append_const_msg)
471471
};
472472

473473
let err_msg = self.get_standard_error_message(
@@ -588,9 +588,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
588588
if let Some((msg, span)) = type_def {
589589
err.span_label(span, msg);
590590
}
591-
if let Some(s) = note {
591+
for note in notes {
592592
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
593-
err.note(s);
593+
err.note(note);
594594
}
595595
if let Some(s) = parent_label {
596596
let body = obligation.cause.body_id;

library/core/src/marker.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,20 @@ impl<T: ?Sized> Copy for &T {}
621621
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead",
622622
),
623623
on(
624-
_Self = "core::cell::Cell<T>",
624+
all(
625+
_Self = "core::cell::Cell<T>",
626+
not(_Self = "core::cell::Cell<u8>"),
627+
not(_Self = "core::cell::Cell<u16>"),
628+
not(_Self = "core::cell::Cell<u32>"),
629+
not(_Self = "core::cell::Cell<u64>"),
630+
not(_Self = "core::cell::Cell<usize>"),
631+
not(_Self = "core::cell::Cell<i8>"),
632+
not(_Self = "core::cell::Cell<i16>"),
633+
not(_Self = "core::cell::Cell<i32>"),
634+
not(_Self = "core::cell::Cell<i64>"),
635+
not(_Self = "core::cell::Cell<isize>"),
636+
not(_Self = "core::cell::Cell<bool>")
637+
),
625638
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`",
626639
),
627640
on(

tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ LL | takes_foo(());
2626
|
2727
= help: the trait `Foo` is not implemented for `()`
2828
= note: custom note
29+
= note: fallback note
2930
help: this trait has no implementations, consider adding one
3031
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1
3132
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![feature(diagnostic_namespace)]
2+
3+
#[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz", note = "Boom")]
4+
trait Foo {}
5+
6+
#[diagnostic::on_unimplemented(message = "Bar", label = "Foo", note = "Baz")]
7+
#[diagnostic::on_unimplemented(note = "Baz2")]
8+
trait Bar {}
9+
10+
fn takes_foo(_: impl Foo) {}
11+
fn takes_bar(_: impl Bar) {}
12+
13+
fn main() {
14+
takes_foo(());
15+
//~^ERROR Foo
16+
takes_bar(());
17+
//~^ERROR Bar
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error[E0277]: Foo
2+
--> $DIR/multiple_notes.rs:14:15
3+
|
4+
LL | takes_foo(());
5+
| --------- ^^ Bar
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
= help: the trait `Foo` is not implemented for `()`
10+
= note: Baz
11+
= note: Boom
12+
help: this trait has no implementations, consider adding one
13+
--> $DIR/multiple_notes.rs:4:1
14+
|
15+
LL | trait Foo {}
16+
| ^^^^^^^^^
17+
note: required by a bound in `takes_foo`
18+
--> $DIR/multiple_notes.rs:10:22
19+
|
20+
LL | fn takes_foo(_: impl Foo) {}
21+
| ^^^ required by this bound in `takes_foo`
22+
23+
error[E0277]: Bar
24+
--> $DIR/multiple_notes.rs:16:15
25+
|
26+
LL | takes_bar(());
27+
| --------- ^^ Foo
28+
| |
29+
| required by a bound introduced by this call
30+
|
31+
= help: the trait `Bar` is not implemented for `()`
32+
= note: Baz
33+
= note: Baz2
34+
help: this trait has no implementations, consider adding one
35+
--> $DIR/multiple_notes.rs:8:1
36+
|
37+
LL | trait Bar {}
38+
| ^^^^^^^^^
39+
note: required by a bound in `takes_bar`
40+
--> $DIR/multiple_notes.rs:11:22
41+
|
42+
LL | fn takes_bar(_: impl Bar) {}
43+
| ^^^ required by this bound in `takes_bar`
44+
45+
error: aborting due to 2 previous errors
46+
47+
For more information about this error, try `rustc --explain E0277`.

tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ LL | call(foo_unsafe);
5858
| required by a bound introduced by this call
5959
|
6060
= help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
61+
= note: unsafe function cannot be called generically without an unsafe block
6162
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
6263
= note: `#[target_feature]` functions do not implement the `Fn` traits
6364
note: required by a bound in `call`
@@ -75,6 +76,7 @@ LL | call_mut(foo_unsafe);
7576
| required by a bound introduced by this call
7677
|
7778
= help: the trait `FnMut<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
79+
= note: unsafe function cannot be called generically without an unsafe block
7880
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
7981
= note: `#[target_feature]` functions do not implement the `Fn` traits
8082
note: required by a bound in `call_mut`
@@ -92,6 +94,7 @@ LL | call_once(foo_unsafe);
9294
| required by a bound introduced by this call
9395
|
9496
= help: the trait `FnOnce<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
97+
= note: unsafe function cannot be called generically without an unsafe block
9598
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
9699
= note: `#[target_feature]` functions do not implement the `Fn` traits
97100
note: required by a bound in `call_once`

tests/ui/suggestions/path-display.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | println!("{}", path);
55
| ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it
66
|
77
= help: the trait `std::fmt::Display` is not implemented for `Path`
8+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
89
= note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data
910
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
1011

@@ -15,6 +16,7 @@ LL | println!("{}", path);
1516
| ^^^^ `PathBuf` cannot be formatted with the default formatter; call `.display()` on it
1617
|
1718
= help: the trait `std::fmt::Display` is not implemented for `PathBuf`
19+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
1820
= note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data
1921
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
2022

tests/ui/traits/new-solver/fn-trait.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ LL | require_fn(f as unsafe fn() -> i32);
77
| required by a bound introduced by this call
88
|
99
= help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32`
10+
= note: unsafe function cannot be called generically without an unsafe block
1011
= note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
1112
note: required by a bound in `require_fn`
1213
--> $DIR/fn-trait.rs:3:23
@@ -97,6 +98,7 @@ LL | require_fn(h);
9798
| required by a bound introduced by this call
9899
|
99100
= help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() -> i32 {h}`
101+
= note: unsafe function cannot be called generically without an unsafe block
100102
= note: wrap the `unsafe fn() -> i32 {h}` in a closure with no arguments: `|| { /* code */ }`
101103
note: required by a bound in `require_fn`
102104
--> $DIR/fn-trait.rs:3:23

0 commit comments

Comments
 (0)