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