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