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_arg_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);
629            }
630            AbiMismatchArgument { arg_idx, caller_ty, callee_ty } => {
631                diag.arg("arg_idx", arg_idx + 1); // adjust for 1-indexed lists in output
632                diag.arg("caller_ty", caller_ty);
633                diag.arg("callee_ty", callee_ty);
634            }
635            AbiMismatchReturn { caller_ty, callee_ty } => {
636                diag.arg("caller_ty", caller_ty);
637                diag.arg("callee_ty", callee_ty);
638            }
639        }
640    }
641}
642
643impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
644    fn diagnostic_message(&self) -> DiagMessage {
645        use rustc_middle::mir::interpret::ValidationErrorKind::*;
646
647        use crate::fluent_generated::*;
648        match self.kind {
649            PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => {
650                const_eval_validation_box_to_uninhabited
651            }
652            PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => {
653                const_eval_validation_ref_to_uninhabited
654            }
655
656            PointerAsInt { .. } => const_eval_validation_pointer_as_int,
657            PartialPointer => const_eval_validation_partial_pointer,
658            MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
659            MutableRefInConst => const_eval_validation_mutable_ref_in_const,
660            NullFnPtr => const_eval_validation_null_fn_ptr,
661            NeverVal => const_eval_validation_never_val,
662            NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
663            PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
664            OutOfRange { .. } => const_eval_validation_out_of_range,
665            UnsafeCellInImmutable => const_eval_validation_unsafe_cell,
666            UninhabitedVal { .. } => const_eval_validation_uninhabited_val,
667            InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag,
668            UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
669            Uninit { .. } => const_eval_validation_uninit,
670            InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr,
671            InvalidMetaWrongTrait { .. } => const_eval_validation_invalid_vtable_trait,
672            InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
673                const_eval_validation_invalid_box_slice_meta
674            }
675            InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => {
676                const_eval_validation_invalid_ref_slice_meta
677            }
678
679            InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => {
680                const_eval_validation_invalid_box_meta
681            }
682            InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => {
683                const_eval_validation_invalid_ref_meta
684            }
685            UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => {
686                const_eval_validation_unaligned_ref
687            }
688            UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box,
689
690            NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box,
691            NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref,
692            DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
693                const_eval_validation_dangling_box_no_provenance
694            }
695            DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => {
696                const_eval_validation_dangling_ref_no_provenance
697            }
698            DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => {
699                const_eval_validation_dangling_box_out_of_bounds
700            }
701            DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => {
702                const_eval_validation_dangling_ref_out_of_bounds
703            }
704            DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => {
705                const_eval_validation_dangling_box_use_after_free
706            }
707            DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => {
708                const_eval_validation_dangling_ref_use_after_free
709            }
710            InvalidBool { .. } => const_eval_validation_invalid_bool,
711            InvalidChar { .. } => const_eval_validation_invalid_char,
712            InvalidFnPtr { .. } => const_eval_validation_invalid_fn_ptr,
713        }
714    }
715
716    fn add_args<G: EmissionGuarantee>(self, err: &mut Diag<'_, G>) {
717        use rustc_middle::mir::interpret::ValidationErrorKind::*;
718
719        use crate::fluent_generated as fluent;
720
721        if let PointerAsInt { .. } | PartialPointer = self.kind {
722            err.help(fluent::const_eval_ptr_as_bytes_1);
723            err.help(fluent::const_eval_ptr_as_bytes_2);
724        }
725
726        let message = if let Some(path) = self.path {
727            err.dcx.eagerly_translate_to_string(
728                fluent::const_eval_validation_front_matter_invalid_value_with_path,
729                [("path".into(), DiagArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
730            )
731        } else {
732            err.dcx.eagerly_translate_to_string(
733                fluent::const_eval_validation_front_matter_invalid_value,
734                [].into_iter(),
735            )
736        };
737
738        err.arg("front_matter", message);
739
740        fn add_range_arg<G: EmissionGuarantee>(
741            r: WrappingRange,
742            max_hi: u128,
743            err: &mut Diag<'_, G>,
744        ) {
745            let WrappingRange { start: lo, end: hi } = r;
746            assert!(hi <= max_hi);
747            let msg = if lo > hi {
748                fluent::const_eval_range_wrapping
749            } else if lo == hi {
750                fluent::const_eval_range_singular
751            } else if lo == 0 {
752                assert!(hi < max_hi, "should not be printing if the range covers everything");
753                fluent::const_eval_range_upper
754            } else if hi == max_hi {
755                assert!(lo > 0, "should not be printing if the range covers everything");
756                fluent::const_eval_range_lower
757            } else {
758                fluent::const_eval_range
759            };
760
761            let args = [
762                ("lo".into(), DiagArgValue::Str(lo.to_string().into())),
763                ("hi".into(), DiagArgValue::Str(hi.to_string().into())),
764            ];
765            let args = args.iter().map(|(a, b)| (a, b));
766            let message = err.dcx.eagerly_translate_to_string(msg, args);
767            err.arg("in_range", message);
768        }
769
770        match self.kind {
771            PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => {
772                err.arg("ty", ty);
773            }
774            PointerAsInt { expected } | Uninit { expected } => {
775                let msg = match expected {
776                    ExpectedKind::Reference => fluent::const_eval_validation_expected_ref,
777                    ExpectedKind::Box => fluent::const_eval_validation_expected_box,
778                    ExpectedKind::RawPtr => fluent::const_eval_validation_expected_raw_ptr,
779                    ExpectedKind::InitScalar => fluent::const_eval_validation_expected_init_scalar,
780                    ExpectedKind::Bool => fluent::const_eval_validation_expected_bool,
781                    ExpectedKind::Char => fluent::const_eval_validation_expected_char,
782                    ExpectedKind::Float => fluent::const_eval_validation_expected_float,
783                    ExpectedKind::Int => fluent::const_eval_validation_expected_int,
784                    ExpectedKind::FnPtr => fluent::const_eval_validation_expected_fn_ptr,
785                    ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
786                    ExpectedKind::Str => fluent::const_eval_validation_expected_str,
787                };
788                let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
789                err.arg("expected", msg);
790            }
791            InvalidEnumTag { value }
792            | InvalidVTablePtr { value }
793            | InvalidBool { value }
794            | InvalidChar { value }
795            | InvalidFnPtr { value } => {
796                err.arg("value", value);
797            }
798            NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
799                add_range_arg(range, max_value, err)
800            }
801            OutOfRange { range, max_value, value } => {
802                err.arg("value", value);
803                add_range_arg(range, max_value, err);
804            }
805            UnalignedPtr { required_bytes, found_bytes, .. } => {
806                err.arg("required_bytes", required_bytes);
807                err.arg("found_bytes", found_bytes);
808            }
809            DanglingPtrNoProvenance { pointer, .. } => {
810                err.arg("pointer", pointer);
811            }
812            InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } => {
813                err.arg("vtable_dyn_type", vtable_dyn_type.to_string());
814                err.arg("expected_dyn_type", expected_dyn_type.to_string());
815            }
816            NullPtr { .. }
817            | MutableRefToImmutable
818            | MutableRefInConst
819            | NullFnPtr
820            | NeverVal
821            | UnsafeCellInImmutable
822            | InvalidMetaSliceTooLarge { .. }
823            | InvalidMetaTooLarge { .. }
824            | DanglingPtrUseAfterFree { .. }
825            | DanglingPtrOutOfBounds { .. }
826            | UninhabitedEnumVariant
827            | PartialPointer => {}
828        }
829    }
830}
831
832impl ReportErrorExt for UnsupportedOpInfo {
833    fn diagnostic_message(&self) -> DiagMessage {
834        use crate::fluent_generated::*;
835        match self {
836            UnsupportedOpInfo::Unsupported(s) => s.clone().into(),
837            UnsupportedOpInfo::ExternTypeField => const_eval_extern_type_field,
838            UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local,
839            UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite,
840            UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy,
841            UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int,
842            UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static,
843            UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
844        }
845    }
846
847    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
848        use UnsupportedOpInfo::*;
849
850        use crate::fluent_generated::*;
851        if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
852            diag.help(const_eval_ptr_as_bytes_1);
853            diag.help(const_eval_ptr_as_bytes_2);
854        }
855        match self {
856            // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
857            // be further processed by validity checking which then turns it into something nice to
858            // print. So it's not worth the effort of having diagnostics that can print the `info`.
859            UnsizedLocal
860            | UnsupportedOpInfo::ExternTypeField
861            | Unsupported(_)
862            | ReadPointerAsInt(_) => {}
863            OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
864                diag.arg("ptr", ptr);
865            }
866            ThreadLocalStatic(did) | ExternStatic(did) => rustc_middle::ty::tls::with(|tcx| {
867                diag.arg("did", tcx.def_path_str(did));
868            }),
869        }
870    }
871}
872
873impl<'tcx> ReportErrorExt for InterpErrorKind<'tcx> {
874    fn diagnostic_message(&self) -> DiagMessage {
875        match self {
876            InterpErrorKind::UndefinedBehavior(ub) => ub.diagnostic_message(),
877            InterpErrorKind::Unsupported(e) => e.diagnostic_message(),
878            InterpErrorKind::InvalidProgram(e) => e.diagnostic_message(),
879            InterpErrorKind::ResourceExhaustion(e) => e.diagnostic_message(),
880            InterpErrorKind::MachineStop(e) => e.diagnostic_message(),
881        }
882    }
883    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
884        match self {
885            InterpErrorKind::UndefinedBehavior(ub) => ub.add_args(diag),
886            InterpErrorKind::Unsupported(e) => e.add_args(diag),
887            InterpErrorKind::InvalidProgram(e) => e.add_args(diag),
888            InterpErrorKind::ResourceExhaustion(e) => e.add_args(diag),
889            InterpErrorKind::MachineStop(e) => e.add_args(&mut |name, value| {
890                diag.arg(name, value);
891            }),
892        }
893    }
894}
895
896impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
897    fn diagnostic_message(&self) -> DiagMessage {
898        use crate::fluent_generated::*;
899        match self {
900            InvalidProgramInfo::TooGeneric => const_eval_too_generic,
901            InvalidProgramInfo::AlreadyReported(_) => const_eval_already_reported,
902            InvalidProgramInfo::Layout(e) => e.diagnostic_message(),
903        }
904    }
905    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
906        match self {
907            InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
908            InvalidProgramInfo::Layout(e) => {
909                // The level doesn't matter, `dummy_diag` is consumed without it being used.
910                let dummy_level = Level::Bug;
911                let dummy_diag: Diag<'_, ()> = e.into_diagnostic().into_diag(diag.dcx, dummy_level);
912                for (name, val) in dummy_diag.args.iter() {
913                    diag.arg(name.clone(), val.clone());
914                }
915                dummy_diag.cancel();
916            }
917        }
918    }
919}
920
921impl ReportErrorExt for ResourceExhaustionInfo {
922    fn diagnostic_message(&self) -> DiagMessage {
923        use crate::fluent_generated::*;
924        match self {
925            ResourceExhaustionInfo::StackFrameLimitReached => const_eval_stack_frame_limit_reached,
926            ResourceExhaustionInfo::MemoryExhausted => const_eval_memory_exhausted,
927            ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
928            ResourceExhaustionInfo::Interrupted => const_eval_interrupted,
929        }
930    }
931    fn add_args<G: EmissionGuarantee>(self, _: &mut Diag<'_, G>) {}
932}
933
934impl rustc_errors::IntoDiagArg for InternKind {
935    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
936        DiagArgValue::Str(Cow::Borrowed(match self {
937            InternKind::Static(Mutability::Not) => "static",
938            InternKind::Static(Mutability::Mut) => "static_mut",
939            InternKind::Constant => "const",
940            InternKind::Promoted => "promoted",
941        }))
942    }
943}