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, SubdiagMessageOp, 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_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
294        self,
295        diag: &mut Diag<'_, G>,
296        f: &F,
297    ) {
298        diag.arg("times", self.times);
299        diag.arg("where_", self.where_);
300        diag.arg("instance", self.instance);
301        let mut span: MultiSpan = self.span.into();
302        if self.has_label && !self.span.is_dummy() {
303            span.push_span_label(self.span, fluent::const_eval_frame_note_last);
304        }
305        let msg = f(diag, fluent::const_eval_frame_note.into());
306        diag.span_note(span, msg);
307    }
308}
309
310#[derive(Subdiagnostic)]
311#[note(const_eval_raw_bytes)]
312pub struct RawBytesNote {
313    pub size: u64,
314    pub align: u64,
315    pub bytes: String,
316}
317
318// FIXME(fee1-dead) do not use stringly typed `ConstContext`
319
320#[derive(Diagnostic)]
321#[diag(const_eval_non_const_match_eq, code = E0015)]
322#[note]
323pub struct NonConstMatchEq<'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_for_loop_into_iter, code = E0015)]
333pub struct NonConstForLoopIntoIter<'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_branch, code = E0015)]
343pub struct NonConstQuestionBranch<'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_question_from_residual, code = E0015)]
353pub struct NonConstQuestionFromResidual<'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_try_block_from_output, code = E0015)]
363pub struct NonConstTryBlockFromOutput<'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_await, code = E0015)]
373pub struct NonConstAwait<'tcx> {
374    #[primary_span]
375    pub span: Span,
376    pub ty: Ty<'tcx>,
377    pub kind: ConstContext,
378    pub non_or_conditionally: &'static str,
379}
380
381#[derive(Diagnostic)]
382#[diag(const_eval_non_const_closure, code = E0015)]
383pub struct NonConstClosure {
384    #[primary_span]
385    pub span: Span,
386    pub kind: ConstContext,
387    #[subdiagnostic]
388    pub note: Option<NonConstClosureNote>,
389    pub non_or_conditionally: &'static str,
390}
391
392#[derive(Subdiagnostic)]
393pub enum NonConstClosureNote {
394    #[note(const_eval_closure_fndef_not_const)]
395    FnDef {
396        #[primary_span]
397        span: Span,
398    },
399    #[note(const_eval_fn_ptr_call)]
400    FnPtr,
401    #[note(const_eval_closure_call)]
402    Closure,
403}
404
405#[derive(Subdiagnostic)]
406#[multipart_suggestion(const_eval_consider_dereferencing, applicability = "machine-applicable")]
407pub struct ConsiderDereferencing {
408    pub deref: String,
409    #[suggestion_part(code = "{deref}")]
410    pub span: Span,
411    #[suggestion_part(code = "{deref}")]
412    pub rhs_span: Span,
413}
414
415#[derive(Diagnostic)]
416#[diag(const_eval_non_const_operator, code = E0015)]
417pub struct NonConstOperator {
418    #[primary_span]
419    pub span: Span,
420    pub kind: ConstContext,
421    #[subdiagnostic]
422    pub sugg: Option<ConsiderDereferencing>,
423    pub non_or_conditionally: &'static str,
424}
425
426#[derive(Diagnostic)]
427#[diag(const_eval_non_const_deref_coercion, code = E0015)]
428#[note]
429pub struct NonConstDerefCoercion<'tcx> {
430    #[primary_span]
431    pub span: Span,
432    pub ty: Ty<'tcx>,
433    pub kind: ConstContext,
434    pub target_ty: Ty<'tcx>,
435    #[note(const_eval_target_note)]
436    pub deref_target: Option<Span>,
437    pub non_or_conditionally: &'static str,
438}
439
440#[derive(Diagnostic)]
441#[diag(const_eval_live_drop, code = E0493)]
442pub struct LiveDrop<'tcx> {
443    #[primary_span]
444    #[label]
445    pub span: Span,
446    pub kind: ConstContext,
447    pub dropped_ty: Ty<'tcx>,
448    #[label(const_eval_dropped_at_label)]
449    pub dropped_at: Span,
450}
451
452#[derive(Diagnostic)]
453#[diag(const_eval_error, code = E0080)]
454pub struct ConstEvalError {
455    #[primary_span]
456    pub span: Span,
457    /// One of "const", "const_with_path", and "static"
458    pub error_kind: &'static str,
459    pub instance: String,
460    #[subdiagnostic]
461    pub frame_notes: Vec<FrameNote>,
462}
463
464#[derive(Diagnostic)]
465#[diag(const_eval_nullary_intrinsic_fail)]
466pub struct NullaryIntrinsicError {
467    #[primary_span]
468    pub span: Span,
469}
470
471#[derive(Diagnostic)]
472#[diag(const_eval_validation_failure, code = E0080)]
473pub struct ValidationFailure {
474    #[primary_span]
475    pub span: Span,
476    #[note(const_eval_validation_failure_note)]
477    pub ub_note: (),
478    #[subdiagnostic]
479    pub frames: Vec<FrameNote>,
480    #[subdiagnostic]
481    pub raw_bytes: RawBytesNote,
482}
483
484pub trait ReportErrorExt {
485    /// Returns the diagnostic message for this error.
486    fn diagnostic_message(&self) -> DiagMessage;
487    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>);
488
489    fn debug(self) -> String
490    where
491        Self: Sized,
492    {
493        ty::tls::with(move |tcx| {
494            let dcx = tcx.dcx();
495            let mut diag = dcx.struct_allow(DiagMessage::Str(String::new().into()));
496            let message = self.diagnostic_message();
497            self.add_args(&mut diag);
498            let s = dcx.eagerly_translate_to_string(message, diag.args.iter());
499            diag.cancel();
500            s
501        })
502    }
503}
504
505fn bad_pointer_message(msg: CheckInAllocMsg, dcx: DiagCtxtHandle<'_>) -> String {
506    use crate::fluent_generated::*;
507
508    let msg = match msg {
509        CheckInAllocMsg::MemoryAccessTest => const_eval_memory_access_test,
510        CheckInAllocMsg::PointerArithmeticTest => const_eval_pointer_arithmetic_test,
511        CheckInAllocMsg::OffsetFromTest => const_eval_offset_from_test,
512        CheckInAllocMsg::InboundsTest => const_eval_in_bounds_test,
513    };
514
515    dcx.eagerly_translate_to_string(msg, [].into_iter())
516}
517
518impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
519    fn diagnostic_message(&self) -> DiagMessage {
520        use UndefinedBehaviorInfo::*;
521
522        use crate::fluent_generated::*;
523        match self {
524            Ub(msg) => msg.clone().into(),
525            Custom(x) => (x.msg)(),
526            ValidationError(e) => e.diagnostic_message(),
527
528            Unreachable => const_eval_unreachable,
529            BoundsCheckFailed { .. } => const_eval_bounds_check_failed,
530            DivisionByZero => const_eval_division_by_zero,
531            RemainderByZero => const_eval_remainder_by_zero,
532            DivisionOverflow => const_eval_division_overflow,
533            RemainderOverflow => const_eval_remainder_overflow,
534            PointerArithOverflow => const_eval_pointer_arithmetic_overflow,
535            ArithOverflow { .. } => const_eval_overflow_arith,
536            ShiftOverflow { .. } => const_eval_overflow_shift,
537            InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
538            InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
539            UnterminatedCString(_) => const_eval_unterminated_c_string,
540            PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free,
541            PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
542            DanglingIntPointer { addr: 0, .. } => const_eval_dangling_null_pointer,
543            DanglingIntPointer { .. } => const_eval_dangling_int_pointer,
544            AlignmentCheckFailed { .. } => const_eval_alignment_check_failed,
545            WriteToReadOnly(_) => const_eval_write_to_read_only,
546            DerefFunctionPointer(_) => const_eval_deref_function_pointer,
547            DerefVTablePointer(_) => const_eval_deref_vtable_pointer,
548            InvalidBool(_) => const_eval_invalid_bool,
549            InvalidChar(_) => const_eval_invalid_char,
550            InvalidTag(_) => const_eval_invalid_tag,
551            InvalidFunctionPointer(_) => const_eval_invalid_function_pointer,
552            InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer,
553            InvalidVTableTrait { .. } => const_eval_invalid_vtable_trait,
554            InvalidStr(_) => const_eval_invalid_str,
555            InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown,
556            InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes,
557            DeadLocal => const_eval_dead_local,
558            ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
559            UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written,
560            UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read,
561            InvalidNichedEnumVariantWritten { .. } => {
562                const_eval_invalid_niched_enum_variant_written
563            }
564            AbiMismatchArgument { .. } => const_eval_incompatible_types,
565            AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
566        }
567    }
568
569    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
570        use UndefinedBehaviorInfo::*;
571        let dcx = diag.dcx;
572        match self {
573            Ub(_) => {}
574            Custom(custom) => {
575                (custom.add_args)(&mut |name, value| {
576                    diag.arg(name, value);
577                });
578            }
579            ValidationError(e) => e.add_args(diag),
580
581            Unreachable
582            | DivisionByZero
583            | RemainderByZero
584            | DivisionOverflow
585            | RemainderOverflow
586            | PointerArithOverflow
587            | InvalidMeta(InvalidMetaKind::SliceTooBig)
588            | InvalidMeta(InvalidMetaKind::TooBig)
589            | InvalidUninitBytes(None)
590            | DeadLocal
591            | UninhabitedEnumVariantWritten(_)
592            | UninhabitedEnumVariantRead(_) => {}
593
594            ArithOverflow { intrinsic } => {
595                diag.arg("intrinsic", intrinsic);
596            }
597            ShiftOverflow { intrinsic, shift_amount } => {
598                diag.arg("intrinsic", intrinsic);
599                diag.arg(
600                    "shift_amount",
601                    match shift_amount {
602                        Either::Left(v) => v.to_string(),
603                        Either::Right(v) => v.to_string(),
604                    },
605                );
606            }
607            BoundsCheckFailed { len, index } => {
608                diag.arg("len", len);
609                diag.arg("index", index);
610            }
611            UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
612                diag.arg("pointer", ptr);
613            }
614            InvalidVTableTrait { expected_dyn_type, vtable_dyn_type } => {
615                diag.arg("expected_dyn_type", expected_dyn_type.to_string());
616                diag.arg("vtable_dyn_type", vtable_dyn_type.to_string());
617            }
618            PointerUseAfterFree(alloc_id, msg) => {
619                diag.arg("alloc_id", alloc_id)
620                    .arg("bad_pointer_message", bad_pointer_message(msg, dcx));
621            }
622            PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => {
623                diag.arg("alloc_size", alloc_size.bytes());
624                diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
625                diag.arg("pointer", {
626                    let mut out = format!("{:?}", alloc_id);
627                    if ptr_offset > 0 {
628                        write!(out, "+{:#x}", ptr_offset).unwrap();
629                    } else if ptr_offset < 0 {
630                        write!(out, "-{:#x}", ptr_offset.unsigned_abs()).unwrap();
631                    }
632                    out
633                });
634                diag.arg("inbounds_size_is_neg", inbounds_size < 0);
635                diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
636                diag.arg("ptr_offset_is_neg", ptr_offset < 0);
637                diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs());
638                diag.arg(
639                    "alloc_size_minus_ptr_offset",
640                    alloc_size.bytes().saturating_sub(ptr_offset as u64),
641                );
642            }
643            DanglingIntPointer { addr, inbounds_size, msg } => {
644                if addr != 0 {
645                    diag.arg(
646                        "pointer",
647                        Pointer::<Option<CtfeProvenance>>::from_addr_invalid(addr).to_string(),
648                    );
649                }
650
651                diag.arg("inbounds_size_is_neg", inbounds_size < 0);
652                diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
653                diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
654            }
655            AlignmentCheckFailed(Misalignment { required, has }, msg) => {
656                diag.arg("required", required.bytes());
657                diag.arg("has", has.bytes());
658                diag.arg("msg", format!("{msg:?}"));
659            }
660            WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
661                diag.arg("allocation", alloc);
662            }
663            InvalidBool(b) => {
664                diag.arg("value", format!("{b:02x}"));
665            }
666            InvalidChar(c) => {
667                diag.arg("value", format!("{c:08x}"));
668            }
669            InvalidTag(tag) => {
670                diag.arg("tag", format!("{tag:x}"));
671            }
672            InvalidStr(err) => {
673                diag.arg("err", format!("{err}"));
674            }
675            InvalidUninitBytes(Some((alloc, info))) => {
676                diag.arg("alloc", alloc);
677                diag.arg("access", info.access);
678                diag.arg("uninit", info.bad);
679            }
680            ScalarSizeMismatch(info) => {
681                diag.arg("target_size", info.target_size);
682                diag.arg("data_size", info.data_size);
683            }
684            InvalidNichedEnumVariantWritten { enum_ty } => {
685                diag.arg("ty", enum_ty.to_string());
686            }
687            AbiMismatchArgument { caller_ty, callee_ty }
688            | AbiMismatchReturn { caller_ty, callee_ty } => {
689                diag.arg("caller_ty", caller_ty.to_string());
690                diag.arg("callee_ty", callee_ty.to_string());
691            }
692        }
693    }
694}
695
696impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
697    fn diagnostic_message(&self) -> DiagMessage {
698        use rustc_middle::mir::interpret::ValidationErrorKind::*;
699
700        use crate::fluent_generated::*;
701        match self.kind {
702            PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => {
703                const_eval_validation_box_to_uninhabited
704            }
705            PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => {
706                const_eval_validation_ref_to_uninhabited
707            }
708
709            PointerAsInt { .. } => const_eval_validation_pointer_as_int,
710            PartialPointer => const_eval_validation_partial_pointer,
711            ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
712            ConstRefToExtern => const_eval_validation_const_ref_to_extern,
713            MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
714            NullFnPtr => const_eval_validation_null_fn_ptr,
715            NeverVal => const_eval_validation_never_val,
716            NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
717            PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
718            OutOfRange { .. } => const_eval_validation_out_of_range,
719            UnsafeCellInImmutable => const_eval_validation_unsafe_cell,
720            UninhabitedVal { .. } => const_eval_validation_uninhabited_val,
721            InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag,
722            UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
723            Uninit { .. } => const_eval_validation_uninit,
724            InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr,
725            InvalidMetaWrongTrait { .. } => const_eval_validation_invalid_vtable_trait,
726            InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
727                const_eval_validation_invalid_box_slice_meta
728            }
729            InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => {
730                const_eval_validation_invalid_ref_slice_meta
731            }
732
733            InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => {
734                const_eval_validation_invalid_box_meta
735            }
736            InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => {
737                const_eval_validation_invalid_ref_meta
738            }
739            UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => {
740                const_eval_validation_unaligned_ref
741            }
742            UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box,
743
744            NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box,
745            NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref,
746            DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
747                const_eval_validation_dangling_box_no_provenance
748            }
749            DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => {
750                const_eval_validation_dangling_ref_no_provenance
751            }
752            DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => {
753                const_eval_validation_dangling_box_out_of_bounds
754            }
755            DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => {
756                const_eval_validation_dangling_ref_out_of_bounds
757            }
758            DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => {
759                const_eval_validation_dangling_box_use_after_free
760            }
761            DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => {
762                const_eval_validation_dangling_ref_use_after_free
763            }
764            InvalidBool { .. } => const_eval_validation_invalid_bool,
765            InvalidChar { .. } => const_eval_validation_invalid_char,
766            InvalidFnPtr { .. } => const_eval_validation_invalid_fn_ptr,
767        }
768    }
769
770    fn add_args<G: EmissionGuarantee>(self, err: &mut Diag<'_, G>) {
771        use rustc_middle::mir::interpret::ValidationErrorKind::*;
772
773        use crate::fluent_generated as fluent;
774
775        if let PointerAsInt { .. } | PartialPointer = self.kind {
776            err.help(fluent::const_eval_ptr_as_bytes_1);
777            err.help(fluent::const_eval_ptr_as_bytes_2);
778        }
779
780        let message = if let Some(path) = self.path {
781            err.dcx.eagerly_translate_to_string(
782                fluent::const_eval_validation_front_matter_invalid_value_with_path,
783                [("path".into(), DiagArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
784            )
785        } else {
786            err.dcx.eagerly_translate_to_string(
787                fluent::const_eval_validation_front_matter_invalid_value,
788                [].into_iter(),
789            )
790        };
791
792        err.arg("front_matter", message);
793
794        fn add_range_arg<G: EmissionGuarantee>(
795            r: WrappingRange,
796            max_hi: u128,
797            err: &mut Diag<'_, G>,
798        ) {
799            let WrappingRange { start: lo, end: hi } = r;
800            assert!(hi <= max_hi);
801            let msg = if lo > hi {
802                fluent::const_eval_range_wrapping
803            } else if lo == hi {
804                fluent::const_eval_range_singular
805            } else if lo == 0 {
806                assert!(hi < max_hi, "should not be printing if the range covers everything");
807                fluent::const_eval_range_upper
808            } else if hi == max_hi {
809                assert!(lo > 0, "should not be printing if the range covers everything");
810                fluent::const_eval_range_lower
811            } else {
812                fluent::const_eval_range
813            };
814
815            let args = [
816                ("lo".into(), DiagArgValue::Str(lo.to_string().into())),
817                ("hi".into(), DiagArgValue::Str(hi.to_string().into())),
818            ];
819            let args = args.iter().map(|(a, b)| (a, b));
820            let message = err.dcx.eagerly_translate_to_string(msg, args);
821            err.arg("in_range", message);
822        }
823
824        match self.kind {
825            PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => {
826                err.arg("ty", ty);
827            }
828            PointerAsInt { expected } | Uninit { expected } => {
829                let msg = match expected {
830                    ExpectedKind::Reference => fluent::const_eval_validation_expected_ref,
831                    ExpectedKind::Box => fluent::const_eval_validation_expected_box,
832                    ExpectedKind::RawPtr => fluent::const_eval_validation_expected_raw_ptr,
833                    ExpectedKind::InitScalar => fluent::const_eval_validation_expected_init_scalar,
834                    ExpectedKind::Bool => fluent::const_eval_validation_expected_bool,
835                    ExpectedKind::Char => fluent::const_eval_validation_expected_char,
836                    ExpectedKind::Float => fluent::const_eval_validation_expected_float,
837                    ExpectedKind::Int => fluent::const_eval_validation_expected_int,
838                    ExpectedKind::FnPtr => fluent::const_eval_validation_expected_fn_ptr,
839                    ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
840                    ExpectedKind::Str => fluent::const_eval_validation_expected_str,
841                };
842                let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
843                err.arg("expected", msg);
844            }
845            InvalidEnumTag { value }
846            | InvalidVTablePtr { value }
847            | InvalidBool { value }
848            | InvalidChar { value }
849            | InvalidFnPtr { value } => {
850                err.arg("value", value);
851            }
852            NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
853                add_range_arg(range, max_value, err)
854            }
855            OutOfRange { range, max_value, value } => {
856                err.arg("value", value);
857                add_range_arg(range, max_value, err);
858            }
859            UnalignedPtr { required_bytes, found_bytes, .. } => {
860                err.arg("required_bytes", required_bytes);
861                err.arg("found_bytes", found_bytes);
862            }
863            DanglingPtrNoProvenance { pointer, .. } => {
864                err.arg("pointer", pointer);
865            }
866            InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } => {
867                err.arg("vtable_dyn_type", vtable_dyn_type.to_string());
868                err.arg("expected_dyn_type", expected_dyn_type.to_string());
869            }
870            NullPtr { .. }
871            | ConstRefToMutable
872            | ConstRefToExtern
873            | MutableRefToImmutable
874            | NullFnPtr
875            | NeverVal
876            | UnsafeCellInImmutable
877            | InvalidMetaSliceTooLarge { .. }
878            | InvalidMetaTooLarge { .. }
879            | DanglingPtrUseAfterFree { .. }
880            | DanglingPtrOutOfBounds { .. }
881            | UninhabitedEnumVariant
882            | PartialPointer => {}
883        }
884    }
885}
886
887impl ReportErrorExt for UnsupportedOpInfo {
888    fn diagnostic_message(&self) -> DiagMessage {
889        use crate::fluent_generated::*;
890        match self {
891            UnsupportedOpInfo::Unsupported(s) => s.clone().into(),
892            UnsupportedOpInfo::ExternTypeField => const_eval_extern_type_field,
893            UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local,
894            UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite,
895            UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy,
896            UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int,
897            UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static,
898            UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
899        }
900    }
901
902    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
903        use UnsupportedOpInfo::*;
904
905        use crate::fluent_generated::*;
906        if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
907            diag.help(const_eval_ptr_as_bytes_1);
908            diag.help(const_eval_ptr_as_bytes_2);
909        }
910        match self {
911            // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
912            // be further processed by validity checking which then turns it into something nice to
913            // print. So it's not worth the effort of having diagnostics that can print the `info`.
914            UnsizedLocal
915            | UnsupportedOpInfo::ExternTypeField
916            | Unsupported(_)
917            | ReadPointerAsInt(_) => {}
918            OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
919                diag.arg("ptr", ptr);
920            }
921            ThreadLocalStatic(did) | ExternStatic(did) => rustc_middle::ty::tls::with(|tcx| {
922                diag.arg("did", tcx.def_path_str(did));
923            }),
924        }
925    }
926}
927
928impl<'tcx> ReportErrorExt for InterpErrorKind<'tcx> {
929    fn diagnostic_message(&self) -> DiagMessage {
930        match self {
931            InterpErrorKind::UndefinedBehavior(ub) => ub.diagnostic_message(),
932            InterpErrorKind::Unsupported(e) => e.diagnostic_message(),
933            InterpErrorKind::InvalidProgram(e) => e.diagnostic_message(),
934            InterpErrorKind::ResourceExhaustion(e) => e.diagnostic_message(),
935            InterpErrorKind::MachineStop(e) => e.diagnostic_message(),
936        }
937    }
938    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
939        match self {
940            InterpErrorKind::UndefinedBehavior(ub) => ub.add_args(diag),
941            InterpErrorKind::Unsupported(e) => e.add_args(diag),
942            InterpErrorKind::InvalidProgram(e) => e.add_args(diag),
943            InterpErrorKind::ResourceExhaustion(e) => e.add_args(diag),
944            InterpErrorKind::MachineStop(e) => e.add_args(&mut |name, value| {
945                diag.arg(name, value);
946            }),
947        }
948    }
949}
950
951impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
952    fn diagnostic_message(&self) -> DiagMessage {
953        use crate::fluent_generated::*;
954        match self {
955            InvalidProgramInfo::TooGeneric => const_eval_too_generic,
956            InvalidProgramInfo::AlreadyReported(_) => const_eval_already_reported,
957            InvalidProgramInfo::Layout(e) => e.diagnostic_message(),
958        }
959    }
960    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
961        match self {
962            InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
963            InvalidProgramInfo::Layout(e) => {
964                // The level doesn't matter, `dummy_diag` is consumed without it being used.
965                let dummy_level = Level::Bug;
966                let dummy_diag: Diag<'_, ()> = e.into_diagnostic().into_diag(diag.dcx, dummy_level);
967                for (name, val) in dummy_diag.args.iter() {
968                    diag.arg(name.clone(), val.clone());
969                }
970                dummy_diag.cancel();
971            }
972        }
973    }
974}
975
976impl ReportErrorExt for ResourceExhaustionInfo {
977    fn diagnostic_message(&self) -> DiagMessage {
978        use crate::fluent_generated::*;
979        match self {
980            ResourceExhaustionInfo::StackFrameLimitReached => const_eval_stack_frame_limit_reached,
981            ResourceExhaustionInfo::MemoryExhausted => const_eval_memory_exhausted,
982            ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
983            ResourceExhaustionInfo::Interrupted => const_eval_interrupted,
984        }
985    }
986    fn add_args<G: EmissionGuarantee>(self, _: &mut Diag<'_, G>) {}
987}
988
989impl rustc_errors::IntoDiagArg for InternKind {
990    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
991        DiagArgValue::Str(Cow::Borrowed(match self {
992            InternKind::Static(Mutability::Not) => "static",
993            InternKind::Static(Mutability::Mut) => "static_mut",
994            InternKind::Constant => "const",
995            InternKind::Promoted => "promoted",
996        }))
997    }
998}