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