| use std::borrow::Cow; |
| use std::fmt::Write; |
| |
| use either::Either; |
| use rustc_errors::codes::*; |
| use rustc_errors::{ |
| Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level, |
| }; |
| use rustc_hir::ConstContext; |
| use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; |
| use rustc_middle::mir::interpret::{ |
| CheckInAllocMsg, CtfeProvenance, ExpectedKind, InterpError, InvalidMetaKind, |
| InvalidProgramInfo, Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, |
| UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, |
| }; |
| use rustc_middle::ty::{self, Mutability, Ty}; |
| use rustc_span::Span; |
| use rustc_target::abi::call::AdjustForForeignAbiError; |
| use rustc_target::abi::WrappingRange; |
| |
| use crate::interpret::InternKind; |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_dangling_ptr_in_final)] |
| pub(crate) struct DanglingPtrInFinal { |
| #[primary_span] |
| pub span: Span, |
| pub kind: InternKind, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_nested_static_in_thread_local)] |
| pub(crate) struct NestedStaticInThreadLocal { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag(const_eval_mutable_ptr_in_final)] |
| pub(crate) struct MutablePtrInFinal { |
| // rust-lang/rust#122153: This was marked as `#[primary_span]` under |
| // `derive(Diagnostic)`. Since we expect we may hard-error in future, we are |
| // keeping the field (and skipping it under `derive(LintDiagnostic)`). |
| #[skip_arg] |
| pub span: Span, |
| pub kind: InternKind, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_unstable_in_stable)] |
| pub(crate) struct UnstableInStable { |
| pub gate: String, |
| #[primary_span] |
| pub span: Span, |
| #[suggestion( |
| const_eval_unstable_sugg, |
| code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n", |
| applicability = "has-placeholders" |
| )] |
| #[suggestion( |
| const_eval_bypass_sugg, |
| code = "#[rustc_allow_const_fn_unstable({gate})]\n", |
| applicability = "has-placeholders" |
| )] |
| pub attr_span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_thread_local_access, code = E0625)] |
| pub(crate) struct ThreadLocalAccessErr { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_raw_ptr_to_int)] |
| #[note] |
| #[note(const_eval_note2)] |
| pub(crate) struct RawPtrToIntErr { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_raw_ptr_comparison)] |
| #[note] |
| pub(crate) struct RawPtrComparisonErr { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_panic_non_str)] |
| pub(crate) struct PanicNonStrErr { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_mut_deref, code = E0658)] |
| pub(crate) struct MutDerefErr { |
| #[primary_span] |
| pub span: Span, |
| pub kind: ConstContext, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_transient_mut_borrow, code = E0658)] |
| pub(crate) struct TransientMutBorrowErr { |
| #[primary_span] |
| pub span: Span, |
| pub kind: ConstContext, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_transient_mut_raw, code = E0658)] |
| pub(crate) struct TransientMutRawErr { |
| #[primary_span] |
| pub span: Span, |
| pub kind: ConstContext, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_max_num_nodes_in_const)] |
| pub(crate) struct MaxNumNodesInConstErr { |
| #[primary_span] |
| pub span: Option<Span>, |
| pub global_const_id: String, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_unallowed_fn_pointer_call)] |
| pub(crate) struct UnallowedFnPointerCall { |
| #[primary_span] |
| pub span: Span, |
| pub kind: ConstContext, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_unstable_const_fn)] |
| pub(crate) struct UnstableConstFn { |
| #[primary_span] |
| pub span: Span, |
| pub def_path: String, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_unallowed_mutable_refs, code = E0764)] |
| pub(crate) struct UnallowedMutableRefs { |
| #[primary_span] |
| pub span: Span, |
| pub kind: ConstContext, |
| #[note(const_eval_teach_note)] |
| pub teach: Option<()>, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_unallowed_mutable_raw, code = E0764)] |
| pub(crate) struct UnallowedMutableRaw { |
| #[primary_span] |
| pub span: Span, |
| pub kind: ConstContext, |
| #[note(const_eval_teach_note)] |
| pub teach: Option<()>, |
| } |
| #[derive(Diagnostic)] |
| #[diag(const_eval_non_const_fmt_macro_call, code = E0015)] |
| pub(crate) struct NonConstFmtMacroCall { |
| #[primary_span] |
| pub span: Span, |
| pub kind: ConstContext, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_non_const_fn_call, code = E0015)] |
| pub(crate) struct NonConstFnCall { |
| #[primary_span] |
| pub span: Span, |
| pub def_path_str: String, |
| pub kind: ConstContext, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_unallowed_op_in_const_context)] |
| pub(crate) struct UnallowedOpInConstContext { |
| #[primary_span] |
| pub span: Span, |
| pub msg: String, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_unallowed_heap_allocations, code = E0010)] |
| pub(crate) struct UnallowedHeapAllocations { |
| #[primary_span] |
| #[label] |
| pub span: Span, |
| pub kind: ConstContext, |
| #[note(const_eval_teach_note)] |
| pub teach: Option<()>, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_unallowed_inline_asm, code = E0015)] |
| pub(crate) struct UnallowedInlineAsm { |
| #[primary_span] |
| pub span: Span, |
| pub kind: ConstContext, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_interior_mutable_data_refer, code = E0492)] |
| pub(crate) struct InteriorMutableDataRefer { |
| #[primary_span] |
| #[label] |
| pub span: Span, |
| #[help] |
| pub opt_help: Option<()>, |
| pub kind: ConstContext, |
| #[note(const_eval_teach_note)] |
| pub teach: Option<()>, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_interior_mutability_borrow)] |
| pub(crate) struct InteriorMutabilityBorrow { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag(const_eval_long_running)] |
| #[note] |
| pub struct LongRunning { |
| #[help] |
| pub item_span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_long_running)] |
| pub struct LongRunningWarn { |
| #[primary_span] |
| #[label] |
| pub span: Span, |
| #[help] |
| pub item_span: Span, |
| } |
| |
| #[derive(Subdiagnostic)] |
| #[note(const_eval_non_const_impl)] |
| pub(crate) struct NonConstImplNote { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Subdiagnostic, 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, |
| } |
| |
| // FIXME(fee1-dead) do not use stringly typed `ConstContext` |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_match_eq_non_const, code = E0015)] |
| #[note] |
| pub struct NonConstMatchEq<'tcx> { |
| #[primary_span] |
| pub span: Span, |
| pub ty: Ty<'tcx>, |
| pub kind: ConstContext, |
| } |
| |
| #[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(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(LintDiagnostic)] |
| #[diag(const_eval_write_through_immutable_pointer)] |
| pub struct WriteThroughImmutablePointer { |
| #[subdiagnostic] |
| pub frames: Vec<FrameNote>, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_nullary_intrinsic_fail)] |
| pub struct NullaryIntrinsicError { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag(const_eval_validation_failure, code = E0080)] |
| pub struct ValidationFailure { |
| #[primary_span] |
| pub span: Span, |
| #[note(const_eval_validation_failure_note)] |
| pub ub_note: (), |
| #[subdiagnostic] |
| pub frames: Vec<FrameNote>, |
| #[subdiagnostic] |
| pub raw_bytes: RawBytesNote, |
| } |
| |
| pub trait ReportErrorExt { |
| /// Returns the diagnostic message for this error. |
| fn diagnostic_message(&self) -> DiagMessage; |
| fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>); |
| |
| fn debug(self) -> String |
| where |
| Self: Sized, |
| { |
| ty::tls::with(move |tcx| { |
| let dcx = tcx.dcx(); |
| let mut diag = dcx.struct_allow(DiagMessage::Str(String::new().into())); |
| let message = self.diagnostic_message(); |
| self.add_args(&mut diag); |
| let s = dcx.eagerly_translate_to_string(message, diag.args.iter()); |
| diag.cancel(); |
| s |
| }) |
| } |
| } |
| |
| fn bad_pointer_message(msg: CheckInAllocMsg, dcx: DiagCtxtHandle<'_>) -> String { |
| use crate::fluent_generated::*; |
| |
| let msg = match msg { |
| 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, |
| }; |
| |
| dcx.eagerly_translate_to_string(msg, [].into_iter()) |
| } |
| |
| impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { |
| fn diagnostic_message(&self) -> DiagMessage { |
| use UndefinedBehaviorInfo::*; |
| |
| use crate::fluent_generated::*; |
| match self { |
| Ub(msg) => msg.clone().into(), |
| Custom(x) => (x.msg)(), |
| ValidationError(e) => e.diagnostic_message(), |
| |
| 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, |
| ArithOverflow { .. } => const_eval_overflow_arith, |
| ShiftOverflow { .. } => const_eval_overflow_shift, |
| 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 { .. } => const_eval_pointer_out_of_bounds, |
| DanglingIntPointer { addr: 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, |
| InvalidVTableTrait { .. } => const_eval_invalid_vtable_trait, |
| 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, |
| UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read, |
| InvalidNichedEnumVariantWritten { .. } => { |
| const_eval_invalid_niched_enum_variant_written |
| } |
| AbiMismatchArgument { .. } => const_eval_incompatible_types, |
| AbiMismatchReturn { .. } => const_eval_incompatible_return_types, |
| } |
| } |
| |
| fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { |
| use UndefinedBehaviorInfo::*; |
| let dcx = diag.dcx; |
| match self { |
| Ub(_) => {} |
| Custom(custom) => { |
| (custom.add_args)(&mut |name, value| { |
| diag.arg(name, value); |
| }); |
| } |
| ValidationError(e) => e.add_args(diag), |
| |
| Unreachable |
| | DivisionByZero |
| | RemainderByZero |
| | DivisionOverflow |
| | RemainderOverflow |
| | PointerArithOverflow |
| | InvalidMeta(InvalidMetaKind::SliceTooBig) |
| | InvalidMeta(InvalidMetaKind::TooBig) |
| | InvalidUninitBytes(None) |
| | DeadLocal |
| | UninhabitedEnumVariantWritten(_) |
| | UninhabitedEnumVariantRead(_) => {} |
| |
| ArithOverflow { intrinsic } => { |
| diag.arg("intrinsic", intrinsic); |
| } |
| ShiftOverflow { intrinsic, shift_amount } => { |
| diag.arg("intrinsic", intrinsic); |
| diag.arg( |
| "shift_amount", |
| match shift_amount { |
| Either::Left(v) => v.to_string(), |
| Either::Right(v) => v.to_string(), |
| }, |
| ); |
| } |
| BoundsCheckFailed { len, index } => { |
| diag.arg("len", len); |
| diag.arg("index", index); |
| } |
| UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => { |
| diag.arg("pointer", ptr); |
| } |
| InvalidVTableTrait { expected_trait, vtable_trait } => { |
| diag.arg("expected_trait", expected_trait.to_string()); |
| diag.arg( |
| "vtable_trait", |
| vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("<trivial>")), |
| ); |
| } |
| PointerUseAfterFree(alloc_id, msg) => { |
| diag.arg("alloc_id", alloc_id) |
| .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); |
| } |
| PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => { |
| diag.arg("alloc_size", alloc_size.bytes()); |
| diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); |
| diag.arg("pointer", { |
| let mut out = format!("{:?}", alloc_id); |
| if ptr_offset > 0 { |
| write!(out, "+{:#x}", ptr_offset).unwrap(); |
| } else if ptr_offset < 0 { |
| write!(out, "-{:#x}", ptr_offset.unsigned_abs()).unwrap(); |
| } |
| out |
| }); |
| diag.arg("inbounds_size_is_neg", inbounds_size < 0); |
| diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs()); |
| diag.arg("ptr_offset_is_neg", ptr_offset < 0); |
| diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs()); |
| diag.arg( |
| "alloc_size_minus_ptr_offset", |
| alloc_size.bytes().saturating_sub(ptr_offset as u64), |
| ); |
| } |
| DanglingIntPointer { addr, inbounds_size, msg } => { |
| if addr != 0 { |
| diag.arg( |
| "pointer", |
| Pointer::<Option<CtfeProvenance>>::from_addr_invalid(addr).to_string(), |
| ); |
| } |
| |
| diag.arg("inbounds_size_is_neg", inbounds_size < 0); |
| diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs()); |
| diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); |
| } |
| AlignmentCheckFailed(Misalignment { required, has }, msg) => { |
| diag.arg("required", required.bytes()); |
| diag.arg("has", has.bytes()); |
| diag.arg("msg", format!("{msg:?}")); |
| } |
| WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => { |
| diag.arg("allocation", alloc); |
| } |
| InvalidBool(b) => { |
| diag.arg("value", format!("{b:02x}")); |
| } |
| InvalidChar(c) => { |
| diag.arg("value", format!("{c:08x}")); |
| } |
| InvalidTag(tag) => { |
| diag.arg("tag", format!("{tag:x}")); |
| } |
| InvalidStr(err) => { |
| diag.arg("err", format!("{err}")); |
| } |
| InvalidUninitBytes(Some((alloc, info))) => { |
| diag.arg("alloc", alloc); |
| diag.arg("access", info.access); |
| diag.arg("uninit", info.bad); |
| } |
| ScalarSizeMismatch(info) => { |
| diag.arg("target_size", info.target_size); |
| diag.arg("data_size", info.data_size); |
| } |
| InvalidNichedEnumVariantWritten { enum_ty } => { |
| diag.arg("ty", enum_ty.to_string()); |
| } |
| AbiMismatchArgument { caller_ty, callee_ty } |
| | AbiMismatchReturn { caller_ty, callee_ty } => { |
| diag.arg("caller_ty", caller_ty.to_string()); |
| diag.arg("callee_ty", callee_ty.to_string()); |
| } |
| } |
| } |
| } |
| |
| impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { |
| fn diagnostic_message(&self) -> DiagMessage { |
| use rustc_middle::mir::interpret::ValidationErrorKind::*; |
| |
| use crate::fluent_generated::*; |
| match self.kind { |
| PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => { |
| const_eval_validation_box_to_uninhabited |
| } |
| PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => { |
| const_eval_validation_ref_to_uninhabited |
| } |
| |
| PointerAsInt { .. } => const_eval_validation_pointer_as_int, |
| PartialPointer => const_eval_validation_partial_pointer, |
| ConstRefToMutable => const_eval_validation_const_ref_to_mutable, |
| ConstRefToExtern => const_eval_validation_const_ref_to_extern, |
| MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable, |
| NullFnPtr => const_eval_validation_null_fn_ptr, |
| NeverVal => const_eval_validation_never_val, |
| NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range, |
| PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range, |
| OutOfRange { .. } => const_eval_validation_out_of_range, |
| UnsafeCellInImmutable => const_eval_validation_unsafe_cell, |
| UninhabitedVal { .. } => const_eval_validation_uninhabited_val, |
| InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag, |
| UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant, |
| Uninit { .. } => const_eval_validation_uninit, |
| InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr, |
| InvalidMetaWrongTrait { .. } => const_eval_validation_invalid_vtable_trait, |
| InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => { |
| const_eval_validation_invalid_box_slice_meta |
| } |
| InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => { |
| const_eval_validation_invalid_ref_slice_meta |
| } |
| |
| InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => { |
| const_eval_validation_invalid_box_meta |
| } |
| InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => { |
| const_eval_validation_invalid_ref_meta |
| } |
| UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => { |
| const_eval_validation_unaligned_ref |
| } |
| UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box, |
| |
| NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box, |
| NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref, |
| DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => { |
| const_eval_validation_dangling_box_no_provenance |
| } |
| DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => { |
| const_eval_validation_dangling_ref_no_provenance |
| } |
| DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => { |
| const_eval_validation_dangling_box_out_of_bounds |
| } |
| DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => { |
| const_eval_validation_dangling_ref_out_of_bounds |
| } |
| DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => { |
| const_eval_validation_dangling_box_use_after_free |
| } |
| DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => { |
| const_eval_validation_dangling_ref_use_after_free |
| } |
| InvalidBool { .. } => const_eval_validation_invalid_bool, |
| InvalidChar { .. } => const_eval_validation_invalid_char, |
| InvalidFnPtr { .. } => const_eval_validation_invalid_fn_ptr, |
| } |
| } |
| |
| fn add_args<G: EmissionGuarantee>(self, err: &mut Diag<'_, G>) { |
| use rustc_middle::mir::interpret::ValidationErrorKind::*; |
| |
| use crate::fluent_generated as fluent; |
| |
| if let PointerAsInt { .. } | PartialPointer = self.kind { |
| err.help(fluent::const_eval_ptr_as_bytes_1); |
| err.help(fluent::const_eval_ptr_as_bytes_2); |
| } |
| |
| let message = if let Some(path) = self.path { |
| err.dcx.eagerly_translate_to_string( |
| fluent::const_eval_validation_front_matter_invalid_value_with_path, |
| [("path".into(), DiagArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)), |
| ) |
| } else { |
| err.dcx.eagerly_translate_to_string( |
| fluent::const_eval_validation_front_matter_invalid_value, |
| [].into_iter(), |
| ) |
| }; |
| |
| err.arg("front_matter", message); |
| |
| fn add_range_arg<G: EmissionGuarantee>( |
| r: WrappingRange, |
| max_hi: u128, |
| err: &mut Diag<'_, 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(), DiagArgValue::Str(lo.to_string().into())), |
| ("hi".into(), DiagArgValue::Str(hi.to_string().into())), |
| ]; |
| let args = args.iter().map(|(a, b)| (a, b)); |
| let message = err.dcx.eagerly_translate_to_string(msg, args); |
| err.arg("in_range", message); |
| } |
| |
| match self.kind { |
| PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => { |
| err.arg("ty", ty); |
| } |
| PointerAsInt { expected } | Uninit { expected } => { |
| let msg = match expected { |
| ExpectedKind::Reference => fluent::const_eval_validation_expected_ref, |
| ExpectedKind::Box => fluent::const_eval_validation_expected_box, |
| ExpectedKind::RawPtr => fluent::const_eval_validation_expected_raw_ptr, |
| ExpectedKind::InitScalar => fluent::const_eval_validation_expected_init_scalar, |
| ExpectedKind::Bool => fluent::const_eval_validation_expected_bool, |
| ExpectedKind::Char => fluent::const_eval_validation_expected_char, |
| ExpectedKind::Float => fluent::const_eval_validation_expected_float, |
| ExpectedKind::Int => fluent::const_eval_validation_expected_int, |
| ExpectedKind::FnPtr => fluent::const_eval_validation_expected_fn_ptr, |
| ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag, |
| ExpectedKind::Str => fluent::const_eval_validation_expected_str, |
| }; |
| let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter()); |
| err.arg("expected", msg); |
| } |
| InvalidEnumTag { value } |
| | InvalidVTablePtr { value } |
| | InvalidBool { value } |
| | InvalidChar { value } |
| | InvalidFnPtr { value } => { |
| err.arg("value", value); |
| } |
| NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => { |
| add_range_arg(range, max_value, err) |
| } |
| OutOfRange { range, max_value, value } => { |
| err.arg("value", value); |
| add_range_arg(range, max_value, err); |
| } |
| UnalignedPtr { required_bytes, found_bytes, .. } => { |
| err.arg("required_bytes", required_bytes); |
| err.arg("found_bytes", found_bytes); |
| } |
| DanglingPtrNoProvenance { pointer, .. } => { |
| err.arg("pointer", pointer); |
| } |
| InvalidMetaWrongTrait { expected_trait: ref_trait, vtable_trait } => { |
| err.arg("ref_trait", ref_trait.to_string()); |
| err.arg( |
| "vtable_trait", |
| vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("<trivial>")), |
| ); |
| } |
| NullPtr { .. } |
| | ConstRefToMutable |
| | ConstRefToExtern |
| | MutableRefToImmutable |
| | NullFnPtr |
| | NeverVal |
| | UnsafeCellInImmutable |
| | InvalidMetaSliceTooLarge { .. } |
| | InvalidMetaTooLarge { .. } |
| | DanglingPtrUseAfterFree { .. } |
| | DanglingPtrOutOfBounds { .. } |
| | UninhabitedEnumVariant |
| | PartialPointer => {} |
| } |
| } |
| } |
| |
| impl ReportErrorExt for UnsupportedOpInfo { |
| fn diagnostic_message(&self) -> DiagMessage { |
| use crate::fluent_generated::*; |
| match self { |
| UnsupportedOpInfo::Unsupported(s) => s.clone().into(), |
| UnsupportedOpInfo::ExternTypeField => const_eval_extern_type_field, |
| UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local, |
| UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite, |
| UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy, |
| UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int, |
| UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static, |
| UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static, |
| } |
| } |
| fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { |
| use UnsupportedOpInfo::*; |
| |
| use crate::fluent_generated::*; |
| if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self { |
| diag.help(const_eval_ptr_as_bytes_1); |
| diag.help(const_eval_ptr_as_bytes_2); |
| } |
| match self { |
| // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to |
| // be further processed by validity checking which then turns it into something nice to |
| // print. So it's not worth the effort of having diagnostics that can print the `info`. |
| UnsizedLocal |
| | UnsupportedOpInfo::ExternTypeField |
| | Unsupported(_) |
| | ReadPointerAsInt(_) => {} |
| OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => { |
| diag.arg("ptr", ptr); |
| } |
| ThreadLocalStatic(did) | ExternStatic(did) => { |
| diag.arg("did", format!("{did:?}")); |
| } |
| } |
| } |
| } |
| |
| impl<'tcx> ReportErrorExt for InterpError<'tcx> { |
| fn diagnostic_message(&self) -> DiagMessage { |
| 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, diag: &mut Diag<'_, G>) { |
| match self { |
| InterpError::UndefinedBehavior(ub) => ub.add_args(diag), |
| InterpError::Unsupported(e) => e.add_args(diag), |
| InterpError::InvalidProgram(e) => e.add_args(diag), |
| InterpError::ResourceExhaustion(e) => e.add_args(diag), |
| InterpError::MachineStop(e) => e.add_args(&mut |name, value| { |
| diag.arg(name, value); |
| }), |
| } |
| } |
| } |
| |
| impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { |
| fn diagnostic_message(&self) -> DiagMessage { |
| 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 |
| } |
| } |
| } |
| fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { |
| match self { |
| InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {} |
| InvalidProgramInfo::Layout(e) => { |
| // The level doesn't matter, `dummy_diag` is consumed without it being used. |
| let dummy_level = Level::Bug; |
| let dummy_diag: Diag<'_, ()> = e.into_diagnostic().into_diag(diag.dcx, dummy_level); |
| for (name, val) in dummy_diag.args.iter() { |
| diag.arg(name.clone(), val.clone()); |
| } |
| dummy_diag.cancel(); |
| } |
| InvalidProgramInfo::FnAbiAdjustForForeignAbi( |
| AdjustForForeignAbiError::Unsupported { arch, abi }, |
| ) => { |
| diag.arg("arch", arch); |
| diag.arg("abi", abi.name()); |
| } |
| } |
| } |
| } |
| |
| impl ReportErrorExt for ResourceExhaustionInfo { |
| fn diagnostic_message(&self) -> DiagMessage { |
| 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, |
| ResourceExhaustionInfo::Interrupted => const_eval_interrupted, |
| } |
| } |
| fn add_args<G: EmissionGuarantee>(self, _: &mut Diag<'_, G>) {} |
| } |
| |
| impl rustc_errors::IntoDiagArg for InternKind { |
| fn into_diag_arg(self) -> DiagArgValue { |
| DiagArgValue::Str(Cow::Borrowed(match self { |
| InternKind::Static(Mutability::Not) => "static", |
| InternKind::Static(Mutability::Mut) => "static_mut", |
| InternKind::Constant => "const", |
| InternKind::Promoted => "promoted", |
| })) |
| } |
| } |