Skip to content

Commit 6854fa3

Browse files
committed
const-eval interner: from-scratch rewrite using mutability information from provenance rather than types
1 parent 3ad8e2d commit 6854fa3

Some content is hidden

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

50 files changed

+998
-638
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
@@ -313,6 +313,9 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
313313
cid: GlobalId<'tcx>,
314314
is_static: bool,
315315
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
316+
// `is_static` just means "in static", it could still be a promoted!
317+
debug_assert_eq!(is_static, ecx.tcx.static_mutability(cid.instance.def_id()).is_some());
318+
316319
let res = ecx.load_mir(cid.instance.def, cid.promoted);
317320
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) {
318321
Err(error) => {
@@ -350,8 +353,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
350353
Ok(mplace) => {
351354
// Since evaluation had no errors, validate the resulting constant.
352355
// This is a separate `try` block to provide more targeted error reporting.
353-
let validation =
354-
const_validate_mplace(&ecx, &mplace, is_static, cid.promoted.is_some());
356+
let validation = const_validate_mplace(&ecx, &mplace, cid);
355357

356358
let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
357359

@@ -370,22 +372,26 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
370372
pub fn const_validate_mplace<'mir, 'tcx>(
371373
ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
372374
mplace: &MPlaceTy<'tcx>,
373-
is_static: bool,
374-
is_promoted: bool,
375+
cid: GlobalId<'tcx>,
375376
) -> InterpResult<'tcx> {
376377
let mut ref_tracking = RefTracking::new(mplace.clone());
377378
let mut inner = false;
378379
while let Some((mplace, path)) = ref_tracking.todo.pop() {
379-
let mode = if is_static {
380-
if is_promoted {
381-
// Promoteds in statics are allowed to point to statics.
382-
CtfeValidationMode::Const { inner, allow_static_ptrs: true }
383-
} else {
384-
// a `static`
385-
CtfeValidationMode::Regular
380+
let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
381+
Some(_) if cid.promoted.is_some() => {
382+
// Promoteds in statics are consts that re allowed to point to statics.
383+
CtfeValidationMode::Const {
384+
allow_immutable_unsafe_cell: false,
385+
allow_static_ptrs: true,
386+
}
387+
}
388+
Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
389+
None => {
390+
// In normal `const` (not promoted), the outermost allocation is always only copied,
391+
// so having `UnsafeCell` in there is okay despite them being in immutable memory.
392+
let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
393+
CtfeValidationMode::Const { allow_immutable_unsafe_cell, allow_static_ptrs: false }
386394
}
387-
} else {
388-
CtfeValidationMode::Const { inner, allow_static_ptrs: false }
389395
};
390396
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
391397
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
DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler,
35
IntoDiagnostic,
@@ -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 {
@@ -619,18 +625,16 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
619625
PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_static,
620626
PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_static,
621627

622-
PtrToMut { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_mut,
623-
PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_mut,
624-
625628
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
626629
PartialPointer => const_eval_validation_partial_pointer,
627630
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
631+
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
628632
NullFnPtr => const_eval_validation_null_fn_ptr,
629633
NeverVal => const_eval_validation_never_val,
630634
NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
631635
PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
632636
OutOfRange { .. } => const_eval_validation_out_of_range,
633-
UnsafeCell => const_eval_validation_unsafe_cell,
637+
UnsafeCellInImmutable => const_eval_validation_unsafe_cell,
634638
UninhabitedVal { .. } => const_eval_validation_uninhabited_val,
635639
InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag,
636640
UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
@@ -776,11 +780,11 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
776780
}
777781
NullPtr { .. }
778782
| PtrToStatic { .. }
779-
| PtrToMut { .. }
780783
| MutableRefInConst
784+
| MutableRefToImmutable
781785
| NullFnPtr
782786
| NeverVal
783-
| UnsafeCell
787+
| UnsafeCellInImmutable
784788
| InvalidMetaSliceTooLarge { .. }
785789
| InvalidMetaTooLarge { .. }
786790
| DanglingPtrUseAfterFree { .. }
@@ -906,3 +910,14 @@ impl ReportErrorExt for ResourceExhaustionInfo {
906910
}
907911
fn add_args<G: EmissionGuarantee>(self, _: &Handler, _: &mut DiagnosticBuilder<'_, G>) {}
908912
}
913+
914+
impl rustc_errors::IntoDiagnosticArg for InternKind {
915+
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
916+
DiagnosticArgValue::Str(Cow::Borrowed(match self {
917+
InternKind::Static(Mutability::Not) => "static",
918+
InternKind::Static(Mutability::Mut) => "static_mut",
919+
InternKind::Constant => "const",
920+
InternKind::Promoted => "promoted",
921+
}))
922+
}
923+
}

0 commit comments

Comments
 (0)