1use std::iter;
2use std::path::PathBuf;
3
4use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
5use rustc_errors::codes::*;
6use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
7use rustc_hir as hir;
8use rustc_hir::def::DefKind;
9use rustc_hir::def_id::{DefId, LocalDefId};
10use rustc_hir::{AttrArgs, Attribute};
11use rustc_macros::LintDiagnostic;
12use rustc_middle::bug;
13use rustc_middle::ty::print::PrintTraitRefExt;
14use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt};
15use rustc_session::lint::builtin::{
16 MALFORMED_DIAGNOSTIC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
17};
18use rustc_span::{Span, Symbol, sym};
19use tracing::{debug, info};
20
21use super::{ObligationCauseCode, PredicateObligation};
22use crate::error_reporting::TypeErrCtxt;
23use crate::error_reporting::traits::on_unimplemented_condition::{
24 ConditionOptions, OnUnimplementedCondition,
25};
26use crate::error_reporting::traits::on_unimplemented_format::{
27 Ctx, FormatArgs, FormatString, FormatWarning,
28};
29use crate::errors::{InvalidOnClause, NoValueInOnUnimplemented};
30use crate::infer::InferCtxtExt;
31
32impl<'tcx> TypeErrCtxt<'_, 'tcx> {
33 fn impl_similar_to(
34 &self,
35 trait_pred: ty::PolyTraitPredicate<'tcx>,
36 obligation: &PredicateObligation<'tcx>,
37 ) -> Option<(DefId, GenericArgsRef<'tcx>)> {
38 let tcx = self.tcx;
39 let param_env = obligation.param_env;
40 self.enter_forall(trait_pred, |trait_pred| {
41 let trait_self_ty = trait_pred.self_ty();
42
43 let mut self_match_impls = ::alloc::vec::Vec::new()vec![];
44 let mut fuzzy_match_impls = ::alloc::vec::Vec::new()vec![];
45
46 self.tcx.for_each_relevant_impl(trait_pred.def_id(), trait_self_ty, |def_id| {
47 let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id);
48 let impl_trait_ref = tcx.impl_trait_ref(def_id).instantiate(tcx, impl_args);
49
50 let impl_self_ty = impl_trait_ref.self_ty();
51
52 if self.can_eq(param_env, trait_self_ty, impl_self_ty) {
53 self_match_impls.push((def_id, impl_args));
54
55 if iter::zip(
56 trait_pred.trait_ref.args.types().skip(1),
57 impl_trait_ref.args.types().skip(1),
58 )
59 .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
60 {
61 fuzzy_match_impls.push((def_id, impl_args));
62 }
63 }
64 });
65
66 let impl_def_id_and_args = if let [impl_] = self_match_impls[..] {
67 impl_
68 } else if let [impl_] = fuzzy_match_impls[..] {
69 impl_
70 } else {
71 return None;
72 };
73
74 #[allow(deprecated)]
75 tcx.has_attr(impl_def_id_and_args.0, sym::rustc_on_unimplemented)
76 .then_some(impl_def_id_and_args)
77 })
78 }
79
80 fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str> {
83 match self.tcx.hir_node_by_def_id(def_id) {
84 hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { .. }, .. }) => Some("a function"),
85 hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => {
86 Some("a trait method")
87 }
88 hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
89 Some("a method")
90 }
91 hir::Node::Expr(hir::Expr {
92 kind: hir::ExprKind::Closure(hir::Closure { kind, .. }),
93 ..
94 }) => Some(self.describe_closure(*kind)),
95 _ => None,
96 }
97 }
98
99 pub fn on_unimplemented_note(
100 &self,
101 trait_pred: ty::PolyTraitPredicate<'tcx>,
102 obligation: &PredicateObligation<'tcx>,
103 long_ty_path: &mut Option<PathBuf>,
104 ) -> OnUnimplementedNote {
105 if trait_pred.polarity() != ty::PredicatePolarity::Positive {
106 return OnUnimplementedNote::default();
107 }
108 let (condition_options, format_args) =
109 self.on_unimplemented_components(trait_pred, obligation, long_ty_path);
110 if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, trait_pred.def_id())
111 {
112 command.evaluate(
113 self.tcx,
114 trait_pred.skip_binder().trait_ref,
115 &condition_options,
116 &format_args,
117 )
118 } else {
119 OnUnimplementedNote::default()
120 }
121 }
122
123 pub(crate) fn on_unimplemented_components(
124 &self,
125 trait_pred: ty::PolyTraitPredicate<'tcx>,
126 obligation: &PredicateObligation<'tcx>,
127 long_ty_path: &mut Option<PathBuf>,
128 ) -> (ConditionOptions, FormatArgs<'tcx>) {
129 let (def_id, args) = self
130 .impl_similar_to(trait_pred, obligation)
131 .unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args));
132 let trait_pred = trait_pred.skip_binder();
133
134 let mut self_types = ::alloc::vec::Vec::new()vec![];
135 let mut generic_args: Vec<(Symbol, String)> = ::alloc::vec::Vec::new()vec![];
136 let mut crate_local = false;
137 let item_context = self.describe_enclosure(obligation.cause.body_id).unwrap_or("");
141
142 let direct = match obligation.cause.code() {
143 ObligationCauseCode::BuiltinDerived(..)
144 | ObligationCauseCode::ImplDerived(..)
145 | ObligationCauseCode::WellFormedDerived(..) => false,
146 _ => {
147 true
150 }
151 };
152
153 let from_desugaring = obligation.cause.span.desugaring_kind();
154
155 let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
156 Some("MainFunctionType".to_string())
157 } else {
158 None
159 };
160
161 {
let _guard = NoTrimmedGuard::new();
{
let _guard = NoVisibleGuard::new();
{
let generics = self.tcx.generics_of(def_id);
let self_ty = trait_pred.self_ty();
self_types.push(self_ty.to_string());
if let Some(def) = self_ty.ty_adt_def() {
self_types.push(self.tcx.type_of(def.did()).instantiate_identity().to_string());
}
for GenericParamDef { name, kind, index, .. } in
generics.own_params.iter() {
let value =
match kind {
GenericParamDefKind::Type { .. } |
GenericParamDefKind::Const { .. } => {
args[*index as usize].to_string()
}
GenericParamDefKind::Lifetime => continue,
};
generic_args.push((*name, value));
if let GenericParamDefKind::Type { .. } = kind {
let param_ty = args[*index as usize].expect_ty();
if let Some(def) = param_ty.ty_adt_def() {
generic_args.push((*name,
self.tcx.type_of(def.did()).instantiate_identity().to_string()));
}
}
}
if let Some(true) =
self_ty.ty_adt_def().map(|def| def.did().is_local()) {
crate_local = true;
}
if self_ty.is_integral() {
self_types.push("{integral}".to_owned());
}
if self_ty.is_array_slice() { self_types.push("&[]".to_owned()); }
if self_ty.is_fn() {
let fn_sig = self_ty.fn_sig(self.tcx);
let shortname =
if let ty::FnDef(def_id, _) = self_ty.kind() &&
self.tcx.codegen_fn_attrs(def_id).safe_target_features {
"#[target_feature] fn"
} else {
match fn_sig.safety() {
hir::Safety::Safe => "fn",
hir::Safety::Unsafe => "unsafe fn",
}
};
self_types.push(shortname.to_owned());
}
if let ty::Slice(aty) = self_ty.kind() {
self_types.push("[]".to_owned());
if let Some(def) = aty.ty_adt_def() {
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{0}]",
self.tcx.type_of(def.did()).instantiate_identity()))
}));
}
if aty.is_integral() {
self_types.push("[{integral}]".to_string());
}
}
if let ty::Array(aty, len) = self_ty.kind() {
self_types.push("[]".to_string());
let len = len.try_to_target_usize(self.tcx);
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{0}; _]", aty))
}));
if let Some(n) = len {
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{0}; {1}]", aty, n))
}));
}
if let Some(def) = aty.ty_adt_def() {
let def_ty =
self.tcx.type_of(def.did()).instantiate_identity();
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{0}; _]", def_ty))
}));
if let Some(n) = len {
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{0}; {1}]", def_ty, n))
}));
}
}
if aty.is_integral() {
self_types.push("[{integral}; _]".to_string());
if let Some(n) = len {
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{{integral}}; {0}]", n))
}));
}
}
}
if let ty::Dynamic(traits, _) = self_ty.kind() {
for t in traits.iter() {
if let ty::ExistentialPredicate::Trait(trait_ref) =
t.skip_binder() {
self_types.push(self.tcx.def_path_str(trait_ref.def_id));
}
}
}
if let ty::Ref(_, ref_ty, rustc_ast::Mutability::Not) =
self_ty.kind() && let ty::Slice(sty) = ref_ty.kind() &&
sty.is_integral() {
self_types.push("&[{integral}]".to_owned());
}
}
}
};ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({
164 let generics = self.tcx.generics_of(def_id);
165 let self_ty = trait_pred.self_ty();
166 self_types.push(self_ty.to_string());
167 if let Some(def) = self_ty.ty_adt_def() {
168 self_types.push(self.tcx.type_of(def.did()).instantiate_identity().to_string());
171 }
172
173 for GenericParamDef { name, kind, index, .. } in generics.own_params.iter() {
174 let value = match kind {
175 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
176 args[*index as usize].to_string()
177 }
178 GenericParamDefKind::Lifetime => continue,
179 };
180 generic_args.push((*name, value));
181
182 if let GenericParamDefKind::Type { .. } = kind {
183 let param_ty = args[*index as usize].expect_ty();
184 if let Some(def) = param_ty.ty_adt_def() {
185 generic_args.push((
188 *name,
189 self.tcx.type_of(def.did()).instantiate_identity().to_string(),
190 ));
191 }
192 }
193 }
194
195 if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
196 crate_local = true;
197 }
198
199 if self_ty.is_integral() {
201 self_types.push("{integral}".to_owned());
202 }
203
204 if self_ty.is_array_slice() {
205 self_types.push("&[]".to_owned());
206 }
207
208 if self_ty.is_fn() {
209 let fn_sig = self_ty.fn_sig(self.tcx);
210 let shortname = if let ty::FnDef(def_id, _) = self_ty.kind()
211 && self.tcx.codegen_fn_attrs(def_id).safe_target_features
212 {
213 "#[target_feature] fn"
214 } else {
215 match fn_sig.safety() {
216 hir::Safety::Safe => "fn",
217 hir::Safety::Unsafe => "unsafe fn",
218 }
219 };
220 self_types.push(shortname.to_owned());
221 }
222
223 if let ty::Slice(aty) = self_ty.kind() {
225 self_types.push("[]".to_owned());
226 if let Some(def) = aty.ty_adt_def() {
227 self_types
230 .push(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity()));
231 }
232 if aty.is_integral() {
233 self_types.push("[{integral}]".to_string());
234 }
235 }
236
237 if let ty::Array(aty, len) = self_ty.kind() {
239 self_types.push("[]".to_string());
240 let len = len.try_to_target_usize(self.tcx);
241 self_types.push(format!("[{aty}; _]"));
242 if let Some(n) = len {
243 self_types.push(format!("[{aty}; {n}]"));
244 }
245 if let Some(def) = aty.ty_adt_def() {
246 let def_ty = self.tcx.type_of(def.did()).instantiate_identity();
249 self_types.push(format!("[{def_ty}; _]"));
250 if let Some(n) = len {
251 self_types.push(format!("[{def_ty}; {n}]"));
252 }
253 }
254 if aty.is_integral() {
255 self_types.push("[{integral}; _]".to_string());
256 if let Some(n) = len {
257 self_types.push(format!("[{{integral}}; {n}]"));
258 }
259 }
260 }
261 if let ty::Dynamic(traits, _) = self_ty.kind() {
262 for t in traits.iter() {
263 if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
264 self_types.push(self.tcx.def_path_str(trait_ref.def_id));
265 }
266 }
267 }
268
269 if let ty::Ref(_, ref_ty, rustc_ast::Mutability::Not) = self_ty.kind()
271 && let ty::Slice(sty) = ref_ty.kind()
272 && sty.is_integral()
273 {
274 self_types.push("&[{integral}]".to_owned());
275 }
276 }));
277
278 let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id);
279 let trait_sugared = trait_pred.trait_ref.print_trait_sugared();
280
281 let condition_options = ConditionOptions {
282 self_types,
283 from_desugaring,
284 cause,
285 crate_local,
286 direct,
287 generic_args,
288 };
289
290 let generic_args = self
296 .tcx
297 .generics_of(trait_pred.trait_ref.def_id)
298 .own_params
299 .iter()
300 .filter_map(|param| {
301 let value = match param.kind {
302 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
303 if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type()
304 {
305 self.tcx.short_string(ty, long_ty_path)
306 } else {
307 trait_pred.trait_ref.args[param.index as usize].to_string()
308 }
309 }
310 GenericParamDefKind::Lifetime => return None,
311 };
312 let name = param.name;
313 Some((name, value))
314 })
315 .collect();
316
317 let format_args = FormatArgs { this, trait_sugared, generic_args, item_context };
318 (condition_options, format_args)
319 }
320}
321
322#[derive(#[automatically_derived]
impl ::core::clone::Clone for OnUnimplementedFormatString {
#[inline]
fn clone(&self) -> OnUnimplementedFormatString {
OnUnimplementedFormatString {
symbol: ::core::clone::Clone::clone(&self.symbol),
span: ::core::clone::Clone::clone(&self.span),
is_diagnostic_namespace_variant: ::core::clone::Clone::clone(&self.is_diagnostic_namespace_variant),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for OnUnimplementedFormatString {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"OnUnimplementedFormatString", "symbol", &self.symbol, "span",
&self.span, "is_diagnostic_namespace_variant",
&&self.is_diagnostic_namespace_variant)
}
}Debug)]
325pub struct OnUnimplementedFormatString {
326 symbol: Symbol,
328 span: Span,
330 is_diagnostic_namespace_variant: bool,
331}
332
333#[derive(#[automatically_derived]
impl ::core::fmt::Debug for OnUnimplementedDirective {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["condition", "subcommands", "message", "label", "notes",
"parent_label", "append_const_msg"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.condition, &self.subcommands, &self.message, &self.label,
&self.notes, &self.parent_label, &&self.append_const_msg];
::core::fmt::Formatter::debug_struct_fields_finish(f,
"OnUnimplementedDirective", names, values)
}
}Debug)]
334pub struct OnUnimplementedDirective {
335 condition: Option<OnUnimplementedCondition>,
336 subcommands: Vec<OnUnimplementedDirective>,
337 message: Option<(Span, OnUnimplementedFormatString)>,
338 label: Option<(Span, OnUnimplementedFormatString)>,
339 notes: Vec<OnUnimplementedFormatString>,
340 parent_label: Option<OnUnimplementedFormatString>,
341 append_const_msg: Option<AppendConstMessage>,
342}
343
344#[derive(#[automatically_derived]
impl ::core::default::Default for OnUnimplementedNote {
#[inline]
fn default() -> OnUnimplementedNote {
OnUnimplementedNote {
message: ::core::default::Default::default(),
label: ::core::default::Default::default(),
notes: ::core::default::Default::default(),
parent_label: ::core::default::Default::default(),
append_const_msg: ::core::default::Default::default(),
}
}
}Default, #[automatically_derived]
impl ::core::fmt::Debug for OnUnimplementedNote {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field5_finish(f,
"OnUnimplementedNote", "message", &self.message, "label",
&self.label, "notes", &self.notes, "parent_label",
&self.parent_label, "append_const_msg", &&self.append_const_msg)
}
}Debug)]
346pub struct OnUnimplementedNote {
347 pub message: Option<String>,
348 pub label: Option<String>,
349 pub notes: Vec<String>,
350 pub parent_label: Option<String>,
351 pub append_const_msg: Option<AppendConstMessage>,
353}
354
355#[derive(#[automatically_derived]
impl ::core::clone::Clone for AppendConstMessage {
#[inline]
fn clone(&self) -> AppendConstMessage {
let _: ::core::clone::AssertParamIsClone<Symbol>;
let _: ::core::clone::AssertParamIsClone<Span>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for AppendConstMessage { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for AppendConstMessage {
#[inline]
fn eq(&self, other: &AppendConstMessage) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(AppendConstMessage::Custom(__self_0, __self_1),
AppendConstMessage::Custom(__arg1_0, __arg1_1)) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for AppendConstMessage {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Symbol>;
let _: ::core::cmp::AssertParamIsEq<Span>;
}
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for AppendConstMessage {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
AppendConstMessage::Default =>
::core::fmt::Formatter::write_str(f, "Default"),
AppendConstMessage::Custom(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f, "Custom",
__self_0, &__self_1),
}
}
}Debug, #[automatically_derived]
impl ::core::default::Default for AppendConstMessage {
#[inline]
fn default() -> AppendConstMessage { Self::Default }
}Default)]
357pub enum AppendConstMessage {
358 #[default]
359 Default,
360 Custom(Symbol, Span),
361}
362
363#[derive(const _: () =
{
impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for
MalformedOnUnimplementedAttrLint {
#[track_caller]
fn decorate_lint<'__b>(self,
diag: &'__b mut rustc_errors::Diag<'__a, ()>) {
match self {
MalformedOnUnimplementedAttrLint { span: __binding_0 } => {
diag.primary_message(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("malformed `on_unimplemented` attribute")));
diag.help(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("only `message`, `note` and `label` are allowed as options")));
;
diag.span_label(__binding_0,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("invalid option found here")));
diag
}
};
}
}
};LintDiagnostic)]
364#[diag("malformed `on_unimplemented` attribute")]
365#[help("only `message`, `note` and `label` are allowed as options")]
366pub struct MalformedOnUnimplementedAttrLint {
367 #[label("invalid option found here")]
368 pub span: Span,
369}
370
371impl MalformedOnUnimplementedAttrLint {
372 pub fn new(span: Span) -> Self {
373 Self { span }
374 }
375}
376
377#[derive(const _: () =
{
impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for
MissingOptionsForOnUnimplementedAttr {
#[track_caller]
fn decorate_lint<'__b>(self,
diag: &'__b mut rustc_errors::Diag<'__a, ()>) {
match self {
MissingOptionsForOnUnimplementedAttr => {
diag.primary_message(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("missing options for `on_unimplemented` attribute")));
diag.help(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("at least one of the `message`, `note` and `label` options are expected")));
;
diag
}
};
}
}
};LintDiagnostic)]
378#[diag("missing options for `on_unimplemented` attribute")]
379#[help("at least one of the `message`, `note` and `label` options are expected")]
380pub struct MissingOptionsForOnUnimplementedAttr;
381
382#[derive(const _: () =
{
impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for
IgnoredDiagnosticOption {
#[track_caller]
fn decorate_lint<'__b>(self,
diag: &'__b mut rustc_errors::Diag<'__a, ()>) {
match self {
IgnoredDiagnosticOption {
option_name: __binding_0,
span: __binding_1,
prev_span: __binding_2 } => {
diag.primary_message(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`{$option_name}` is ignored due to previous definition of `{$option_name}`")));
;
diag.arg("option_name", __binding_0);
diag.span_label(__binding_1,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`{$option_name}` is already declared here")));
diag.span_label(__binding_2,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`{$option_name}` is first declared here")));
diag
}
};
}
}
};LintDiagnostic)]
383#[diag("`{$option_name}` is ignored due to previous definition of `{$option_name}`")]
384pub struct IgnoredDiagnosticOption {
385 pub option_name: &'static str,
386 #[label("`{$option_name}` is already declared here")]
387 pub span: Span,
388 #[label("`{$option_name}` is first declared here")]
389 pub prev_span: Span,
390}
391
392impl IgnoredDiagnosticOption {
393 pub fn maybe_emit_warning<'tcx>(
394 tcx: TyCtxt<'tcx>,
395 item_def_id: DefId,
396 new: Option<Span>,
397 old: Option<Span>,
398 option_name: &'static str,
399 ) {
400 if let (Some(new_item), Some(old_item)) = (new, old)
401 && let Some(item_def_id) = item_def_id.as_local()
402 {
403 tcx.emit_node_span_lint(
404 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
405 tcx.local_def_id_to_hir_id(item_def_id),
406 new_item,
407 IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name },
408 );
409 }
410 }
411}
412
413#[derive(const _: () =
{
impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for
WrappedParserError {
#[track_caller]
fn decorate_lint<'__b>(self,
diag: &'__b mut rustc_errors::Diag<'__a, ()>) {
match self {
WrappedParserError {
description: __binding_0, label: __binding_1 } => {
diag.primary_message(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("{$description}")));
;
diag.arg("description", __binding_0);
diag.arg("label", __binding_1);
diag
}
};
}
}
};LintDiagnostic)]
414#[diag("{$description}")]
415pub struct WrappedParserError {
416 pub description: String,
417 pub label: String,
418}
419
420impl<'tcx> OnUnimplementedDirective {
421 fn parse(
422 tcx: TyCtxt<'tcx>,
423 item_def_id: DefId,
424 items: &[MetaItemInner],
425 span: Span,
426 is_root: bool,
427 is_diagnostic_namespace_variant: bool,
428 ) -> Result<Option<Self>, ErrorGuaranteed> {
429 let mut errored = None;
430 let mut item_iter = items.iter();
431
432 let parse_value = |value_str, span| {
433 OnUnimplementedFormatString::try_parse(
434 tcx,
435 item_def_id,
436 value_str,
437 span,
438 is_diagnostic_namespace_variant,
439 )
440 .map(Some)
441 };
442
443 let condition = if is_root {
444 None
445 } else {
446 let cond = item_iter
447 .next()
448 .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClause::Empty { span }))?;
449
450 let generics: Vec<Symbol> = tcx
451 .generics_of(item_def_id)
452 .own_params
453 .iter()
454 .filter_map(|param| {
455 if #[allow(non_exhaustive_omitted_patterns)] match param.kind {
GenericParamDefKind::Lifetime => true,
_ => false,
}matches!(param.kind, GenericParamDefKind::Lifetime) {
456 None
457 } else {
458 Some(param.name)
459 }
460 })
461 .collect();
462 match OnUnimplementedCondition::parse(cond, &generics) {
463 Ok(condition) => Some(condition),
464 Err(e) => return Err(tcx.dcx().emit_err(e)),
465 }
466 };
467
468 let mut message = None;
469 let mut label = None;
470 let mut notes = Vec::new();
471 let mut parent_label = None;
472 let mut subcommands = ::alloc::vec::Vec::new()vec![];
473 let mut append_const_msg = None;
474
475 let get_value_and_span = |item: &_, key| {
476 if let MetaItemInner::MetaItem(MetaItem {
477 path,
478 kind: MetaItemKind::NameValue(MetaItemLit { span, kind: LitKind::Str(s, _), .. }),
479 ..
480 }) = item
481 && *path == key
482 {
483 Some((*s, *span))
484 } else {
485 None
486 }
487 };
488
489 for item in item_iter {
490 if let Some((message_, span)) = get_value_and_span(item, sym::message)
491 && message.is_none()
492 {
493 message = parse_value(message_, span)?.map(|l| (item.span(), l));
494 continue;
495 } else if let Some((label_, span)) = get_value_and_span(item, sym::label)
496 && label.is_none()
497 {
498 label = parse_value(label_, span)?.map(|l| (item.span(), l));
499 continue;
500 } else if let Some((note_, span)) = get_value_and_span(item, sym::note) {
501 if let Some(note) = parse_value(note_, span)? {
502 notes.push(note);
503 continue;
504 }
505 } else if item.has_name(sym::parent_label)
506 && parent_label.is_none()
507 && !is_diagnostic_namespace_variant
508 {
509 if let Some(parent_label_) = item.value_str() {
510 parent_label = parse_value(parent_label_, item.span())?;
511 continue;
512 }
513 } else if item.has_name(sym::on)
514 && is_root
515 && message.is_none()
516 && label.is_none()
517 && notes.is_empty()
518 && !is_diagnostic_namespace_variant
519 {
521 if let Some(items) = item.meta_item_list() {
522 match Self::parse(
523 tcx,
524 item_def_id,
525 items,
526 item.span(),
527 false,
528 is_diagnostic_namespace_variant,
529 ) {
530 Ok(Some(subcommand)) => subcommands.push(subcommand),
531 Ok(None) => ::rustc_middle::util::bug::bug_fmt(format_args!("This cannot happen for now as we only reach that if `is_diagnostic_namespace_variant` is false"))bug!(
532 "This cannot happen for now as we only reach that if `is_diagnostic_namespace_variant` is false"
533 ),
534 Err(reported) => errored = Some(reported),
535 };
536 continue;
537 }
538 } else if item.has_name(sym::append_const_msg)
539 && append_const_msg.is_none()
540 && !is_diagnostic_namespace_variant
541 {
542 if let Some(msg) = item.value_str() {
543 append_const_msg = Some(AppendConstMessage::Custom(msg, item.span()));
544 continue;
545 } else if item.is_word() {
546 append_const_msg = Some(AppendConstMessage::Default);
547 continue;
548 }
549 }
550
551 if is_diagnostic_namespace_variant {
552 if let Some(def_id) = item_def_id.as_local() {
553 tcx.emit_node_span_lint(
554 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
555 tcx.local_def_id_to_hir_id(def_id),
556 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[item.span()]))vec![item.span()],
557 MalformedOnUnimplementedAttrLint::new(item.span()),
558 );
559 }
560 } else {
561 tcx.dcx().emit_err(NoValueInOnUnimplemented { span: item.span() });
563 }
564 }
565
566 if let Some(reported) = errored {
567 if is_diagnostic_namespace_variant { Ok(None) } else { Err(reported) }
568 } else {
569 Ok(Some(OnUnimplementedDirective {
570 condition,
571 subcommands,
572 message,
573 label,
574 notes,
575 parent_label,
576 append_const_msg,
577 }))
578 }
579 }
580
581 pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
582 let attr = if tcx.is_trait(item_def_id) {
583 sym::on_unimplemented
584 } else if let DefKind::Impl { of_trait: true } = tcx.def_kind(item_def_id) {
585 sym::on_const
586 } else {
587 return Ok(None);
592 };
593 if let Some(attr) = {
594 #[allow(deprecated)]
595 tcx.get_attr(item_def_id, sym::rustc_on_unimplemented)
596 } {
597 return Self::parse_attribute(attr, false, tcx, item_def_id);
598 } else {
599 tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, attr])
600 .filter_map(|attr| Self::parse_attribute(attr, true, tcx, item_def_id).transpose())
601 .try_fold(None, |aggr: Option<Self>, directive| {
602 let directive = directive?;
603 if let Some(aggr) = aggr {
604 let mut subcommands = aggr.subcommands;
605 subcommands.extend(directive.subcommands);
606 let mut notes = aggr.notes;
607 notes.extend(directive.notes);
608 IgnoredDiagnosticOption::maybe_emit_warning(
609 tcx,
610 item_def_id,
611 directive.message.as_ref().map(|f| f.0),
612 aggr.message.as_ref().map(|f| f.0),
613 "message",
614 );
615 IgnoredDiagnosticOption::maybe_emit_warning(
616 tcx,
617 item_def_id,
618 directive.label.as_ref().map(|f| f.0),
619 aggr.label.as_ref().map(|f| f.0),
620 "label",
621 );
622 IgnoredDiagnosticOption::maybe_emit_warning(
623 tcx,
624 item_def_id,
625 directive.condition.as_ref().map(|i| i.span()),
626 aggr.condition.as_ref().map(|i| i.span()),
627 "condition",
628 );
629 IgnoredDiagnosticOption::maybe_emit_warning(
630 tcx,
631 item_def_id,
632 directive.parent_label.as_ref().map(|f| f.span),
633 aggr.parent_label.as_ref().map(|f| f.span),
634 "parent_label",
635 );
636 IgnoredDiagnosticOption::maybe_emit_warning(
637 tcx,
638 item_def_id,
639 directive.append_const_msg.as_ref().and_then(|c| {
640 if let AppendConstMessage::Custom(_, s) = c {
641 Some(*s)
642 } else {
643 None
644 }
645 }),
646 aggr.append_const_msg.as_ref().and_then(|c| {
647 if let AppendConstMessage::Custom(_, s) = c {
648 Some(*s)
649 } else {
650 None
651 }
652 }),
653 "append_const_msg",
654 );
655
656 Ok(Some(Self {
657 condition: aggr.condition.or(directive.condition),
658 subcommands,
659 message: aggr.message.or(directive.message),
660 label: aggr.label.or(directive.label),
661 notes,
662 parent_label: aggr.parent_label.or(directive.parent_label),
663 append_const_msg: aggr.append_const_msg.or(directive.append_const_msg),
664 }))
665 } else {
666 Ok(Some(directive))
667 }
668 })
669 }
670 }
671
672 fn parse_attribute(
673 attr: &Attribute,
674 is_diagnostic_namespace_variant: bool,
675 tcx: TyCtxt<'tcx>,
676 item_def_id: DefId,
677 ) -> Result<Option<Self>, ErrorGuaranteed> {
678 let result = if let Some(items) = attr.meta_item_list() {
679 Self::parse(
680 tcx,
681 item_def_id,
682 &items,
683 attr.span(),
684 true,
685 is_diagnostic_namespace_variant,
686 )
687 } else if let Some(value) = attr.value_str() {
688 if !is_diagnostic_namespace_variant {
689 Ok(Some(OnUnimplementedDirective {
690 condition: None,
691 message: None,
692 subcommands: ::alloc::vec::Vec::new()vec![],
693 label: Some((
694 attr.span(),
695 OnUnimplementedFormatString::try_parse(
696 tcx,
697 item_def_id,
698 value,
699 attr.value_span().unwrap_or(attr.span()),
700 is_diagnostic_namespace_variant,
701 )?,
702 )),
703 notes: Vec::new(),
704 parent_label: None,
705 append_const_msg: None,
706 }))
707 } else {
708 let item = attr.get_normal_item();
709 let report_span = match &item.args {
710 AttrArgs::Empty => item.path.span,
711 AttrArgs::Delimited(args) => args.dspan.entire(),
712 AttrArgs::Eq { eq_span, expr } => eq_span.to(expr.span),
713 };
714
715 if let Some(item_def_id) = item_def_id.as_local() {
716 tcx.emit_node_span_lint(
717 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
718 tcx.local_def_id_to_hir_id(item_def_id),
719 report_span,
720 MalformedOnUnimplementedAttrLint::new(report_span),
721 );
722 }
723 Ok(None)
724 }
725 } else if is_diagnostic_namespace_variant {
726 match attr {
727 Attribute::Unparsed(p) if !#[allow(non_exhaustive_omitted_patterns)] match p.args {
AttrArgs::Empty => true,
_ => false,
}matches!(p.args, AttrArgs::Empty) => {
728 if let Some(item_def_id) = item_def_id.as_local() {
729 tcx.emit_node_span_lint(
730 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
731 tcx.local_def_id_to_hir_id(item_def_id),
732 attr.span(),
733 MalformedOnUnimplementedAttrLint::new(attr.span()),
734 );
735 }
736 }
737 _ => {
738 if let Some(item_def_id) = item_def_id.as_local() {
739 tcx.emit_node_span_lint(
740 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
741 tcx.local_def_id_to_hir_id(item_def_id),
742 attr.span(),
743 MissingOptionsForOnUnimplementedAttr,
744 )
745 }
746 }
747 };
748
749 Ok(None)
750 } else {
751 let reported = tcx.dcx().delayed_bug("of_item: neither meta_item_list nor value_str");
752 return Err(reported);
753 };
754 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs:754",
"rustc_trait_selection::error_reporting::traits::on_unimplemented",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs"),
::tracing_core::__macro_support::Option::Some(754u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::traits::on_unimplemented"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("of_item({0:?}) = {1:?}",
item_def_id, result) as &dyn Value))])
});
} else { ; }
};debug!("of_item({:?}) = {:?}", item_def_id, result);
755 result
756 }
757
758 pub(crate) fn evaluate(
759 &self,
760 tcx: TyCtxt<'tcx>,
761 trait_ref: ty::TraitRef<'tcx>,
762 condition_options: &ConditionOptions,
763 args: &FormatArgs<'tcx>,
764 ) -> OnUnimplementedNote {
765 let mut message = None;
766 let mut label = None;
767 let mut notes = Vec::new();
768 let mut parent_label = None;
769 let mut append_const_msg = None;
770 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs:770",
"rustc_trait_selection::error_reporting::traits::on_unimplemented",
::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs"),
::tracing_core::__macro_support::Option::Some(770u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::traits::on_unimplemented"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("evaluate({0:?}, trait_ref={1:?}, options={2:?}, args ={3:?})",
self, trait_ref, condition_options, args) as &dyn Value))])
});
} else { ; }
};info!(
771 "evaluate({:?}, trait_ref={:?}, options={:?}, args ={:?})",
772 self, trait_ref, condition_options, args
773 );
774
775 for command in self.subcommands.iter().chain(Some(self)).rev() {
776 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs:776",
"rustc_trait_selection::error_reporting::traits::on_unimplemented",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs"),
::tracing_core::__macro_support::Option::Some(776u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::traits::on_unimplemented"),
::tracing_core::field::FieldSet::new(&["command"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&command) as
&dyn Value))])
});
} else { ; }
};debug!(?command);
777 if let Some(ref condition) = command.condition
778 && !condition.matches_predicate(condition_options)
779 {
780 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs:780",
"rustc_trait_selection::error_reporting::traits::on_unimplemented",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs"),
::tracing_core::__macro_support::Option::Some(780u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::traits::on_unimplemented"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("evaluate: skipping {0:?} due to condition",
command) as &dyn Value))])
});
} else { ; }
};debug!("evaluate: skipping {:?} due to condition", command);
781 continue;
782 }
783 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs:783",
"rustc_trait_selection::error_reporting::traits::on_unimplemented",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs"),
::tracing_core::__macro_support::Option::Some(783u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::traits::on_unimplemented"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("evaluate: {0:?} succeeded",
command) as &dyn Value))])
});
} else { ; }
};debug!("evaluate: {:?} succeeded", command);
784 if let Some(ref message_) = command.message {
785 message = Some(message_.clone());
786 }
787
788 if let Some(ref label_) = command.label {
789 label = Some(label_.clone());
790 }
791
792 notes.extend(command.notes.clone());
793
794 if let Some(ref parent_label_) = command.parent_label {
795 parent_label = Some(parent_label_.clone());
796 }
797
798 append_const_msg = command.append_const_msg;
799 }
800
801 OnUnimplementedNote {
802 label: label.map(|l| l.1.format(tcx, trait_ref, args)),
803 message: message.map(|m| m.1.format(tcx, trait_ref, args)),
804 notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, args)).collect(),
805 parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, args)),
806 append_const_msg,
807 }
808 }
809}
810
811impl<'tcx> OnUnimplementedFormatString {
812 fn try_parse(
813 tcx: TyCtxt<'tcx>,
814 item_def_id: DefId,
815 from: Symbol,
816 span: Span,
817 is_diagnostic_namespace_variant: bool,
818 ) -> Result<Self, ErrorGuaranteed> {
819 let result =
820 OnUnimplementedFormatString { symbol: from, span, is_diagnostic_namespace_variant };
821 result.verify(tcx, item_def_id)?;
822 Ok(result)
823 }
824
825 fn verify(&self, tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> {
826 if !tcx.is_trait(trait_def_id) {
827 return Ok(());
828 };
829
830 let ctx = if self.is_diagnostic_namespace_variant {
831 Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }
832 } else {
833 Ctx::RustcOnUnimplemented { tcx, trait_def_id }
834 };
835
836 let mut result = Ok(());
837
838 let snippet = tcx.sess.source_map().span_to_snippet(self.span).ok();
839 match FormatString::parse(self.symbol, snippet, self.span, &ctx) {
840 Ok(FormatString { warnings, .. }) => {
843 if self.is_diagnostic_namespace_variant {
844 for w in warnings {
845 w.emit_warning(tcx, trait_def_id)
846 }
847 } else {
848 for w in warnings {
849 match w {
850 FormatWarning::UnknownParam { argument_name, span } => {
851 let reported = {
tcx.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot find parameter {0} on this trait",
argument_name))
})).with_code(E0230)
}struct_span_code_err!(
852 tcx.dcx(),
853 span,
854 E0230,
855 "cannot find parameter {} on this trait",
856 argument_name,
857 )
858 .emit();
859 result = Err(reported);
860 }
861 FormatWarning::PositionalArgument { span, .. } => {
862 let reported = {
tcx.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("positional format arguments are not allowed here"))
})).with_code(E0231)
}struct_span_code_err!(
863 tcx.dcx(),
864 span,
865 E0231,
866 "positional format arguments are not allowed here"
867 )
868 .emit();
869 result = Err(reported);
870 }
871 FormatWarning::InvalidSpecifier { .. }
872 | FormatWarning::FutureIncompat { .. } => {}
873 }
874 }
875 }
876 }
877 Err(e) => {
879 if self.is_diagnostic_namespace_variant {
885 if let Some(trait_def_id) = trait_def_id.as_local() {
886 tcx.emit_node_span_lint(
887 MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
888 tcx.local_def_id_to_hir_id(trait_def_id),
889 self.span,
890 WrappedParserError { description: e.description, label: e.label },
891 );
892 }
893 } else {
894 let reported =
895 {
tcx.dcx().struct_span_err(self.span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", e.description))
})).with_code(E0231)
}struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description)
896 .emit();
897 result = Err(reported);
898 }
899 }
900 }
901
902 result
903 }
904
905 pub fn format(
906 &self,
907 tcx: TyCtxt<'tcx>,
908 trait_ref: ty::TraitRef<'tcx>,
909 args: &FormatArgs<'tcx>,
910 ) -> String {
911 let trait_def_id = trait_ref.def_id;
912 let ctx = if self.is_diagnostic_namespace_variant {
913 Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }
914 } else {
915 Ctx::RustcOnUnimplemented { tcx, trait_def_id }
916 };
917
918 if let Ok(s) = FormatString::parse(self.symbol, None, self.span, &ctx) {
920 s.format(args)
921 } else {
922 self.symbol.as_str().into()
932 }
933 }
934}