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> } }