Convert to inline diagnostics in rustc_const_eval

This commit is contained in:
Guillaume Gomez
2026-02-05 22:25:42 +01:00
parent 035b01b794
commit c6829020b0
16 changed files with 736 additions and 760 deletions
-1
View File
@@ -3703,7 +3703,6 @@ dependencies = [
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_infer",
-1
View File
@@ -11,7 +11,6 @@ rustc_apfloat = "0.2.0"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
-507
View File
@@ -1,507 +0,0 @@
const_eval_address_space_full =
there are no more free addresses in the address space
const_eval_alignment_check_failed =
{$msg ->
[AccessedPtr] accessing memory
*[other] accessing memory based on pointer
} with alignment {$has}, but alignment {$required} is required
const_eval_already_reported =
an error has already been reported elsewhere (this should not usually be printed)
const_eval_assume_false =
`assume` called with `false`
const_eval_bad_pointer_op = {$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}
const_eval_bad_pointer_op_attempting = {const_eval_bad_pointer_op}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}
const_eval_bounds_check_failed =
indexing out of bounds: the len is {$len} but the index is {$index}
const_eval_call_nonzero_intrinsic =
`{$name}` called on 0
const_eval_closure_call =
closures need an RFC before allowed to be called in {const_eval_const_context}s
const_eval_closure_fndef_not_const =
function defined here, but it is not `const`
const_eval_consider_dereferencing =
consider dereferencing here
const_eval_const_accesses_mut_global =
constant accesses mutable global memory
const_eval_const_context = {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}
const_eval_const_heap_ptr_in_final = encountered `const_allocate` pointer in final value that was not made global
.note = use `const_make_global` to turn allocated pointers into immutable globals before returning
const_eval_const_make_global_ptr_already_made_global = attempting to call `const_make_global` twice on the same allocation {$alloc}
const_eval_const_make_global_ptr_is_non_heap = pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}
const_eval_const_make_global_with_dangling_ptr = pointer passed to `const_make_global` is dangling: {$ptr}
const_eval_const_make_global_with_offset = making {$ptr} global which does not point to the beginning of an object
const_eval_copy_nonoverlapping_overlapping =
`copy_nonoverlapping` called on overlapping ranges
const_eval_dangling_int_pointer =
{const_eval_bad_pointer_op_attempting}, but got {$pointer} which is a dangling pointer (it has no provenance)
const_eval_dangling_null_pointer =
{const_eval_bad_pointer_op_attempting}, but got null pointer
const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind}
const_eval_dead_local =
accessing a dead local variable
const_eval_dealloc_immutable =
deallocating immutable allocation {$alloc}
const_eval_dealloc_incorrect_layout =
incorrect layout on deallocation: {$alloc} has size {$size} and alignment {$align}, but gave size {$size_found} and alignment {$align_found}
const_eval_dealloc_kind_mismatch =
deallocating {$alloc}, which is {$alloc_kind} memory, using {$kind} deallocation operation
const_eval_deref_function_pointer =
accessing {$allocation} which contains a function
const_eval_deref_typeid_pointer =
accessing {$allocation} which contains a `TypeId`
const_eval_deref_vtable_pointer =
accessing {$allocation} which contains a vtable
const_eval_division_by_zero =
dividing by zero
const_eval_division_overflow =
overflow in signed division (dividing MIN by -1)
const_eval_dyn_call_not_a_method =
`dyn` call trying to call something that is not a method
const_eval_error = evaluation of `{$instance}` failed {$num_frames ->
[0] here
*[other] inside this call
}
const_eval_exact_div_has_remainder =
exact_div: {$a} cannot be divided by {$b} without remainder
const_eval_extern_static =
cannot access extern static `{$did}`
const_eval_extern_type_field = `extern type` field does not have a known offset
const_eval_fn_ptr_call =
function pointers need an RFC before allowed to be called in {const_eval_const_context}s
const_eval_frame_note = {$times ->
[0] {const_eval_frame_note_inner}
*[other] [... {$times} additional calls {const_eval_frame_note_inner} ...]
}
const_eval_frame_note_inner = inside {$where_ ->
[closure] closure
[instance] `{$instance}`
*[other] {""}
}
const_eval_frame_note_last = the failure occurred here
const_eval_incompatible_arg_types =
calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty}
const_eval_incompatible_calling_conventions =
calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}"
const_eval_incompatible_return_types =
calling a function with return type {$callee_ty} passing return place of type {$caller_ty}
const_eval_interior_mutable_borrow_escaping =
interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
.label = this borrow of an interior mutable value refers to such a temporary
.note = temporaries in constants and statics can have their lifetime extended until the end of the program
.note2 = to avoid accidentally creating global mutable state, such temporaries must be immutable
.help = if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
const_eval_intern_kind = {$kind ->
[static] static
[static_mut] mutable static
[const] constant
[promoted] promoted
*[other] {""}
}
const_eval_interrupted = compilation was interrupted
const_eval_invalid_align_details =
invalid align passed to `{$name}`: {$align} is {$err_kind ->
[not_power_of_two] not a power of 2
[too_large] too large
*[other] {""}
}
const_eval_invalid_bool =
interpreting an invalid 8-bit value as a bool: 0x{$value}
const_eval_invalid_char =
interpreting an invalid 32-bit value as a char: 0x{$value}
const_eval_invalid_dealloc =
deallocating {$alloc_id}, which is {$kind ->
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {""}
}
const_eval_invalid_function_pointer =
using {$pointer} as function pointer but it does not point to a function
const_eval_invalid_meta =
invalid metadata in wide pointer: total size is bigger than largest supported object
const_eval_invalid_meta_slice =
invalid metadata in wide pointer: slice is bigger than largest supported object
const_eval_invalid_niched_enum_variant_written =
trying to set discriminant of a {$ty} to the niched variant, but the value does not match
const_eval_invalid_str =
this string is not valid UTF-8: {$err}
const_eval_invalid_tag =
enum value has invalid tag: {$tag}
const_eval_invalid_transmute =
transmuting from {$src_bytes}-byte type to {$dest_bytes}-byte type: `{$src}` -> `{$dest}`
const_eval_invalid_uninit_bytes =
reading memory at {$alloc}{$access}, but memory is uninitialized at {$uninit}, and this operation requires initialized memory
const_eval_invalid_uninit_bytes_unknown =
using uninitialized data, but this operation requires initialized memory
const_eval_invalid_vtable_pointer =
using {$pointer} as vtable pointer but it does not point to a vtable
const_eval_invalid_vtable_trait =
using vtable for `{$vtable_dyn_type}` but `{$expected_dyn_type}` was expected
const_eval_lazy_lock =
consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
const_eval_live_drop =
destructor of `{$dropped_ty}` cannot be evaluated at compile-time
.label = the destructor for this type cannot be evaluated in {const_eval_const_context}s
.dropped_at_label = value is dropped here
const_eval_long_running =
constant evaluation is taking a long time
.note = this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
.label = the const evaluator is currently interpreting this expression
.help = the constant being evaluated
const_eval_memory_exhausted =
tried to allocate more memory than available to compiler
const_eval_modified_global =
modifying a static's initial value from another static's initializer
const_eval_mutable_borrow_escaping =
mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
.label = this mutable borrow refers to such a temporary
.note = temporaries in constants and statics can have their lifetime extended until the end of the program
.note2 = to avoid accidentally creating global mutable state, such temporaries must be immutable
.help = if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
const_eval_non_const_await =
cannot convert `{$ty}` into a future in {const_eval_const_context}s
const_eval_non_const_closure =
cannot call {$non_or_conditionally}-const closure in {const_eval_const_context}s
const_eval_non_const_deref_coercion =
cannot perform {$non_or_conditionally}-const deref coercion on `{$ty}` in {const_eval_const_context}s
.note = attempting to deref into `{$target_ty}`
.target_note = deref defined here
const_eval_non_const_fmt_macro_call =
cannot call {$non_or_conditionally}-const formatting macro in {const_eval_const_context}s
const_eval_non_const_fn_call =
cannot call {$non_or_conditionally}-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s
const_eval_non_const_for_loop_into_iter =
cannot use `for` loop on `{$ty}` in {const_eval_const_context}s
const_eval_non_const_impl =
impl defined here, but it is not `const`
const_eval_non_const_intrinsic =
cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s
const_eval_non_const_match_eq = cannot match on `{$ty}` in {const_eval_const_context}s
.note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es
const_eval_non_const_operator =
cannot call {$non_or_conditionally}-const operator in {const_eval_const_context}s
const_eval_non_const_question_branch =
`?` is not allowed on `{$ty}` in {const_eval_const_context}s
const_eval_non_const_question_from_residual =
`?` is not allowed on `{$ty}` in {const_eval_const_context}s
const_eval_non_const_try_block_from_output =
`try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s
const_eval_not_enough_caller_args =
calling a function with fewer arguments than it requires
const_eval_offset_from_different_allocations =
`{$name}` called on two different pointers that are not both derived from the same allocation
const_eval_offset_from_out_of_bounds =
`{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation
const_eval_offset_from_overflow =
`{$name}` called when first pointer is too far ahead of second
const_eval_offset_from_underflow =
`{$name}` called when first pointer is too far before second
const_eval_offset_from_unsigned_overflow =
`ptr_offset_from_unsigned` called when first pointer has smaller {$is_addr ->
[true] address
*[false] offset
} than second: {$a_offset} < {$b_offset}
const_eval_overflow_arith =
arithmetic overflow in `{$intrinsic}`
const_eval_overflow_shift =
overflowing shift by {$shift_amount} in `{$intrinsic}`
const_eval_panic = evaluation panicked: {$msg}
const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str`
const_eval_partial_pointer_in_final = encountered partial pointer in final value of {const_eval_intern_kind}
.note = while pointers can be broken apart into individual bytes during const-evaluation, only complete pointers (with all their bytes in the right order) are supported in the final value
const_eval_partial_pointer_read =
unable to read parts of a pointer from memory at {$ptr}
const_eval_pointer_arithmetic_overflow =
overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
const_eval_pointer_out_of_bounds =
{const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$ptr_offset_is_neg ->
[true] points to before the beginning of the allocation
*[false] {$inbounds_size_is_neg ->
[false] {$alloc_size_minus_ptr_offset ->
[0] is at or beyond the end of the allocation of size {$alloc_size ->
[1] 1 byte
*[x] {$alloc_size} bytes
}
[1] is only 1 byte from the end of the allocation
*[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
}
*[true] {$ptr_offset_abs ->
[0] is at the beginning of the allocation
*[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation
}
}
}
const_eval_pointer_use_after_free =
{const_eval_bad_pointer_op}: {$alloc_id} has been freed, so this pointer is dangling
const_eval_ptr_as_bytes_1 =
this code performed an operation that depends on the underlying bytes representing a pointer
const_eval_ptr_as_bytes_2 =
the absolute address of a pointer is not known at compile-time, so such operations are not supported
const_eval_range = in the range {$lo}..={$hi}
const_eval_range_lower = greater or equal to {$lo}
const_eval_range_singular = equal to {$lo}
const_eval_range_upper = less or equal to {$hi}
const_eval_range_wrapping = less or equal to {$hi}, or greater or equal to {$lo}
const_eval_raw_bytes = the raw bytes of the constant (size: {$size}, align: {$align}) {"{"}{$bytes}{"}"}
const_eval_raw_ptr_comparison =
pointers cannot be reliably compared during const eval
.note = see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
const_eval_raw_ptr_to_int =
pointers cannot be cast to integers during const eval
.note = at compile-time, pointers do not have an integer value
.note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
const_eval_read_pointer_as_int =
unable to turn pointer into integer
const_eval_realloc_or_alloc_with_offset =
{$kind ->
[dealloc] deallocating
[realloc] reallocating
*[other] {""}
} {$ptr} which does not point to the beginning of an object
const_eval_recursive_static = encountered static that tried to access itself during initialization
const_eval_remainder_by_zero =
calculating the remainder with a divisor of zero
const_eval_remainder_overflow =
overflow in signed remainder (dividing MIN by -1)
const_eval_scalar_size_mismatch =
scalar size mismatch: expected {$target_size} bytes but got {$data_size} bytes instead
const_eval_size_overflow =
overflow computing total size of `{$name}`
const_eval_stack_frame_limit_reached =
reached the configured maximum number of stack frames
const_eval_thread_local_access =
thread-local statics cannot be accessed at compile-time
const_eval_thread_local_static =
cannot access thread local static `{$did}`
const_eval_too_generic =
encountered overly generic constant
const_eval_too_many_caller_args =
calling a function with more arguments than it expected
const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s
const_eval_unallowed_heap_allocations =
allocations are not allowed in {const_eval_const_context}s
.label = allocation not allowed in {const_eval_const_context}s
.teach_note =
The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created.
const_eval_unallowed_inline_asm =
inline assembly is not allowed in {const_eval_const_context}s
const_eval_unallowed_op_in_const_context =
{$msg}
const_eval_uninhabited_enum_variant_read =
read discriminant of an uninhabited enum variant
const_eval_uninhabited_enum_variant_written =
writing discriminant of an uninhabited enum variant
const_eval_unmarked_const_item_exposed = `{$def_path}` cannot be (indirectly) exposed to stable
.help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable
.help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval)
const_eval_unreachable = entering unreachable code
const_eval_unreachable_unwind =
unwinding past a stack frame that does not allow unwinding
const_eval_unsized_local = unsized locals are not supported
const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
const_eval_unstable_const_trait = `{$def_path}` is not yet stable as a const trait
const_eval_unstable_in_stable_exposed =
const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`
.is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features
.unstable_sugg = if the {$is_function_call2 ->
[true] caller
*[false] function
} is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]`
const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic
const_eval_unstable_intrinsic_suggestion = add `#![feature({$feature})]` to the crate attributes to enable
const_eval_unterminated_c_string =
reading a null-terminated string starting at {$pointer} with no null found before end of allocation
const_eval_unwind_past_top =
unwinding past the topmost frame of the stack
## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`.
## (We'd love to sort this differently to make that more clear but tidy won't let us...)
const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)
const_eval_validation_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)
const_eval_validation_dangling_box_use_after_free = {$front_matter}: encountered a dangling box (use-after-free)
const_eval_validation_dangling_ref_no_provenance = {$front_matter}: encountered a dangling reference ({$pointer} has no provenance)
const_eval_validation_dangling_ref_out_of_bounds = {$front_matter}: encountered a dangling reference (going beyond the bounds of its allocation)
const_eval_validation_dangling_ref_use_after_free = {$front_matter}: encountered a dangling reference (use-after-free)
const_eval_validation_expected_bool = expected a boolean
const_eval_validation_expected_box = expected a box
const_eval_validation_expected_char = expected a unicode scalar value
const_eval_validation_expected_enum_tag = expected a valid enum tag
const_eval_validation_expected_float = expected a floating point number
const_eval_validation_expected_fn_ptr = expected a function pointer
const_eval_validation_expected_init_scalar = expected initialized scalar value
const_eval_validation_expected_int = expected an integer
const_eval_validation_expected_raw_ptr = expected a raw pointer
const_eval_validation_expected_ref = expected a reference
const_eval_validation_expected_str = expected a string
const_eval_validation_failure =
it is undefined behavior to use this value
const_eval_validation_failure_note =
the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
const_eval_validation_front_matter_invalid_value = constructing invalid value
const_eval_validation_front_matter_invalid_value_with_path = constructing invalid value at {$path}
const_eval_validation_invalid_bool = {$front_matter}: encountered {$value}, but expected a boolean
const_eval_validation_invalid_box_meta = {$front_matter}: encountered invalid box metadata: total size is bigger than largest supported object
const_eval_validation_invalid_box_slice_meta = {$front_matter}: encountered invalid box metadata: slice is bigger than largest supported object
const_eval_validation_invalid_char = {$front_matter}: encountered {$value}, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
const_eval_validation_invalid_enum_tag = {$front_matter}: encountered {$value}, but expected a valid enum tag
const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, but expected a function pointer
const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object
const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}`
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
const_eval_validation_nonnull_ptr_out_of_range = {$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero
const_eval_validation_null_box = {$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} box
const_eval_validation_null_fn_ptr = {$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} function pointer
const_eval_validation_null_ref = {$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} reference
const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range}
const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers
const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected}
const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range}
const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty}
const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})
const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})
const_eval_validation_uninhabited_enum_variant = {$front_matter}: encountered an uninhabited enum variant
const_eval_validation_uninhabited_val = {$front_matter}: encountered a value of uninhabited type `{$ty}`
const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected}
const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in read-only memory
const_eval_write_through_immutable_pointer =
writing through a pointer that was derived from a shared (immutable) reference
const_eval_write_to_read_only =
writing to {$allocation} which is read-only
@@ -2,7 +2,7 @@
use hir::{ConstContext, LangItem};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, MultiSpan};
use rustc_errors::{Applicability, Diag, MultiSpan, inline_fluent};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
@@ -23,7 +23,7 @@
use tracing::debug;
use super::ConstCx;
use crate::{errors, fluent_generated};
use crate::errors;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Status {
@@ -181,7 +181,9 @@ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
);
if let ConstContext::Static(_) = ccx.const_kind() {
err.note(fluent_generated::const_eval_lazy_lock);
err.note(inline_fluent!(
"consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`"
));
}
err
@@ -43,21 +43,41 @@ pub enum ConstEvalErrKind {
impl MachineStopType for ConstEvalErrKind {
fn diagnostic_message(&self) -> DiagMessage {
use ConstEvalErrKind::*;
use rustc_errors::inline_fluent;
use crate::fluent_generated::*;
match self {
ConstAccessesMutGlobal => const_eval_const_accesses_mut_global,
ModifiedGlobal => const_eval_modified_global,
Panic { .. } => const_eval_panic,
RecursiveStatic => const_eval_recursive_static,
AssertFailure(x) => x.diagnostic_message(),
WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer,
ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => {
const_eval_const_make_global_ptr_already_made_global
ConstAccessesMutGlobal => "constant accesses mutable global memory".into(),
ModifiedGlobal => {
"modifying a static's initial value from another static's initializer".into()
}
Panic { .. } => inline_fluent!("evaluation panicked: {$msg}"),
RecursiveStatic => {
"encountered static that tried to access itself during initialization".into()
}
AssertFailure(x) => x.diagnostic_message(),
WriteThroughImmutablePointer => {
inline_fluent!(
"writing through a pointer that was derived from a shared (immutable) reference"
)
}
ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => {
inline_fluent!(
"attempting to call `const_make_global` twice on the same allocation {$alloc}"
)
}
ConstMakeGlobalPtrIsNonHeap(_) => {
inline_fluent!(
"pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}"
)
}
ConstMakeGlobalWithDanglingPtr(_) => {
inline_fluent!("pointer passed to `const_make_global` is dangling: {$ptr}")
}
ConstMakeGlobalWithOffset(_) => {
inline_fluent!(
"making {$ptr} global which does not point to the beginning of an object"
)
}
ConstMakeGlobalPtrIsNonHeap(_) => const_eval_const_make_global_ptr_is_non_heap,
ConstMakeGlobalWithDanglingPtr(_) => const_eval_const_make_global_with_dangling_ptr,
ConstMakeGlobalWithOffset(_) => const_eval_const_make_global_with_offset,
}
}
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) {
@@ -2,7 +2,7 @@
use either::{Left, Right};
use rustc_abi::{self as abi, BackendRepr};
use rustc_errors::E0080;
use rustc_errors::{E0080, inline_fluent};
use rustc_hir::def::DefKind;
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo};
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
@@ -467,7 +467,15 @@ fn report_eval_error<'tcx>(
let num_frames = frames.len();
// FIXME(oli-obk): figure out how to use structured diagnostics again.
diag.code(E0080);
diag.span_label(span, crate::fluent_generated::const_eval_error);
diag.span_label(
span,
inline_fluent!(
"evaluation of `{$instance}` failed {$num_frames ->
[0] here
*[other] inside this call
}"
),
);
for frame in frames {
diag.subdiagnostic(frame);
}
@@ -506,8 +514,8 @@ fn report_validation_error<'tcx>(
move |diag, span, frames| {
// FIXME(oli-obk): figure out how to use structured diagnostics again.
diag.code(E0080);
diag.span_label(span, crate::fluent_generated::const_eval_validation_failure);
diag.note(crate::fluent_generated::const_eval_validation_failure_note);
diag.span_label(span, "it is undefined behavior to use this value");
diag.note("the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.");
for frame in frames {
diag.subdiagnostic(frame);
}
@@ -5,6 +5,7 @@
use rustc_abi::{Align, Size};
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
use rustc_errors::inline_fluent;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem};
use rustc_middle::mir::AssertMessage;
@@ -19,7 +20,6 @@
use super::error::*;
use crate::errors::{LongRunning, LongRunningWarn};
use crate::fluent_generated as fluent;
use crate::interpret::{
self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, RangeSet, Scalar,
@@ -489,7 +489,13 @@ fn call_intrinsic(
let align = match Align::from_bytes(align) {
Ok(a) => a,
Err(err) => throw_ub_custom!(
fluent::const_eval_invalid_align_details,
inline_fluent!(
"invalid align passed to `{$name}`: {$align} is {$err_kind ->
[not_power_of_two] not a power of 2
[too_large] too large
*[other] {\"\"}
}"
),
name = "const_allocate",
err_kind = err.diag_ident(),
align = err.align()
@@ -513,7 +519,13 @@ fn call_intrinsic(
let align = match Align::from_bytes(align) {
Ok(a) => a,
Err(err) => throw_ub_custom!(
fluent::const_eval_invalid_align_details,
inline_fluent!(
"invalid align passed to `{$name}`: {$align} is {$err_kind ->
[not_power_of_two] not a power of 2
[too_large] too large
*[other] {\"\"}
}"
),
name = "const_deallocate",
err_kind = err.diag_ident(),
align = err.align()
+558 -189
View File
@@ -5,7 +5,8 @@
use rustc_abi::WrappingRange;
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan, Subdiagnostic,
Diag, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan,
Subdiagnostic, inline_fluent,
};
use rustc_hir::ConstContext;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -17,11 +18,18 @@
use rustc_middle::ty::{self, Mutability, Ty};
use rustc_span::{Span, Symbol};
use crate::fluent_generated as fluent;
use crate::interpret::InternKind;
#[derive(Diagnostic)]
#[diag(const_eval_dangling_ptr_in_final)]
#[diag(
r#"encountered dangling pointer in final value of {$kind ->
[static] static
[static_mut] mutable static
[const] constant
[promoted] promoted
*[other] {""}
}"#
)]
pub(crate) struct DanglingPtrInFinal {
#[primary_span]
pub span: Span,
@@ -29,14 +37,24 @@ pub(crate) struct DanglingPtrInFinal {
}
#[derive(Diagnostic)]
#[diag(const_eval_nested_static_in_thread_local)]
#[diag(
"#[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead"
)]
pub(crate) struct NestedStaticInThreadLocal {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(const_eval_mutable_ptr_in_final)]
#[diag(
r#"encountered mutable pointer in final value of {$kind ->
[static] static
[static_mut] mutable static
[const] constant
[promoted] promoted
*[other] {""}
}"#
)]
pub(crate) struct MutablePtrInFinal {
#[primary_span]
pub span: Span,
@@ -44,16 +62,28 @@ pub(crate) struct MutablePtrInFinal {
}
#[derive(Diagnostic)]
#[diag(const_eval_const_heap_ptr_in_final)]
#[note]
#[diag("encountered `const_allocate` pointer in final value that was not made global")]
#[note(
"use `const_make_global` to turn allocated pointers into immutable globals before returning"
)]
pub(crate) struct ConstHeapPtrInFinal {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(const_eval_partial_pointer_in_final)]
#[note]
#[diag(
r#"encountered partial pointer in final value of {$kind ->
[static] static
[static_mut] mutable static
[const] constant
[promoted] promoted
*[other] {""}
}"#
)]
#[note(
"while pointers can be broken apart into individual bytes during const-evaluation, only complete pointers (with all their bytes in the right order) are supported in the final value"
)]
pub(crate) struct PartialPtrInFinal {
#[primary_span]
pub span: Span,
@@ -61,17 +91,24 @@ pub(crate) struct PartialPtrInFinal {
}
#[derive(Diagnostic)]
#[diag(const_eval_unstable_in_stable_exposed)]
#[diag(
"const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`"
)]
pub(crate) struct UnstableInStableExposed {
pub gate: String,
#[primary_span]
pub span: Span,
#[help(const_eval_is_function_call)]
#[help(
"mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features"
)]
pub is_function_call: bool,
/// Need to duplicate the field so that fluent also provides it as a variable...
pub is_function_call2: bool,
#[suggestion(
const_eval_unstable_sugg,
"if the {$is_function_call2 ->
[true] caller
*[false] function
} is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]`",
code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
applicability = "has-placeholders"
)]
@@ -79,38 +116,47 @@ pub(crate) struct UnstableInStableExposed {
}
#[derive(Diagnostic)]
#[diag(const_eval_thread_local_access, code = E0625)]
#[diag("thread-local statics cannot be accessed at compile-time", 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)]
#[diag("pointers cannot be cast to integers during const eval")]
#[note("at compile-time, pointers do not have an integer value")]
#[note(
"avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior"
)]
pub(crate) struct RawPtrToIntErr {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(const_eval_raw_ptr_comparison)]
#[note]
#[diag("pointers cannot be reliably compared during const eval")]
#[note("see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information")]
pub(crate) struct RawPtrComparisonErr {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(const_eval_panic_non_str)]
#[diag("argument to `panic!()` in a const context must have type `&str`")]
pub(crate) struct PanicNonStrErr {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(const_eval_unallowed_fn_pointer_call)]
#[diag(
r#"function pointer calls are not allowed in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#
)]
pub(crate) struct UnallowedFnPointerCall {
#[primary_span]
pub span: Span,
@@ -118,7 +164,7 @@ pub(crate) struct UnallowedFnPointerCall {
}
#[derive(Diagnostic)]
#[diag(const_eval_unstable_const_fn)]
#[diag("`{$def_path}` is not yet stable as a const fn")]
pub(crate) struct UnstableConstFn {
#[primary_span]
pub span: Span,
@@ -126,7 +172,7 @@ pub(crate) struct UnstableConstFn {
}
#[derive(Diagnostic)]
#[diag(const_eval_unstable_const_trait)]
#[diag("`{$def_path}` is not yet stable as a const trait")]
pub(crate) struct UnstableConstTrait {
#[primary_span]
pub span: Span,
@@ -134,14 +180,14 @@ pub(crate) struct UnstableConstTrait {
}
#[derive(Diagnostic)]
#[diag(const_eval_unstable_intrinsic)]
#[diag("`{$name}` is not yet stable as a const intrinsic")]
pub(crate) struct UnstableIntrinsic {
#[primary_span]
pub span: Span,
pub name: Symbol,
pub feature: Symbol,
#[suggestion(
const_eval_unstable_intrinsic_suggestion,
"add `#![feature({$feature})]` to the crate attributes to enable",
code = "#![feature({feature})]\n",
applicability = "machine-applicable"
)]
@@ -149,8 +195,10 @@ pub(crate) struct UnstableIntrinsic {
}
#[derive(Diagnostic)]
#[diag(const_eval_unmarked_const_item_exposed)]
#[help]
#[diag("`{$def_path}` cannot be (indirectly) exposed to stable")]
#[help(
"either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`"
)]
pub(crate) struct UnmarkedConstItemExposed {
#[primary_span]
pub span: Span,
@@ -158,8 +206,10 @@ pub(crate) struct UnmarkedConstItemExposed {
}
#[derive(Diagnostic)]
#[diag(const_eval_unmarked_intrinsic_exposed)]
#[help]
#[diag("intrinsic `{$def_path}` cannot be (indirectly) exposed to stable")]
#[help(
"mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval)"
)]
pub(crate) struct UnmarkedIntrinsicExposed {
#[primary_span]
pub span: Span,
@@ -167,19 +217,31 @@ pub(crate) struct UnmarkedIntrinsicExposed {
}
#[derive(Diagnostic)]
#[diag(const_eval_mutable_borrow_escaping, code = E0764)]
#[note]
#[note(const_eval_note2)]
#[help]
#[diag("mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed", code = E0764)]
#[note(
"temporaries in constants and statics can have their lifetime extended until the end of the program"
)]
#[note("to avoid accidentally creating global mutable state, such temporaries must be immutable")]
#[help(
"if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`"
)]
pub(crate) struct MutableBorrowEscaping {
#[primary_span]
#[label]
#[label("this mutable borrow refers to such a temporary")]
pub span: Span,
pub kind: ConstContext,
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_fmt_macro_call, code = E0015)]
#[diag(
r#"cannot call {$non_or_conditionally}-const formatting macro in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#,
code = E0015,
)]
pub(crate) struct NonConstFmtMacroCall {
#[primary_span]
pub span: Span,
@@ -188,7 +250,12 @@ pub(crate) struct NonConstFmtMacroCall {
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_fn_call, code = E0015)]
#[diag(r#"cannot call {$non_or_conditionally}-const {$def_descr} `{$def_path_str}` in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
pub(crate) struct NonConstFnCall {
#[primary_span]
pub span: Span,
@@ -199,7 +266,14 @@ pub(crate) struct NonConstFnCall {
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_intrinsic)]
#[diag(
r#"cannot call non-const intrinsic `{$name}` in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#
)]
pub(crate) struct NonConstIntrinsic {
#[primary_span]
pub span: Span,
@@ -208,7 +282,7 @@ pub(crate) struct NonConstIntrinsic {
}
#[derive(Diagnostic)]
#[diag(const_eval_unallowed_op_in_const_context)]
#[diag("{$msg}")]
pub(crate) struct UnallowedOpInConstContext {
#[primary_span]
pub span: Span,
@@ -216,18 +290,37 @@ pub(crate) struct UnallowedOpInConstContext {
}
#[derive(Diagnostic)]
#[diag(const_eval_unallowed_heap_allocations, code = E0010)]
#[diag(r#"allocations are not allowed in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0010)]
pub(crate) struct UnallowedHeapAllocations {
#[primary_span]
#[label]
#[label(
r#"allocation not allowed in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#
)]
pub span: Span,
pub kind: ConstContext,
#[note(const_eval_teach_note)]
#[note(
"The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created."
)]
pub teach: bool,
}
#[derive(Diagnostic)]
#[diag(const_eval_unallowed_inline_asm, code = E0015)]
#[diag(r#"inline assembly is not allowed in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
pub(crate) struct UnallowedInlineAsm {
#[primary_span]
pub span: Span,
@@ -235,39 +328,46 @@ pub(crate) struct UnallowedInlineAsm {
}
#[derive(Diagnostic)]
#[diag(const_eval_interior_mutable_borrow_escaping, code = E0492)]
#[note]
#[note(const_eval_note2)]
#[help]
#[diag("interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed", code = E0492)]
#[note(
"temporaries in constants and statics can have their lifetime extended until the end of the program"
)]
#[note("to avoid accidentally creating global mutable state, such temporaries must be immutable")]
#[help(
"if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`"
)]
pub(crate) struct InteriorMutableBorrowEscaping {
#[primary_span]
#[label]
#[label("this borrow of an interior mutable value refers to such a temporary")]
pub span: Span,
pub kind: ConstContext,
}
#[derive(LintDiagnostic)]
#[diag(const_eval_long_running)]
#[note]
#[diag("constant evaluation is taking a long time")]
#[note(
"this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint."
)]
pub struct LongRunning {
#[help]
#[help("the constant being evaluated")]
pub item_span: Span,
}
#[derive(Diagnostic)]
#[diag(const_eval_long_running)]
#[diag("constant evaluation is taking a long time")]
pub struct LongRunningWarn {
#[primary_span]
#[label]
#[label("the const evaluator is currently interpreting this expression")]
pub span: Span,
#[help]
#[help("the constant being evaluated")]
pub item_span: Span,
// Used for evading `-Z deduplicate-diagnostics`.
pub force_duplicate: usize,
}
#[derive(Subdiagnostic)]
#[note(const_eval_non_const_impl)]
#[note("impl defined here, but it is not `const`")]
pub(crate) struct NonConstImplNote {
#[primary_span]
pub span: Span,
@@ -289,9 +389,21 @@ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("instance", self.instance);
let mut span: MultiSpan = self.span.into();
if self.has_label && !self.span.is_dummy() {
span.push_span_label(self.span, fluent::const_eval_frame_note_last);
span.push_span_label(self.span, inline_fluent!("the failure occurred here"));
}
let msg = diag.eagerly_translate(fluent::const_eval_frame_note);
let msg = diag.eagerly_translate(inline_fluent!(
r#"{$times ->
[0] {const_eval_frame_note_inner}
*[other] [... {$times} additional calls {const_eval_frame_note_inner} ...]
}
const_eval_frame_note_inner = inside {$where_ ->
[closure] closure
[instance] `{$instance}`
*[other] {""}
}
"#
));
diag.remove_arg("times");
diag.remove_arg("where_");
diag.remove_arg("instance");
@@ -300,7 +412,7 @@ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
}
#[derive(Subdiagnostic)]
#[note(const_eval_raw_bytes)]
#[note(r#"the raw bytes of the constant (size: {$size}, align: {$align}) {"{"}{$bytes}{"}"}"#)]
pub struct RawBytesNote {
pub size: u64,
pub align: u64,
@@ -310,8 +422,15 @@ pub struct RawBytesNote {
// FIXME(fee1-dead) do not use stringly typed `ConstContext`
#[derive(Diagnostic)]
#[diag(const_eval_non_const_match_eq, code = E0015)]
#[note]
#[diag(
r#"cannot match on `{$ty}` in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#
)]
#[note("`{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es")]
pub struct NonConstMatchEq<'tcx> {
#[primary_span]
pub span: Span,
@@ -321,7 +440,12 @@ pub struct NonConstMatchEq<'tcx> {
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_for_loop_into_iter, code = E0015)]
#[diag(r#"cannot use `for` loop on `{$ty}` in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
pub struct NonConstForLoopIntoIter<'tcx> {
#[primary_span]
pub span: Span,
@@ -331,7 +455,12 @@ pub struct NonConstForLoopIntoIter<'tcx> {
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_question_branch, code = E0015)]
#[diag(r#"`?` is not allowed on `{$ty}` in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
pub struct NonConstQuestionBranch<'tcx> {
#[primary_span]
pub span: Span,
@@ -341,7 +470,12 @@ pub struct NonConstQuestionBranch<'tcx> {
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_question_from_residual, code = E0015)]
#[diag(r#"`?` is not allowed on `{$ty}` in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
pub struct NonConstQuestionFromResidual<'tcx> {
#[primary_span]
pub span: Span,
@@ -351,7 +485,12 @@ pub struct NonConstQuestionFromResidual<'tcx> {
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_try_block_from_output, code = E0015)]
#[diag(r#"`try` block cannot convert `{$ty}` to the result in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
pub struct NonConstTryBlockFromOutput<'tcx> {
#[primary_span]
pub span: Span,
@@ -361,7 +500,12 @@ pub struct NonConstTryBlockFromOutput<'tcx> {
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_await, code = E0015)]
#[diag(r#"cannot convert `{$ty}` into a future in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
pub struct NonConstAwait<'tcx> {
#[primary_span]
pub span: Span,
@@ -371,7 +515,12 @@ pub struct NonConstAwait<'tcx> {
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_closure, code = E0015)]
#[diag(r#"cannot call {$non_or_conditionally}-const closure in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
pub struct NonConstClosure {
#[primary_span]
pub span: Span,
@@ -383,19 +532,33 @@ pub struct NonConstClosure {
#[derive(Subdiagnostic)]
pub enum NonConstClosureNote {
#[note(const_eval_closure_fndef_not_const)]
#[note("function defined here, but it is not `const`")]
FnDef {
#[primary_span]
span: Span,
},
#[note(const_eval_fn_ptr_call)]
#[note(
r#"function pointers need an RFC before allowed to be called in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#
)]
FnPtr,
#[note(const_eval_closure_call)]
#[note(
r#"closures need an RFC before allowed to be called in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#
)]
Closure,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(const_eval_consider_dereferencing, applicability = "machine-applicable")]
#[multipart_suggestion("consider dereferencing here", applicability = "machine-applicable")]
pub struct ConsiderDereferencing {
pub deref: String,
#[suggestion_part(code = "{deref}")]
@@ -405,7 +568,12 @@ pub struct ConsiderDereferencing {
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_operator, code = E0015)]
#[diag(r#"cannot call {$non_or_conditionally}-const operator in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
pub struct NonConstOperator {
#[primary_span]
pub span: Span,
@@ -416,28 +584,40 @@ pub struct NonConstOperator {
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_deref_coercion, code = E0015)]
#[note]
#[diag(r#"cannot perform {$non_or_conditionally}-const deref coercion on `{$ty}` in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
#[note("attempting to deref into `{$target_ty}`")]
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)]
#[note("deref defined here")]
pub deref_target: Option<Span>,
pub non_or_conditionally: &'static str,
}
#[derive(Diagnostic)]
#[diag(const_eval_live_drop, code = E0493)]
#[diag("destructor of `{$dropped_ty}` cannot be evaluated at compile-time", code = E0493)]
pub struct LiveDrop<'tcx> {
#[primary_span]
#[label]
#[label(
r#"the destructor for this type cannot be evaluated in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#
)]
pub span: Span,
pub kind: ConstContext,
pub dropped_ty: Ty<'tcx>,
#[label(const_eval_dropped_at_label)]
#[label("value is dropped here")]
pub dropped_at: Span,
}
@@ -466,51 +646,128 @@ 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,
DerefTypeIdPointer(_) => const_eval_deref_typeid_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
Unreachable => "entering unreachable code".into(),
BoundsCheckFailed { .. } => inline_fluent!("indexing out of bounds: the len is {$len} but the index is {$index}"),
DivisionByZero => "dividing by zero".into(),
RemainderByZero => "calculating the remainder with a divisor of zero".into(),
DivisionOverflow => "overflow in signed division (dividing MIN by -1)".into(),
RemainderOverflow => "overflow in signed remainder (dividing MIN by -1)".into(),
PointerArithOverflow => "overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`".into(),
ArithOverflow { .. } => inline_fluent!("arithmetic overflow in `{$intrinsic}`"),
ShiftOverflow { .. } => inline_fluent!("overflowing shift by {$shift_amount} in `{$intrinsic}`"),
InvalidMeta(InvalidMetaKind::SliceTooBig) => "invalid metadata in wide pointer: slice is bigger than largest supported object".into(),
InvalidMeta(InvalidMetaKind::TooBig) => "invalid metadata in wide pointer: total size is bigger than largest supported object".into(),
UnterminatedCString(_) => "reading a null-terminated string starting at {$pointer} with no null found before end of allocation".into(),
PointerUseAfterFree(_, _) => inline_fluent!("{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$alloc_id} has been freed, so this pointer is dangling"),
PointerOutOfBounds { .. } => inline_fluent!("{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}, but got {$pointer} which {$ptr_offset_is_neg ->
[true] points to before the beginning of the allocation
*[false] {$inbounds_size_is_neg ->
[false] {$alloc_size_minus_ptr_offset ->
[0] is at or beyond the end of the allocation of size {$alloc_size ->
[1] 1 byte
*[x] {$alloc_size} bytes
}
AbiMismatchArgument { .. } => const_eval_incompatible_arg_types,
AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
[1] is only 1 byte from the end of the allocation
*[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
}
*[true] {$ptr_offset_abs ->
[0] is at the beginning of the allocation
*[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation
}
}
}
"),
DanglingIntPointer { addr: 0, .. } => inline_fluent!("{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}, but got null pointer"),
DanglingIntPointer { .. } => inline_fluent!("{$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}, but got {$pointer} which is a dangling pointer (it has no provenance)"),
AlignmentCheckFailed { .. } => inline_fluent!("{$msg ->
[AccessedPtr] accessing memory
*[other] accessing memory based on pointer
} with alignment {$has}, but alignment {$required} is required"),
WriteToReadOnly(_) => inline_fluent!("writing to {$allocation} which is read-only"),
DerefFunctionPointer(_) => inline_fluent!("accessing {$allocation} which contains a function"),
DerefVTablePointer(_) => inline_fluent!("accessing {$allocation} which contains a vtable"),
DerefTypeIdPointer(_) => inline_fluent!("accessing {$allocation} which contains a `TypeId`"),
InvalidBool(_) => inline_fluent!("interpreting an invalid 8-bit value as a bool: 0x{$value}"),
InvalidChar(_) => inline_fluent!("interpreting an invalid 32-bit value as a char: 0x{$value}"),
InvalidTag(_) => inline_fluent!("enum value has invalid tag: {$tag}"),
InvalidFunctionPointer(_) => inline_fluent!("using {$pointer} as function pointer but it does not point to a function"),
InvalidVTablePointer(_) => inline_fluent!("using {$pointer} as vtable pointer but it does not point to a vtable"),
InvalidVTableTrait { .. } => inline_fluent!("using vtable for `{$vtable_dyn_type}` but `{$expected_dyn_type}` was expected"),
InvalidStr(_) => inline_fluent!("this string is not valid UTF-8: {$err}"),
InvalidUninitBytes(None) => "using uninitialized data, but this operation requires initialized memory".into(),
InvalidUninitBytes(Some(_)) => inline_fluent!("reading memory at {$alloc}{$access}, but memory is uninitialized at {$uninit}, and this operation requires initialized memory"),
DeadLocal => "accessing a dead local variable".into(),
ScalarSizeMismatch(_) => inline_fluent!("scalar size mismatch: expected {$target_size} bytes but got {$data_size} bytes instead"),
UninhabitedEnumVariantWritten(_) => "writing discriminant of an uninhabited enum variant".into(),
UninhabitedEnumVariantRead(_) => "read discriminant of an uninhabited enum variant".into(),
InvalidNichedEnumVariantWritten { .. } => {
inline_fluent!("trying to set discriminant of a {$ty} to the niched variant, but the value does not match")
}
AbiMismatchArgument { .. } => inline_fluent!("calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty}"),
AbiMismatchReturn { .. } => inline_fluent!("calling a function with return type {$callee_ty} passing return place of type {$caller_ty}"),
}
}
@@ -653,92 +910,189 @@ 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
inline_fluent!(
"{$front_matter}: encountered a box pointing to uninhabited type {$ty}"
)
}
PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => {
const_eval_validation_ref_to_uninhabited
inline_fluent!(
"{$front_matter}: encountered a reference pointing to uninhabited type {$ty}"
)
}
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
PartialPointer => const_eval_validation_partial_pointer,
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
NullFnPtr { .. } => const_eval_validation_null_fn_ptr,
NeverVal => const_eval_validation_never_val,
NonnullPtrMaybeNull { .. } => const_eval_validation_nonnull_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,
PointerAsInt { .. } => {
inline_fluent!("{$front_matter}: encountered a pointer, but {$expected}")
}
PartialPointer => inline_fluent!(
"{$front_matter}: encountered a partial pointer or a mix of pointers"
),
MutableRefToImmutable => {
inline_fluent!(
"{$front_matter}: encountered mutable reference or box pointing to read-only memory"
)
}
NullFnPtr { .. } => {
inline_fluent!(
"{$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} function pointer"
)
}
NeverVal => {
inline_fluent!("{$front_matter}: encountered a value of the never type `!`")
}
NonnullPtrMaybeNull { .. } => {
inline_fluent!(
"{$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero"
)
}
PtrOutOfRange { .. } => {
inline_fluent!(
"{$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range}"
)
}
OutOfRange { .. } => {
inline_fluent!(
"{$front_matter}: encountered {$value}, but expected something {$in_range}"
)
}
UnsafeCellInImmutable => {
inline_fluent!("{$front_matter}: encountered `UnsafeCell` in read-only memory")
}
UninhabitedVal { .. } => {
inline_fluent!("{$front_matter}: encountered a value of uninhabited type `{$ty}`")
}
InvalidEnumTag { .. } => {
inline_fluent!(
"{$front_matter}: encountered {$value}, but expected a valid enum tag"
)
}
UninhabitedEnumVariant => {
inline_fluent!("{$front_matter}: encountered an uninhabited enum variant")
}
Uninit { .. } => {
inline_fluent!("{$front_matter}: encountered uninitialized memory, but {$expected}")
}
InvalidVTablePtr { .. } => {
inline_fluent!(
"{$front_matter}: encountered {$value}, but expected a vtable pointer"
)
}
InvalidMetaWrongTrait { .. } => {
inline_fluent!(
"{$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}`"
)
}
InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
const_eval_validation_invalid_box_slice_meta
inline_fluent!(
"{$front_matter}: encountered invalid box metadata: slice is bigger than largest supported object"
)
}
InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => {
const_eval_validation_invalid_ref_slice_meta
inline_fluent!(
"{$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object"
)
}
InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => {
const_eval_validation_invalid_box_meta
inline_fluent!(
"{$front_matter}: encountered invalid box metadata: total size is bigger than largest supported object"
)
}
InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => {
const_eval_validation_invalid_ref_meta
inline_fluent!(
"{$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object"
)
}
UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => {
const_eval_validation_unaligned_ref
inline_fluent!(
"{$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})"
)
}
UnalignedPtr { ptr_kind: PointerKind::Box, .. } => {
inline_fluent!(
"{$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})"
)
}
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,
NullPtr { ptr_kind: PointerKind::Box, .. } => {
inline_fluent!(
"{$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} box"
)
}
NullPtr { ptr_kind: PointerKind::Ref(_), .. } => {
inline_fluent!(
"{$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} reference"
)
}
DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
const_eval_validation_dangling_box_no_provenance
inline_fluent!(
"{$front_matter}: encountered a dangling box ({$pointer} has no provenance)"
)
}
DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => {
const_eval_validation_dangling_ref_no_provenance
inline_fluent!(
"{$front_matter}: encountered a dangling reference ({$pointer} has no provenance)"
)
}
DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => {
const_eval_validation_dangling_box_out_of_bounds
inline_fluent!(
"{$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)"
)
}
DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => {
const_eval_validation_dangling_ref_out_of_bounds
inline_fluent!(
"{$front_matter}: encountered a dangling reference (going beyond the bounds of its allocation)"
)
}
DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => {
const_eval_validation_dangling_box_use_after_free
inline_fluent!("{$front_matter}: encountered a dangling box (use-after-free)")
}
DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => {
const_eval_validation_dangling_ref_use_after_free
inline_fluent!("{$front_matter}: encountered a dangling reference (use-after-free)")
}
InvalidBool { .. } => {
inline_fluent!("{$front_matter}: encountered {$value}, but expected a boolean")
}
InvalidChar { .. } => {
inline_fluent!(
"{$front_matter}: encountered {$value}, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)"
)
}
InvalidFnPtr { .. } => {
inline_fluent!(
"{$front_matter}: encountered {$value}, but expected a function pointer"
)
}
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_errors::inline_fluent;
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);
err.help(inline_fluent!("this code performed an operation that depends on the underlying bytes representing a pointer"));
err.help(inline_fluent!("the absolute address of a pointer is not known at compile-time, so such operations are not supported"));
}
let message = if let Some(path) = self.path {
err.dcx.eagerly_translate_to_string(
fluent::const_eval_validation_front_matter_invalid_value_with_path,
inline_fluent!("constructing invalid value at {$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,
inline_fluent!("constructing invalid value"),
[].into_iter(),
)
};
@@ -753,17 +1107,17 @@ fn add_range_arg<G: EmissionGuarantee>(
let WrappingRange { start: lo, end: hi } = r;
assert!(hi <= max_hi);
let msg = if lo > hi {
fluent::const_eval_range_wrapping
inline_fluent!("less or equal to {$hi}, or greater or equal to {$lo}")
} else if lo == hi {
fluent::const_eval_range_singular
inline_fluent!("equal to {$lo}")
} else if lo == 0 {
assert!(hi < max_hi, "should not be printing if the range covers everything");
fluent::const_eval_range_upper
inline_fluent!("less or equal to {$hi}")
} else if hi == max_hi {
assert!(lo > 0, "should not be printing if the range covers everything");
fluent::const_eval_range_lower
inline_fluent!("greater or equal to {$lo}")
} else {
fluent::const_eval_range
inline_fluent!("in the range {$lo}..={$hi}")
};
let args = [
@@ -781,17 +1135,17 @@ fn add_range_arg<G: EmissionGuarantee>(
}
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,
ExpectedKind::Reference => inline_fluent!("expected a reference"),
ExpectedKind::Box => inline_fluent!("expected a box"),
ExpectedKind::RawPtr => inline_fluent!("expected a raw pointer"),
ExpectedKind::InitScalar => inline_fluent!("expected initialized scalar value"),
ExpectedKind::Bool => inline_fluent!("expected a boolean"),
ExpectedKind::Char => inline_fluent!("expected a unicode scalar value"),
ExpectedKind::Float => inline_fluent!("expected a floating point number"),
ExpectedKind::Int => inline_fluent!("expected an integer"),
ExpectedKind::FnPtr => inline_fluent!("expected a function pointer"),
ExpectedKind::EnumTag => inline_fluent!("expected a valid enum tag"),
ExpectedKind::Str => inline_fluent!("expected a string"),
};
let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
err.arg("expected", msg);
@@ -838,25 +1192,32 @@ fn add_range_arg<G: EmissionGuarantee>(
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::ReadPartialPointer(_) => const_eval_partial_pointer_read,
UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int,
UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static,
UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
UnsupportedOpInfo::ExternTypeField => {
"`extern type` field does not have a known offset".into()
}
UnsupportedOpInfo::UnsizedLocal => "unsized locals are not supported".into(),
UnsupportedOpInfo::ReadPartialPointer(_) => {
inline_fluent!("unable to read parts of a pointer from memory at {$ptr}")
}
UnsupportedOpInfo::ReadPointerAsInt(_) => "unable to turn pointer into integer".into(),
UnsupportedOpInfo::ThreadLocalStatic(_) => {
inline_fluent!("cannot access thread local static `{$did}`")
}
UnsupportedOpInfo::ExternStatic(_) => {
inline_fluent!("cannot access extern static `{$did}`")
}
}
.into()
}
fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
use UnsupportedOpInfo::*;
use crate::fluent_generated::*;
if let ReadPointerAsInt(_) | ReadPartialPointer(_) = self {
diag.help(const_eval_ptr_as_bytes_1);
diag.help(const_eval_ptr_as_bytes_2);
diag.help("this code performed an operation that depends on the underlying bytes representing a pointer");
diag.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
}
match self {
// `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
@@ -901,10 +1262,12 @@ fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
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::TooGeneric => "encountered overly generic constant".into(),
InvalidProgramInfo::AlreadyReported(_) => {
"an error has already been reported elsewhere (this should not usually be printed)"
.into()
}
InvalidProgramInfo::Layout(e) => e.diagnostic_message(),
}
}
@@ -926,13 +1289,19 @@ fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
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,
ResourceExhaustionInfo::StackFrameLimitReached => {
"reached the configured maximum number of stack frames"
}
ResourceExhaustionInfo::MemoryExhausted => {
"tried to allocate more memory than available to compiler"
}
ResourceExhaustionInfo::AddressSpaceFull => {
"there are no more free addresses in the address space"
}
ResourceExhaustionInfo::Interrupted => "compilation was interrupted",
}
.into()
}
fn add_args<G: EmissionGuarantee>(self, _: &mut Diag<'_, G>) {}
}
@@ -1,10 +1,12 @@
//! Manages calling a concrete function (with known MIR body) with argument passing,
//! and returning the return value to the caller.
use std::borrow::Cow;
use either::{Left, Right};
use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx};
use rustc_data_structures::assert_matches;
use rustc_errors::inline_fluent;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
@@ -19,8 +21,8 @@
Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok,
throw_ub, throw_ub_custom, throw_unsup_format,
};
use crate::enter_trace_span;
use crate::interpret::EnteredTraceSpan;
use crate::{enter_trace_span, fluent_generated as fluent};
/// An argument passed to a function.
#[derive(Clone, Debug)]
@@ -292,7 +294,9 @@ fn pass_argument<'x, 'y>(
}
// Find next caller arg.
let Some((caller_arg, caller_abi)) = caller_args.next() else {
throw_ub_custom!(fluent::const_eval_not_enough_caller_args);
throw_ub_custom!(inline_fluent!(
"calling a function with fewer arguments than it requires"
));
};
assert_eq!(caller_arg.layout().layout, caller_abi.layout.layout);
// Sadly we cannot assert that `caller_arg.layout().ty` and `caller_abi.layout.ty` are
@@ -359,7 +363,9 @@ pub fn init_stack_frame(
if caller_fn_abi.conv != callee_fn_abi.conv {
throw_ub_custom!(
fluent::const_eval_incompatible_calling_conventions,
rustc_errors::inline_fluent!(
"calling a function with calling convention \"{$callee_conv}\" using calling convention \"{$caller_conv}\""
),
callee_conv = format!("{}", callee_fn_abi.conv),
caller_conv = format!("{}", caller_fn_abi.conv),
)
@@ -490,7 +496,9 @@ pub fn init_stack_frame(
"mismatch between callee ABI and callee body arguments"
);
if caller_args.next().is_some() {
throw_ub_custom!(fluent::const_eval_too_many_caller_args);
throw_ub_custom!(inline_fluent!(
"calling a function with more arguments than it expected"
));
}
// Don't forget to check the return type!
if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
@@ -690,7 +698,9 @@ pub(super) fn init_fn_call(
let vtable_entries = self.vtable_entries(receiver_trait.principal(), dyn_ty);
let Some(ty::VtblEntry::Method(fn_inst)) = vtable_entries.get(idx).copied() else {
// FIXME(fee1-dead) these could be variants of the UB info enum instead of this
throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method);
throw_ub_custom!(inline_fluent!(
"`dyn` call trying to call something that is not a method"
));
};
trace!("Virtual call dispatches to {fn_inst:#?}");
// We can also do the lookup based on `def_id` and `dyn_ty`, and check that that
@@ -887,7 +897,7 @@ pub(super) fn return_from_current_stack_frame(
}
);
if unwinding && self.frame_idx() == 0 {
throw_ub_custom!(fluent::const_eval_unwind_past_top);
throw_ub_custom!(inline_fluent!("unwinding past the topmost frame of the stack"));
}
// Get out the return value. Must happen *before* the frame is popped as we have to get the
@@ -2,6 +2,7 @@
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_apfloat::{Float, FloatConvert};
use rustc_data_structures::assert_matches;
use rustc_errors::inline_fluent;
use rustc_middle::mir::CastKind;
use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
use rustc_middle::ty::adjustment::PointerCoercion;
@@ -15,8 +16,8 @@
FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, interp_ok, throw_ub,
throw_ub_custom,
};
use crate::enter_trace_span;
use crate::interpret::Writeable;
use crate::{enter_trace_span, fluent_generated as fluent};
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
pub fn cast(
@@ -138,7 +139,9 @@ pub fn cast(
assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely...
if src.layout.size != dest.layout.size {
throw_ub_custom!(
fluent::const_eval_invalid_transmute,
inline_fluent!(
"transmuting from {$src_bytes}-byte type to {$dest_bytes}-byte type: `{$src}` -> `{$dest}`"
),
src_bytes = src.layout.size.bytes(),
dest_bytes = dest.layout.size.bytes(),
src = src.layout.ty,
@@ -1,7 +1,7 @@
use either::{Left, Right};
use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
use rustc_data_structures::debug_assert_matches;
use rustc_errors::DiagCtxtHandle;
use rustc_errors::{DiagCtxtHandle, inline_fluent};
use rustc_hir::def_id::DefId;
use rustc_hir::limit::Limit;
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
@@ -23,7 +23,7 @@
MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance,
err_inval, interp_ok, throw_inval, throw_ub, throw_ub_custom,
};
use crate::{ReportErrorExt, enter_trace_span, fluent_generated as fluent, util};
use crate::{ReportErrorExt, enter_trace_span, util};
pub struct InterpCx<'tcx, M: Machine<'tcx>> {
/// Stores the `Machine` instance.
@@ -555,7 +555,9 @@ pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tc
mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
mir::UnwindAction::Continue => Right(self.frame_mut().body.span),
mir::UnwindAction::Unreachable => {
throw_ub_custom!(fluent::const_eval_unreachable_unwind);
throw_ub_custom!(inline_fluent!(
"unwinding past a stack frame that does not allow unwinding"
));
}
mir::UnwindAction::Terminate(reason) => {
self.frame_mut().loc = Right(self.frame_mut().body.span);
@@ -7,6 +7,7 @@
use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size, VariantIdx};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_data_structures::assert_matches;
use rustc_errors::inline_fluent;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
@@ -25,7 +26,6 @@
PointerArithmetic, Provenance, Scalar, err_ub_custom, err_unsup_format, interp_ok, throw_inval,
throw_ub_custom, throw_ub_format,
};
use crate::fluent_generated as fluent;
use crate::interpret::Writeable;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -438,7 +438,9 @@ pub fn eval_intrinsic(
_ => {
// Not into the same allocation -- this is UB.
throw_ub_custom!(
fluent::const_eval_offset_from_different_allocations,
inline_fluent!(
"`{$name}` called on two different pointers that are not both derived from the same allocation"
),
name = intrinsic_name,
);
}
@@ -459,7 +461,10 @@ pub fn eval_intrinsic(
// a < b
if intrinsic_name == sym::ptr_offset_from_unsigned {
throw_ub_custom!(
fluent::const_eval_offset_from_unsigned_overflow,
inline_fluent!("`ptr_offset_from_unsigned` called when first pointer has smaller {$is_addr ->
[true] address
*[false] offset
} than second: {$a_offset} < {$b_offset}"),
a_offset = a_offset,
b_offset = b_offset,
is_addr = is_addr,
@@ -471,7 +476,9 @@ pub fn eval_intrinsic(
let dist = val.to_target_isize(self)?;
if dist >= 0 || i128::from(dist) == self.pointer_size().signed_int_min() {
throw_ub_custom!(
fluent::const_eval_offset_from_underflow,
inline_fluent!(
"`{$name}` called when first pointer is too far before second"
),
name = intrinsic_name,
);
}
@@ -483,7 +490,9 @@ pub fn eval_intrinsic(
// because they were more than isize::MAX apart.
if dist < 0 {
throw_ub_custom!(
fluent::const_eval_offset_from_overflow,
inline_fluent!(
"`{$name}` called when first pointer is too far ahead of second"
),
name = intrinsic_name,
);
}
@@ -502,12 +511,12 @@ pub fn eval_intrinsic(
&& a_alloc_id == b_alloc_id
{
err_ub_custom!(
fluent::const_eval_offset_from_out_of_bounds,
inline_fluent!("`{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation"),
name = intrinsic_name,
)
} else {
err_ub_custom!(
fluent::const_eval_offset_from_different_allocations,
inline_fluent!("`{$name}` called on two different pointers that are not both derived from the same allocation"),
name = intrinsic_name,
)
}
@@ -522,7 +531,7 @@ pub fn eval_intrinsic(
.map_err_kind(|_| {
// Make the error more specific.
err_ub_custom!(
fluent::const_eval_offset_from_different_allocations,
inline_fluent!("`{$name}` called on two different pointers that are not both derived from the same allocation"),
name = intrinsic_name,
)
})?;
@@ -752,7 +761,7 @@ pub(super) fn eval_nondiverging_intrinsic(
let op = self.eval_operand(op, None)?;
let cond = self.read_scalar(&op)?.to_bool()?;
if !cond {
throw_ub_custom!(fluent::const_eval_assume_false);
throw_ub_custom!(inline_fluent!("`assume` called with `false`"));
}
interp_ok(())
}
@@ -782,7 +791,7 @@ pub fn numeric_intrinsic(
let bits_out = match name {
sym::ctpop => u128::from(bits.count_ones()),
sym::ctlz_nonzero | sym::cttz_nonzero if bits == 0 => {
throw_ub_custom!(fluent::const_eval_call_nonzero_intrinsic, name = name,);
throw_ub_custom!(inline_fluent!("`{$name}` called on 0"), name = name,);
}
sym::ctlz | sym::ctlz_nonzero => u128::from(bits.leading_zeros()) - extra,
sym::cttz | sym::cttz_nonzero => u128::from((bits << extra).trailing_zeros()) - extra,
@@ -815,7 +824,7 @@ pub fn exact_div(
// sign does not matter for 0 test, so `to_bits` is fine
if rem.to_scalar().to_bits(a.layout.size)? != 0 {
throw_ub_custom!(
fluent::const_eval_exact_div_has_remainder,
inline_fluent!("exact_div: {$a} cannot be divided by {$b} without remainder"),
a = format!("{a}"),
b = format!("{b}")
)
@@ -900,7 +909,7 @@ pub(crate) fn copy_intrinsic(
let size = self.compute_size_in_bytes(size, count).ok_or_else(|| {
err_ub_custom!(
fluent::const_eval_size_overflow,
inline_fluent!("overflow computing total size of `{$name}`"),
name = if nonoverlapping { "copy_nonoverlapping" } else { "copy" }
)
})?;
@@ -963,9 +972,12 @@ pub fn write_bytes_intrinsic(
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
// but no actual allocation can be big enough for the difference to be noticeable.
let len = self
.compute_size_in_bytes(layout.size, count)
.ok_or_else(|| err_ub_custom!(fluent::const_eval_size_overflow, name = name))?;
let len = self.compute_size_in_bytes(layout.size, count).ok_or_else(|| {
err_ub_custom!(
inline_fluent!("overflow computing total size of `{$name}`"),
name = name
)
})?;
let bytes = std::iter::repeat_n(byte, len.bytes_usize());
self.write_bytes_ptr(dst, bytes)
@@ -15,6 +15,7 @@
use rustc_ast::Mutability;
use rustc_data_structures::assert_matches;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::inline_fluent;
use rustc_middle::mir::display_allocation;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::{bug, throw_ub_format};
@@ -27,7 +28,6 @@
err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
};
use crate::const_eval::ConstEvalErrKind;
use crate::fluent_generated as fluent;
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum MemoryKind<T> {
@@ -291,7 +291,13 @@ pub fn reallocate_ptr(
let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr, 0)?;
if offset.bytes() != 0 {
throw_ub_custom!(
fluent::const_eval_realloc_or_alloc_with_offset,
inline_fluent!(
"{$kind ->
[dealloc] deallocating
[realloc] reallocating
*[other] {\"\"}
} {$ptr} which does not point to the beginning of an object"
),
ptr = format!("{ptr:?}"),
kind = "realloc"
);
@@ -371,7 +377,13 @@ pub fn deallocate_ptr(
if offset.bytes() != 0 {
throw_ub_custom!(
fluent::const_eval_realloc_or_alloc_with_offset,
inline_fluent!(
"{$kind ->
[dealloc] deallocating
[realloc] reallocating
*[other] {\"\"}
} {$ptr} which does not point to the beginning of an object"
),
ptr = format!("{ptr:?}"),
kind = "dealloc",
);
@@ -382,28 +394,56 @@ pub fn deallocate_ptr(
return Err(match self.tcx.try_get_global_alloc(alloc_id) {
Some(GlobalAlloc::Function { .. }) => {
err_ub_custom!(
fluent::const_eval_invalid_dealloc,
inline_fluent!(
"deallocating {$alloc_id}, which is {$kind ->
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
),
alloc_id = alloc_id,
kind = "fn",
)
}
Some(GlobalAlloc::VTable(..)) => {
err_ub_custom!(
fluent::const_eval_invalid_dealloc,
inline_fluent!(
"deallocating {$alloc_id}, which is {$kind ->
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
),
alloc_id = alloc_id,
kind = "vtable",
)
}
Some(GlobalAlloc::TypeId { .. }) => {
err_ub_custom!(
fluent::const_eval_invalid_dealloc,
inline_fluent!(
"deallocating {$alloc_id}, which is {$kind ->
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
),
alloc_id = alloc_id,
kind = "typeid",
)
}
Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
err_ub_custom!(
fluent::const_eval_invalid_dealloc,
inline_fluent!(
"deallocating {$alloc_id}, which is {$kind ->
[fn] a function
[vtable] a vtable
[static_mem] static memory
*[other] {\"\"}
}"
),
alloc_id = alloc_id,
kind = "static_mem"
)
@@ -414,11 +454,16 @@ pub fn deallocate_ptr(
};
if alloc.mutability.is_not() {
throw_ub_custom!(fluent::const_eval_dealloc_immutable, alloc = alloc_id,);
throw_ub_custom!(
inline_fluent!("deallocating immutable allocation {$alloc}"),
alloc = alloc_id,
);
}
if alloc_kind != kind {
throw_ub_custom!(
fluent::const_eval_dealloc_kind_mismatch,
inline_fluent!(
"deallocating {$alloc}, which is {$alloc_kind} memory, using {$kind} deallocation operation"
),
alloc = alloc_id,
alloc_kind = format!("{alloc_kind}"),
kind = format!("{kind}"),
@@ -427,7 +472,9 @@ pub fn deallocate_ptr(
if let Some((size, align)) = old_size_and_align {
if size != alloc.size() || align != alloc.align {
throw_ub_custom!(
fluent::const_eval_dealloc_incorrect_layout,
inline_fluent!(
"incorrect layout on deallocation: {$alloc} has size {$size} and alignment {$align}, but gave size {$size_found} and alignment {$align_found}"
),
alloc = alloc_id,
size = alloc.size().bytes(),
align = alloc.align.bytes(),
@@ -1546,7 +1593,9 @@ pub fn mem_copy_repeatedly(
if (src_offset <= dest_offset && src_offset + size > dest_offset)
|| (dest_offset <= src_offset && dest_offset + size > src_offset)
{
throw_ub_custom!(fluent::const_eval_copy_nonoverlapping_overlapping);
throw_ub_custom!(inline_fluent!(
"`copy_nonoverlapping` called on overlapping ranges"
));
}
}
}
-2
View File
@@ -26,8 +26,6 @@
pub use self::errors::ReportErrorExt;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
pub fn provide(providers: &mut Providers) {
const_eval::provide(&mut providers.queries);
providers.queries.tag_for_variant = const_eval::tag_for_variant_provider;
-1
View File
@@ -113,7 +113,6 @@ pub fn default_translator() -> Translator {
pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
// tidy-alphabetical-start
rustc_const_eval::DEFAULT_LOCALE_RESOURCE,
rustc_lint::DEFAULT_LOCALE_RESOURCE,
rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
rustc_parse::DEFAULT_LOCALE_RESOURCE,
@@ -30,6 +30,7 @@ LL | Some(())?;
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `FromResidual` is not yet stable as a const trait
--> $DIR/const-try-feature-gate.rs:4:5