unstably allow constants to refer to statics and read from immutable statics
This commit is contained in:
parent
5f40394baa
commit
4e77e368eb
50 changed files with 548 additions and 530 deletions
|
@ -30,7 +30,9 @@ const_eval_closure_non_const =
|
|||
cannot call non-const closure in {const_eval_const_context}s
|
||||
const_eval_consider_dereferencing =
|
||||
consider dereferencing here
|
||||
const_eval_const_accesses_static = constant accesses static
|
||||
|
||||
const_eval_const_accesses_mut_global =
|
||||
constant accesses mutable global memory
|
||||
|
||||
const_eval_const_context = {$kind ->
|
||||
[const] constant
|
||||
|
@ -213,6 +215,9 @@ const_eval_modified_global =
|
|||
const_eval_mut_deref =
|
||||
mutation through a reference is not allowed in {const_eval_const_context}s
|
||||
|
||||
const_eval_mutable_data_in_const =
|
||||
constant refers to mutable data
|
||||
|
||||
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
|
||||
|
||||
const_eval_non_const_fmt_macro_call =
|
||||
|
@ -319,12 +324,6 @@ const_eval_size_overflow =
|
|||
const_eval_stack_frame_limit_reached =
|
||||
reached the configured maximum number of stack frames
|
||||
|
||||
const_eval_static_access =
|
||||
{const_eval_const_context}s cannot refer to statics
|
||||
.help = consider extracting the value of the `static` to a `const`, and referring to that
|
||||
.teach_note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
|
||||
.teach_help = To fix this, the value can be extracted to a `const` and then used.
|
||||
|
||||
const_eval_thread_local_access =
|
||||
thread-local statics cannot be accessed at compile-time
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, MachineStopTy
|
|||
/// The CTFE machine has some custom error kinds.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ConstEvalErrKind {
|
||||
ConstAccessesStatic,
|
||||
ConstAccessesMutGlobal,
|
||||
ModifiedGlobal,
|
||||
AssertFailure(AssertKind<ConstInt>),
|
||||
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
|
||||
|
@ -28,7 +28,7 @@ impl MachineStopType for ConstEvalErrKind {
|
|||
use crate::fluent_generated::*;
|
||||
use ConstEvalErrKind::*;
|
||||
match self {
|
||||
ConstAccessesStatic => const_eval_const_accesses_static,
|
||||
ConstAccessesMutGlobal => const_eval_const_accesses_mut_global,
|
||||
ModifiedGlobal => const_eval_modified_global,
|
||||
Panic { .. } => const_eval_panic,
|
||||
AssertFailure(x) => x.diagnostic_message(),
|
||||
|
@ -37,7 +37,7 @@ impl MachineStopType for ConstEvalErrKind {
|
|||
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) {
|
||||
use ConstEvalErrKind::*;
|
||||
match *self {
|
||||
ConstAccessesStatic | ModifiedGlobal => {}
|
||||
ConstAccessesMutGlobal | ModifiedGlobal => {}
|
||||
AssertFailure(kind) => kind.add_args(adder),
|
||||
Panic { msg, line, col, file } => {
|
||||
adder("msg".into(), msg.into_diagnostic_arg());
|
||||
|
|
|
@ -11,7 +11,7 @@ use rustc_middle::ty::{self, TyCtxt};
|
|||
use rustc_span::Span;
|
||||
use rustc_target::abi::{self, Abi};
|
||||
|
||||
use super::{CanAccessStatics, CompileTimeEvalContext, CompileTimeInterpreter};
|
||||
use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter};
|
||||
use crate::const_eval::CheckAlignment;
|
||||
use crate::errors;
|
||||
use crate::errors::ConstEvalError;
|
||||
|
@ -90,14 +90,14 @@ pub(crate) fn mk_eval_cx<'mir, 'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
root_span: Span,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
can_access_statics: CanAccessStatics,
|
||||
can_access_mut_global: CanAccessMutGlobal,
|
||||
) -> CompileTimeEvalContext<'mir, 'tcx> {
|
||||
debug!("mk_eval_cx: {:?}", param_env);
|
||||
InterpCx::new(
|
||||
tcx,
|
||||
root_span,
|
||||
param_env,
|
||||
CompileTimeInterpreter::new(can_access_statics, CheckAlignment::No),
|
||||
CompileTimeInterpreter::new(can_access_mut_global, CheckAlignment::No),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
|
|||
tcx,
|
||||
tcx.def_span(key.value.instance.def_id()),
|
||||
key.param_env,
|
||||
CanAccessStatics::from(is_static),
|
||||
CanAccessMutGlobal::from(is_static),
|
||||
);
|
||||
|
||||
let mplace = ecx.raw_const_to_mplace(constant).expect(
|
||||
|
@ -277,9 +277,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||
tcx,
|
||||
tcx.def_span(def),
|
||||
key.param_env,
|
||||
// Statics (and promoteds inside statics) may access other statics, because unlike consts
|
||||
// Statics (and promoteds inside statics) may access mutable global memory, because unlike consts
|
||||
// they do not have to behave "as if" they were evaluated at runtime.
|
||||
CompileTimeInterpreter::new(CanAccessStatics::from(is_static), CheckAlignment::Error),
|
||||
// For consts however we want to ensure they behave "as if" they were evaluated at runtime,
|
||||
// so we have to reject reading mutable global memory.
|
||||
CompileTimeInterpreter::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error),
|
||||
);
|
||||
eval_in_interpreter(ecx, cid, is_static)
|
||||
}
|
||||
|
|
|
@ -51,13 +51,10 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
|
|||
/// The virtual call stack.
|
||||
pub(super) stack: Vec<Frame<'mir, 'tcx>>,
|
||||
|
||||
/// We need to make sure consts never point to anything mutable, even recursively. That is
|
||||
/// relied on for pattern matching on consts with references.
|
||||
/// To achieve this, two pieces have to work together:
|
||||
/// * Interning makes everything outside of statics immutable.
|
||||
/// * Pointers to allocations inside of statics can never leak outside, to a non-static global.
|
||||
/// This boolean here controls the second part.
|
||||
pub(super) can_access_statics: CanAccessStatics,
|
||||
/// Pattern matching on consts with references would be unsound if those references
|
||||
/// could point to anything mutable. Therefore, when evaluating consts and when constructing valtrees,
|
||||
/// we ensure that only immutable global memory can be accessed.
|
||||
pub(super) can_access_mut_global: CanAccessMutGlobal,
|
||||
|
||||
/// Whether to check alignment during evaluation.
|
||||
pub(super) check_alignment: CheckAlignment,
|
||||
|
@ -73,12 +70,12 @@ pub enum CheckAlignment {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub(crate) enum CanAccessStatics {
|
||||
pub(crate) enum CanAccessMutGlobal {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
||||
impl From<bool> for CanAccessStatics {
|
||||
impl From<bool> for CanAccessMutGlobal {
|
||||
fn from(value: bool) -> Self {
|
||||
if value { Self::Yes } else { Self::No }
|
||||
}
|
||||
|
@ -86,13 +83,13 @@ impl From<bool> for CanAccessStatics {
|
|||
|
||||
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
|
||||
pub(crate) fn new(
|
||||
can_access_statics: CanAccessStatics,
|
||||
can_access_mut_global: CanAccessMutGlobal,
|
||||
check_alignment: CheckAlignment,
|
||||
) -> Self {
|
||||
CompileTimeInterpreter {
|
||||
num_evaluated_steps: 0,
|
||||
stack: Vec::new(),
|
||||
can_access_statics,
|
||||
can_access_mut_global,
|
||||
check_alignment,
|
||||
}
|
||||
}
|
||||
|
@ -680,7 +677,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
machine: &Self,
|
||||
alloc_id: AllocId,
|
||||
alloc: ConstAllocation<'tcx>,
|
||||
static_def_id: Option<DefId>,
|
||||
_static_def_id: Option<DefId>,
|
||||
is_write: bool,
|
||||
) -> InterpResult<'tcx> {
|
||||
let alloc = alloc.inner();
|
||||
|
@ -692,22 +689,15 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
}
|
||||
} else {
|
||||
// Read access. These are usually allowed, with some exceptions.
|
||||
if machine.can_access_statics == CanAccessStatics::Yes {
|
||||
if machine.can_access_mut_global == CanAccessMutGlobal::Yes {
|
||||
// Machine configuration allows us read from anything (e.g., `static` initializer).
|
||||
Ok(())
|
||||
} else if static_def_id.is_some() {
|
||||
// Machine configuration does not allow us to read statics
|
||||
// (e.g., `const` initializer).
|
||||
// See const_eval::machine::MemoryExtra::can_access_statics for why
|
||||
// this check is so important: if we could read statics, we could read pointers
|
||||
// to mutable allocations *inside* statics. These allocations are not themselves
|
||||
// statics, so pointers to them can get around the check in `validity.rs`.
|
||||
Err(ConstEvalErrKind::ConstAccessesStatic.into())
|
||||
} else if alloc.mutability == Mutability::Mut {
|
||||
// Machine configuration does not allow us to read statics (e.g., `const`
|
||||
// initializer).
|
||||
Err(ConstEvalErrKind::ConstAccessesMutGlobal.into())
|
||||
} else {
|
||||
// Immutable global, this read is fine.
|
||||
// But make sure we never accept a read from something mutable, that would be
|
||||
// unsound. The reason is that as the content of this allocation may be different
|
||||
// now and at run-time, so if we permit reading now we might return the wrong value.
|
||||
assert_eq!(alloc.mutability, Mutability::Not);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
// Not in interpret to make sure we do not use private implementation details
|
||||
|
||||
use crate::errors::MaxNumNodesInConstErr;
|
||||
use crate::interpret::InterpCx;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
|
||||
use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
||||
mod error;
|
||||
mod eval_queries;
|
||||
|
@ -18,55 +16,32 @@ pub use error::*;
|
|||
pub use eval_queries::*;
|
||||
pub use fn_queries::*;
|
||||
pub use machine::*;
|
||||
pub(crate) use valtrees::{const_to_valtree_inner, valtree_to_const_value};
|
||||
pub(crate) use valtrees::{eval_to_valtree, valtree_to_const_value};
|
||||
|
||||
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
|
||||
const VALTREE_MAX_NODES: usize = 100000;
|
||||
|
||||
pub(crate) enum ValTreeCreationError {
|
||||
NodesOverflow,
|
||||
/// Values of this type, or this particular value, are not supported as valtrees.
|
||||
NonSupportedType,
|
||||
/// The value pointed to non-read-only memory, so we cannot make it a valtree.
|
||||
NotReadOnly,
|
||||
Other,
|
||||
}
|
||||
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
|
||||
|
||||
/// Evaluates a constant and turns it into a type-level constant value.
|
||||
pub(crate) fn eval_to_valtree<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
cid: GlobalId<'tcx>,
|
||||
) -> EvalToValTreeResult<'tcx> {
|
||||
let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?;
|
||||
|
||||
// FIXME Need to provide a span to `eval_to_valtree`
|
||||
let ecx = mk_eval_cx(
|
||||
tcx,
|
||||
DUMMY_SP,
|
||||
param_env,
|
||||
// It is absolutely crucial for soundness that
|
||||
// we do not read from static items or other mutable memory.
|
||||
CanAccessStatics::No,
|
||||
);
|
||||
let place = ecx.raw_const_to_mplace(const_alloc).unwrap();
|
||||
debug!(?place);
|
||||
|
||||
let mut num_nodes = 0;
|
||||
let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
|
||||
|
||||
match valtree_result {
|
||||
Ok(valtree) => Ok(Some(valtree)),
|
||||
Err(err) => {
|
||||
let did = cid.instance.def_id();
|
||||
let global_const_id = cid.display(tcx);
|
||||
match err {
|
||||
ValTreeCreationError::NodesOverflow => {
|
||||
let span = tcx.hir().span_if_local(did);
|
||||
tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
|
||||
|
||||
Ok(None)
|
||||
impl From<InterpErrorInfo<'_>> for ValTreeCreationError {
|
||||
fn from(err: InterpErrorInfo<'_>) -> Self {
|
||||
match err.kind() {
|
||||
InterpError::MachineStop(err) => {
|
||||
let err = err.downcast_ref::<ConstEvalErrKind>().unwrap();
|
||||
match err {
|
||||
ConstEvalErrKind::ConstAccessesMutGlobal => ValTreeCreationError::NotReadOnly,
|
||||
_ => ValTreeCreationError::Other,
|
||||
}
|
||||
ValTreeCreationError::NonSupportedType | ValTreeCreationError::Other => Ok(None),
|
||||
}
|
||||
_ => ValTreeCreationError::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +53,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
|
|||
ty: Ty<'tcx>,
|
||||
) -> Option<mir::DestructuredConstant<'tcx>> {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let ecx = mk_eval_cx(tcx.tcx, tcx.span, param_env, CanAccessStatics::No);
|
||||
let ecx = mk_eval_cx(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No);
|
||||
let op = ecx.const_val_to_op(val, ty, None).ok()?;
|
||||
|
||||
// We go to `usize` as we cannot allocate anything bigger anyway.
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::{Abi, VariantIdx};
|
||||
|
||||
use super::eval_queries::{mk_eval_cx, op_to_const};
|
||||
use super::machine::CompileTimeEvalContext;
|
||||
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
|
||||
use crate::const_eval::CanAccessStatics;
|
||||
use crate::const_eval::CanAccessMutGlobal;
|
||||
use crate::errors::{MaxNumNodesInConstErr, MutableDataInConstErr};
|
||||
use crate::interpret::MPlaceTy;
|
||||
use crate::interpret::{
|
||||
intern_const_alloc_recursive, ImmTy, Immediate, InternKind, MemPlaceMeta, MemoryKind, PlaceTy,
|
||||
Projectable, Scalar,
|
||||
};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::{Abi, VariantIdx};
|
||||
|
||||
#[instrument(skip(ecx), level = "debug")]
|
||||
fn branches<'tcx>(
|
||||
|
@ -70,7 +73,7 @@ fn slice_branches<'tcx>(
|
|||
}
|
||||
|
||||
#[instrument(skip(ecx), level = "debug")]
|
||||
pub(crate) fn const_to_valtree_inner<'tcx>(
|
||||
fn const_to_valtree_inner<'tcx>(
|
||||
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
|
||||
place: &MPlaceTy<'tcx>,
|
||||
num_nodes: &mut usize,
|
||||
|
@ -88,9 +91,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
|||
Ok(ty::ValTree::zst())
|
||||
}
|
||||
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
|
||||
let Ok(val) = ecx.read_immediate(place) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
let val = ecx.read_immediate(place)?;
|
||||
let val = val.to_scalar();
|
||||
*num_nodes += 1;
|
||||
|
||||
|
@ -102,19 +103,17 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
|||
// equality at compile-time (see `ptr_guaranteed_cmp`).
|
||||
// However we allow those that are just integers in disguise.
|
||||
// First, get the pointer. Remember it might be wide!
|
||||
let Ok(val) = ecx.read_immediate(place) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
let val = ecx.read_immediate(place)?;
|
||||
// We could allow wide raw pointers where both sides are integers in the future,
|
||||
// but for now we reject them.
|
||||
if matches!(val.layout.abi, Abi::ScalarPair(..)) {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
return Err(ValTreeCreationError::NonSupportedType);
|
||||
}
|
||||
let val = val.to_scalar();
|
||||
// We are in the CTFE machine, so ptr-to-int casts will fail.
|
||||
// This can only be `Ok` if `val` already is an integer.
|
||||
let Ok(val) = val.try_to_int() else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
return Err(ValTreeCreationError::NonSupportedType);
|
||||
};
|
||||
// It's just a ScalarInt!
|
||||
Ok(ty::ValTree::Leaf(val))
|
||||
|
@ -125,11 +124,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
|||
ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType),
|
||||
|
||||
ty::Ref(_, _, _) => {
|
||||
let Ok(derefd_place)= ecx.deref_pointer(place) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
debug!(?derefd_place);
|
||||
|
||||
let derefd_place = ecx.deref_pointer(place)?;
|
||||
const_to_valtree_inner(ecx, &derefd_place, num_nodes)
|
||||
}
|
||||
|
||||
|
@ -153,9 +148,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
|||
bug!("uninhabited types should have errored and never gotten converted to valtree")
|
||||
}
|
||||
|
||||
let Ok(variant) = ecx.read_discriminant(place) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
let variant = ecx.read_discriminant(place)?;
|
||||
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
|
||||
}
|
||||
|
||||
|
@ -221,6 +214,59 @@ fn create_valtree_place<'tcx>(
|
|||
ecx.allocate_dyn(layout, MemoryKind::Stack, meta).unwrap()
|
||||
}
|
||||
|
||||
/// Evaluates a constant and turns it into a type-level constant value.
|
||||
pub(crate) fn eval_to_valtree<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
cid: GlobalId<'tcx>,
|
||||
) -> EvalToValTreeResult<'tcx> {
|
||||
let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?;
|
||||
|
||||
// FIXME Need to provide a span to `eval_to_valtree`
|
||||
let ecx = mk_eval_cx(
|
||||
tcx,
|
||||
DUMMY_SP,
|
||||
param_env,
|
||||
// It is absolutely crucial for soundness that
|
||||
// we do not read from mutable memory.
|
||||
CanAccessMutGlobal::No,
|
||||
);
|
||||
let place = ecx.raw_const_to_mplace(const_alloc).unwrap();
|
||||
debug!(?place);
|
||||
|
||||
let mut num_nodes = 0;
|
||||
let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
|
||||
|
||||
match valtree_result {
|
||||
Ok(valtree) => Ok(Some(valtree)),
|
||||
Err(err) => {
|
||||
let did = cid.instance.def_id();
|
||||
let global_const_id = cid.display(tcx);
|
||||
let span = tcx.hir().span_if_local(did);
|
||||
match err {
|
||||
ValTreeCreationError::NodesOverflow => {
|
||||
let handled =
|
||||
tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
|
||||
Err(handled.into())
|
||||
}
|
||||
ValTreeCreationError::NotReadOnly => {
|
||||
let handled =
|
||||
tcx.dcx().emit_err(MutableDataInConstErr { span, global_const_id });
|
||||
Err(handled.into())
|
||||
}
|
||||
ValTreeCreationError::Other => {
|
||||
let handled = tcx.dcx().span_delayed_bug(
|
||||
span.unwrap_or(DUMMY_SP),
|
||||
"unexpected error during valtree construction",
|
||||
);
|
||||
Err(handled.into())
|
||||
}
|
||||
ValTreeCreationError::NonSupportedType => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
|
||||
/// construction has finished.
|
||||
// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
|
||||
|
@ -253,7 +299,7 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
}
|
||||
}
|
||||
ty::Ref(_, inner_ty, _) => {
|
||||
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
|
||||
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
|
||||
let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty);
|
||||
let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap());
|
||||
op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
|
||||
|
@ -280,7 +326,7 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
bug!("could not find non-ZST field during in {layout:#?}");
|
||||
}
|
||||
|
||||
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
|
||||
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
|
||||
|
||||
// Need to create a place for this valtree.
|
||||
let place = create_valtree_place(&mut ecx, layout, valtree);
|
||||
|
|
|
@ -56,23 +56,11 @@ pub(crate) struct UnstableInStable {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_thread_local_access, code = E0625)]
|
||||
pub(crate) struct NonConstOpErr {
|
||||
pub(crate) struct ThreadLocalAccessErr {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_static_access, code = E0013)]
|
||||
#[help]
|
||||
pub(crate) struct StaticAccessErr {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub kind: ConstContext,
|
||||
#[note(const_eval_teach_note)]
|
||||
#[help(const_eval_teach_help)]
|
||||
pub teach: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_raw_ptr_to_int)]
|
||||
#[note]
|
||||
|
@ -129,6 +117,14 @@ pub(crate) struct MaxNumNodesInConstErr {
|
|||
pub global_const_id: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_mutable_data_in_const)]
|
||||
pub(crate) struct MutableDataInConstErr {
|
||||
#[primary_span]
|
||||
pub span: Option<Span>,
|
||||
pub global_const_id: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unallowed_fn_pointer_call)]
|
||||
pub(crate) struct UnallowedFnPointerCall {
|
||||
|
|
|
@ -132,7 +132,6 @@ pub enum CtfeValidationMode {
|
|||
/// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the
|
||||
/// case for the top-level allocation of a `const`, where this is fine because the allocation will be
|
||||
/// copied at each use site).
|
||||
/// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics).
|
||||
Const { allow_immutable_unsafe_cell: bool, allow_static_ptrs: bool },
|
||||
}
|
||||
|
||||
|
@ -146,13 +145,6 @@ impl CtfeValidationMode {
|
|||
}
|
||||
}
|
||||
|
||||
fn allow_static_ptrs(self) -> bool {
|
||||
match self {
|
||||
CtfeValidationMode::Static { .. } => true, // statics can point to statics
|
||||
CtfeValidationMode::Const { allow_static_ptrs, .. } => allow_static_ptrs,
|
||||
}
|
||||
}
|
||||
|
||||
fn may_contain_mutable_ref(self) -> bool {
|
||||
match self {
|
||||
CtfeValidationMode::Static { mutbl } => mutbl == Mutability::Mut,
|
||||
|
@ -468,13 +460,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
// Special handling for pointers to statics (irrespective of their type).
|
||||
assert!(!self.ecx.tcx.is_thread_local_static(did));
|
||||
assert!(self.ecx.tcx.is_static(did));
|
||||
if self.ctfe_mode.is_some_and(|c| !c.allow_static_ptrs()) {
|
||||
// See const_eval::machine::MemoryExtra::can_access_statics for why
|
||||
// this check is so important.
|
||||
// This check is reachable when the const just referenced the static,
|
||||
// but never read it (so we never entered `before_access_global`).
|
||||
throw_validation_failure!(self.path, PtrToStatic { ptr_kind });
|
||||
}
|
||||
// Mutability check.
|
||||
if ptr_expected_mutbl == Mutability::Mut {
|
||||
if matches!(
|
||||
|
|
|
@ -580,16 +580,21 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
|
|||
if let hir::ConstContext::Static(_) = ccx.const_kind() {
|
||||
Status::Allowed
|
||||
} else {
|
||||
Status::Forbidden
|
||||
Status::Unstable(sym::const_refs_to_static)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
ccx.dcx().create_err(errors::StaticAccessErr {
|
||||
let mut err = feature_err(
|
||||
&ccx.tcx.sess,
|
||||
sym::const_refs_to_static,
|
||||
span,
|
||||
kind: ccx.const_kind(),
|
||||
teach: ccx.tcx.sess.teach(E0013).then_some(()),
|
||||
})
|
||||
format!("referencing statics in {}s is unstable", ccx.const_kind(),),
|
||||
);
|
||||
err
|
||||
.note("`static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.")
|
||||
.help("to fix this, the value can be extracted to a `const` and then used.");
|
||||
err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,7 +603,7 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
|
|||
pub struct ThreadLocalAccess;
|
||||
impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
ccx.dcx().create_err(errors::NonConstOpErr { span })
|
||||
ccx.dcx().create_err(errors::ThreadLocalAccessErr { span })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use rustc_middle::ty::layout::LayoutOf;
|
|||
use rustc_span::symbol::Symbol;
|
||||
use rustc_type_ir::Mutability;
|
||||
|
||||
use crate::const_eval::{mk_eval_cx, CanAccessStatics, CompileTimeEvalContext};
|
||||
use crate::const_eval::{mk_eval_cx, CanAccessMutGlobal, CompileTimeEvalContext};
|
||||
use crate::interpret::*;
|
||||
|
||||
/// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
|
||||
|
@ -57,7 +57,7 @@ pub(crate) fn const_caller_location_provider(
|
|||
col: u32,
|
||||
) -> mir::ConstValue<'_> {
|
||||
trace!("const_caller_location: {}:{}:{}", file, line, col);
|
||||
let mut ecx = mk_eval_cx(tcx.tcx, tcx.span, ty::ParamEnv::reveal_all(), CanAccessStatics::No);
|
||||
let mut ecx = mk_eval_cx(tcx.tcx, tcx.span, ty::ParamEnv::reveal_all(), CanAccessMutGlobal::No);
|
||||
|
||||
let loc_place = alloc_caller_location(&mut ecx, file, line, col);
|
||||
if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
|
||||
|
|
|
@ -2,7 +2,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, Val
|
|||
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
|
||||
|
||||
use crate::const_eval::{CanAccessStatics, CheckAlignment, CompileTimeInterpreter};
|
||||
use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeInterpreter};
|
||||
use crate::interpret::{InterpCx, MemoryKind, OpTy};
|
||||
|
||||
/// Determines if this type permits "raw" initialization by just transmuting some memory into an
|
||||
|
@ -44,7 +44,7 @@ fn might_permit_raw_init_strict<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
kind: ValidityRequirement,
|
||||
) -> Result<bool, &'tcx LayoutError<'tcx>> {
|
||||
let machine = CompileTimeInterpreter::new(CanAccessStatics::No, CheckAlignment::Error);
|
||||
let machine = CompileTimeInterpreter::new(CanAccessMutGlobal::No, CheckAlignment::Error);
|
||||
|
||||
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue