rustc_const_eval/
errors.rs

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