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