From 1a1cd6e6db4b147f854f93122315b3c0e14d3e82 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 1 Dec 2023 07:26:05 +0100 Subject: [PATCH] Restrict what symbols can be used in `#[diagnostic::on_unimplemented]` format strings This commit restricts what symbols can be used in a format string for any option of the `diagnostic::on_unimplemented` attribute. We previously allowed all the ad-hoc options supported by the internal `#[rustc_on_unimplemented]` attribute. For the stable attribute we only want to support generic parameter names and `{Self}` as parameters. For any other parameter an warning is emitted and the parameter is replaced by the literal parameter string, so for example `{integer}` turns into `{integer}`. This follows the general design of attributes in the `#[diagnostic]` attribute namespace, that any syntax "error" is treated as warning and subsequently ignored. --- compiler/rustc_trait_selection/messages.ftl | 3 + .../error_reporting/on_unimplemented.rs | 147 ++++++--- ...options_of_the_internal_rustc_attribute.rs | 67 ++++ ...ons_of_the_internal_rustc_attribute.stderr | 305 ++++++++++++++++++ ...o_not_fail_parsing_on_invalid_options_1.rs | 8 + ...t_fail_parsing_on_invalid_options_1.stderr | 54 +++- 6 files changed, 523 insertions(+), 61 deletions(-) create mode 100644 tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs create mode 100644 tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index d753aa8618e84..41db8059cbee3 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -55,3 +55,6 @@ trait_selection_trait_has_no_impls = this trait has no implementations, consider trait_selection_ty_alias_overflow = in case this is a recursive type alias, consider using a struct, enum, or union instead trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated} + +trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}` + .help = expect either a generic argument name or {"`{Self}`"} as format argument diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index feeeaa51f81d4..ca48586405001 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -321,7 +321,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } #[derive(Clone, Debug)] -pub struct OnUnimplementedFormatString(Symbol, Span); +pub struct OnUnimplementedFormatString { + symbol: Symbol, + span: Span, + is_diagnostic_namespace_variant: bool, +} #[derive(Debug)] pub struct OnUnimplementedDirective { @@ -401,6 +405,14 @@ impl IgnoredDiagnosticOption { } } +#[derive(LintDiagnostic)] +#[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)] +#[help] +pub struct UnknownFormatParameterForOnUnimplementedAttr { + argument_name: Symbol, + trait_name: Symbol, +} + impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, @@ -414,8 +426,14 @@ impl<'tcx> OnUnimplementedDirective { let mut item_iter = items.iter(); let parse_value = |value_str, value_span| { - OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span, value_span) - .map(Some) + OnUnimplementedFormatString::try_parse( + tcx, + item_def_id, + value_str, + value_span, + is_diagnostic_namespace_variant, + ) + .map(Some) }; let condition = if is_root { @@ -552,15 +570,15 @@ impl<'tcx> OnUnimplementedDirective { IgnoredDiagnosticOption::maybe_emit_warning( tcx, item_def_id, - directive.message.as_ref().map(|f| f.1), - aggr.message.as_ref().map(|f| f.1), + directive.message.as_ref().map(|f| f.span), + aggr.message.as_ref().map(|f| f.span), "message", ); IgnoredDiagnosticOption::maybe_emit_warning( tcx, item_def_id, - directive.label.as_ref().map(|f| f.1), - aggr.label.as_ref().map(|f| f.1), + directive.label.as_ref().map(|f| f.span), + aggr.label.as_ref().map(|f| f.span), "label", ); IgnoredDiagnosticOption::maybe_emit_warning( @@ -573,8 +591,8 @@ impl<'tcx> OnUnimplementedDirective { IgnoredDiagnosticOption::maybe_emit_warning( tcx, item_def_id, - directive.parent_label.as_ref().map(|f| f.1), - aggr.parent_label.as_ref().map(|f| f.1), + directive.parent_label.as_ref().map(|f| f.span), + aggr.parent_label.as_ref().map(|f| f.span), "parent_label", ); IgnoredDiagnosticOption::maybe_emit_warning( @@ -634,7 +652,7 @@ impl<'tcx> OnUnimplementedDirective { item_def_id, value, attr.span, - attr.span, + is_diagnostic_namespace_variant, )?), notes: Vec::new(), parent_label: None, @@ -712,7 +730,12 @@ impl<'tcx> OnUnimplementedDirective { // `with_no_visible_paths` is also used when generating the options, // so we need to match it here. ty::print::with_no_visible_paths!( - OnUnimplementedFormatString(v, cfg.span).format( + OnUnimplementedFormatString { + symbol: v, + span: cfg.span, + is_diagnostic_namespace_variant: false + } + .format( tcx, trait_ref, &options_map @@ -760,20 +783,19 @@ impl<'tcx> OnUnimplementedFormatString { tcx: TyCtxt<'tcx>, item_def_id: DefId, from: Symbol, - err_sp: Span, value_span: Span, + is_diagnostic_namespace_variant: bool, ) -> Result { - let result = OnUnimplementedFormatString(from, value_span); - result.verify(tcx, item_def_id, err_sp)?; + let result = OnUnimplementedFormatString { + symbol: from, + span: value_span, + is_diagnostic_namespace_variant, + }; + result.verify(tcx, item_def_id)?; Ok(result) } - fn verify( - &self, - tcx: TyCtxt<'tcx>, - item_def_id: DefId, - span: Span, - ) -> Result<(), ErrorGuaranteed> { + fn verify(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<(), ErrorGuaranteed> { let trait_def_id = if tcx.is_trait(item_def_id) { item_def_id } else { @@ -782,7 +804,7 @@ impl<'tcx> OnUnimplementedFormatString { }; let trait_name = tcx.item_name(trait_def_id); let generics = tcx.generics_of(item_def_id); - let s = self.0.as_str(); + let s = self.symbol.as_str(); let parser = Parser::new(s, None, None, false, ParseMode::Format); let mut result = Ok(()); for token in parser { @@ -792,24 +814,40 @@ impl<'tcx> OnUnimplementedFormatString { Position::ArgumentNamed(s) => { match Symbol::intern(s) { // `{ThisTraitsName}` is allowed - s if s == trait_name => (), - s if ALLOWED_FORMAT_SYMBOLS.contains(&s) => (), + s if s == trait_name && !self.is_diagnostic_namespace_variant => (), + s if ALLOWED_FORMAT_SYMBOLS.contains(&s) + && !self.is_diagnostic_namespace_variant => + { + () + } // So is `{A}` if A is a type parameter s if generics.params.iter().any(|param| param.name == s) => (), s => { - result = Err(struct_span_err!( - tcx.sess, - span, - E0230, - "there is no parameter `{}` on {}", - s, - if trait_def_id == item_def_id { - format!("trait `{trait_name}`") - } else { - "impl".to_string() - } - ) - .emit()); + if self.is_diagnostic_namespace_variant { + tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), + self.span, + UnknownFormatParameterForOnUnimplementedAttr { + argument_name: s, + trait_name, + }, + ); + } else { + result = Err(struct_span_err!( + tcx.sess, + self.span, + E0230, + "there is no parameter `{}` on {}", + s, + if trait_def_id == item_def_id { + format!("trait `{trait_name}`") + } else { + "impl".to_string() + } + ) + .emit()); + } } } } @@ -817,7 +855,7 @@ impl<'tcx> OnUnimplementedFormatString { Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { let reported = struct_span_err!( tcx.sess, - span, + self.span, E0231, "only named substitution parameters are allowed" ) @@ -856,37 +894,42 @@ impl<'tcx> OnUnimplementedFormatString { .collect::>(); let empty_string = String::new(); - let s = self.0.as_str(); + let s = self.symbol.as_str(); let parser = Parser::new(s, None, None, false, ParseMode::Format); let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string); parser .map(|p| match p { - Piece::String(s) => s, + Piece::String(s) => s.to_owned(), Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(s) => { - let s = Symbol::intern(s); + Position::ArgumentNamed(arg) => { + let s = Symbol::intern(arg); match generic_map.get(&s) { - Some(val) => val, - None if s == name => &trait_str, + Some(val) => val.to_string(), + None if self.is_diagnostic_namespace_variant => { + format!("{{{arg}}}") + } + None if s == name => trait_str.clone(), None => { if let Some(val) = options.get(&s) { - val + val.clone() } else if s == sym::from_desugaring { // don't break messages using these two arguments incorrectly - &empty_string - } else if s == sym::ItemContext { - item_context + String::new() + } else if s == sym::ItemContext + && !self.is_diagnostic_namespace_variant + { + item_context.clone() } else if s == sym::integral { - "{integral}" + String::from("{integral}") } else if s == sym::integer_ { - "{integer}" + String::from("{integer}") } else if s == sym::float { - "{float}" + String::from("{float}") } else { bug!( "broken on_unimplemented {:?} for {:?}: \ no argument matching {:?}", - self.0, + self.symbol, trait_ref, s ) @@ -894,7 +937,7 @@ impl<'tcx> OnUnimplementedFormatString { } } } - _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0), + _ => bug!("broken on_unimplemented {:?} - bad format arg", self.symbol), }, }) .collect() diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs new file mode 100644 index 0000000000000..eb985c062f3dd --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs @@ -0,0 +1,67 @@ +#![feature(diagnostic_namespace)] + +#[diagnostic::on_unimplemented( + on(_Self = "&str"), + //~^WARN malformed `on_unimplemented` attribute + //~|WARN malformed `on_unimplemented` attribute + message = "trait has `{Self}` and `{T}` as params", + label = "trait has `{Self}` and `{T}` as params", + note = "trait has `{Self}` and `{T}` as params", + parent_label = "in this scope", + //~^WARN malformed `on_unimplemented` attribute + //~|WARN malformed `on_unimplemented` attribute + append_const_msg + //~^WARN malformed `on_unimplemented` attribute + //~|WARN malformed `on_unimplemented` attribute +)] +trait Foo {} + +#[diagnostic::on_unimplemented = "Message"] +//~^WARN malformed `on_unimplemented` attribute +//~|WARN malformed `on_unimplemented` attribute +trait Bar {} + +#[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl")] +//~^WARN #[diagnostic::on_unimplemented]` can only be applied to trait definitions +impl Bar for i32 {} + +// cannot use special rustc_on_unimplement symbols +// in the format string +#[diagnostic::on_unimplemented( + message = "{from_desugaring}{direct}{cause}{integral}{integer}", + //~^WARN there is no parameter `from_desugaring` on trait `Baz` + //~|WARN there is no parameter `from_desugaring` on trait `Baz` + //~|WARN there is no parameter `direct` on trait `Baz` + //~|WARN there is no parameter `direct` on trait `Baz` + //~|WARN there is no parameter `cause` on trait `Baz` + //~|WARN there is no parameter `cause` on trait `Baz` + //~|WARN there is no parameter `integral` on trait `Baz` + //~|WARN there is no parameter `integral` on trait `Baz` + //~|WARN there is no parameter `integer` on trait `Baz` + //~|WARN there is no parameter `integer` on trait `Baz` + label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + //~^WARN there is no parameter `float` on trait `Baz` + //~|WARN there is no parameter `float` on trait `Baz` + //~|WARN there is no parameter `_Self` on trait `Baz` + //~|WARN there is no parameter `_Self` on trait `Baz` + //~|WARN there is no parameter `crate_local` on trait `Baz` + //~|WARN there is no parameter `crate_local` on trait `Baz` + //~|WARN there is no parameter `Trait` on trait `Baz` + //~|WARN there is no parameter `Trait` on trait `Baz` + //~|WARN there is no parameter `ItemContext` on trait `Baz` + //~|WARN there is no parameter `ItemContext` on trait `Baz` +)] +trait Baz {} + +fn takes_foo(_: impl Foo) {} +fn takes_bar(_: impl Bar) {} +fn takes_baz(_: impl Baz) {} + +fn main() { + takes_foo(()); + //~^ERROR trait has `()` and `i32` as params + takes_bar(()); + //~^ERROR the trait bound `(): Bar` is not satisfied + takes_baz(()); + //~^ERROR {from_desugaring}{direct}{cause}{integral}{integer} +} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr new file mode 100644 index 0000000000000..75a701f0b5f65 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr @@ -0,0 +1,305 @@ +warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:24:1 + | +LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default + +warning: malformed `on_unimplemented` attribute + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:4:5 + | +LL | on(_Self = "&str"), + | ^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + +warning: malformed `on_unimplemented` attribute + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:10:5 + | +LL | parent_label = "in this scope", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + +warning: malformed `on_unimplemented` attribute + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:13:5 + | +LL | append_const_msg + | ^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + +warning: malformed `on_unimplemented` attribute + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:19:32 + | +LL | #[diagnostic::on_unimplemented = "Message"] + | ^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + +warning: there is no parameter `from_desugaring` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `direct` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `cause` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `integral` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `integer` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `float` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `_Self` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `crate_local` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `Trait` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `ItemContext` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: malformed `on_unimplemented` attribute + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:4:5 + | +LL | on(_Self = "&str"), + | ^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: malformed `on_unimplemented` attribute + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:10:5 + | +LL | parent_label = "in this scope", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: malformed `on_unimplemented` attribute + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:13:5 + | +LL | append_const_msg + | ^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: trait has `()` and `i32` as params + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:61:15 + | +LL | takes_foo(()); + | --------- ^^ trait has `()` and `i32` as params + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is not implemented for `()` + = note: trait has `()` and `i32` as params +help: this trait has no implementations, consider adding one + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:17:1 + | +LL | trait Foo {} + | ^^^^^^^^^^^^ +note: required by a bound in `takes_foo` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:22 + | +LL | fn takes_foo(_: impl Foo) {} + | ^^^^^^^^ required by this bound in `takes_foo` + +warning: malformed `on_unimplemented` attribute + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:19:32 + | +LL | #[diagnostic::on_unimplemented = "Message"] + | ^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `(): Bar` is not satisfied + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15 + | +LL | takes_bar(()); + | --------- ^^ the trait `Bar` is not implemented for `()` + | | + | required by a bound introduced by this call + | + = help: the trait `Bar` is implemented for `i32` +note: required by a bound in `takes_bar` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:57:22 + | +LL | fn takes_bar(_: impl Bar) {} + | ^^^ required by this bound in `takes_bar` + +warning: there is no parameter `from_desugaring` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: there is no parameter `direct` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: there is no parameter `cause` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: there is no parameter `integral` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: there is no parameter `integer` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: there is no parameter `float` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: there is no parameter `_Self` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: there is no parameter `crate_local` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: there is no parameter `Trait` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: there is no parameter `ItemContext` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer} + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:65:15 + | +LL | takes_baz(()); + | --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext} + | | + | required by a bound introduced by this call + | + = help: the trait `Baz` is not implemented for `()` +help: this trait has no implementations, consider adding one + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:54:1 + | +LL | trait Baz {} + | ^^^^^^^^^ +note: required by a bound in `takes_baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:58:22 + | +LL | fn takes_baz(_: impl Baz) {} + | ^^^ required by this bound in `takes_baz` + +error: aborting due to 3 previous errors; 29 warnings emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs index 346d8373f7398..12fe988170ac1 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs @@ -28,10 +28,16 @@ trait Doom {} //~|WARN missing options for `on_unimplemented` attribute trait Whatever {} +#[diagnostic::on_unimplemented(message = "{DoesNotExist}")] +//~^WARN there is no parameter `DoesNotExist` on trait `Test` +//~|WARN there is no parameter `DoesNotExist` on trait `Test` +trait Test {} + fn take_foo(_: impl Foo) {} fn take_baz(_: impl Baz) {} fn take_boom(_: impl Boom) {} fn take_whatever(_: impl Whatever) {} +fn take_test(_: impl Test) {} fn main() { take_foo(1_i32); @@ -42,4 +48,6 @@ fn main() { //~^ERROR Boom take_whatever(1_i32); //~^ERROR the trait bound `i32: Whatever` is not satisfied + take_test(()); + //~^ERROR {DoesNotExist} } diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr index 162ddd79fbbd9..11263580b15e2 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr @@ -46,6 +46,14 @@ LL | #[diagnostic::on_unimplemented] | = help: at least one of the `message`, `note` and `label` options are expected +warning: there is no parameter `DoesNotExist` on trait `Test` + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 + | +LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 | @@ -56,7 +64,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Foo` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14 | LL | take_foo(1_i32); | -------- ^^^^^ the trait `Foo` is not implemented for `i32` @@ -69,7 +77,7 @@ help: this trait has no implementations, consider adding one LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `take_foo` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:21 | LL | fn take_foo(_: impl Foo) {} | ^^^ required by this bound in `take_foo` @@ -84,7 +92,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:14 | LL | take_baz(1_i32); | -------- ^^^^^ the trait `Baz` is not implemented for `i32` @@ -97,7 +105,7 @@ help: this trait has no implementations, consider adding one LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `take_baz` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:21 | LL | fn take_baz(_: impl Baz) {} | ^^^ required by this bound in `take_baz` @@ -112,7 +120,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:15 | LL | take_boom(1_i32); | --------- ^^^^^ the trait `Boom` is not implemented for `i32` @@ -125,7 +133,7 @@ help: this trait has no implementations, consider adding one LL | trait Boom {} | ^^^^^^^^^^ note: required by a bound in `take_boom` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22 | LL | fn take_boom(_: impl Boom) {} | ^^^^ required by this bound in `take_boom` @@ -140,7 +148,7 @@ LL | #[diagnostic::on_unimplemented] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Whatever` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:19 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:19 | LL | take_whatever(1_i32); | ------------- ^^^^^ the trait `Whatever` is not implemented for `i32` @@ -153,11 +161,39 @@ help: this trait has no implementations, consider adding one LL | trait Whatever {} | ^^^^^^^^^^^^^^ note: required by a bound in `take_whatever` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:26 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:26 | LL | fn take_whatever(_: impl Whatever) {} | ^^^^^^^^ required by this bound in `take_whatever` -error: aborting due to 4 previous errors; 10 warnings emitted +warning: there is no parameter `DoesNotExist` on trait `Test` + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 + | +LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: {DoesNotExist} + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:51:15 + | +LL | take_test(()); + | --------- ^^ the trait `Test` is not implemented for `()` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:1 + | +LL | trait Test {} + | ^^^^^^^^^^ +note: required by a bound in `take_test` + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:40:22 + | +LL | fn take_test(_: impl Test) {} + | ^^^^ required by this bound in `take_test` + +error: aborting due to 5 previous errors; 12 warnings emitted For more information about this error, try `rustc --explain E0277`.