Change:
let trait_name = tcx.item_name(trait_def_id); let generics = tcx.generics_of(item_def_id); let s = self.symbol.as_str(); <del> let parser = Parser::new(s, None, None, false, ParseMode::Format); </del> <ins> let mut parser = Parser::new(s, None, None, false, ParseMode::Format); </ins> let mut result = Ok(()); <del> for token in parser { </del> <ins> for token in &mut parser { </ins> match token { Piece::String(_) => (), // Normal string, no need to check it <del> Piece::NextArgument(a) => match a.position { Position::ArgumentNamed(s) => { match Symbol::intern(s) { // `{ThisTraitsName}` is allowed 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 => { if self.is_diagnostic_namespace_variant { tcx.emit_node_span_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_code_err!( tcx.dcx(), 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()); </del> <ins> Piece::NextArgument(a) => { let format_spec = a.format; if self.is_diagnostic_namespace_variant && (format_spec.ty_span.is_some() || format_spec.width_span.is_some() || format_spec.precision_span.is_some() || format_spec.fill_span.is_some()) { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id.expect_local()), self.span, InvalidFormatSpecifier, ); } match a.position { Position::ArgumentNamed(s) => { match Symbol::intern(s) { // `{ThisTraitsName}` is allowed 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 => { if self.is_diagnostic_namespace_variant { tcx.emit_node_span_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_code_err!( tcx.dcx(), 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()); } </ins> } } } <ins> // `{:1}` and `{}` are not to be used Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { if self.is_diagnostic_namespace_variant { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id.expect_local()), self.span, DisallowedPositionalArgument, ); } else { let reported = struct_span_code_err!( tcx.dcx(), self.span, E0231, "only named generic parameters are allowed" ) .emit(); result = Err(reported); } } </ins> } <del> // `{:1}` and `{}` are not to be used Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { let reported = struct_span_code_err!( tcx.dcx(), self.span, E0231, "only named generic parameters are allowed" ) .emit(); result = Err(reported); } }, </del> <ins> } } } // we cannot return errors from processing the format string as hard error here // as the diagnostic namespace gurantees that malformed input cannot cause an error // // if we encounter any error while processing we nevertheless want to show it as warning // so that users are aware that something is not correct for e in parser.errors { if self.is_diagnostic_namespace_variant { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id.expect_local()), self.span, WrappedParserError { description: e.description, label: e.label }, ); } else { let reported = struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,).emit(); result = Err(reported); </ins> } }

Discussion:
The following are some unexpected behaviors I see with the formatting strings in the attribute. I'm not sure that the attribute should actually be using std's format parsing, but if it is, the following seem like issues with the current implementation. Anything after the is ignored, and not included in the message output. Expectation: There should be a warning that the string is malformed. or These generate an error. However, my understanding of the attribute is that it tries to only generate warnings for things it doesn't understand. I would expect this to also generate a warning. This does not generate a warning or error. I would expect it to generate a warning that anything after the is ignored. This includes width, precision, debug formatting, etc. The error message generated with this is the type followed by a . I would expect this to generate a warning that the format arguments are not valid (similar to how works). : cc
I filled to hopefully address this.
Good catch! This should probably support a strict subset of formatting (only named arguments and no format options), and warn whenever the string is either not valid for or not in the supported subset. When it shows a warning, not sure what the behavior of the string should be -- maybe just take it as a literal without any interpolation?