rustc_const_eval/
errors.rs

1use std::borrow::Cow;
2use std::fmt::Write;
3
4use either::Either;
5use rustc_abi::WrappingRange;
6use rustc_errors::codes::*;
7use rustc_errors::{
8    Diag, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan, Subdiagnostic,
9};
10use rustc_hir::ConstContext;
11use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
12use rustc_middle::mir::interpret::{
13    CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind, InvalidProgramInfo,
14    Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo,
15    UnsupportedOpInfo, ValidationErrorInfo,
16};
17use rustc_middle::ty::{self, Mutability, Ty};
18use rustc_span::{Span, Symbol};
19
20use crate::fluent_generated as fluent;
21use crate::interpret::InternKind;
22
23#[derive(Diagnostic)]
24#[diag(const_eval_dangling_ptr_in_final)]
25pub(crate) struct DanglingPtrInFinal {
26    #[primary_span]
27    pub span: Span,
28    pub kind: InternKind,
29}
30
31#[derive(Diagnostic)]
32#[diag(const_eval_nested_static_in_thread_local)]
33pub(crate) struct NestedStaticInThreadLocal {
34    #[primary_span]
35    pub span: Span,
36}
37
38#[derive(Diagnostic)]
39#[diag(const_eval_mutable_ptr_in_final)]
40pub(crate) struct MutablePtrInFinal {
41    #[primary_span]
42    pub span: Span,
43    pub kind: InternKind,
44}
45
46#[derive(Diagnostic)]
47#[diag(const_eval_unstable_in_stable_exposed)]
48pub(crate) struct UnstableInStableExposed {
49    pub gate: String,
50    #[primary_span]
51    pub span: Span,
52    #[help(const_eval_is_function_call)]
53    pub is_function_call: bool,
54    /// Need to duplicate the field so that fluent also provides it as a variable...
55    pub is_function_call2: bool,
56    #[suggestion(
57        const_eval_unstable_sugg,
58        code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
59        applicability = "has-placeholders"
60    )]
61    #[suggestion(
62        const_eval_bypass_sugg,
63        code = "#[rustc_allow_const_fn_unstable({gate})]\n",
64        applicability = "has-placeholders"
65    )]
66    pub attr_span: Span,
67}
68
69#[derive(Diagnostic)]
70#[diag(const_eval_thread_local_access, code = E0625)]
71pub(crate) struct ThreadLocalAccessErr {
72    #[primary_span]
73    pub span: Span,
74}
75
76#[derive(Diagnostic)]
77#[diag(const_eval_raw_ptr_to_int)]
78#[note]
79#[note(const_eval_note2)]
80pub(crate) struct RawPtrToIntErr {
81    #[primary_span]
82    pub span: Span,
83}
84
85#[derive(Diagnostic)]
86#[diag(const_eval_raw_ptr_comparison)]
87#[note]
88pub(crate) struct RawPtrComparisonErr {
89    #[primary_span]
90    pub span: Span,
91}
92
93#[derive(Diagnostic)]
94#[diag(const_eval_panic_non_str)]
95pub(crate) struct PanicNonStrErr {
96    #[primary_span]
97    pub span: Span,
98}
99
100#[derive(Diagnostic)]
101#[diag(const_eval_max_num_nodes_in_const)]
102pub(crate) struct MaxNumNodesInConstErr {
103    #[primary_span]
104    pub span: Option<Span>,
105    pub global_const_id: String,
106}
107
108#[derive(Diagnostic)]
109#[diag(const_eval_unallowed_fn_pointer_call)]
110pub(crate) struct UnallowedFnPointerCall {
111    #[primary_span]
112    pub span: Span,
113    pub kind: ConstContext,
114}
115
116#[derive(Diagnostic)]
117#[diag(const_eval_unstable_const_fn)]
118pub(crate) struct UnstableConstFn {
119    #[primary_span]
120    pub span: Span,
121    pub def_path: String,
122}
123
124#[derive(Diagnostic)]
125#[diag(const_eval_unstable_const_trait)]
126pub(crate) struct UnstableConstTrait {
127    #[primary_span]
128    pub span: Span,
129    pub def_path: String,
130}
131
132#[derive(Diagnostic)]
133#[diag(const_eval_unstable_intrinsic)]
134pub(crate) struct UnstableIntrinsic {
135    #[primary_span]
136    pub span: Span,
137    pub name: Symbol,
138    pub feature: Symbol,
139    #[suggestion(
140        const_eval_unstable_intrinsic_suggestion,
141        code = "#![feature({feature})]\n",
142        applicability = "machine-applicable"
143    )]
144    pub suggestion: Option<Span>,
145    #[help(const_eval_unstable_intrinsic_suggestion)]
146    pub help: bool,
147}
148
149#[derive(Diagnostic)]
150#[diag(const_eval_unmarked_const_item_exposed)]
151#[help]
152pub(crate) struct UnmarkedConstItemExposed {
153    #[primary_span]
154    pub span: Span,
155    pub def_path: String,
156}
157
158#[derive(Diagnostic)]
159#[diag(const_eval_unmarked_intrinsic_exposed)]
160#[help]
161pub(crate) struct UnmarkedIntrinsicExposed {
162    #[primary_span]
163    pub span: Span,
164    pub def_path: String,
165}
166
167#[derive(Diagnostic)]
168#[diag(const_eval_mutable_ref_escaping, code = E0764)]
169pub(crate) struct MutableRefEscaping {
170    #[primary_span]
171    pub span: Span,
172    pub kind: ConstContext,
173    #[note(const_eval_teach_note)]
174    pub teach: bool,
175}
176
177#[derive(Diagnostic)]
178#[diag(const_eval_mutable_raw_escaping, code = E0764)]
179pub(crate) struct MutableRawEscaping {
180    #[primary_span]
181    pub span: Span,
182    pub kind: ConstContext,
183    #[note(const_eval_teach_note)]
184    pub teach: bool,
185}
186#[derive(Diagnostic)]
187#[diag(const_eval_non_const_fmt_macro_call, code = E0015)]
188pub(crate) struct NonConstFmtMacroCall {
189    #[primary_span]
190    pub span: Span,
191    pub kind: ConstContext,
192    pub non_or_conditionally: &'static str,
193}
194
195#[derive(Diagnostic)]
196#[diag(const_eval_non_const_fn_call, code = E0015)]
197pub(crate) struct NonConstFnCall {
198    #[primary_span]
199    pub span: Span,
200    pub def_path_str: String,
201    pub def_descr: &'static str,
202    pub kind: ConstContext,
203    pub non_or_conditionally: &'static str,
204}
205
206#[derive(Diagnostic)]
207#[diag(const_eval_non_const_intrinsic)]
208pub(crate) struct NonConstIntrinsic {
209    #[primary_span]
210    pub span: Span,
211    pub name: Symbol,
212    pub kind: ConstContext,
213}
214
215#[derive(Diagnostic)]
216#[diag(const_eval_unallowed_op_in_const_context)]
217pub(crate) struct UnallowedOpInConstContext {
218    #[primary_span]
219    pub span: Span,
220    pub msg: String,
221}
222
223#[derive(Diagnostic)]
224#[diag(const_eval_unallowed_heap_allocations, code = E0010)]
225pub(crate) struct UnallowedHeapAllocations {
226    #[primary_span]
227    #[label]
228    pub span: Span,
229    pub kind: ConstContext,
230    #[note(const_eval_teach_note)]
231    pub teach: bool,
232}
233
234#[derive(Diagnostic)]
235#[diag(const_eval_unallowed_inline_asm, code = E0015)]
236pub(crate) struct UnallowedInlineAsm {
237    #[primary_span]
238    pub span: Span,
239    pub kind: ConstContext,
240}
241
242#[derive(Diagnostic)]
243#[diag(const_eval_interior_mutable_ref_escaping, code = E0492)]
244pub(crate) struct InteriorMutableRefEscaping {
245    #[primary_span]
246    #[label]
247    pub span: Span,
248    #[help]
249    pub opt_help: bool,
250    pub kind: ConstContext,
251    #[note(const_eval_teach_note)]
252    pub teach: bool,
253}
254
255#[derive(LintDiagnostic)]
256#[diag(const_eval_long_running)]
257#[note]
258pub struct LongRunning {
259    #[help]
260    pub item_span: Span,
261}
262
263#[derive(Diagnostic)]
264#[diag(const_eval_long_running)]
265pub struct LongRunningWarn {
266    #[primary_span]
267    #[label]
268    pub span: Span,
269    #[help]
270    pub item_span: Span,
271    // Used for evading `-Z deduplicate-diagnostics`.
272    pub force_duplicate: usize,
273}
274
275#[derive(Subdiagnostic)]
276#[note(const_eval_non_const_impl)]
277pub(crate) struct NonConstImplNote {
278    #[primary_span]
279    pub span: Span,
280}
281
282#[derive(Clone)]
283pub struct FrameNote {
284    pub span: Span,
285    pub times: i32,
286    pub where_: &'static str,
287    pub instance: String,
288    pub has_label: bool,
289}
290
291impl Subdiagnostic for FrameNote {
292    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
293        diag.arg("times", self.times);
294        diag.arg("where_", self.where_);
295        diag.arg("instance", self.instance);
296        let mut span: MultiSpan = self.span.into();
297        if self.has_label && !self.span.is_dummy() {
298            span.push_span_label(self.span, fluent::const_eval_frame_note_last);
299        }
300        let msg = diag.eagerly_translate(fluent::const_eval_frame_note);
301        diag.span_note(span, msg);
302    }
303}
304
305#[derive(Subdiagnostic)]
306#[note(const_eval_raw_bytes)]
307pub struct RawBytesNote {
308    pub size: u64,
309    pub align: u64,
310    pub bytes: String,
311}
312
313// FIXME(fee1-dead) do not use stringly typed `ConstContext`
314
315#[derive(Diagnostic)]
316#[diag(const_eval_non_const_match_eq, code = E0015)]
317#[note]
318pub struct NonConstMatchEq<'tcx> {
319    #[primary_span]
320    pub span: Span,
321    pub ty: Ty<'tcx>,
322    pub kind: ConstContext,
323    pub non_or_conditionally: &'static str,
324}
325
326#[derive(Diagnostic)]
327#[diag(const_eval_non_const_for_loop_into_iter, code = E0015)]
328pub struct NonConstForLoopIntoIter<'tcx> {
329    #[primary_span]
330    pub span: Span,
331    pub ty: Ty<'tcx>,
332    pub kind: ConstContext,
333    pub non_or_conditionally: &'static str,
334}
335
336#[derive(Diagnostic)]
337#[diag(const_eval_non_const_question_branch, code = E0015)]
338pub struct NonConstQuestionBranch<'tcx> {
339    #[primary_span]
340    pub span: Span,
341    pub ty: Ty<'tcx>,
342    pub kind: ConstContext,
343    pub non_or_conditionally: &'static str,
344}
345
346#[derive(Diagnostic)]
347#[diag(const_eval_non_const_question_from_residual, code = E0015)]
348pub struct NonConstQuestionFromResidual<'tcx> {
349    #[primary_span]
350    pub span: Span,
351    pub ty: Ty<'tcx>,
352    pub kind: ConstContext,
353    pub non_or_conditionally: &'static str,
354}
355
356#[derive(Diagnostic)]
357#[diag(const_eval_non_const_try_block_from_output, code = E0015)]
358pub struct NonConstTryBlockFromOutput<'tcx> {
359    #[primary_span]
360    pub span: Span,
361    pub ty: Ty<'tcx>,
362    pub kind: ConstContext,
363    pub non_or_conditionally: &'static str,
364}
365
366#[derive(Diagnostic)]
367#[diag(const_eval_non_const_await, code = E0015)]
368pub struct NonConstAwait<'tcx> {
369    #[primary_span]
370    pub span: Span,
371    pub ty: Ty<'tcx>,
372    pub kind: ConstContext,
373    pub non_or_conditionally: &'static str,
374}
375
376#[derive(Diagnostic)]
377#[diag(const_eval_non_const_closure, code = E0015)]
378pub struct NonConstClosure {
379    #[primary_span]
380    pub span: Span,
381    pub kind: ConstContext,
382    #[subdiagnostic]
383    pub note: Option<NonConstClosureNote>,
384    pub non_or_conditionally: &'static str,
385}
386
387#[derive(Subdiagnostic)]
388pub enum NonConstClosureNote {
389    #[note(const_eval_closure_fndef_not_const)]
390    FnDef {
391        #[primary_span]
392        span: Span,
393    },
394    #[note(const_eval_fn_ptr_call)]
395    FnPtr,
396    #[note(const_eval_closure_call)]
397    Closure,
398}
399
400#[derive(Subdiagnostic)]
401#[multipart_suggestion(const_eval_consider_dereferencing, applicability = "machine-applicable")]
402pub struct ConsiderDereferencing {
403    pub deref: String,
404    #[suggestion_part(code = "{deref}")]
405    pub span: Span,
406    #[suggestion_part(code = "{deref}")]
407    pub rhs_span: Span,
408}
409
410#[derive(Diagnostic)]
411#[diag(const_eval_non_const_operator, code = E0015)]
412pub struct NonConstOperator {
413    #[primary_span]
414    pub span: Span,
415    pub kind: ConstContext,
416    #[subdiagnostic]
417    pub sugg: Option<ConsiderDereferencing>,
418    pub non_or_conditionally: &'static str,
419}
420
421#[derive(Diagnostic)]
422#[diag(const_eval_non_const_deref_coercion, code = E0015)]
423#[note]
424pub struct NonConstDerefCoercion<'tcx> {
425    #[primary_span]
426    pub span: Span,
427    pub ty: Ty<'tcx>,
428    pub kind: ConstContext,
429    pub target_ty: Ty<'tcx>,
430    #[note(const_eval_target_note)]
431    pub deref_target: Option<Span>,
432    pub non_or_conditionally: &'static str,
433}
434
435#[derive(Diagnostic)]
436#[diag(const_eval_live_drop, code = E0493)]
437pub struct LiveDrop<'tcx> {
438    #[primary_span]
439    #[label]
440    pub span: Span,
441    pub kind: ConstContext,
442    pub dropped_ty: Ty<'tcx>,
443    #[label(const_eval_dropped_at_label)]
444    pub dropped_at: Span,
445}
446
447#[derive(Diagnostic)]
448#[diag(const_eval_error, code = E0080)]
449pub struct ConstEvalError {
450    #[primary_span]
451    pub span: Span,
452    /// One of "const", "const_with_path", and "static"
453    pub error_kind: &'static str,
454    pub instance: String,
455    #[subdiagnostic]
456    pub frame_notes: Vec<FrameNote>,
457}
458
459#[derive(Diagnostic)]
460#[diag(const_eval_nullary_intrinsic_fail)]
461pub struct NullaryIntrinsicError {
462    #[primary_span]
463    pub span: Span,
464}
465
466#[derive(Diagnostic)]
467#[diag(const_eval_validation_failure, code = E0080)]
468pub struct ValidationFailure {
469    #[primary_span]
470    pub span: Span,
471    #[note(const_eval_validation_failure_note)]
472    pub ub_note: (),
473    #[subdiagnostic]
474    pub frames: Vec<FrameNote>,
475    #[subdiagnostic]
476    pub raw_bytes: RawBytesNote,
477}
478
479pub trait ReportErrorExt {
480    /// Returns the diagnostic message for this error.
481    fn diagnostic_message(&self) -> DiagMessage;
482    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>);
483
484    fn debug(self) -> String
485    where
486        Self: Sized,
487    {
488        ty::tls::with(move |tcx| {
489            let dcx = tcx.dcx();
490            let mut diag = dcx.struct_allow(DiagMessage::Str(String::new().into()));
491            let message = self.diagnostic_message();
492            self.add_args(&mut diag);
493            let s = dcx.eagerly_translate_to_string(message, diag.args.iter());
494            diag.cancel();
495            s
496        })
497    }
498}
499
500impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
501    fn diagnostic_message(&self) -> DiagMessage {
502        use UndefinedBehaviorInfo::*;
503
504        use crate::fluent_generated::*;
505        match self {
506            Ub(msg) => msg.clone().into(),
507            Custom(x) => (x.msg)(),
508            ValidationError(e) => e.diagnostic_message(),
509
510            Unreachable => const_eval_unreachable,
511            BoundsCheckFailed { .. } => const_eval_bounds_check_failed,
512            DivisionByZero => const_eval_division_by_zero,
513            RemainderByZero => const_eval_remainder_by_zero,
514            DivisionOverflow => const_eval_division_overflow,
515            RemainderOverflow => const_eval_remainder_overflow,
516            PointerArithOverflow => const_eval_pointer_arithmetic_overflow,
517            ArithOverflow { .. } => const_eval_overflow_arith,
518            ShiftOverflow { .. } => const_eval_overflow_shift,
519            InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
520            InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
521            UnterminatedCString(_) => const_eval_unterminated_c_string,
522            PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free,
523            PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
524            DanglingIntPointer { addr: 0, .. } => const_eval_dangling_null_pointer,
525            DanglingIntPointer { .. } => const_eval_dangling_int_pointer,
526            AlignmentCheckFailed { .. } => const_eval_alignment_check_failed,
527            WriteToReadOnly(_) => const_eval_write_to_read_only,
528            DerefFunctionPointer(_) => const_eval_deref_function_pointer,
529            DerefVTablePointer(_) => const_eval_deref_vtable_pointer,
530            InvalidBool(_) => const_eval_invalid_bool,
531            InvalidChar(_) => const_eval_invalid_char,
532            InvalidTag(_) => const_eval_invalid_tag,
533            InvalidFunctionPointer(_) => const_eval_invalid_function_pointer,
534            InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer,
535            InvalidVTableTrait { .. } => const_eval_invalid_vtable_trait,
536            InvalidStr(_) => const_eval_invalid_str,
537            InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown,
538            InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes,
539            DeadLocal => const_eval_dead_local,
540            ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
541            UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written,
542            UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read,
543            InvalidNichedEnumVariantWritten { .. } => {
544                const_eval_invalid_niched_enum_variant_written
545            }
546            AbiMismatchArgument { .. } => const_eval_incompatible_types,
547            AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
548        }
549    }
550
551    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
552        use UndefinedBehaviorInfo::*;
553        match self {
554            Ub(_) => {}
555            Custom(custom) => {
556                (custom.add_args)(&mut |name, value| {
557                    diag.arg(name, value);
558                });
559            }
560            ValidationError(e) => e.add_args(diag),
561
562            Unreachable
563            | DivisionByZero
564            | RemainderByZero
565            | DivisionOverflow
566            | RemainderOverflow
567            | PointerArithOverflow
568            | InvalidMeta(InvalidMetaKind::SliceTooBig)
569            | InvalidMeta(InvalidMetaKind::TooBig)
570            | InvalidUninitBytes(None)
571            | DeadLocal
572            | UninhabitedEnumVariantWritten(_)
573            | UninhabitedEnumVariantRead(_) => {}
574
575            ArithOverflow { intrinsic } => {
576                diag.arg("intrinsic", intrinsic);
577            }
578            ShiftOverflow { intrinsic, shift_amount } => {
579                diag.arg("intrinsic", intrinsic);
580                diag.arg(
581                    "shift_amount",
582                    match shift_amount {
583                        Either::Left(v) => v.to_string(),
584                        Either::Right(v) => v.to_string(),
585                    },
586                );
587            }
588            BoundsCheckFailed { len, index } => {
589                diag.arg("len", len);
590                diag.arg("index", index);
591            }
592            UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
593                diag.arg("pointer", ptr);
594            }
595            InvalidVTableTrait { expected_dyn_type, vtable_dyn_type } => {
596                diag.arg("expected_dyn_type", expected_dyn_type.to_string());
597                diag.arg("vtable_dyn_type", vtable_dyn_type.to_string());
598            }
599            PointerUseAfterFree(alloc_id, msg) => {
600                diag.arg("alloc_id", alloc_id).arg("operation", format!("{:?}", msg));
601            }
602            PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => {
603                diag.arg("alloc_size", alloc_size.bytes());
604                diag.arg("pointer", {
605                    let mut out = format!("{:?}", alloc_id);
606                    if ptr_offset > 0 {
607                        write!(out, "+{:#x}", ptr_offset).unwrap();
608                    } else if ptr_offset < 0 {
609                        write!(out, "-{:#x}", ptr_offset.unsigned_abs()).unwrap();
610                    }
611                    out
612                });
613                diag.arg("inbounds_size", inbounds_size);
614                diag.arg("inbounds_size_is_neg", inbounds_size < 0);
615                diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
616                diag.arg("ptr_offset", ptr_offset);
617                diag.arg("ptr_offset_is_neg", ptr_offset < 0);
618                diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs());
619                diag.arg(
620                    "alloc_size_minus_ptr_offset",
621                    alloc_size.bytes().saturating_sub(ptr_offset as u64),
622                );
623                diag.arg("operation", format!("{:?}", msg));
624            }
625            DanglingIntPointer { addr, inbounds_size, msg } => {
626                if addr != 0 {
627                    diag.arg(
628                        "pointer",
629                        Pointer::<Option<CtfeProvenance>>::from_addr_invalid(addr).to_string(),
630                    );
631                }
632
633                diag.arg("inbounds_size", inbounds_size);
634                diag.arg("inbounds_size_is_neg", inbounds_size < 0);
635                diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
636                diag.arg("operation", format!("{:?}", msg));
637            }
638            AlignmentCheckFailed(Misalignment { required, has }, msg) => {
639                diag.arg("required", required.bytes());
640                diag.arg("has", has.bytes());
641                diag.arg("msg", format!("{msg:?}"));
642            }
643            WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
644                diag.arg("allocation", alloc);
645            }
646            InvalidBool(b) => {
647                diag.arg("value", format!("{b:02x}"));
648            }
649            InvalidChar(c) => {
650                diag.arg("value", format!("{c:08x}"));
651            }
652            InvalidTag(tag) => {
653                diag.arg("tag", format!("{tag:x}"));
654            }
655            InvalidStr(err) => {
656                diag.arg("err", format!("{err}"));
657            }
658            InvalidUninitBytes(Some((alloc, info))) => {
659                diag.arg("alloc", alloc);
660                diag.arg("access", info.access);
661                diag.arg("uninit", info.bad);
662            }
663            ScalarSizeMismatch(info) => {
664                diag.arg("target_size", info.target_size);
665                diag.arg("data_size", info.data_size);
666            }
667            InvalidNichedEnumVariantWritten { enum_ty } => {
668                diag.arg("ty", enum_ty.to_string());
669            }
670            AbiMismatchArgument { caller_ty, callee_ty }
671            | AbiMismatchReturn { caller_ty, callee_ty } => {
672                diag.arg("caller_ty", caller_ty.to_string());
673                diag.arg("callee_ty", callee_ty.to_string());
674            }
675        }
676    }
677}
678
679impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
680    fn diagnostic_message(&self) -> DiagMessage {
681        use rustc_middle::mir::interpret::ValidationErrorKind::*;
682
683        use crate::fluent_generated::*;
684        match self.kind {
685            PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => {
686                const_eval_validation_box_to_uninhabited
687            }
688            PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => {
689                const_eval_validation_ref_to_uninhabited
690            }
691
692            PointerAsInt { .. } => const_eval_validation_pointer_as_int,
693            PartialPointer => const_eval_validation_partial_pointer,
694            ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
695            ConstRefToExtern => const_eval_validation_const_ref_to_extern,
696            MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
697            NullFnPtr => const_eval_validation_null_fn_ptr,
698            NeverVal => const_eval_validation_never_val,
699            NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
700            PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
701            OutOfRange { .. } => const_eval_validation_out_of_range,
702            UnsafeCellInImmutable => const_eval_validation_unsafe_cell,
703            UninhabitedVal { .. } => const_eval_validation_uninhabited_val,
704            InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag,
705            UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
706            Uninit { .. } => const_eval_validation_uninit,
707            InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr,
708            InvalidMetaWrongTrait { .. } => const_eval_validation_invalid_vtable_trait,
709            InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
710                const_eval_validation_invalid_box_slice_meta
711            }
712            InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => {
713                const_eval_validation_invalid_ref_slice_meta
714            }
715
716            InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => {
717                const_eval_validation_invalid_box_meta
718            }
719            InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => {
720                const_eval_validation_invalid_ref_meta
721            }
722            UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => {
723                const_eval_validation_unaligned_ref
724            }
725            UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box,
726
727            NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box,
728            NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref,
729            DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
730                const_eval_validation_dangling_box_no_provenance
731            }
732            DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => {
733                const_eval_validation_dangling_ref_no_provenance
734            }
735            DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => {
736                const_eval_validation_dangling_box_out_of_bounds
737            }
738            DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => {
739                const_eval_validation_dangling_ref_out_of_bounds
740            }
741            DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => {
742                const_eval_validation_dangling_box_use_after_free
743            }
744            DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => {
745                const_eval_validation_dangling_ref_use_after_free
746            }
747            InvalidBool { .. } => const_eval_validation_invalid_bool,
748            InvalidChar { .. } => const_eval_validation_invalid_char,
749            InvalidFnPtr { .. } => const_eval_validation_invalid_fn_ptr,
750        }
751    }
752
753    fn add_args<G: EmissionGuarantee>(self, err: &mut Diag<'_, G>) {
754        use rustc_middle::mir::interpret::ValidationErrorKind::*;
755
756        use crate::fluent_generated as fluent;
757
758        if let PointerAsInt { .. } | PartialPointer = self.kind {
759            err.help(fluent::const_eval_ptr_as_bytes_1);
760            err.help(fluent::const_eval_ptr_as_bytes_2);
761        }
762
763        let message = if let Some(path) = self.path {
764            err.dcx.eagerly_translate_to_string(
765                fluent::const_eval_validation_front_matter_invalid_value_with_path,
766                [("path".into(), DiagArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
767            )
768        } else {
769            err.dcx.eagerly_translate_to_string(
770                fluent::const_eval_validation_front_matter_invalid_value,
771                [].into_iter(),
772            )
773        };
774
775        err.arg("front_matter", message);
776
777        fn add_range_arg<G: EmissionGuarantee>(
778            r: WrappingRange,
779            max_hi: u128,
780            err: &mut Diag<'_, G>,
781        ) {
782            let WrappingRange { start: lo, end: hi } = r;
783            assert!(hi <= max_hi);
784            let msg = if lo > hi {
785                fluent::const_eval_range_wrapping
786            } else if lo == hi {
787                fluent::const_eval_range_singular
788            } else if lo == 0 {
789                assert!(hi < max_hi, "should not be printing if the range covers everything");
790                fluent::const_eval_range_upper
791            } else if hi == max_hi {
792                assert!(lo > 0, "should not be printing if the range covers everything");
793                fluent::const_eval_range_lower
794            } else {
795                fluent::const_eval_range
796            };
797
798            let args = [
799                ("lo".into(), DiagArgValue::Str(lo.to_string().into())),
800                ("hi".into(), DiagArgValue::Str(hi.to_string().into())),
801            ];
802            let args = args.iter().map(|(a, b)| (a, b));
803            let message = err.dcx.eagerly_translate_to_string(msg, args);
804            err.arg("in_range", message);
805        }
806
807        match self.kind {
808            PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => {
809                err.arg("ty", ty);
810            }
811            PointerAsInt { expected } | Uninit { expected } => {
812                let msg = match expected {
813                    ExpectedKind::Reference => fluent::const_eval_validation_expected_ref,
814                    ExpectedKind::Box => fluent::const_eval_validation_expected_box,
815                    ExpectedKind::RawPtr => fluent::const_eval_validation_expected_raw_ptr,
816                    ExpectedKind::InitScalar => fluent::const_eval_validation_expected_init_scalar,
817                    ExpectedKind::Bool => fluent::const_eval_validation_expected_bool,
818                    ExpectedKind::Char => fluent::const_eval_validation_expected_char,
819                    ExpectedKind::Float => fluent::const_eval_validation_expected_float,
820                    ExpectedKind::Int => fluent::const_eval_validation_expected_int,
821                    ExpectedKind::FnPtr => fluent::const_eval_validation_expected_fn_ptr,
822                    ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
823                    ExpectedKind::Str => fluent::const_eval_validation_expected_str,
824                };
825                let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
826                err.arg("expected", msg);
827            }
828            InvalidEnumTag { value }
829            | InvalidVTablePtr { value }
830            | InvalidBool { value }
831            | InvalidChar { value }
832            | InvalidFnPtr { value } => {
833                err.arg("value", value);
834            }
835            NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
836                add_range_arg(range, max_value, err)
837            }
838            OutOfRange { range, max_value, value } => {
839                err.arg("value", value);
840                add_range_arg(range, max_value, err);
841            }
842            UnalignedPtr { required_bytes, found_bytes, .. } => {
843                err.arg("required_bytes", required_bytes);
844                err.arg("found_bytes", found_bytes);
845            }
846            DanglingPtrNoProvenance { pointer, .. } => {
847                err.arg("pointer", pointer);
848            }
849            InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } => {
850                err.arg("vtable_dyn_type", vtable_dyn_type.to_string());
851                err.arg("expected_dyn_type", expected_dyn_type.to_string());
852            }
853            NullPtr { .. }
854            | ConstRefToMutable
855            | ConstRefToExtern
856            | MutableRefToImmutable
857            | NullFnPtr
858            | NeverVal
859            | UnsafeCellInImmutable
860            | InvalidMetaSliceTooLarge { .. }
861            | InvalidMetaTooLarge { .. }
862            | DanglingPtrUseAfterFree { .. }
863            | DanglingPtrOutOfBounds { .. }
864            | UninhabitedEnumVariant
865            | PartialPointer => {}
866        }
867    }
868}
869
870impl ReportErrorExt for UnsupportedOpInfo {
871    fn diagnostic_message(&self) -> DiagMessage {
872        use crate::fluent_generated::*;
873        match self {
874            UnsupportedOpInfo::Unsupported(s) => s.clone().into(),
875            UnsupportedOpInfo::ExternTypeField => const_eval_extern_type_field,
876            UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local,
877            UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite,
878            UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy,
879            UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int,
880            UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static,
881            UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
882        }
883    }
884
885    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
886        use UnsupportedOpInfo::*;
887
888        use crate::fluent_generated::*;
889        if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
890            diag.help(const_eval_ptr_as_bytes_1);
891            diag.help(const_eval_ptr_as_bytes_2);
892        }
893        match self {
894            // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
895            // be further processed by validity checking which then turns it into something nice to
896            // print. So it's not worth the effort of having diagnostics that can print the `info`.
897            UnsizedLocal
898            | UnsupportedOpInfo::ExternTypeField
899            | Unsupported(_)
900            | ReadPointerAsInt(_) => {}
901            OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
902                diag.arg("ptr", ptr);
903            }
904            ThreadLocalStatic(did) | ExternStatic(did) => rustc_middle::ty::tls::with(|tcx| {
905                diag.arg("did", tcx.def_path_str(did));
906            }),
907        }
908    }
909}
910
911impl<'tcx> ReportErrorExt for InterpErrorKind<'tcx> {
912    fn diagnostic_message(&self) -> DiagMessage {
913        match self {
914            InterpErrorKind::UndefinedBehavior(ub) => ub.diagnostic_message(),
915            InterpErrorKind::Unsupported(e) => e.diagnostic_message(),
916            InterpErrorKind::InvalidProgram(e) => e.diagnostic_message(),
917            InterpErrorKind::ResourceExhaustion(e) => e.diagnostic_message(),
918            InterpErrorKind::MachineStop(e) => e.diagnostic_message(),
919        }
920    }
921    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
922        match self {
923            InterpErrorKind::UndefinedBehavior(ub) => ub.add_args(diag),
924            InterpErrorKind::Unsupported(e) => e.add_args(diag),
925            InterpErrorKind::InvalidProgram(e) => e.add_args(diag),
926            InterpErrorKind::ResourceExhaustion(e) => e.add_args(diag),
927            InterpErrorKind::MachineStop(e) => e.add_args(&mut |name, value| {
928                diag.arg(name, value);
929            }),
930        }
931    }
932}
933
934impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
935    fn diagnostic_message(&self) -> DiagMessage {
936        use crate::fluent_generated::*;
937        match self {
938            InvalidProgramInfo::TooGeneric => const_eval_too_generic,
939            InvalidProgramInfo::AlreadyReported(_) => const_eval_already_reported,
940            InvalidProgramInfo::Layout(e) => e.diagnostic_message(),
941        }
942    }
943    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
944        match self {
945            InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
946            InvalidProgramInfo::Layout(e) => {
947                // The level doesn't matter, `dummy_diag` is consumed without it being used.
948                let dummy_level = Level::Bug;
949                let dummy_diag: Diag<'_, ()> = e.into_diagnostic().into_diag(diag.dcx, dummy_level);
950                for (name, val) in dummy_diag.args.iter() {
951                    diag.arg(name.clone(), val.clone());
952                }
953                dummy_diag.cancel();
954            }
955        }
956    }
957}
958
959impl ReportErrorExt for ResourceExhaustionInfo {
960    fn diagnostic_message(&self) -> DiagMessage {
961        use crate::fluent_generated::*;
962        match self {
963            ResourceExhaustionInfo::StackFrameLimitReached => const_eval_stack_frame_limit_reached,
964            ResourceExhaustionInfo::MemoryExhausted => const_eval_memory_exhausted,
965            ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
966            ResourceExhaustionInfo::Interrupted => const_eval_interrupted,
967        }
968    }
969    fn add_args<G: EmissionGuarantee>(self, _: &mut Diag<'_, G>) {}
970}
971
972impl rustc_errors::IntoDiagArg for InternKind {
973    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
974        DiagArgValue::Str(Cow::Borrowed(match self {
975            InternKind::Static(Mutability::Not) => "static",
976            InternKind::Static(Mutability::Mut) => "static_mut",
977            InternKind::Constant => "const",
978            InternKind::Promoted => "promoted",
979        }))
980    }
981}