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