about summary refs log tree commit diff
path: root/compiler/rustc_const_eval/src/errors.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_const_eval/src/errors.rs')
-rw-r--r--compiler/rustc_const_eval/src/errors.rs643
1 files changed, 641 insertions, 2 deletions
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index ad2e68e752d..8a71e3b3401 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -1,6 +1,24 @@
+use rustc_errors::{
+    DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler,
+    IntoDiagnostic,
+};
 use rustc_hir::ConstContext;
-use rustc_macros::{Diagnostic, LintDiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
+use rustc_middle::mir::interpret::{
+    CheckInAllocMsg, ExpectedKind, InterpError, InvalidMetaKind, InvalidProgramInfo, PointerKind,
+    ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
+};
+use rustc_middle::ty::Ty;
 use rustc_span::Span;
+use rustc_target::abi::call::AdjustForForeignAbiError;
+use rustc_target::abi::{Size, WrappingRange};
+
+#[derive(Diagnostic)]
+#[diag(const_eval_dangling_ptr_in_final)]
+pub(crate) struct DanglingPtrInFinal {
+    #[primary_span]
+    pub span: Span,
+}
 
 #[derive(Diagnostic)]
 #[diag(const_eval_unstable_in_stable)]
@@ -92,7 +110,7 @@ pub(crate) struct TransientMutBorrowErrRaw {
 #[diag(const_eval_max_num_nodes_in_const)]
 pub(crate) struct MaxNumNodesInConstErr {
     #[primary_span]
-    pub span: Span,
+    pub span: Option<Span>,
     pub global_const_id: String,
 }
 
@@ -176,6 +194,14 @@ pub(crate) struct UnallowedInlineAsm {
 }
 
 #[derive(Diagnostic)]
+#[diag(const_eval_unsupported_untyped_pointer)]
+#[note]
+pub(crate) struct UnsupportedUntypedPointer {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(const_eval_interior_mutable_data_refer, code = "E0492")]
 pub(crate) struct InteriorMutableDataRefer {
     #[primary_span]
@@ -212,3 +238,616 @@ pub struct LongRunningWarn {
     #[help]
     pub item_span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(const_eval_erroneous_constant)]
+pub(crate) struct ErroneousConstUsed {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[note(const_eval_non_const_impl)]
+pub(crate) struct NonConstImplNote {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Subdiagnostic, PartialEq, Eq, Clone)]
+#[note(const_eval_frame_note)]
+pub struct FrameNote {
+    #[primary_span]
+    pub span: Span,
+    pub times: i32,
+    pub where_: &'static str,
+    pub instance: String,
+}
+
+#[derive(Subdiagnostic)]
+#[note(const_eval_raw_bytes)]
+pub struct RawBytesNote {
+    pub size: u64,
+    pub align: u64,
+    pub bytes: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_for_loop_into_iter_non_const, code = "E0015")]
+pub struct NonConstForLoopIntoIter<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+    pub kind: ConstContext,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_question_branch_non_const, code = "E0015")]
+pub struct NonConstQuestionBranch<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+    pub kind: ConstContext,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_question_from_residual_non_const, code = "E0015")]
+pub struct NonConstQuestionFromResidual<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+    pub kind: ConstContext,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_try_block_from_output_non_const, code = "E0015")]
+pub struct NonConstTryBlockFromOutput<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+    pub kind: ConstContext,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_await_non_const, code = "E0015")]
+pub struct NonConstAwait<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+    pub kind: ConstContext,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_closure_non_const, code = "E0015")]
+pub struct NonConstClosure {
+    #[primary_span]
+    pub span: Span,
+    pub kind: ConstContext,
+    #[subdiagnostic]
+    pub note: Option<NonConstClosureNote>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum NonConstClosureNote {
+    #[note(const_eval_closure_fndef_not_const)]
+    FnDef {
+        #[primary_span]
+        span: Span,
+    },
+    #[note(const_eval_fn_ptr_call)]
+    FnPtr,
+    #[note(const_eval_closure_call)]
+    Closure,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(const_eval_consider_dereferencing, applicability = "machine-applicable")]
+pub struct ConsiderDereferencing {
+    pub deref: String,
+    #[suggestion_part(code = "{deref}")]
+    pub span: Span,
+    #[suggestion_part(code = "{deref}")]
+    pub rhs_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_operator_non_const, code = "E0015")]
+pub struct NonConstOperator {
+    #[primary_span]
+    pub span: Span,
+    pub kind: ConstContext,
+    #[subdiagnostic]
+    pub sugg: Option<ConsiderDereferencing>,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_deref_coercion_non_const, code = "E0015")]
+#[note]
+pub struct NonConstDerefCoercion<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+    pub kind: ConstContext,
+    pub target_ty: Ty<'tcx>,
+    #[note(const_eval_target_note)]
+    pub deref_target: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_live_drop, code = "E0493")]
+pub struct LiveDrop<'tcx> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub kind: ConstContext,
+    pub dropped_ty: Ty<'tcx>,
+    #[label(const_eval_dropped_at_label)]
+    pub dropped_at: Option<Span>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(const_eval_align_check_failed)]
+pub struct AlignmentCheckFailed {
+    pub has: u64,
+    pub required: u64,
+    #[subdiagnostic]
+    pub frames: Vec<FrameNote>,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_error, code = "E0080")]
+pub struct ConstEvalError {
+    #[primary_span]
+    pub span: Span,
+    /// One of "const", "const_with_path", and "static"
+    pub error_kind: &'static str,
+    pub instance: String,
+    #[subdiagnostic]
+    pub frame_notes: Vec<FrameNote>,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_nullary_intrinsic_fail)]
+pub struct NullaryIntrinsicError {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_undefined_behavior, code = "E0080")]
+pub struct UndefinedBehavior {
+    #[primary_span]
+    pub span: Span,
+    #[note(const_eval_undefined_behavior_note)]
+    pub ub_note: Option<()>,
+    #[subdiagnostic]
+    pub frames: Vec<FrameNote>,
+    #[subdiagnostic]
+    pub raw_bytes: RawBytesNote,
+}
+
+pub trait ReportErrorExt {
+    /// Returns the diagnostic message for this error.
+    fn diagnostic_message(&self) -> DiagnosticMessage;
+    fn add_args<G: EmissionGuarantee>(
+        self,
+        handler: &Handler,
+        builder: &mut DiagnosticBuilder<'_, G>,
+    );
+}
+
+fn bad_pointer_message(msg: CheckInAllocMsg, handler: &Handler) -> String {
+    use crate::fluent_generated::*;
+
+    let msg = match msg {
+        CheckInAllocMsg::DerefTest => const_eval_deref_test,
+        CheckInAllocMsg::MemoryAccessTest => const_eval_memory_access_test,
+        CheckInAllocMsg::PointerArithmeticTest => const_eval_pointer_arithmetic_test,
+        CheckInAllocMsg::OffsetFromTest => const_eval_offset_from_test,
+        CheckInAllocMsg::InboundsTest => const_eval_in_bounds_test,
+    };
+
+    handler.eagerly_translate_to_string(msg, [].into_iter())
+}
+
+impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
+    fn diagnostic_message(&self) -> DiagnosticMessage {
+        use crate::fluent_generated::*;
+        use UndefinedBehaviorInfo::*;
+        match self {
+            Ub(msg) => (&**msg).into(),
+            Unreachable => const_eval_unreachable,
+            BoundsCheckFailed { .. } => const_eval_bounds_check_failed,
+            DivisionByZero => const_eval_division_by_zero,
+            RemainderByZero => const_eval_remainder_by_zero,
+            DivisionOverflow => const_eval_division_overflow,
+            RemainderOverflow => const_eval_remainder_overflow,
+            PointerArithOverflow => const_eval_pointer_arithmetic_overflow,
+            InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
+            InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
+            UnterminatedCString(_) => const_eval_unterminated_c_string,
+            PointerUseAfterFree(_) => const_eval_pointer_use_after_free,
+            PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds,
+            PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
+            DanglingIntPointer(0, _) => const_eval_dangling_null_pointer,
+            DanglingIntPointer(_, _) => const_eval_dangling_int_pointer,
+            AlignmentCheckFailed { .. } => const_eval_alignment_check_failed,
+            WriteToReadOnly(_) => const_eval_write_to_read_only,
+            DerefFunctionPointer(_) => const_eval_deref_function_pointer,
+            DerefVTablePointer(_) => const_eval_deref_vtable_pointer,
+            InvalidBool(_) => const_eval_invalid_bool,
+            InvalidChar(_) => const_eval_invalid_char,
+            InvalidTag(_) => const_eval_invalid_tag,
+            InvalidFunctionPointer(_) => const_eval_invalid_function_pointer,
+            InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer,
+            InvalidStr(_) => const_eval_invalid_str,
+            InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown,
+            InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes,
+            DeadLocal => const_eval_dead_local,
+            ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
+            UninhabitedEnumVariantWritten => const_eval_uninhabited_enum_variant_written,
+            Validation(e) => e.diagnostic_message(),
+            Custom(x) => (x.msg)(),
+        }
+    }
+
+    fn add_args<G: EmissionGuarantee>(
+        self,
+        handler: &Handler,
+        builder: &mut DiagnosticBuilder<'_, G>,
+    ) {
+        use UndefinedBehaviorInfo::*;
+        match self {
+            Ub(_)
+            | Unreachable
+            | DivisionByZero
+            | RemainderByZero
+            | DivisionOverflow
+            | RemainderOverflow
+            | PointerArithOverflow
+            | InvalidMeta(InvalidMetaKind::SliceTooBig)
+            | InvalidMeta(InvalidMetaKind::TooBig)
+            | InvalidUninitBytes(None)
+            | DeadLocal
+            | UninhabitedEnumVariantWritten => {}
+            BoundsCheckFailed { len, index } => {
+                builder.set_arg("len", len);
+                builder.set_arg("index", index);
+            }
+            UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
+                builder.set_arg("pointer", ptr);
+            }
+            PointerUseAfterFree(allocation) => {
+                builder.set_arg("allocation", allocation);
+            }
+            PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
+                builder
+                    .set_arg("alloc_id", alloc_id)
+                    .set_arg("alloc_size", alloc_size.bytes())
+                    .set_arg("ptr_offset", ptr_offset)
+                    .set_arg("ptr_size", ptr_size.bytes())
+                    .set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
+            }
+            DanglingIntPointer(ptr, msg) => {
+                if ptr != 0 {
+                    builder.set_arg("pointer", format!("{ptr:#x}[noalloc]"));
+                }
+
+                builder.set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
+            }
+            AlignmentCheckFailed { required, has } => {
+                builder.set_arg("required", required.bytes());
+                builder.set_arg("has", has.bytes());
+            }
+            WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
+                builder.set_arg("allocation", alloc);
+            }
+            InvalidBool(b) => {
+                builder.set_arg("value", format!("{b:02x}"));
+            }
+            InvalidChar(c) => {
+                builder.set_arg("value", format!("{c:08x}"));
+            }
+            InvalidTag(tag) => {
+                builder.set_arg("tag", format!("{tag:x}"));
+            }
+            InvalidStr(err) => {
+                builder.set_arg("err", format!("{err}"));
+            }
+            InvalidUninitBytes(Some((alloc, info))) => {
+                builder.set_arg("alloc", alloc);
+                builder.set_arg("access", info.access);
+                builder.set_arg("uninit", info.uninit);
+            }
+            ScalarSizeMismatch(info) => {
+                builder.set_arg("target_size", info.target_size);
+                builder.set_arg("data_size", info.data_size);
+            }
+            Validation(e) => e.add_args(handler, builder),
+            Custom(custom) => {
+                (custom.add_args)(&mut |name, value| {
+                    builder.set_arg(name, value);
+                });
+            }
+        }
+    }
+}
+
+impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
+    fn diagnostic_message(&self) -> DiagnosticMessage {
+        use crate::fluent_generated::*;
+        use rustc_middle::mir::interpret::ValidationErrorKind::*;
+        match self.kind {
+            PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => const_eval_box_to_uninhabited,
+            PtrToUninhabited { ptr_kind: PointerKind::Ref, .. } => const_eval_ref_to_uninhabited,
+
+            PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_box_to_static,
+            PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_ref_to_static,
+
+            PtrToMut { ptr_kind: PointerKind::Box } => const_eval_box_to_mut,
+            PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_ref_to_mut,
+
+            ExpectedNonPtr { .. } => const_eval_expected_non_ptr,
+            MutableRefInConst => const_eval_mutable_ref_in_const,
+            NullFnPtr => const_eval_null_fn_ptr,
+            NeverVal => const_eval_never_val,
+            NullablePtrOutOfRange { .. } => const_eval_nullable_ptr_out_of_range,
+            PtrOutOfRange { .. } => const_eval_ptr_out_of_range,
+            OutOfRange { .. } => const_eval_out_of_range,
+            UnsafeCell => const_eval_unsafe_cell,
+            UninhabitedVal { .. } => const_eval_uninhabited_val,
+            InvalidEnumTag { .. } => const_eval_invalid_enum_tag,
+            UninitEnumTag => const_eval_uninit_enum_tag,
+            UninitStr => const_eval_uninit_str,
+            Uninit { expected: ExpectedKind::Bool } => const_eval_uninit_bool,
+            Uninit { expected: ExpectedKind::Reference } => const_eval_uninit_ref,
+            Uninit { expected: ExpectedKind::Box } => const_eval_uninit_box,
+            Uninit { expected: ExpectedKind::RawPtr } => const_eval_uninit_raw_ptr,
+            Uninit { expected: ExpectedKind::InitScalar } => const_eval_uninit_init_scalar,
+            Uninit { expected: ExpectedKind::Char } => const_eval_uninit_char,
+            Uninit { expected: ExpectedKind::Float } => const_eval_uninit_float,
+            Uninit { expected: ExpectedKind::Int } => const_eval_uninit_int,
+            Uninit { expected: ExpectedKind::FnPtr } => const_eval_uninit_fn_ptr,
+            UninitVal => const_eval_uninit,
+            InvalidVTablePtr { .. } => const_eval_invalid_vtable_ptr,
+            InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
+                const_eval_invalid_box_slice_meta
+            }
+            InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref } => {
+                const_eval_invalid_ref_slice_meta
+            }
+
+            InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => const_eval_invalid_box_meta,
+            InvalidMetaTooLarge { ptr_kind: PointerKind::Ref } => const_eval_invalid_ref_meta,
+            UnalignedPtr { ptr_kind: PointerKind::Ref, .. } => const_eval_unaligned_ref,
+            UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_unaligned_box,
+
+            NullPtr { ptr_kind: PointerKind::Box } => const_eval_null_box,
+            NullPtr { ptr_kind: PointerKind::Ref } => const_eval_null_ref,
+            DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
+                const_eval_dangling_box_no_provenance
+            }
+            DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref, .. } => {
+                const_eval_dangling_ref_no_provenance
+            }
+            DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => {
+                const_eval_dangling_box_out_of_bounds
+            }
+            DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref } => {
+                const_eval_dangling_ref_out_of_bounds
+            }
+            DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => {
+                const_eval_dangling_box_use_after_free
+            }
+            DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref } => {
+                const_eval_dangling_ref_use_after_free
+            }
+            InvalidBool { .. } => const_eval_validation_invalid_bool,
+            InvalidChar { .. } => const_eval_validation_invalid_char,
+            InvalidFnPtr { .. } => const_eval_invalid_fn_ptr,
+        }
+    }
+
+    fn add_args<G: EmissionGuarantee>(self, handler: &Handler, err: &mut DiagnosticBuilder<'_, G>) {
+        use crate::fluent_generated as fluent;
+        use rustc_middle::mir::interpret::ValidationErrorKind::*;
+
+        let message = if let Some(path) = self.path {
+            handler.eagerly_translate_to_string(
+                fluent::const_eval_invalid_value_with_path,
+                [("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
+            )
+        } else {
+            handler.eagerly_translate_to_string(fluent::const_eval_invalid_value, [].into_iter())
+        };
+
+        err.set_arg("front_matter", message);
+
+        fn add_range_arg<G: EmissionGuarantee>(
+            r: WrappingRange,
+            max_hi: u128,
+            handler: &Handler,
+            err: &mut DiagnosticBuilder<'_, G>,
+        ) {
+            let WrappingRange { start: lo, end: hi } = r;
+            assert!(hi <= max_hi);
+            let msg = if lo > hi {
+                fluent::const_eval_range_wrapping
+            } else if lo == hi {
+                fluent::const_eval_range_singular
+            } else if lo == 0 {
+                assert!(hi < max_hi, "should not be printing if the range covers everything");
+                fluent::const_eval_range_upper
+            } else if hi == max_hi {
+                assert!(lo > 0, "should not be printing if the range covers everything");
+                fluent::const_eval_range_lower
+            } else {
+                fluent::const_eval_range
+            };
+
+            let args = [
+                ("lo".into(), DiagnosticArgValue::Str(lo.to_string().into())),
+                ("hi".into(), DiagnosticArgValue::Str(hi.to_string().into())),
+            ];
+            let args = args.iter().map(|(a, b)| (a, b));
+            let message = handler.eagerly_translate_to_string(msg, args);
+            err.set_arg("in_range", message);
+        }
+
+        match self.kind {
+            PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => {
+                err.set_arg("ty", ty);
+            }
+            ExpectedNonPtr { value }
+            | InvalidEnumTag { value }
+            | InvalidVTablePtr { value }
+            | InvalidBool { value }
+            | InvalidChar { value }
+            | InvalidFnPtr { value } => {
+                err.set_arg("value", value);
+            }
+            NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
+                add_range_arg(range, max_value, handler, err)
+            }
+            OutOfRange { range, max_value, value } => {
+                err.set_arg("value", value);
+                add_range_arg(range, max_value, handler, err);
+            }
+            UnalignedPtr { required_bytes, found_bytes, .. } => {
+                err.set_arg("required_bytes", required_bytes);
+                err.set_arg("found_bytes", found_bytes);
+            }
+            DanglingPtrNoProvenance { pointer, .. } => {
+                err.set_arg("pointer", pointer);
+            }
+            NullPtr { .. }
+            | PtrToStatic { .. }
+            | PtrToMut { .. }
+            | MutableRefInConst
+            | NullFnPtr
+            | NeverVal
+            | UnsafeCell
+            | UninitEnumTag
+            | UninitStr
+            | Uninit { .. }
+            | UninitVal
+            | InvalidMetaSliceTooLarge { .. }
+            | InvalidMetaTooLarge { .. }
+            | DanglingPtrUseAfterFree { .. }
+            | DanglingPtrOutOfBounds { .. } => {}
+        }
+    }
+}
+
+impl ReportErrorExt for UnsupportedOpInfo {
+    fn diagnostic_message(&self) -> DiagnosticMessage {
+        use crate::fluent_generated::*;
+        match self {
+            UnsupportedOpInfo::Unsupported(s) => s.clone().into(),
+            UnsupportedOpInfo::PartialPointerOverwrite(_) => const_eval_partial_pointer_overwrite,
+            UnsupportedOpInfo::PartialPointerCopy(_) => const_eval_partial_pointer_copy,
+            UnsupportedOpInfo::ReadPointerAsBytes => const_eval_read_pointer_as_bytes,
+            UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static,
+            UnsupportedOpInfo::ReadExternStatic(_) => const_eval_read_extern_static,
+        }
+    }
+    fn add_args<G: EmissionGuarantee>(self, _: &Handler, builder: &mut DiagnosticBuilder<'_, G>) {
+        use crate::fluent_generated::*;
+
+        use UnsupportedOpInfo::*;
+        if let ReadPointerAsBytes | PartialPointerOverwrite(_) | PartialPointerCopy(_) = self {
+            builder.help(const_eval_ptr_as_bytes_1);
+            builder.help(const_eval_ptr_as_bytes_2);
+        }
+        match self {
+            Unsupported(_) | ReadPointerAsBytes => {}
+            PartialPointerOverwrite(ptr) | PartialPointerCopy(ptr) => {
+                builder.set_arg("ptr", ptr);
+            }
+            ThreadLocalStatic(did) | ReadExternStatic(did) => {
+                builder.set_arg("did", format!("{did:?}"));
+            }
+        }
+    }
+}
+
+impl<'tcx> ReportErrorExt for InterpError<'tcx> {
+    fn diagnostic_message(&self) -> DiagnosticMessage {
+        match self {
+            InterpError::UndefinedBehavior(ub) => ub.diagnostic_message(),
+            InterpError::Unsupported(e) => e.diagnostic_message(),
+            InterpError::InvalidProgram(e) => e.diagnostic_message(),
+            InterpError::ResourceExhaustion(e) => e.diagnostic_message(),
+            InterpError::MachineStop(e) => e.diagnostic_message(),
+        }
+    }
+    fn add_args<G: EmissionGuarantee>(
+        self,
+        handler: &Handler,
+        builder: &mut DiagnosticBuilder<'_, G>,
+    ) {
+        match self {
+            InterpError::UndefinedBehavior(ub) => ub.add_args(handler, builder),
+            InterpError::Unsupported(e) => e.add_args(handler, builder),
+            InterpError::InvalidProgram(e) => e.add_args(handler, builder),
+            InterpError::ResourceExhaustion(e) => e.add_args(handler, builder),
+            InterpError::MachineStop(e) => e.add_args(&mut |name, value| {
+                builder.set_arg(name, value);
+            }),
+        }
+    }
+}
+
+impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
+    fn diagnostic_message(&self) -> DiagnosticMessage {
+        use crate::fluent_generated::*;
+        match self {
+            InvalidProgramInfo::TooGeneric => const_eval_too_generic,
+            InvalidProgramInfo::AlreadyReported(_) => const_eval_already_reported,
+            InvalidProgramInfo::Layout(e) => e.diagnostic_message(),
+            InvalidProgramInfo::FnAbiAdjustForForeignAbi(_) => {
+                rustc_middle::error::middle_adjust_for_foreign_abi_error
+            }
+            InvalidProgramInfo::SizeOfUnsizedType(_) => const_eval_size_of_unsized,
+            InvalidProgramInfo::UninitUnsizedLocal => const_eval_uninit_unsized_local,
+        }
+    }
+    fn add_args<G: EmissionGuarantee>(
+        self,
+        handler: &Handler,
+        builder: &mut DiagnosticBuilder<'_, G>,
+    ) {
+        match self {
+            InvalidProgramInfo::TooGeneric
+            | InvalidProgramInfo::AlreadyReported(_)
+            | InvalidProgramInfo::UninitUnsizedLocal => {}
+            InvalidProgramInfo::Layout(e) => {
+                let diag: DiagnosticBuilder<'_, ()> = e.into_diagnostic().into_diagnostic(handler);
+                for (name, val) in diag.args() {
+                    builder.set_arg(name.clone(), val.clone());
+                }
+                diag.cancel();
+            }
+            InvalidProgramInfo::FnAbiAdjustForForeignAbi(
+                AdjustForForeignAbiError::Unsupported { arch, abi },
+            ) => {
+                builder.set_arg("arch", arch);
+                builder.set_arg("abi", abi.name());
+            }
+            InvalidProgramInfo::SizeOfUnsizedType(ty) => {
+                builder.set_arg("ty", ty);
+            }
+        }
+    }
+}
+
+impl ReportErrorExt for ResourceExhaustionInfo {
+    fn diagnostic_message(&self) -> DiagnosticMessage {
+        use crate::fluent_generated::*;
+        match self {
+            ResourceExhaustionInfo::StackFrameLimitReached => const_eval_stack_frame_limit_reached,
+            ResourceExhaustionInfo::MemoryExhausted => const_eval_memory_exhausted,
+            ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
+        }
+    }
+    fn add_args<G: EmissionGuarantee>(self, _: &Handler, _: &mut DiagnosticBuilder<'_, G>) {}
+}