const-eval: allow constants to refer to mutable/external memory, but reject such constants as patterns

This commit is contained in:
Ralf Jung
2025-05-12 13:34:46 +02:00
parent 8f21a5c92e
commit 492526548d
34 changed files with 349 additions and 258 deletions
+1 -5
View File
@@ -207,8 +207,6 @@ const_eval_long_running =
.label = the const evaluator is currently interpreting this expression
.help = the constant being evaluated
const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
const_eval_memory_exhausted =
tried to allocate more memory than available to compiler
@@ -437,9 +435,6 @@ const_eval_unwind_past_top =
## (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_const_ref_to_extern = {$front_matter}: encountered reference to `extern` static in `const`
const_eval_validation_const_ref_to_mutable = {$front_matter}: encountered reference to mutable memory in `const`
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)
@@ -479,6 +474,7 @@ const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid re
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_in_const = {$front_matter}: encountered mutable reference in `const` value
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_null_box = {$front_matter}: encountered a null box
@@ -26,13 +26,6 @@
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
const VALTREE_MAX_NODES: usize = 100000;
pub(crate) enum ValTreeCreationError<'tcx> {
NodesOverflow,
/// Values of this type, or this particular value, are not supported as valtrees.
NonSupportedType(Ty<'tcx>),
}
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError<'tcx>>;
#[instrument(skip(tcx), level = "debug")]
pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -1,17 +1,16 @@
use rustc_abi::{BackendRepr, FieldIdx, VariantIdx};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ReportedErrorInfo};
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError};
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, mir};
use rustc_span::DUMMY_SP;
use tracing::{debug, instrument, trace};
use super::VALTREE_MAX_NODES;
use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const};
use super::machine::CompileTimeInterpCx;
use super::{VALTREE_MAX_NODES, ValTreeCreationError, ValTreeCreationResult};
use crate::const_eval::CanAccessMutGlobal;
use crate::errors::MaxNumNodesInConstErr;
use crate::interpret::{
ImmTy, Immediate, InternKind, MPlaceTy, MemPlaceMeta, MemoryKind, PlaceTy, Projectable, Scalar,
intern_const_alloc_recursive,
@@ -24,7 +23,7 @@ fn branches<'tcx>(
field_count: usize,
variant: Option<VariantIdx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
) -> EvalToValTreeResult<'tcx> {
let place = match variant {
Some(variant) => ecx.project_downcast(place, variant).unwrap(),
None => place.clone(),
@@ -58,7 +57,7 @@ fn slice_branches<'tcx>(
ecx: &CompileTimeInterpCx<'tcx>,
place: &MPlaceTy<'tcx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
) -> EvalToValTreeResult<'tcx> {
let n = place.len(ecx).unwrap_or_else(|_| panic!("expected to use len of place {place:?}"));
let mut elems = Vec::with_capacity(n as usize);
@@ -76,7 +75,7 @@ fn const_to_valtree_inner<'tcx>(
ecx: &CompileTimeInterpCx<'tcx>,
place: &MPlaceTy<'tcx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
) -> EvalToValTreeResult<'tcx> {
let tcx = *ecx.tcx;
let ty = place.layout.ty;
debug!("ty kind: {:?}", ty.kind());
@@ -91,7 +90,7 @@ fn const_to_valtree_inner<'tcx>(
Ok(ty::ValTree::zst(tcx))
}
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
let val = ecx.read_immediate(place).unwrap();
let val = ecx.read_immediate(place).report_err()?;
let val = val.to_scalar_int().unwrap();
*num_nodes += 1;
@@ -113,7 +112,7 @@ 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 val = ecx.read_immediate(place).unwrap();
let val = ecx.read_immediate(place).report_err()?;
// We could allow wide raw pointers where both sides are integers in the future,
// but for now we reject them.
if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) {
@@ -134,7 +133,7 @@ fn const_to_valtree_inner<'tcx>(
ty::FnPtr(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
ty::Ref(_, _, _) => {
let derefd_place = ecx.deref_pointer(place).unwrap();
let derefd_place = ecx.deref_pointer(place).report_err()?;
const_to_valtree_inner(ecx, &derefd_place, num_nodes)
}
@@ -158,7 +157,7 @@ fn const_to_valtree_inner<'tcx>(
bug!("uninhabited types should have errored and never gotten converted to valtree")
}
let variant = ecx.read_discriminant(place).unwrap();
let variant = ecx.read_discriminant(place).report_err()?;
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
}
@@ -249,24 +248,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
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(Ok(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(ReportedErrorInfo::allowed_in_infallible(handled).into())
}
ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)),
}
}
}
const_to_valtree_inner(&ecx, &place, &mut num_nodes)
}
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
+2 -12
View File
@@ -92,14 +92,6 @@ pub(crate) struct PanicNonStrErr {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(const_eval_max_num_nodes_in_const)]
pub(crate) struct MaxNumNodesInConstErr {
#[primary_span]
pub span: Option<Span>,
pub global_const_id: String,
}
#[derive(Diagnostic)]
#[diag(const_eval_unallowed_fn_pointer_call)]
pub(crate) struct UnallowedFnPointerCall {
@@ -655,9 +647,8 @@ fn diagnostic_message(&self) -> DiagMessage {
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
PartialPointer => const_eval_validation_partial_pointer,
ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
ConstRefToExtern => const_eval_validation_const_ref_to_extern,
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
NullFnPtr => const_eval_validation_null_fn_ptr,
NeverVal => const_eval_validation_never_val,
NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
@@ -815,9 +806,8 @@ fn add_range_arg<G: EmissionGuarantee>(
err.arg("expected_dyn_type", expected_dyn_type.to_string());
}
NullPtr { .. }
| ConstRefToMutable
| ConstRefToExtern
| MutableRefToImmutable
| MutableRefInConst
| NullFnPtr
| NeverVal
| UnsafeCellInImmutable
@@ -570,6 +570,8 @@ fn check_safe_pointer(
};
let (size, _align) =
global_alloc.size_and_align(*self.ecx.tcx, self.ecx.typing_env);
let alloc_actual_mutbl =
global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env);
if let GlobalAlloc::Static(did) = global_alloc {
let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else {
@@ -597,9 +599,11 @@ fn check_safe_pointer(
skip_recursive_check = !nested;
}
CtfeValidationMode::Const { .. } => {
// We can't recursively validate `extern static`, so we better reject them.
if self.ecx.tcx.is_foreign_item(did) {
throw_validation_failure!(self.path, ConstRefToExtern);
// If this is mutable memory or an `extern static`, there's no point in checking it -- we'd
// just get errors trying to read the value.
if alloc_actual_mutbl.is_mut() || self.ecx.tcx.is_foreign_item(did)
{
skip_recursive_check = true;
}
}
}
@@ -618,9 +622,6 @@ fn check_safe_pointer(
mutbl
}
};
// Determine what it actually points to.
let alloc_actual_mutbl =
global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env);
// Mutable pointer to immutable memory is no good.
if ptr_expected_mutbl == Mutability::Mut
&& alloc_actual_mutbl == Mutability::Not
@@ -628,12 +629,10 @@ fn check_safe_pointer(
// This can actually occur with transmutes.
throw_validation_failure!(self.path, MutableRefToImmutable);
}
// In a const, everything must be completely immutable.
// In a const, any kind of mutable reference is not good.
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) {
if ptr_expected_mutbl == Mutability::Mut
|| alloc_actual_mutbl == Mutability::Mut
{
throw_validation_failure!(self.path, ConstRefToMutable);
if ptr_expected_mutbl == Mutability::Mut {
throw_validation_failure!(self.path, MutableRefInConst);
}
}
}
+7
View File
@@ -78,6 +78,11 @@ middle_erroneous_constant = erroneous constant encountered
middle_failed_writing_file =
failed to write file {$path}: {$error}"
# Note: We only mention patterns here since the error can only occur with references, and those
# are forbidden in const generics.
middle_invalid_const_in_valtree = constant {$global_const_id} cannot be used as pattern
.note = constants that reference mutable or external memory cannot be used as pattern
middle_layout_cycle =
a cycle occurred during layout computation
@@ -95,6 +100,8 @@ middle_layout_too_generic = the type `{$ty}` does not have a fixed layout
middle_layout_unknown =
the type `{$ty}` has an unknown layout
middle_max_num_nodes_in_valtree = maximum number of nodes exceeded in constant {$global_const_id}
middle_opaque_hidden_type_mismatch =
concrete type differs from previous defining opaque type use
.label = expected `{$self_ty}`, got `{$other_ty}`
+17
View File
@@ -170,3 +170,20 @@ pub(crate) struct TypeLengthLimit {
pub path: PathBuf,
pub type_length: usize,
}
#[derive(Diagnostic)]
#[diag(middle_max_num_nodes_in_valtree)]
pub(crate) struct MaxNumNodesInValtree {
#[primary_span]
pub span: Span,
pub global_const_id: String,
}
#[derive(Diagnostic)]
#[diag(middle_invalid_const_in_valtree)]
#[note]
pub(crate) struct InvalidConstInValtree {
#[primary_span]
pub span: Span,
pub global_const_id: String,
}
@@ -35,7 +35,7 @@ fn from(error: ReportedErrorInfo) -> ErrorHandled {
}
impl ErrorHandled {
pub fn with_span(self, span: Span) -> Self {
pub(crate) fn with_span(self, span: Span) -> Self {
match self {
ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span),
ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span),
@@ -94,14 +94,51 @@ fn from(val: ReportedErrorInfo) -> Self {
}
}
/// An error type for the `const_to_valtree` query. Some error should be reported with a "use-site span",
/// which means the query cannot emit the error, so those errors are represented as dedicated variants here.
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
pub enum ValTreeCreationError<'tcx> {
/// The constant is too big to be valtree'd.
NodesOverflow,
/// The constant references mutable or external memory, so it cannot be valtree'd.
InvalidConst,
/// Values of this type, or this particular value, are not supported as valtrees.
NonSupportedType(Ty<'tcx>),
/// The error has already been handled by const evaluation.
ErrorHandled(ErrorHandled),
}
impl<'tcx> From<ErrorHandled> for ValTreeCreationError<'tcx> {
fn from(err: ErrorHandled) -> Self {
ValTreeCreationError::ErrorHandled(err)
}
}
impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> {
fn from(err: InterpErrorInfo<'tcx>) -> Self {
// An error ocurred outside the const-eval query, as part of constructing the valtree. We
// don't currently preserve the details of this error, since `InterpErrorInfo` cannot be put
// into a query result and it can only be access of some mutable or external memory.
let (_kind, backtrace) = err.into_parts();
backtrace.print_backtrace();
ValTreeCreationError::InvalidConst
}
}
impl<'tcx> ValTreeCreationError<'tcx> {
pub(crate) fn with_span(self, span: Span) -> Self {
use ValTreeCreationError::*;
match self {
ErrorHandled(handled) => ErrorHandled(handled.with_span(span)),
other => other,
}
}
}
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>;
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed
/// because the value contains something of type `ty` that is not valtree-compatible.
/// The caller can then show an appropriate error; the query does not have the
/// necessary context to give good user-facing errors for this case.
pub type EvalToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
pub type EvalToValTreeResult<'tcx> = Result<ValTree<'tcx>, ValTreeCreationError<'tcx>>;
#[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8);
@@ -450,10 +487,9 @@ pub enum ValidationErrorKind<'tcx> {
ptr_kind: PointerKind,
ty: Ty<'tcx>,
},
ConstRefToMutable,
ConstRefToExtern,
MutableRefToImmutable,
UnsafeCellInImmutable,
MutableRefInConst,
NullFnPtr,
NeverVal,
NullablePtrOutOfRange {
@@ -38,8 +38,8 @@
EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind,
InterpErrorInfo, InterpErrorKind, InterpResult, InvalidMetaKind, InvalidProgramInfo,
MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo,
ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
ValidationErrorKind, interp_ok,
ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValTreeCreationError,
ValidationErrorInfo, ValidationErrorKind, interp_ok,
};
pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
pub use self::value::Scalar;
@@ -5,11 +5,11 @@
use tracing::{debug, instrument};
use super::{
ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId,
ReportedErrorInfo,
ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, GlobalId, ReportedErrorInfo,
};
use crate::mir;
use crate::ty::{self, GenericArgs, TyCtxt, TypeVisitableExt};
use crate::mir::interpret::ValTreeCreationError;
use crate::ty::{self, ConstToValTreeResult, GenericArgs, TyCtxt, TypeVisitableExt};
use crate::{error, mir};
impl<'tcx> TyCtxt<'tcx> {
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
@@ -92,7 +92,7 @@ pub fn const_eval_resolve_for_typeck(
typing_env: ty::TypingEnv<'tcx>,
ct: ty::UnevaluatedConst<'tcx>,
span: Span,
) -> EvalToValTreeResult<'tcx> {
) -> ConstToValTreeResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
// variables. We reject those here since `resolve`
// would fail otherwise.
@@ -103,47 +103,54 @@ pub fn const_eval_resolve_for_typeck(
bug!("did not expect inference variables here");
}
match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: None };
self.const_eval_global_id_for_typeck(typing_env, cid, span).inspect(|_| {
// We are emitting the lint here instead of in `is_const_evaluatable`
// as we normalize obligations before checking them, and normalization
// uses this function to evaluate this constant.
//
// @lcnr believes that successfully evaluating even though there are
// used generic parameters is a bug of evaluation, so checking for it
// here does feel somewhat sensible.
if !self.features().generic_const_exprs()
&& ct.args.has_non_region_param()
// We only FCW for anon consts as repeat expr counts with anon consts are the only place
// that we have a back compat hack for. We don't need to check this is a const argument
// as only anon consts as const args should get evaluated "for the type system".
//
// If we don't *only* FCW anon consts we can wind up incorrectly FCW'ing uses of assoc
// consts in pattern positions. #140447
&& self.def_kind(instance.def_id()) == DefKind::AnonConst
{
let mir_body = self.mir_for_ctfe(instance.def_id());
if mir_body.is_polymorphic {
let Some(local_def_id) = ct.def.as_local() else { return };
self.node_span_lint(
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
self.local_def_id_to_hir_id(local_def_id),
self.def_span(ct.def),
|lint| { lint.primary_message("cannot use constants which depend on generic parameters in types"); },
)
}
}
})
}
let cid = match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) {
Ok(Some(instance)) => GlobalId { instance, promoted: None },
// For errors during resolution, we deliberately do not point at the usage site of the constant,
// since for these errors the place the constant is used shouldn't matter.
Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
Ok(None) => return Err(ErrorHandled::TooGeneric(DUMMY_SP).into()),
Err(err) => {
Err(ErrorHandled::Reported(ReportedErrorInfo::non_const_eval_error(err), DUMMY_SP))
return Err(ErrorHandled::Reported(
ReportedErrorInfo::non_const_eval_error(err),
DUMMY_SP,
)
.into());
}
}
};
self.const_eval_global_id_for_typeck(typing_env, cid, span).inspect(|_| {
// We are emitting the lint here instead of in `is_const_evaluatable`
// as we normalize obligations before checking them, and normalization
// uses this function to evaluate this constant.
//
// @lcnr believes that successfully evaluating even though there are
// used generic parameters is a bug of evaluation, so checking for it
// here does feel somewhat sensible.
if !self.features().generic_const_exprs()
&& ct.args.has_non_region_param()
// We only FCW for anon consts as repeat expr counts with anon consts are the only place
// that we have a back compat hack for. We don't need to check this is a const argument
// as only anon consts as const args should get evaluated "for the type system".
//
// If we don't *only* FCW anon consts we can wind up incorrectly FCW'ing uses of assoc
// consts in pattern positions. #140447
&& self.def_kind(cid.instance.def_id()) == DefKind::AnonConst
{
let mir_body = self.mir_for_ctfe(cid.instance.def_id());
if mir_body.is_polymorphic {
let Some(local_def_id) = ct.def.as_local() else { return };
self.node_span_lint(
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
self.local_def_id_to_hir_id(local_def_id),
self.def_span(ct.def),
|lint| {
lint.primary_message(
"cannot use constants which depend on generic parameters in types",
);
},
)
}
}
})
}
pub fn const_eval_instance(
@@ -182,17 +189,42 @@ pub fn const_eval_global_id_for_typeck(
typing_env: ty::TypingEnv<'tcx>,
cid: GlobalId<'tcx>,
span: Span,
) -> EvalToValTreeResult<'tcx> {
) -> ConstToValTreeResult<'tcx> {
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs =
self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid));
debug!(?inputs);
if !span.is_dummy() {
let res = if !span.is_dummy() {
// The query doesn't know where it is being invoked, so we need to fix the span.
self.at(span).eval_to_valtree(inputs).map_err(|e| e.with_span(span))
} else {
self.eval_to_valtree(inputs)
};
match res {
Ok(valtree) => Ok(Ok(valtree)),
Err(err) => {
match err {
// Let the caller decide how to handle this.
ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)),
// Report the others.
ValTreeCreationError::NodesOverflow => {
let handled = self.dcx().emit_err(error::MaxNumNodesInValtree {
span,
global_const_id: cid.display(self),
});
Err(ReportedErrorInfo::allowed_in_infallible(handled).into())
}
ValTreeCreationError::InvalidConst => {
let handled = self.dcx().emit_err(error::InvalidConstInValtree {
span,
global_const_id: cid.display(self),
});
Err(ReportedErrorInfo::allowed_in_infallible(handled).into())
}
ValTreeCreationError::ErrorHandled(handled) => Err(handled),
}
}
}
}
}
+3 -4
View File
@@ -4,6 +4,7 @@
use rustc_span::ErrorGuaranteed;
use crate::mir::interpret::EvalToValTreeResult;
use crate::query::CyclePlaceholder;
use crate::ty::adjustment::CoerceUnsizedInfo;
use crate::ty::{self, Ty, TyCtxt};
@@ -156,10 +157,8 @@ impl EraseType for Result<mir::ConstValue<'_>, mir::interpret::ErrorHandled> {
type Result = [u8; size_of::<Result<mir::ConstValue<'static>, mir::interpret::ErrorHandled>>()];
}
impl EraseType for Result<Result<ty::ValTree<'_>, Ty<'_>>, mir::interpret::ErrorHandled> {
type Result = [u8; size_of::<
Result<Result<ty::ValTree<'static>, Ty<'static>>, mir::interpret::ErrorHandled>,
>()];
impl EraseType for EvalToValTreeResult<'_> {
type Result = [u8; size_of::<EvalToValTreeResult<'static>>()];
}
impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
@@ -5,7 +5,7 @@
use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use super::ScalarInt;
use crate::mir::interpret::Scalar;
use crate::mir::interpret::{ErrorHandled, Scalar};
use crate::ty::{self, Ty, TyCtxt};
/// This datastructure is used to represent the value of constants used in the type system.
@@ -124,6 +124,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed
/// because the value contains something of type `ty` that is not valtree-compatible.
/// The caller can then show an appropriate error; the query does not have the
/// necessary context to give good user-facing errors for this case.
pub type ConstToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
/// A type-level constant value.
///
/// Represents a typed, fully evaluated constant.
+2 -2
View File
@@ -75,8 +75,8 @@
place_to_string_for_capture,
};
pub use self::consts::{
AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt,
UnevaluatedConst, ValTree, ValTreeKind, Value,
AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, ConstToValTreeResult, Expr,
ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind, Value,
};
pub use self::context::{
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,
@@ -36,8 +36,8 @@
self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast,
};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_span::{DUMMY_SP, Span};
use tracing::{debug, instrument};
pub use self::coherence::{
@@ -644,7 +644,9 @@ pub fn try_evaluate_const<'tcx>(
let erased_uv = tcx.erase_regions(uv);
use rustc_middle::mir::interpret::ErrorHandled;
match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) {
// FIXME: `def_span` will point at the definition of this const; ideally, we'd point at
// where it gets used as a const generic.
match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, tcx.def_span(uv.def)) {
Ok(Ok(val)) => Ok(ty::Const::new_value(
tcx,
val,
@@ -28,6 +28,10 @@ pub const fn v21() -> v18 {}
impl<const v10: usize> v17<v10, v2> {
//~^ ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
//~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
//~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
//~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
//~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
//~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
pub const fn v21() -> v18 {
//~^ ERROR cannot find type `v18` in this scope
v18 { _p: () }
@@ -1,5 +1,5 @@
error[E0432]: unresolved import `v20::v13`
--> $DIR/unevaluated-const-ice-119731.rs:38:15
--> $DIR/unevaluated-const-ice-119731.rs:42:15
|
LL | pub use v20::{v13, v17};
| ^^^
@@ -23,7 +23,7 @@ LL | pub const fn v21() -> v18 {}
| ^^^ help: a type alias with a similar name exists: `v11`
error[E0412]: cannot find type `v18` in this scope
--> $DIR/unevaluated-const-ice-119731.rs:31:31
--> $DIR/unevaluated-const-ice-119731.rs:35:31
|
LL | pub type v11 = [[usize; v4]; v4];
| --------------------------------- similarly named type alias `v11` defined here
@@ -32,7 +32,7 @@ LL | pub const fn v21() -> v18 {
| ^^^ help: a type alias with a similar name exists: `v11`
error[E0422]: cannot find struct, variant or union type `v18` in this scope
--> $DIR/unevaluated-const-ice-119731.rs:33:13
--> $DIR/unevaluated-const-ice-119731.rs:37:13
|
LL | pub type v11 = [[usize; v4]; v4];
| --------------------------------- similarly named type alias `v11` defined here
@@ -86,6 +86,38 @@ LL | impl<const v10: usize> v17<v10, v2> {
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
--> $DIR/unevaluated-const-ice-119731.rs:28:37
|
LL | impl<const v10: usize> v17<v10, v2> {
| ^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
--> $DIR/unevaluated-const-ice-119731.rs:28:37
|
LL | impl<const v10: usize> v17<v10, v2> {
| ^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
--> $DIR/unevaluated-const-ice-119731.rs:28:37
|
LL | impl<const v10: usize> v17<v10, v2> {
| ^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
--> $DIR/unevaluated-const-ice-119731.rs:28:37
|
LL | impl<const v10: usize> v17<v10, v2> {
| ^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0592]: duplicate definitions with name `v21`
--> $DIR/unevaluated-const-ice-119731.rs:23:9
|
@@ -95,7 +127,7 @@ LL | pub const fn v21() -> v18 {}
LL | pub const fn v21() -> v18 {
| ------------------------- other definition for `v21`
error: aborting due to 10 previous errors; 2 warnings emitted
error: aborting due to 14 previous errors; 2 warnings emitted
Some errors have detailed explanations: E0412, E0422, E0425, E0432, E0592.
For more information about an error, try `rustc --explain E0412`.
@@ -16,7 +16,7 @@
const fn helper() -> Option<&'static mut i32> { unsafe {
Some(&mut *std::ptr::addr_of_mut!(BUFFER))
} }
const MUT: Option<&mut i32> = helper(); //~ ERROR encountered reference to mutable
const MUT: Option<&mut i32> = helper(); //~ ERROR encountered mutable reference
const fn helper_int2ptr() -> Option<&'static mut i32> { unsafe {
// Undefined behaviour (integer as pointer), who doesn't love tests like this.
@@ -1,4 +1,4 @@
error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered reference to mutable memory in `const`
error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered mutable reference in `const` value
--> $DIR/mut_ref_in_final_dynamic_check.rs:19:1
|
LL | const MUT: Option<&mut i32> = helper();
+8 -4
View File
@@ -11,13 +11,17 @@ LL | bytes: [u8; std::mem::size_of::<Foo>()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Foo`...
= note: ...which requires computing layout of `[u8; std::mem::size_of::<Foo>()]`...
= note: ...which requires normalizing `[u8; std::mem::size_of::<Foo>()]`...
note: ...which requires normalizing `[u8; std::mem::size_of::<Foo>()]`...
--> $DIR/const-size_of-cycle.rs:2:17
|
LL | bytes: [u8; std::mem::size_of::<Foo>()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires evaluating type-level constant, completing the cycle
note: cycle used when checking that `Foo` is well-formed
--> $DIR/const-size_of-cycle.rs:1:1
--> $DIR/const-size_of-cycle.rs:2:17
|
LL | struct Foo {
| ^^^^^^^^^^
LL | bytes: [u8; std::mem::size_of::<Foo>()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error: aborting due to 1 previous error
+5
View File
@@ -1,4 +1,5 @@
//@ run-pass
use std::sync::atomic::AtomicU32;
static S: i32 = 0;
static mut S_MUT: i32 = 0;
@@ -10,9 +11,13 @@
};
const C2: *const i32 = std::ptr::addr_of!(S_MUT);
static FOO: AtomicU32 = AtomicU32::new(0);
const NOT_VALID_AS_PATTERN: &'static AtomicU32 = &FOO;
fn main() {
assert_eq!(*C1, 0);
assert_eq!(unsafe { *C2 }, 0);
// Computing this pattern will read from an immutable static. That's fine.
assert!(matches!(&0, C1));
let _val = NOT_VALID_AS_PATTERN;
}
+13 -3
View File
@@ -9,13 +9,23 @@
static S: SyncUnsafeCell<i32> = SyncUnsafeCell::new(0);
static mut S_MUT: i32 = 0;
const C1: &SyncUnsafeCell<i32> = &S; //~ERROR encountered reference to mutable memory
const C1: &SyncUnsafeCell<i32> = &S;
const C1_READ: () = unsafe {
assert!(*C1.get() == 0);
assert!(*C1.get() == 0); //~ERROR constant accesses mutable global memory
};
const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) };
const C2_READ: () = unsafe {
assert!(*C2 == 0); //~ERROR constant accesses mutable global memory
};
fn main() {}
const BAD_PATTERN: &i32 = {
static mut S: i32 = 0;
unsafe { &mut S }
};
fn main() {
match &0 {
BAD_PATTERN => {}, //~ ERROR cannot be used as pattern
_ => {},
}
}
@@ -1,19 +1,8 @@
error[E0080]: constructing invalid value: encountered reference to mutable memory in `const`
--> $DIR/const_refs_to_static_fail.rs:12:1
|
LL | const C1: &SyncUnsafeCell<i32> = &S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= 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.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
note: erroneous constant encountered
--> $DIR/const_refs_to_static_fail.rs:14:14
error[E0080]: constant accesses mutable global memory
--> $DIR/const_refs_to_static_fail.rs:14:13
|
LL | assert!(*C1.get() == 0);
| ^^
| ^^^^^^^^^ evaluation of `C1_READ` failed here
error[E0080]: constant accesses mutable global memory
--> $DIR/const_refs_to_static_fail.rs:18:13
@@ -21,6 +10,14 @@ error[E0080]: constant accesses mutable global memory
LL | assert!(*C2 == 0);
| ^^^ evaluation of `C2_READ` failed here
error: aborting due to 2 previous errors
error: constant BAD_PATTERN cannot be used as pattern
--> $DIR/const_refs_to_static_fail.rs:28:9
|
LL | BAD_PATTERN => {},
| ^^^^^^^^^^^
|
= note: constants that reference mutable or external memory cannot be used as pattern
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0080`.
@@ -23,11 +23,10 @@ fn extern_() {
}
const C: &i8 = unsafe { &S };
//~^ERROR: `extern` static
// This must be rejected here (or earlier), since the pattern cannot be read.
match &0 {
C => {} // ok, `const` already emitted an error
C => {} //~ ERROR cannot be used as pattern
_ => {}
}
}
@@ -36,12 +35,11 @@ fn mutable() {
static mut S_MUT: i32 = 0;
const C: &i32 = unsafe { &S_MUT };
//~^ERROR: encountered reference to mutable memory
// This *must not build*, the constant we are matching against
// could change its value!
match &42 {
C => {} // ok, `const` already emitted an error
C => {} //~ ERROR cannot be used as pattern
_ => {}
}
}
@@ -9,27 +9,21 @@ LL | const C: &bool = unsafe { std::mem::transmute(&S) };
HEX_DUMP
}
error[E0080]: constructing invalid value: encountered reference to `extern` static in `const`
--> $DIR/const_refs_to_static_fail_invalid.rs:25:5
error: constant extern_::C cannot be used as pattern
--> $DIR/const_refs_to_static_fail_invalid.rs:29:9
|
LL | const C: &i8 = unsafe { &S };
| ^^^^^^^^^^^^ it is undefined behavior to use this value
LL | C => {}
| ^
|
= 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.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
= note: constants that reference mutable or external memory cannot be used as pattern
error[E0080]: constructing invalid value: encountered reference to mutable memory in `const`
--> $DIR/const_refs_to_static_fail_invalid.rs:38:5
error: constant mutable::C cannot be used as pattern
--> $DIR/const_refs_to_static_fail_invalid.rs:42:9
|
LL | const C: &i32 = unsafe { &S_MUT };
| ^^^^^^^^^^^^^ it is undefined behavior to use this value
LL | C => {}
| ^
|
= 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.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
= note: constants that reference mutable or external memory cannot be used as pattern
error: aborting due to 3 previous errors
@@ -9,6 +9,6 @@
static mut S: i32 = 3;
const C2: &'static mut i32 = unsafe { &mut S };
//~^ ERROR: reference to mutable memory
//~^ ERROR: encountered mutable reference
fn main() {}
@@ -4,7 +4,7 @@ error[E0764]: mutable references are not allowed in the final value of constants
LL | const C1: &'static mut [usize] = &mut [];
| ^^^^^^^
error[E0080]: constructing invalid value: encountered reference to mutable memory in `const`
error[E0080]: constructing invalid value: encountered mutable reference in `const` value
--> $DIR/issue-17718-const-bad-values.rs:11:1
|
LL | const C2: &'static mut i32 = unsafe { &mut S };
+8 -4
View File
@@ -11,13 +11,17 @@ LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Foo`...
= note: ...which requires computing layout of `[u8; unsafe { intrinsics::size_of::<Foo>() }]`...
= note: ...which requires normalizing `[u8; unsafe { intrinsics::size_of::<Foo>() }]`...
note: ...which requires normalizing `[u8; unsafe { intrinsics::size_of::<Foo>() }]`...
--> $DIR/issue-44415.rs:6:17
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires evaluating type-level constant, completing the cycle
note: cycle used when checking that `Foo` is well-formed
--> $DIR/issue-44415.rs:5:1
--> $DIR/issue-44415.rs:6:17
|
LL | struct Foo {
| ^^^^^^^^^^
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error: aborting due to 1 previous error
@@ -20,7 +20,7 @@
const READ_MUT: u32 = unsafe { MUTABLE }; //~ERROR constant accesses mutable global memory
// Evaluating this does not read anything mutable, but validation does, so this should error.
const REF_INTERIOR_MUT: &usize = { //~ ERROR encountered reference to mutable memory
const REF_INTERIOR_MUT: &usize = {
static FOO: AtomicUsize = AtomicUsize::new(0);
unsafe { &*(&FOO as *const _ as *const usize) }
};
@@ -30,6 +30,13 @@
const REF_IMMUT: &u8 = &MY_STATIC;
const READ_IMMUT: u8 = *REF_IMMUT;
fn foo() {
match &0 {
REF_INTERIOR_MUT => {}, //~ ERROR cannot be used as pattern
_ => {},
}
}
fn main() {}
//~? WARN skipping const checks
@@ -16,16 +16,13 @@ error[E0080]: constant accesses mutable global memory
LL | const READ_MUT: u32 = unsafe { MUTABLE };
| ^^^^^^^ evaluation of `READ_MUT` failed here
error[E0080]: constructing invalid value: encountered reference to mutable memory in `const`
--> $DIR/const_refers_to_static.rs:23:1
error: constant REF_INTERIOR_MUT cannot be used as pattern
--> $DIR/const_refers_to_static.rs:35:9
|
LL | const REF_INTERIOR_MUT: &usize = {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
LL | REF_INTERIOR_MUT => {},
| ^^^^^^^^^^^^^^^^
|
= 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.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
= note: constants that reference mutable or external memory cannot be used as pattern
warning: skipping const checks
|
@@ -11,18 +11,15 @@
// Sneaky: reference to a mutable static.
// Allowing this would be a disaster for pattern matching, we could violate exhaustiveness checking!
const SLICE_MUT: &[u8; 1] = {
//~^ ERROR encountered reference to mutable memory
unsafe { &static_cross_crate::ZERO }
};
const U8_MUT: &u8 = {
//~^ ERROR encountered reference to mutable memory
unsafe { &static_cross_crate::ZERO[0] }
};
// Also test indirection that reads from other static.
const U8_MUT2: &u8 = {
//~^ ERROR encountered reference to mutable memory
unsafe { &(*static_cross_crate::ZERO_REF)[0] }
};
const U8_MUT3: &u8 = {
@@ -37,14 +34,14 @@
pub fn test(x: &[u8; 1]) -> bool {
match x {
SLICE_MUT => true, // ok, `const` error already emitted
SLICE_MUT => true, //~ ERROR cannot be used as pattern
&[1..] => false,
}
}
pub fn test2(x: &u8) -> bool {
match x {
U8_MUT => true, // ok, `const` error already emitted
U8_MUT => true, //~ ERROR cannot be used as pattern
&(1..) => false,
}
}
@@ -53,7 +50,7 @@ pub fn test2(x: &u8) -> bool {
// the errors above otherwise stop compilation too early?
pub fn test3(x: &u8) -> bool {
match x {
U8_MUT2 => true, // ok, `const` error already emitted
U8_MUT2 => true, //~ ERROR cannot be used as pattern
&(1..) => false,
}
}
@@ -1,42 +1,33 @@
error[E0080]: constructing invalid value: encountered reference to mutable memory in `const`
--> $DIR/const_refers_to_static_cross_crate.rs:13:1
|
LL | const SLICE_MUT: &[u8; 1] = {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= 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.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error[E0080]: constructing invalid value: encountered reference to mutable memory in `const`
--> $DIR/const_refers_to_static_cross_crate.rs:18:1
|
LL | const U8_MUT: &u8 = {
| ^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= 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.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error[E0080]: constructing invalid value: encountered reference to mutable memory in `const`
--> $DIR/const_refers_to_static_cross_crate.rs:24:1
|
LL | const U8_MUT2: &u8 = {
| ^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= 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.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error[E0080]: constant accesses mutable global memory
--> $DIR/const_refers_to_static_cross_crate.rs:30:15
--> $DIR/const_refers_to_static_cross_crate.rs:27:15
|
LL | match static_cross_crate::OPT_ZERO {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `U8_MUT3` failed here
error: constant SLICE_MUT cannot be used as pattern
--> $DIR/const_refers_to_static_cross_crate.rs:37:9
|
LL | SLICE_MUT => true,
| ^^^^^^^^^
|
= note: constants that reference mutable or external memory cannot be used as pattern
error: constant U8_MUT cannot be used as pattern
--> $DIR/const_refers_to_static_cross_crate.rs:44:9
|
LL | U8_MUT => true,
| ^^^^^^
|
= note: constants that reference mutable or external memory cannot be used as pattern
error: constant U8_MUT2 cannot be used as pattern
--> $DIR/const_refers_to_static_cross_crate.rs:53:9
|
LL | U8_MUT2 => true,
| ^^^^^^^
|
= note: constants that reference mutable or external memory cannot be used as pattern
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0080`.
@@ -26,7 +26,7 @@
//~^ ERROR: pointing to read-only memory
const SUBTLE: &mut i32 = unsafe {
//~^ ERROR: constructing invalid value: encountered reference to mutable memory in `const`
//~^ ERROR: encountered mutable reference
static mut STATIC: i32 = 0;
&mut STATIC
};
@@ -65,7 +65,10 @@ unsafe impl Sync for Synced {}
// # Check for consts pointing to mutable memory
static mut MUTABLE: i32 = 42;
const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; //~ ERROR encountered reference to mutable memory
const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; // OK, as long as it is not used as a pattern.
// This fails since `&*MUTABLE_REF` is basically a copy of `MUTABLE_REF`, but we
// can't read from that static as it is mutable.
static mut MUTABLE_REF: &mut i32 = &mut 42;
const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
//~^ ERROR accesses mutable global memory
@@ -43,7 +43,7 @@ LL | const BLUNT: &mut i32 = &mut 42;
HEX_DUMP
}
error[E0080]: constructing invalid value: encountered reference to mutable memory in `const`
error[E0080]: constructing invalid value: encountered mutable reference in `const` value
--> $DIR/mutable_references.rs:28:1
|
LL | const SUBTLE: &mut i32 = unsafe {
@@ -98,49 +98,38 @@ LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const
HEX_DUMP
}
error[E0080]: constructing invalid value: encountered reference to mutable memory in `const`
--> $DIR/mutable_references.rs:68:1
|
LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= 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.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error[E0080]: constant accesses mutable global memory
--> $DIR/mutable_references.rs:70:43
--> $DIR/mutable_references.rs:73:43
|
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
| ^^^^^^^^^^^^^ evaluation of `POINTS_TO_MUTABLE2` failed here
error: encountered mutable pointer in final value of constant
--> $DIR/mutable_references.rs:73:1
--> $DIR/mutable_references.rs:76:1
|
LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: encountered mutable pointer in final value of constant
--> $DIR/mutable_references.rs:76:1
--> $DIR/mutable_references.rs:79:1
|
LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: encountered mutable pointer in final value of constant
--> $DIR/mutable_references.rs:96:1
--> $DIR/mutable_references.rs:99:1
|
LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: encountered mutable pointer in final value of constant
--> $DIR/mutable_references.rs:99:1
--> $DIR/mutable_references.rs:102:1
|
LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item
--> $DIR/mutable_references.rs:106:5
--> $DIR/mutable_references.rs:109:5
|
LL | *OH_YES = 99;
| ^^^^^^^^^^^^ cannot assign
@@ -188,37 +177,37 @@ help: skipping check that does not even have a feature gate
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:73:45
--> $DIR/mutable_references.rs:76:45
|
LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:76:46
--> $DIR/mutable_references.rs:79:46
|
LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:81:47
--> $DIR/mutable_references.rs:84:47
|
LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
| ^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:93:51
--> $DIR/mutable_references.rs:96:51
|
LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
| ^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:96:49
--> $DIR/mutable_references.rs:99:49
|
LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:99:51
--> $DIR/mutable_references.rs:102:51
|
LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
| ^^^^^^
error: aborting due to 17 previous errors; 1 warning emitted
error: aborting due to 16 previous errors; 1 warning emitted
Some errors have detailed explanations: E0080, E0594.
For more information about an error, try `rustc --explain E0080`.
@@ -64,10 +64,10 @@ LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
= note: ...which again requires evaluating type-level constant, completing the cycle
note: cycle used when checking that `accept0` is well-formed
--> $DIR/unsatisfied-const-trait-bound.rs:29:1
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error[E0391]: cycle detected when caching mir of `accept1::{constant#0}` for CTFE