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