1use std::backtrace::Backtrace;
2use std::borrow::Cow;
3use std::fmt;
4use std::num::ParseIntError;
5use std::path::{Path, PathBuf};
6use std::process::ExitStatus;
7
8use rustc_abi::TargetDataLayoutErrors;
9use rustc_ast::util::parser::ExprPrecedence;
10use rustc_ast_pretty::pprust;
11use rustc_hir::RustcVersion;
12use rustc_hir::attrs::{MirDialect, MirPhase};
13use rustc_macros::Subdiagnostic;
14use rustc_span::edition::Edition;
15use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol};
16use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTuple};
17use rustc_type_ir::{ClosureKind, FloatTy};
18use {rustc_ast as ast, rustc_hir as hir};
19
20use crate::diagnostic::DiagLocation;
21use crate::{
22 Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level,
23 Subdiagnostic, fluent_generated as fluent,
24};
25
26pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display);
27
28impl IntoDiagArg for DiagArgFromDisplay<'_> {
29 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
30 self.0.to_string().into_diag_arg(path)
31 }
32}
33
34impl<'a> From<&'a dyn fmt::Display> for DiagArgFromDisplay<'a> {
35 fn from(t: &'a dyn fmt::Display) -> Self {
36 DiagArgFromDisplay(t)
37 }
38}
39
40impl<'a, T: fmt::Display> From<&'a T> for DiagArgFromDisplay<'a> {
41 fn from(t: &'a T) -> Self {
42 DiagArgFromDisplay(t)
43 }
44}
45
46impl<'a, T: Clone + IntoDiagArg> IntoDiagArg for &'a T {
47 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
48 self.clone().into_diag_arg(path)
49 }
50}
51
52#[macro_export]
53macro_rules! into_diag_arg_using_display {
54 ($( $ty:ty ),+ $(,)?) => {
55 $(
56 impl IntoDiagArg for $ty {
57 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
58 self.to_string().into_diag_arg(path)
59 }
60 }
61 )+
62 }
63}
64
65macro_rules! into_diag_arg_for_number {
66 ($( $ty:ty ),+ $(,)?) => {
67 $(
68 impl IntoDiagArg for $ty {
69 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
70 #[allow(irrefutable_let_patterns)]
72 if let Ok(n) = TryInto::<i32>::try_into(self) {
73 DiagArgValue::Number(n)
74 } else {
75 self.to_string().into_diag_arg(path)
76 }
77 }
78 }
79 )+
80 }
81}
82
83into_diag_arg_using_display!(
84 ast::ParamKindOrd,
85 std::io::Error,
86 Box<dyn std::error::Error>,
87 std::num::NonZero<u32>,
88 hir::Target,
89 Edition,
90 Ident,
91 MacroRulesNormalizedIdent,
92 ParseIntError,
93 StackProtector,
94 &TargetTuple,
95 SplitDebuginfo,
96 ExitStatus,
97 ErrCode,
98 rustc_abi::ExternAbi,
99);
100
101impl IntoDiagArg for RustcVersion {
102 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
103 DiagArgValue::Str(Cow::Owned(self.to_string()))
104 }
105}
106
107impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::TraitRef<I> {
108 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
109 self.to_string().into_diag_arg(path)
110 }
111}
112
113impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::ExistentialTraitRef<I> {
114 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
115 self.to_string().into_diag_arg(path)
116 }
117}
118
119impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst<I> {
120 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
121 format!("{self:?}").into_diag_arg(path)
122 }
123}
124
125impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::FnSig<I> {
126 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
127 format!("{self:?}").into_diag_arg(path)
128 }
129}
130
131impl<I: rustc_type_ir::Interner, T> IntoDiagArg for rustc_type_ir::Binder<I, T>
132where
133 T: IntoDiagArg,
134{
135 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
136 self.skip_binder().into_diag_arg(path)
137 }
138}
139
140into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
141
142impl IntoDiagArg for bool {
143 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
144 if self {
145 DiagArgValue::Str(Cow::Borrowed("true"))
146 } else {
147 DiagArgValue::Str(Cow::Borrowed("false"))
148 }
149 }
150}
151
152impl IntoDiagArg for char {
153 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
154 DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
155 }
156}
157
158impl IntoDiagArg for Vec<char> {
159 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
160 DiagArgValue::StrListSepByAnd(
161 self.into_iter().map(|c| Cow::Owned(format!("{c:?}"))).collect(),
162 )
163 }
164}
165
166impl IntoDiagArg for Symbol {
167 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
168 self.to_ident_string().into_diag_arg(path)
169 }
170}
171
172impl<'a> IntoDiagArg for &'a str {
173 fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
174 self.to_string().into_diag_arg(path)
175 }
176}
177
178impl IntoDiagArg for String {
179 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
180 DiagArgValue::Str(Cow::Owned(self))
181 }
182}
183
184impl<'a> IntoDiagArg for Cow<'a, str> {
185 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
186 DiagArgValue::Str(Cow::Owned(self.into_owned()))
187 }
188}
189
190impl<'a> IntoDiagArg for &'a Path {
191 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
192 DiagArgValue::Str(Cow::Owned(self.display().to_string()))
193 }
194}
195
196impl IntoDiagArg for PathBuf {
197 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
198 DiagArgValue::Str(Cow::Owned(self.display().to_string()))
199 }
200}
201
202impl IntoDiagArg for PanicStrategy {
203 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
204 DiagArgValue::Str(Cow::Owned(self.desc().to_string()))
205 }
206}
207
208impl IntoDiagArg for hir::ConstContext {
209 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
210 DiagArgValue::Str(Cow::Borrowed(match self {
211 hir::ConstContext::ConstFn => "const_fn",
212 hir::ConstContext::Static(_) => "static",
213 hir::ConstContext::Const { .. } => "const",
214 }))
215 }
216}
217
218impl IntoDiagArg for ast::Expr {
219 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
220 DiagArgValue::Str(Cow::Owned(pprust::expr_to_string(&self)))
221 }
222}
223
224impl IntoDiagArg for ast::Path {
225 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
226 DiagArgValue::Str(Cow::Owned(pprust::path_to_string(&self)))
227 }
228}
229
230impl IntoDiagArg for ast::token::Token {
231 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
232 DiagArgValue::Str(pprust::token_to_string(&self))
233 }
234}
235
236impl IntoDiagArg for ast::token::TokenKind {
237 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
238 DiagArgValue::Str(pprust::token_kind_to_string(&self))
239 }
240}
241
242impl IntoDiagArg for FloatTy {
243 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
244 DiagArgValue::Str(Cow::Borrowed(self.name_str()))
245 }
246}
247
248impl IntoDiagArg for std::ffi::CString {
249 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
250 DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned()))
251 }
252}
253
254impl IntoDiagArg for rustc_data_structures::small_c_str::SmallCStr {
255 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
256 DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned()))
257 }
258}
259
260impl IntoDiagArg for ast::Visibility {
261 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
262 let s = pprust::vis_to_string(&self);
263 let s = s.trim_end().to_string();
264 DiagArgValue::Str(Cow::Owned(s))
265 }
266}
267
268impl IntoDiagArg for rustc_lint_defs::Level {
269 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
270 DiagArgValue::Str(Cow::Borrowed(self.to_cmd_flag()))
271 }
272}
273
274impl<Id> IntoDiagArg for hir::def::Res<Id> {
275 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
276 DiagArgValue::Str(Cow::Borrowed(self.descr()))
277 }
278}
279
280impl IntoDiagArg for DiagLocation {
281 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
282 DiagArgValue::Str(Cow::from(self.to_string()))
283 }
284}
285
286impl IntoDiagArg for Backtrace {
287 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
288 DiagArgValue::Str(Cow::from(self.to_string()))
289 }
290}
291
292impl IntoDiagArg for Level {
293 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
294 DiagArgValue::Str(Cow::from(self.to_string()))
295 }
296}
297
298impl IntoDiagArg for ClosureKind {
299 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
300 DiagArgValue::Str(self.as_str().into())
301 }
302}
303
304impl IntoDiagArg for hir::def::Namespace {
305 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
306 DiagArgValue::Str(Cow::Borrowed(self.descr()))
307 }
308}
309
310impl IntoDiagArg for ExprPrecedence {
311 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
312 DiagArgValue::Number(self as i32)
313 }
314}
315
316impl IntoDiagArg for MirDialect {
317 fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> DiagArgValue {
318 let arg = match self {
319 MirDialect::Analysis => "analysis",
320 MirDialect::Built => "built",
321 MirDialect::Runtime => "runtime",
322 };
323 DiagArgValue::Str(Cow::Borrowed(arg))
324 }
325}
326
327impl IntoDiagArg for MirPhase {
328 fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> DiagArgValue {
329 let arg = match self {
330 MirPhase::Initial => "initial",
331 MirPhase::PostCleanup => "post-cleanup",
332 MirPhase::Optimized => "optimized",
333 };
334 DiagArgValue::Str(Cow::Borrowed(arg))
335 }
336}
337
338#[derive(Clone)]
339pub struct DiagSymbolList<S = Symbol>(Vec<S>);
340
341impl<S> From<Vec<S>> for DiagSymbolList<S> {
342 fn from(v: Vec<S>) -> Self {
343 DiagSymbolList(v)
344 }
345}
346
347impl<S> FromIterator<S> for DiagSymbolList<S> {
348 fn from_iter<T: IntoIterator<Item = S>>(iter: T) -> Self {
349 iter.into_iter().collect::<Vec<_>>().into()
350 }
351}
352
353impl<S: std::fmt::Display> IntoDiagArg for DiagSymbolList<S> {
354 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
355 DiagArgValue::StrListSepByAnd(
356 self.0.into_iter().map(|sym| Cow::Owned(format!("`{sym}`"))).collect(),
357 )
358 }
359}
360
361impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutErrors<'_> {
362 fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
363 match self {
364 TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
365 Diag::new(dcx, level, fluent::errors_target_invalid_address_space)
366 .with_arg("addr_space", addr_space)
367 .with_arg("cause", cause)
368 .with_arg("err", err)
369 }
370 TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
371 Diag::new(dcx, level, fluent::errors_target_invalid_bits)
372 .with_arg("kind", kind)
373 .with_arg("bit", bit)
374 .with_arg("cause", cause)
375 .with_arg("err", err)
376 }
377 TargetDataLayoutErrors::MissingAlignment { cause } => {
378 Diag::new(dcx, level, fluent::errors_target_missing_alignment)
379 .with_arg("cause", cause)
380 }
381 TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
382 Diag::new(dcx, level, fluent::errors_target_invalid_alignment)
383 .with_arg("cause", cause)
384 .with_arg("err_kind", err.diag_ident())
385 .with_arg("align", err.align())
386 }
387 TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
388 Diag::new(dcx, level, fluent::errors_target_inconsistent_architecture)
389 .with_arg("dl", dl)
390 .with_arg("target", target)
391 }
392 TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
393 Diag::new(dcx, level, fluent::errors_target_inconsistent_pointer_width)
394 .with_arg("pointer_size", pointer_size)
395 .with_arg("target", target)
396 }
397 TargetDataLayoutErrors::InvalidBitsSize { err } => {
398 Diag::new(dcx, level, fluent::errors_target_invalid_bits_size).with_arg("err", err)
399 }
400 TargetDataLayoutErrors::UnknownPointerSpecification { err } => {
401 Diag::new(dcx, level, fluent::errors_target_invalid_datalayout_pointer_spec)
402 .with_arg("err", err)
403 }
404 }
405 }
406}
407
408pub struct SingleLabelManySpans {
410 pub spans: Vec<Span>,
411 pub label: &'static str,
412}
413impl Subdiagnostic for SingleLabelManySpans {
414 fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
415 diag.span_labels(self.spans, self.label);
416 }
417}
418
419#[derive(Subdiagnostic)]
420#[label(errors_expected_lifetime_parameter)]
421pub struct ExpectedLifetimeParameter {
422 #[primary_span]
423 pub span: Span,
424 pub count: usize,
425}
426
427#[derive(Subdiagnostic)]
428#[suggestion(errors_indicate_anonymous_lifetime, code = "{suggestion}", style = "verbose")]
429pub struct IndicateAnonymousLifetime {
430 #[primary_span]
431 pub span: Span,
432 pub count: usize,
433 pub suggestion: String,
434}
435
436#[derive(Subdiagnostic)]
437pub struct ElidedLifetimeInPathSubdiag {
438 #[subdiagnostic]
439 pub expected: ExpectedLifetimeParameter,
440 #[subdiagnostic]
441 pub indicate: Option<IndicateAnonymousLifetime>,
442}