Skip to content

Commit 2f1a8e2

Browse files
committed
const-eval interner: from-scratch rewrite using mutability information from provenance rather than types
1 parent a58ec8f commit 2f1a8e2

File tree

52 files changed

+1080
-675
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1080
-675
lines changed

compiler/rustc_const_eval/messages.ftl

+14-8
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ const_eval_dangling_int_pointer =
4646
{$bad_pointer_message}: {$pointer} is a dangling pointer (it has no provenance)
4747
const_eval_dangling_null_pointer =
4848
{$bad_pointer_message}: null pointer is a dangling pointer (it has no provenance)
49-
const_eval_dangling_ptr_in_final = encountered dangling pointer in final constant
5049
50+
const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind}
5151
const_eval_dead_local =
5252
accessing a dead local variable
5353
const_eval_dealloc_immutable =
@@ -134,6 +134,14 @@ const_eval_interior_mutable_data_refer =
134134
This would make multiple uses of a constant to be able to see different values and allow circumventing
135135
the `Send` and `Sync` requirements for shared mutable data, which is unsound.
136136
137+
const_eval_intern_kind = {$kind ->
138+
[static] static
139+
[static_mut] mutable static
140+
[const] constant
141+
[promoted] promoted
142+
*[other] {""}
143+
}
144+
137145
const_eval_invalid_align =
138146
align has to be a power of 2
139147
@@ -205,6 +213,8 @@ const_eval_modified_global =
205213
const_eval_mut_deref =
206214
mutation through a reference is not allowed in {const_eval_const_context}s
207215
216+
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
217+
208218
const_eval_non_const_fmt_macro_call =
209219
cannot call non-const formatting macro in {const_eval_const_context}s
210220
@@ -392,9 +402,6 @@ const_eval_unstable_in_stable =
392402
.unstable_sugg = if it is not part of the public API, make this function unstably const
393403
.bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
394404
395-
const_eval_unsupported_untyped_pointer = unsupported untyped pointer in constant
396-
.note = memory only reachable via raw pointers is not supported
397-
398405
const_eval_unterminated_c_string =
399406
reading a null-terminated string starting at {$pointer} with no null found before end of allocation
400407
@@ -406,7 +413,6 @@ const_eval_upcast_mismatch =
406413
407414
## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`.
408415
## (We'd love to sort this differently to make that more clear but tidy won't let us...)
409-
const_eval_validation_box_to_mut = {$front_matter}: encountered a box pointing to mutable memory in a constant
410416
const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant
411417
const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
412418
const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)
@@ -441,7 +447,8 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu
441447
const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object
442448
const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
443449
const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
444-
const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in a `const`
450+
const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in a `const` or `static`
451+
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
445452
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
446453
const_eval_validation_null_box = {$front_matter}: encountered a null box
447454
const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer
@@ -451,15 +458,14 @@ const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but
451458
const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers
452459
const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected}
453460
const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range}
454-
const_eval_validation_ref_to_mut = {$front_matter}: encountered a reference pointing to mutable memory in a constant
455461
const_eval_validation_ref_to_static = {$front_matter}: encountered a reference pointing to a static variable in a constant
456462
const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty}
457463
const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})
458464
const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})
459465
const_eval_validation_uninhabited_enum_variant = {$front_matter}: encountered an uninhabited enum variant
460466
const_eval_validation_uninhabited_val = {$front_matter}: encountered a value of uninhabited type `{$ty}`
461467
const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected}
462-
const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const`
468+
const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in read-only memory
463469
464470
const_eval_write_through_immutable_pointer =
465471
writing through a pointer that was derived from a shared (immutable) reference

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
293293
cid: GlobalId<'tcx>,
294294
is_static: bool,
295295
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
296+
// `is_static` just means "in static", it could still be a promoted!
297+
debug_assert_eq!(is_static, ecx.tcx.static_mutability(cid.instance.def_id()).is_some());
298+
296299
let res = ecx.load_mir(cid.instance.def, cid.promoted);
297300
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) {
298301
Err(error) => {
@@ -330,8 +333,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
330333
Ok(mplace) => {
331334
// Since evaluation had no errors, validate the resulting constant.
332335
// This is a separate `try` block to provide more targeted error reporting.
333-
let validation =
334-
const_validate_mplace(&ecx, &mplace, is_static, cid.promoted.is_some());
336+
let validation = const_validate_mplace(&ecx, &mplace, cid);
335337

336338
let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
337339

@@ -350,22 +352,26 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
350352
pub fn const_validate_mplace<'mir, 'tcx>(
351353
ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
352354
mplace: &MPlaceTy<'tcx>,
353-
is_static: bool,
354-
is_promoted: bool,
355+
cid: GlobalId<'tcx>,
355356
) -> InterpResult<'tcx> {
356357
let mut ref_tracking = RefTracking::new(mplace.clone());
357358
let mut inner = false;
358359
while let Some((mplace, path)) = ref_tracking.todo.pop() {
359-
let mode = if is_static {
360-
if is_promoted {
361-
// Promoteds in statics are allowed to point to statics.
362-
CtfeValidationMode::Const { inner, allow_static_ptrs: true }
363-
} else {
364-
// a `static`
365-
CtfeValidationMode::Regular
360+
let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
361+
Some(_) if cid.promoted.is_some() => {
362+
// Promoteds in statics are consts that re allowed to point to statics.
363+
CtfeValidationMode::Const {
364+
allow_immutable_unsafe_cell: false,
365+
allow_static_ptrs: true,
366+
}
367+
}
368+
Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
369+
None => {
370+
// In normal `const` (not promoted), the outermost allocation is always only copied,
371+
// so having `UnsafeCell` in there is okay despite them being in immutable memory.
372+
let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
373+
CtfeValidationMode::Const { allow_immutable_unsafe_cell, allow_static_ptrs: false }
366374
}
367-
} else {
368-
CtfeValidationMode::Const { inner, allow_static_ptrs: false }
369375
};
370376
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
371377
inner = true;

compiler/rustc_const_eval/src/const_eval/machine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
723723
&& ty.is_freeze(*ecx.tcx, ecx.param_env)
724724
{
725725
let place = ecx.ref_to_mplace(val)?;
726-
let new_place = place.map_provenance(|p| p.map(CtfeProvenance::as_immutable));
726+
let new_place = place.map_provenance(CtfeProvenance::as_immutable);
727727
Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout))
728728
} else {
729729
Ok(val.clone())

compiler/rustc_const_eval/src/errors.rs

+29-14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::borrow::Cow;
2+
13
use rustc_errors::{
24
DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee,
35
IntoDiagnostic, Level,
@@ -13,12 +15,24 @@ use rustc_middle::ty::{self, Ty};
1315
use rustc_span::Span;
1416
use rustc_target::abi::call::AdjustForForeignAbiError;
1517
use rustc_target::abi::{Size, WrappingRange};
18+
use rustc_type_ir::Mutability;
19+
20+
use crate::interpret::InternKind;
1621

1722
#[derive(Diagnostic)]
1823
#[diag(const_eval_dangling_ptr_in_final)]
1924
pub(crate) struct DanglingPtrInFinal {
2025
#[primary_span]
2126
pub span: Span,
27+
pub kind: InternKind,
28+
}
29+
30+
#[derive(Diagnostic)]
31+
#[diag(const_eval_mutable_ptr_in_final)]
32+
pub(crate) struct MutablePtrInFinal {
33+
#[primary_span]
34+
pub span: Span,
35+
pub kind: InternKind,
2236
}
2337

2438
#[derive(Diagnostic)]
@@ -194,14 +208,6 @@ pub(crate) struct UnallowedInlineAsm {
194208
pub kind: ConstContext,
195209
}
196210

197-
#[derive(Diagnostic)]
198-
#[diag(const_eval_unsupported_untyped_pointer)]
199-
#[note]
200-
pub(crate) struct UnsupportedUntypedPointer {
201-
#[primary_span]
202-
pub span: Span,
203-
}
204-
205211
#[derive(Diagnostic)]
206212
#[diag(const_eval_interior_mutable_data_refer, code = "E0492")]
207213
pub(crate) struct InteriorMutableDataRefer {
@@ -615,18 +621,16 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
615621
PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_static,
616622
PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_static,
617623

618-
PtrToMut { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_mut,
619-
PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_mut,
620-
621624
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
622625
PartialPointer => const_eval_validation_partial_pointer,
623626
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
627+
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
624628
NullFnPtr => const_eval_validation_null_fn_ptr,
625629
NeverVal => const_eval_validation_never_val,
626630
NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
627631
PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
628632
OutOfRange { .. } => const_eval_validation_out_of_range,
629-
UnsafeCell => const_eval_validation_unsafe_cell,
633+
UnsafeCellInImmutable => const_eval_validation_unsafe_cell,
630634
UninhabitedVal { .. } => const_eval_validation_uninhabited_val,
631635
InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag,
632636
UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
@@ -772,11 +776,11 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
772776
}
773777
NullPtr { .. }
774778
| PtrToStatic { .. }
775-
| PtrToMut { .. }
776779
| MutableRefInConst
780+
| MutableRefToImmutable
777781
| NullFnPtr
778782
| NeverVal
779-
| UnsafeCell
783+
| UnsafeCellInImmutable
780784
| InvalidMetaSliceTooLarge { .. }
781785
| InvalidMetaTooLarge { .. }
782786
| DanglingPtrUseAfterFree { .. }
@@ -905,3 +909,14 @@ impl ReportErrorExt for ResourceExhaustionInfo {
905909
}
906910
fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, _: &mut DiagnosticBuilder<'_, G>) {}
907911
}
912+
913+
impl rustc_errors::IntoDiagnosticArg for InternKind {
914+
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
915+
DiagnosticArgValue::Str(Cow::Borrowed(match self {
916+
InternKind::Static(Mutability::Not) => "static",
917+
InternKind::Static(Mutability::Mut) => "static_mut",
918+
InternKind::Constant => "const",
919+
InternKind::Promoted => "promoted",
920+
}))
921+
}
922+
}

0 commit comments

Comments
 (0)