From 492526548d8741ed477dbf9f0079ce59177e62b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 May 2025 13:34:46 +0200 Subject: [PATCH 1/3] const-eval: allow constants to refer to mutable/external memory, but reject such constants as patterns --- compiler/rustc_const_eval/messages.ftl | 6 +- .../rustc_const_eval/src/const_eval/mod.rs | 7 - .../src/const_eval/valtrees.rs | 38 ++---- compiler/rustc_const_eval/src/errors.rs | 14 +- .../src/interpret/validity.rs | 21 ++- compiler/rustc_middle/messages.ftl | 7 + compiler/rustc_middle/src/error.rs | 17 +++ .../rustc_middle/src/mir/interpret/error.rs | 52 ++++++-- .../rustc_middle/src/mir/interpret/mod.rs | 4 +- .../rustc_middle/src/mir/interpret/queries.rs | 120 +++++++++++------- compiler/rustc_middle/src/query/erase.rs | 7 +- .../rustc_middle/src/ty/consts/valtree.rs | 8 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- .../rustc_trait_selection/src/traits/mod.rs | 6 +- .../unevaluated-const-ice-119731.rs | 4 + .../unevaluated-const-ice-119731.stderr | 40 +++++- .../mut_ref_in_final_dynamic_check.rs | 2 +- .../mut_ref_in_final_dynamic_check.stderr | 2 +- tests/ui/consts/const-size_of-cycle.stderr | 12 +- tests/ui/consts/const_refs_to_static.rs | 5 + tests/ui/consts/const_refs_to_static_fail.rs | 16 ++- .../consts/const_refs_to_static_fail.stderr | 27 ++-- .../const_refs_to_static_fail_invalid.rs | 6 +- .../const_refs_to_static_fail_invalid.stderr | 26 ++-- .../ui/consts/issue-17718-const-bad-values.rs | 2 +- .../issue-17718-const-bad-values.stderr | 2 +- tests/ui/consts/issue-44415.stderr | 12 +- .../miri_unleashed/const_refers_to_static.rs | 9 +- .../const_refers_to_static.stderr | 13 +- .../const_refers_to_static_cross_crate.rs | 9 +- .../const_refers_to_static_cross_crate.stderr | 49 +++---- .../miri_unleashed/mutable_references.rs | 7 +- .../miri_unleashed/mutable_references.stderr | 39 ++---- .../unsatisfied-const-trait-bound.stderr | 4 +- 34 files changed, 344 insertions(+), 253 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 7f9abe8aa8e72..84b08a80cf08e 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -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 diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 6fd0b9d26e393..73cb1e774361d 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -26,13 +26,6 @@ pub(crate) use self::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<'tcx> { - NodesOverflow, - /// Values of this type, or this particular value, are not supported as valtrees. - NonSupportedType(Ty<'tcx>), -} -pub(crate) type ValTreeCreationResult<'tcx> = Result, ValTreeCreationError<'tcx>>; - #[instrument(skip(tcx), level = "debug")] pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 58d230af683ed..b3d2e1a0598e2 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -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, 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 diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 609749554cece..6f028791916fc 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -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, - pub global_const_id: String, -} - #[derive(Diagnostic)] #[diag(const_eval_unallowed_fn_pointer_call)] pub(crate) struct UnallowedFnPointerCall { @@ -655,9 +647,8 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { 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 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { err.arg("expected_dyn_type", expected_dyn_type.to_string()); } NullPtr { .. } - | ConstRefToMutable - | ConstRefToExtern | MutableRefToImmutable + | MutableRefInConst | NullFnPtr | NeverVal | UnsafeCellInImmutable diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 7d76d925ef23e..7e26b7f3d9629 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -570,6 +570,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { }; 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 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { 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 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { 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 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // 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); } } } diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 3d27e587b6cb4..0073deb18da29 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -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}` diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 6c6b12fed674f..f36ae83165319 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -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, +} diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 6ff3cac049b3a..41a166083d079 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -35,7 +35,7 @@ impl From for 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 @@ impl From for ErrorGuaranteed { } } +/// 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 for ValTreeCreationError<'tcx> { + fn from(err: ErrorHandled) -> Self { + ValTreeCreationError::ErrorHandled(err) + } +} + +impl<'tcx> From> 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, ErrorHandled>; pub type EvalStaticInitializerRawResult<'tcx> = Result, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result, 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, Ty<'tcx>>, ErrorHandled>; +pub type EvalToValTreeResult<'tcx> = Result, 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 { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index c2438af6a1e19..ea2f84d46d7f7 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -38,8 +38,8 @@ pub use self::error::{ 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; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 97db45a70d7fe..e25f35c59c286 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -5,11 +5,11 @@ use rustc_span::{DUMMY_SP, Span}; 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 @@ impl<'tcx> TyCtxt<'tcx> { 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 @@ impl<'tcx> TyCtxt<'tcx> { 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 @@ impl<'tcx> TyCtxt<'tcx> { 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), + } + } } } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 7c998761a9d44..26a31cb055ebe 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -4,6 +4,7 @@ use std::mem::MaybeUninit; 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::interpret::ErrorHandled> { type Result = [u8; size_of::, mir::interpret::ErrorHandled>>()]; } -impl EraseType for Result, Ty<'_>>, mir::interpret::ErrorHandled> { - type Result = [u8; size_of::< - Result, Ty<'static>>, mir::interpret::ErrorHandled>, - >()]; +impl EraseType for EvalToValTreeResult<'_> { + type Result = [u8; size_of::>()]; } impl EraseType for Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop> { diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 2f21d19e03c70..d95006dcf4a62 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -5,7 +5,7 @@ use rustc_data_structures::intern::Interned; 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 @@ impl fmt::Debug for ValTree<'_> { } } +/// `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, Ty<'tcx>>, ErrorHandled>; + /// A type-level constant value. /// /// Represents a typed, fully evaluated constant. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 97408e31854ae..40ea2a23a701b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -75,8 +75,8 @@ pub use self::closure::{ 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, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 999ef97683ca8..43806d3977b94 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -36,8 +36,8 @@ use rustc_middle::ty::{ 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, diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs index a55be99fc0be5..02a95ed3e9082 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs @@ -28,6 +28,10 @@ mod v20 { impl v17 { //~^ ERROR maximum number of nodes exceeded in constant v20::v17::::{constant#0} //~| ERROR maximum number of nodes exceeded in constant v20::v17::::{constant#0} + //~| ERROR maximum number of nodes exceeded in constant v20::v17::::{constant#0} + //~| ERROR maximum number of nodes exceeded in constant v20::v17::::{constant#0} + //~| ERROR maximum number of nodes exceeded in constant v20::v17::::{constant#0} + //~| ERROR maximum number of nodes exceeded in constant v20::v17::::{constant#0} pub const fn v21() -> v18 { //~^ ERROR cannot find type `v18` in this scope v18 { _p: () } diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr index b73611c79b291..cf0bdd0e9a150 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr @@ -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 v17 { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: maximum number of nodes exceeded in constant v20::v17::::{constant#0} + --> $DIR/unevaluated-const-ice-119731.rs:28:37 + | +LL | impl v17 { + | ^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: maximum number of nodes exceeded in constant v20::v17::::{constant#0} + --> $DIR/unevaluated-const-ice-119731.rs:28:37 + | +LL | impl v17 { + | ^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: maximum number of nodes exceeded in constant v20::v17::::{constant#0} + --> $DIR/unevaluated-const-ice-119731.rs:28:37 + | +LL | impl v17 { + | ^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: maximum number of nodes exceeded in constant v20::v17::::{constant#0} + --> $DIR/unevaluated-const-ice-119731.rs:28:37 + | +LL | impl v17 { + | ^^ + | + = 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`. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs index 2707e8a14ec38..1ae901f1653a8 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs @@ -16,7 +16,7 @@ static mut BUFFER: i32 = 42; 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. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr index 6456587b77a48..302e342bce61a 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at ..0: encountered reference to mutable memory in `const` +error[E0080]: constructing invalid value at ..0: encountered mutable reference in `const` value --> $DIR/mut_ref_in_final_dynamic_check.rs:19:1 | LL | const MUT: Option<&mut i32> = helper(); diff --git a/tests/ui/consts/const-size_of-cycle.stderr b/tests/ui/consts/const-size_of-cycle.stderr index bf17d76a092bf..b127f83d8853c 100644 --- a/tests/ui/consts/const-size_of-cycle.stderr +++ b/tests/ui/consts/const-size_of-cycle.stderr @@ -11,13 +11,17 @@ LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires computing layout of `[u8; std::mem::size_of::()]`... - = note: ...which requires normalizing `[u8; std::mem::size_of::()]`... +note: ...which requires normalizing `[u8; std::mem::size_of::()]`... + --> $DIR/const-size_of-cycle.rs:2:17 + | +LL | bytes: [u8; std::mem::size_of::()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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::()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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 diff --git a/tests/ui/consts/const_refs_to_static.rs b/tests/ui/consts/const_refs_to_static.rs index 3c59697e8eda4..187fab86a8948 100644 --- a/tests/ui/consts/const_refs_to_static.rs +++ b/tests/ui/consts/const_refs_to_static.rs @@ -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 C1_READ: () = { }; 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; } diff --git a/tests/ui/consts/const_refs_to_static_fail.rs b/tests/ui/consts/const_refs_to_static_fail.rs index b8bab91e005db..5bb9ca0a65e39 100644 --- a/tests/ui/consts/const_refs_to_static_fail.rs +++ b/tests/ui/consts/const_refs_to_static_fail.rs @@ -9,13 +9,23 @@ use std::cell::SyncUnsafeCell; static S: SyncUnsafeCell = SyncUnsafeCell::new(0); static mut S_MUT: i32 = 0; -const C1: &SyncUnsafeCell = &S; //~ERROR encountered reference to mutable memory +const C1: &SyncUnsafeCell = &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 + _ => {}, + } +} diff --git a/tests/ui/consts/const_refs_to_static_fail.stderr b/tests/ui/consts/const_refs_to_static_fail.stderr index 86d6c11dc0c31..c567b3e0ce1f4 100644 --- a/tests/ui/consts/const_refs_to_static_fail.stderr +++ b/tests/ui/consts/const_refs_to_static_fail.stderr @@ -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 = &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`. diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.rs b/tests/ui/consts/const_refs_to_static_fail_invalid.rs index 34ed8540f3fdc..229b9fdcc6027 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.rs +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.rs @@ -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 _ => {} } } diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr index 8a034aa00bc56..8be8b4bc50f50 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr @@ -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 diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index 40fc02cf64466..5abbebfa30c58 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -9,6 +9,6 @@ const C1: &'static mut [usize] = &mut []; static mut S: i32 = 3; const C2: &'static mut i32 = unsafe { &mut S }; -//~^ ERROR: reference to mutable memory +//~^ ERROR: encountered mutable reference fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index effb614b15bce..376ad2fef6ec6 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -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 }; diff --git a/tests/ui/consts/issue-44415.stderr b/tests/ui/consts/issue-44415.stderr index 641945fce9fd4..0e3f2e6199f76 100644 --- a/tests/ui/consts/issue-44415.stderr +++ b/tests/ui/consts/issue-44415.stderr @@ -11,13 +11,17 @@ LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires computing layout of `[u8; unsafe { intrinsics::size_of::() }]`... - = note: ...which requires normalizing `[u8; unsafe { intrinsics::size_of::() }]`... +note: ...which requires normalizing `[u8; unsafe { intrinsics::size_of::() }]`... + --> $DIR/issue-44415.rs:6:17 + | +LL | bytes: [u8; unsafe { intrinsics::size_of::() }], + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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::() }], + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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 diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static.rs index 6cc670943463b..eb78b5335cba9 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.rs @@ -20,7 +20,7 @@ static mut MUTABLE: u32 = 0; 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 @@ static MY_STATIC: u8 = 4; 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 diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr index eed3b4d906596..6b70a211a72cc 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -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 | diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs index 6c7e78356616c..cb093305429d4 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs @@ -11,18 +11,15 @@ extern crate static_cross_crate; // 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 @@ const U8_MUT3: &u8 = { 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, } } diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr index 8af3a1948f0f3..d753506cc94e3 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr @@ -1,41 +1,32 @@ -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 +error[E0080]: constant accesses mutable global memory + --> $DIR/const_refers_to_static_cross_crate.rs:27:15 | - = 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 - } +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `U8_MUT3` failed here -error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` - --> $DIR/const_refers_to_static_cross_crate.rs:18:1 +error: constant SLICE_MUT cannot be used as pattern + --> $DIR/const_refers_to_static_cross_crate.rs:37:9 | -LL | const U8_MUT: &u8 = { - | ^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value +LL | SLICE_MUT => true, + | ^^^^^^^^^ | - = 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_refers_to_static_cross_crate.rs:24:1 +error: constant U8_MUT cannot be used as pattern + --> $DIR/const_refers_to_static_cross_crate.rs:44:9 | -LL | const U8_MUT2: &u8 = { - | ^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value +LL | U8_MUT => true, + | ^^^^^^ | - = 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]: constant accesses mutable global memory - --> $DIR/const_refers_to_static_cross_crate.rs:30:15 +error: constant U8_MUT2 cannot be used as pattern + --> $DIR/const_refers_to_static_cross_crate.rs:53:9 | -LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `U8_MUT3` failed here +LL | U8_MUT2 => true, + | ^^^^^^^ + | + = note: constants that reference mutable or external memory cannot be used as pattern error: aborting due to 4 previous errors diff --git a/tests/ui/consts/miri_unleashed/mutable_references.rs b/tests/ui/consts/miri_unleashed/mutable_references.rs index 63d243f892cd0..2e95393ccbf56 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.rs +++ b/tests/ui/consts/miri_unleashed/mutable_references.rs @@ -26,7 +26,7 @@ const BLUNT: &mut i32 = &mut 42; //~^ 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 @@ static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as // # 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 diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index 22860e4f6d9b0..137efde44b312 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -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 = 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 = 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 = 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 = 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 = 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`. diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr index 03e26615d7edc..f5cadc9f1830f 100644 --- a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr +++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr @@ -64,10 +64,10 @@ LL | fn accept0(_: 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(_: 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 From ff17a225e6f0545d447546a12c520b932c9bcc88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 Jun 2025 22:47:25 +0900 Subject: [PATCH 2/3] add more sensible mut-ref-to-immutable test --- .../consts/const-mut-refs/mut_ref_in_final.rs | 2 ++ .../const-mut-refs/mut_ref_in_final.stderr | 27 +++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs index 28facc1888600..5306820dc9a5d 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs @@ -26,6 +26,8 @@ const B4: Option<&mut i32> = helper(&mut 42); //~ ERROR temporary value dropped // Not ok, since it points to read-only memory. const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; //~^ ERROR pointing to read-only memory +static IMMUT_MUT_REF_STATIC: &mut u16 = unsafe { mem::transmute(&13) }; +//~^ ERROR pointing to read-only memory // Ok, because no references to mutable data exist here, since the `{}` moves // its value and then takes a reference to that. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr index 122e5c1bdf0ae..a42ac8da678f2 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -31,8 +31,19 @@ LL | const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; HEX_DUMP } +error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory + --> $DIR/mut_ref_in_final.rs:29:1 + | +LL | static IMMUT_MUT_REF_STATIC: &mut u16 = unsafe { mem::transmute(&13) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:50:65 + --> $DIR/mut_ref_in_final.rs:52:65 | LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -42,7 +53,7 @@ LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a constant requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:53:67 + --> $DIR/mut_ref_in_final.rs:55:67 | LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -52,7 +63,7 @@ LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a static requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:56:71 + --> $DIR/mut_ref_in_final.rs:58:71 | LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -62,30 +73,30 @@ LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a static requires that borrow lasts for `'static` error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/mut_ref_in_final.rs:69:53 + --> $DIR/mut_ref_in_final.rs:71:53 | LL | static RAW_MUT_CAST_S: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/mut_ref_in_final.rs:71:54 + --> $DIR/mut_ref_in_final.rs:73:54 | LL | static RAW_MUT_COERCE_S: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/mut_ref_in_final.rs:73:52 + --> $DIR/mut_ref_in_final.rs:75:52 | LL | const RAW_MUT_CAST_C: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/mut_ref_in_final.rs:75:53 + --> $DIR/mut_ref_in_final.rs:77:53 | LL | const RAW_MUT_COERCE_C: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors Some errors have detailed explanations: E0080, E0716, E0764. For more information about an error, try `rustc --explain E0080`. From bade3fd0580815f1a5a4abd33244982dc458d54d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 Jun 2025 10:04:43 +0900 Subject: [PATCH 3/3] clarify and unify 'transient mutable borrow' errors --- compiler/rustc_const_eval/messages.ftl | 27 +++++++------------ .../src/check_consts/check.rs | 6 +---- .../rustc_const_eval/src/check_consts/ops.rs | 23 +++++----------- compiler/rustc_const_eval/src/errors.rs | 17 +++--------- tests/ui/consts/const-mut-refs/issue-76510.rs | 2 +- .../consts/const-mut-refs/issue-76510.stderr | 2 +- .../consts/const-mut-refs/mut_ref_in_final.rs | 14 +++++----- .../const-mut-refs/mut_ref_in_final.stderr | 12 ++++----- .../const-promoted-opaque.atomic.stderr | 4 +-- tests/ui/consts/const-promoted-opaque.rs | 2 +- .../ui/consts/issue-17718-const-bad-values.rs | 2 +- .../issue-17718-const-bad-values.stderr | 2 +- tests/ui/consts/issue-17718-const-borrow.rs | 6 ++--- .../ui/consts/issue-17718-const-borrow.stderr | 12 ++++----- tests/ui/consts/partial_qualif.rs | 2 +- tests/ui/consts/partial_qualif.stderr | 4 +-- tests/ui/consts/qualif_overwrite.rs | 2 +- tests/ui/consts/qualif_overwrite.stderr | 4 +-- tests/ui/consts/qualif_overwrite_2.rs | 2 +- tests/ui/consts/qualif_overwrite_2.stderr | 4 +-- tests/ui/consts/refs-to-cell-in-final.rs | 6 ++--- tests/ui/consts/refs-to-cell-in-final.stderr | 12 ++++----- .../ui/consts/write_to_static_via_mut_ref.rs | 2 +- .../consts/write_to_static_via_mut_ref.stderr | 2 +- tests/ui/error-codes/E0017.rs | 4 +-- tests/ui/error-codes/E0017.stderr | 4 +-- tests/ui/error-codes/E0492.stderr | 8 +++--- tests/ui/issues/issue-46604.rs | 2 +- tests/ui/issues/issue-46604.stderr | 2 +- .../ui/statics/check-immutable-mut-slices.rs | 2 +- .../statics/check-immutable-mut-slices.stderr | 2 +- 31 files changed, 83 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 84b08a80cf08e..97b154ad14235 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -124,12 +124,13 @@ const_eval_incompatible_return_types = const_eval_incompatible_types = calling a function with argument of type {$callee_ty} passing data of type {$caller_ty} -const_eval_interior_mutable_ref_escaping = - {const_eval_const_context}s cannot refer to interior mutable data - .label = this borrow of an interior mutable value may end up in the final value +const_eval_interior_mutable_borrow_escaping = + interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a {const_eval_const_context} are not allowed + .label = this borrow of an interior mutable value refers to a lifetime-extended temporary .help = to fix this, the value can be extracted to a separate `static` item and then referenced .teach_note = - References that escape into the final value of a constant or static must be immutable. + This creates a raw pointer to a temporary that has its lifetime extended to last for the entire program. + Lifetime-extended temporaries in constants and statics must be immutable. This is to avoid accidentally creating shared mutable state. @@ -213,25 +214,17 @@ const_eval_memory_exhausted = const_eval_modified_global = modifying a static's initial value from another static's initializer -const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} - -const_eval_mutable_raw_escaping = - raw mutable pointers are not allowed in the final value of {const_eval_const_context}s +const_eval_mutable_borrow_escaping = + mutable borrows of lifetime-extended temporaries in the top-level scope of a {const_eval_const_context} are not allowed .teach_note = - Pointers that escape into the final value of a constant or static must be immutable. + This creates a reference to a temporary that has its lifetime extended to last for the entire program. + Lifetime-extended temporaries in constants and statics must be immutable. This is to avoid accidentally creating shared mutable state. If you really want global mutable state, try using an interior mutable `static` or a `static mut`. -const_eval_mutable_ref_escaping = - mutable references are not allowed in the final value of {const_eval_const_context}s - .teach_note = - References that escape into the final value of a constant or static must be immutable. - This is to avoid accidentally creating shared mutable state. - - - If you really want global mutable state, try using an interior mutable `static` or a `static mut`. +const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 576b174369d46..c151e8acf9229 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -595,11 +595,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut); if !is_allowed && self.place_may_escape(place) { - self.check_op(ops::EscapingMutBorrow(if matches!(rvalue, Rvalue::Ref(..)) { - hir::BorrowKind::Ref - } else { - hir::BorrowKind::Raw - })); + self.check_op(ops::EscapingMutBorrow); } } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index f5b7a6066c8b7..02edff8f63294 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -567,7 +567,7 @@ impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow { DiagImportance::Secondary } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::InteriorMutableRefEscaping { + ccx.dcx().create_err(errors::InteriorMutableBorrowEscaping { span, opt_help: matches!(ccx.const_kind(), hir::ConstContext::Static(_)), kind: ccx.const_kind(), @@ -580,7 +580,7 @@ impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow { /// This op is for `&mut` borrows in the trailing expression of a constant /// which uses the "enclosing scopes rule" to leak its locals into anonymous /// static or const items. -pub(crate) struct EscapingMutBorrow(pub hir::BorrowKind); +pub(crate) struct EscapingMutBorrow; impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow { fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { @@ -594,20 +594,11 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow { } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - match self.0 { - hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::MutableRawEscaping { - span, - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0764), - }), - hir::BorrowKind::Ref | hir::BorrowKind::Pin => { - ccx.dcx().create_err(errors::MutableRefEscaping { - span, - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0764), - }) - } - } + ccx.dcx().create_err(errors::MutableBorrowEscaping { + span, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(E0764), + }) } } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 6f028791916fc..b2c3103c34af6 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -150,8 +150,8 @@ pub(crate) struct UnmarkedIntrinsicExposed { } #[derive(Diagnostic)] -#[diag(const_eval_mutable_ref_escaping, code = E0764)] -pub(crate) struct MutableRefEscaping { +#[diag(const_eval_mutable_borrow_escaping, code = E0764)] +pub(crate) struct MutableBorrowEscaping { #[primary_span] pub span: Span, pub kind: ConstContext, @@ -159,15 +159,6 @@ pub(crate) struct MutableRefEscaping { pub teach: bool, } -#[derive(Diagnostic)] -#[diag(const_eval_mutable_raw_escaping, code = E0764)] -pub(crate) struct MutableRawEscaping { - #[primary_span] - pub span: Span, - pub kind: ConstContext, - #[note(const_eval_teach_note)] - pub teach: bool, -} #[derive(Diagnostic)] #[diag(const_eval_non_const_fmt_macro_call, code = E0015)] pub(crate) struct NonConstFmtMacroCall { @@ -225,8 +216,8 @@ pub(crate) struct UnallowedInlineAsm { } #[derive(Diagnostic)] -#[diag(const_eval_interior_mutable_ref_escaping, code = E0492)] -pub(crate) struct InteriorMutableRefEscaping { +#[diag(const_eval_interior_mutable_borrow_escaping, code = E0492)] +pub(crate) struct InteriorMutableBorrowEscaping { #[primary_span] #[label] pub span: Span, diff --git a/tests/ui/consts/const-mut-refs/issue-76510.rs b/tests/ui/consts/const-mut-refs/issue-76510.rs index 6ebbd4e50f6df..3b248d77a6b9a 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.rs +++ b/tests/ui/consts/const-mut-refs/issue-76510.rs @@ -1,7 +1,7 @@ use std::mem::{transmute, ManuallyDrop}; const S: &'static mut str = &mut " hello "; -//~^ ERROR: mutable references are not allowed in the final value of constants +//~^ ERROR: mutable borrows of lifetime-extended temporaries const fn trigger() -> [(); unsafe { let s = transmute::<(*const u8, usize), &ManuallyDrop>((S.as_ptr(), 3)); diff --git a/tests/ui/consts/const-mut-refs/issue-76510.stderr b/tests/ui/consts/const-mut-refs/issue-76510.stderr index aff86e83578d7..6d5dac268e532 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.stderr +++ b/tests/ui/consts/const-mut-refs/issue-76510.stderr @@ -1,4 +1,4 @@ -error[E0764]: mutable references are not allowed in the final value of constants +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/issue-76510.rs:3:29 | LL | const S: &'static mut str = &mut " hello "; diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs index 5306820dc9a5d..2af92bd1b9d9d 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs @@ -12,13 +12,13 @@ const A: *const i32 = &4; // It could be made sound to allow it to compile, // but we do not want to allow this to compile, // as that would be an enormous footgun in oli-obk's opinion. -const B: *mut i32 = &mut 4; //~ ERROR mutable references are not allowed +const B: *mut i32 = &mut 4; //~ ERROR mutable borrows of lifetime-extended temporaries // Ok, no actual mutable allocation exists const B2: Option<&mut i32> = None; // Not ok, can't prove that no mutable allocation ends up in final value -const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR mutable references are not allowed +const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR mutable borrows of lifetime-extended temporaries const fn helper(x: &mut i32) -> Option<&mut i32> { Some(x) } const B4: Option<&mut i32> = helper(&mut 42); //~ ERROR temporary value dropped while borrowed @@ -29,7 +29,7 @@ const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; static IMMUT_MUT_REF_STATIC: &mut u16 = unsafe { mem::transmute(&13) }; //~^ ERROR pointing to read-only memory -// Ok, because no references to mutable data exist here, since the `{}` moves +// Ok, because no borrows of mutable data exist here, since the `{}` moves // its value and then takes a reference to that. const C: *const i32 = &{ let mut x = 42; @@ -69,13 +69,13 @@ unsafe impl Sync for SyncPtr {} // (This relies on `SyncPtr` being a curly brace struct.) // However, we intern the inner memory as read-only, so this must be rejected. static RAW_MUT_CAST_S: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; -//~^ ERROR mutable references are not allowed +//~^ ERROR mutable borrows of lifetime-extended temporaries static RAW_MUT_COERCE_S: SyncPtr = SyncPtr { x: &mut 0 }; -//~^ ERROR mutable references are not allowed +//~^ ERROR mutable borrows of lifetime-extended temporaries const RAW_MUT_CAST_C: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; -//~^ ERROR mutable references are not allowed +//~^ ERROR mutable borrows of lifetime-extended temporaries const RAW_MUT_COERCE_C: SyncPtr = SyncPtr { x: &mut 0 }; -//~^ ERROR mutable references are not allowed +//~^ ERROR mutable borrows of lifetime-extended temporaries fn main() { println!("{}", unsafe { *A }); diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr index a42ac8da678f2..a55ccf71bc4e9 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -1,10 +1,10 @@ -error[E0764]: mutable references are not allowed in the final value of constants +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/mut_ref_in_final.rs:15:21 | LL | const B: *mut i32 = &mut 4; | ^^^^^^ -error[E0764]: mutable references are not allowed in the final value of constants +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/mut_ref_in_final.rs:21:35 | LL | const B3: Option<&mut i32> = Some(&mut 42); @@ -72,25 +72,25 @@ LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | | creates a temporary value which is freed while still in use | using this value as a static requires that borrow lasts for `'static` -error[E0764]: mutable references are not allowed in the final value of statics +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed --> $DIR/mut_ref_in_final.rs:71:53 | LL | static RAW_MUT_CAST_S: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ -error[E0764]: mutable references are not allowed in the final value of statics +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed --> $DIR/mut_ref_in_final.rs:73:54 | LL | static RAW_MUT_COERCE_S: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ -error[E0764]: mutable references are not allowed in the final value of constants +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/mut_ref_in_final.rs:75:52 | LL | const RAW_MUT_CAST_C: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ -error[E0764]: mutable references are not allowed in the final value of constants +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/mut_ref_in_final.rs:77:53 | LL | const RAW_MUT_COERCE_C: SyncPtr = SyncPtr { x: &mut 0 }; diff --git a/tests/ui/consts/const-promoted-opaque.atomic.stderr b/tests/ui/consts/const-promoted-opaque.atomic.stderr index 9c0c969d586ce..337bfa4137a9e 100644 --- a/tests/ui/consts/const-promoted-opaque.atomic.stderr +++ b/tests/ui/consts/const-promoted-opaque.atomic.stderr @@ -7,11 +7,11 @@ LL | LL | }; | - value is dropped here -error[E0492]: constants cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/const-promoted-opaque.rs:36:19 | LL | const BAZ: &Foo = &FOO; - | ^^^^ this borrow of an interior mutable value may end up in the final value + | ^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary error[E0716]: temporary value dropped while borrowed --> $DIR/const-promoted-opaque.rs:40:26 diff --git a/tests/ui/consts/const-promoted-opaque.rs b/tests/ui/consts/const-promoted-opaque.rs index 188dacd100343..9ad2b108ca78a 100644 --- a/tests/ui/consts/const-promoted-opaque.rs +++ b/tests/ui/consts/const-promoted-opaque.rs @@ -34,7 +34,7 @@ const BAR: () = { }; const BAZ: &Foo = &FOO; -//[atomic]~^ ERROR: constants cannot refer to interior mutable data +//[atomic]~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries fn main() { let _: &'static _ = &FOO; diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index 5abbebfa30c58..ae101927fd4e7 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -5,7 +5,7 @@ #![allow(static_mut_refs)] const C1: &'static mut [usize] = &mut []; -//~^ ERROR: mutable references are not allowed +//~^ ERROR: mutable borrows of lifetime-extended temporaries static mut S: i32 = 3; const C2: &'static mut i32 = unsafe { &mut S }; diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index 376ad2fef6ec6..f0b02bdbc4554 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -1,4 +1,4 @@ -error[E0764]: mutable references are not allowed in the final value of constants +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/issue-17718-const-bad-values.rs:7:34 | LL | const C1: &'static mut [usize] = &mut []; diff --git a/tests/ui/consts/issue-17718-const-borrow.rs b/tests/ui/consts/issue-17718-const-borrow.rs index 89316dbd5c41a..541d27965f249 100644 --- a/tests/ui/consts/issue-17718-const-borrow.rs +++ b/tests/ui/consts/issue-17718-const-borrow.rs @@ -2,13 +2,13 @@ use std::cell::UnsafeCell; const A: UnsafeCell = UnsafeCell::new(1); const B: &'static UnsafeCell = &A; -//~^ ERROR: cannot refer to interior mutable +//~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries struct C { a: UnsafeCell } const D: C = C { a: UnsafeCell::new(1) }; const E: &'static UnsafeCell = &D.a; -//~^ ERROR: cannot refer to interior mutable +//~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries const F: &'static C = &D; -//~^ ERROR: cannot refer to interior mutable +//~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries fn main() {} diff --git a/tests/ui/consts/issue-17718-const-borrow.stderr b/tests/ui/consts/issue-17718-const-borrow.stderr index e3ff6c923ad7f..962a81e70b3e8 100644 --- a/tests/ui/consts/issue-17718-const-borrow.stderr +++ b/tests/ui/consts/issue-17718-const-borrow.stderr @@ -1,20 +1,20 @@ -error[E0492]: constants cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/issue-17718-const-borrow.rs:4:39 | LL | const B: &'static UnsafeCell = &A; - | ^^ this borrow of an interior mutable value may end up in the final value + | ^^ this borrow of an interior mutable value refers to a lifetime-extended temporary -error[E0492]: constants cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/issue-17718-const-borrow.rs:9:39 | LL | const E: &'static UnsafeCell = &D.a; - | ^^^^ this borrow of an interior mutable value may end up in the final value + | ^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary -error[E0492]: constants cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/issue-17718-const-borrow.rs:11:23 | LL | const F: &'static C = &D; - | ^^ this borrow of an interior mutable value may end up in the final value + | ^^ this borrow of an interior mutable value refers to a lifetime-extended temporary error: aborting due to 3 previous errors diff --git a/tests/ui/consts/partial_qualif.rs b/tests/ui/consts/partial_qualif.rs index 7c28b8b8a628e..6770e138eca0f 100644 --- a/tests/ui/consts/partial_qualif.rs +++ b/tests/ui/consts/partial_qualif.rs @@ -3,7 +3,7 @@ use std::cell::Cell; const FOO: &(Cell, bool) = { let mut a = (Cell::new(0), false); a.1 = true; // sets `qualif(a)` to `qualif(a) | qualif(true)` - &{a} //~ ERROR cannot refer to interior mutable + &{a} //~ ERROR interior mutable shared borrows of lifetime-extended temporaries }; fn main() {} diff --git a/tests/ui/consts/partial_qualif.stderr b/tests/ui/consts/partial_qualif.stderr index 05e0eeee13329..eb1a388ddee90 100644 --- a/tests/ui/consts/partial_qualif.stderr +++ b/tests/ui/consts/partial_qualif.stderr @@ -1,8 +1,8 @@ -error[E0492]: constants cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/partial_qualif.rs:6:5 | LL | &{a} - | ^^^^ this borrow of an interior mutable value may end up in the final value + | ^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary error: aborting due to 1 previous error diff --git a/tests/ui/consts/qualif_overwrite.rs b/tests/ui/consts/qualif_overwrite.rs index aae4e41ffd7ee..3b494caa2c118 100644 --- a/tests/ui/consts/qualif_overwrite.rs +++ b/tests/ui/consts/qualif_overwrite.rs @@ -7,7 +7,7 @@ use std::cell::Cell; const FOO: &Option> = { let mut a = Some(Cell::new(0)); a = None; // sets `qualif(a)` to `qualif(a) | qualif(None)` - &{a} //~ ERROR cannot refer to interior mutable + &{a} //~ ERROR interior mutable shared borrows of lifetime-extended temporaries }; fn main() {} diff --git a/tests/ui/consts/qualif_overwrite.stderr b/tests/ui/consts/qualif_overwrite.stderr index 976cf7bd79ebb..92430a89b9ed8 100644 --- a/tests/ui/consts/qualif_overwrite.stderr +++ b/tests/ui/consts/qualif_overwrite.stderr @@ -1,8 +1,8 @@ -error[E0492]: constants cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/qualif_overwrite.rs:10:5 | LL | &{a} - | ^^^^ this borrow of an interior mutable value may end up in the final value + | ^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary error: aborting due to 1 previous error diff --git a/tests/ui/consts/qualif_overwrite_2.rs b/tests/ui/consts/qualif_overwrite_2.rs index 1819d9a6d203d..e06fd3225539d 100644 --- a/tests/ui/consts/qualif_overwrite_2.rs +++ b/tests/ui/consts/qualif_overwrite_2.rs @@ -5,7 +5,7 @@ use std::cell::Cell; const FOO: &Option> = { let mut a = (Some(Cell::new(0)),); a.0 = None; // sets `qualif(a)` to `qualif(a) | qualif(None)` - &{a.0} //~ ERROR cannot refer to interior mutable + &{a.0} //~ ERROR interior mutable shared borrows of lifetime-extended temporaries }; fn main() {} diff --git a/tests/ui/consts/qualif_overwrite_2.stderr b/tests/ui/consts/qualif_overwrite_2.stderr index a107c4a5c6dbf..a994ab61ea7b3 100644 --- a/tests/ui/consts/qualif_overwrite_2.stderr +++ b/tests/ui/consts/qualif_overwrite_2.stderr @@ -1,8 +1,8 @@ -error[E0492]: constants cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/qualif_overwrite_2.rs:8:5 | LL | &{a.0} - | ^^^^^^ this borrow of an interior mutable value may end up in the final value + | ^^^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary error: aborting due to 1 previous error diff --git a/tests/ui/consts/refs-to-cell-in-final.rs b/tests/ui/consts/refs-to-cell-in-final.rs index 844b140cff2b5..28a26f8690919 100644 --- a/tests/ui/consts/refs-to-cell-in-final.rs +++ b/tests/ui/consts/refs-to-cell-in-final.rs @@ -11,9 +11,9 @@ unsafe impl Sync for SyncPtr {} // The resulting constant would pass all validation checks, so it is crucial that this gets rejected // by static const checks! static RAW_SYNC_S: SyncPtr> = SyncPtr { x: &Cell::new(42) }; -//~^ ERROR: cannot refer to interior mutable data +//~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries const RAW_SYNC_C: SyncPtr> = SyncPtr { x: &Cell::new(42) }; -//~^ ERROR: cannot refer to interior mutable data +//~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries // This one does not get promoted because of `Drop`, and then enters interesting codepaths because // as a value it has no interior mutability, but as a type it does. See @@ -39,7 +39,7 @@ const NONE_EXPLICIT_PROMOTED: &'static Option> = { // Not okay, since we are borrowing something with interior mutability. const INTERIOR_MUT_VARIANT: &Option> = &{ - //~^ERROR: cannot refer to interior mutable data + //~^ERROR: interior mutable shared borrows of lifetime-extended temporaries let mut x = None; assert!(x.is_none()); x = Some(UnsafeCell::new(false)); diff --git a/tests/ui/consts/refs-to-cell-in-final.stderr b/tests/ui/consts/refs-to-cell-in-final.stderr index 8d82d94f4126f..41f7a23852cad 100644 --- a/tests/ui/consts/refs-to-cell-in-final.stderr +++ b/tests/ui/consts/refs-to-cell-in-final.stderr @@ -1,18 +1,18 @@ -error[E0492]: statics cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed --> $DIR/refs-to-cell-in-final.rs:13:54 | LL | static RAW_SYNC_S: SyncPtr> = SyncPtr { x: &Cell::new(42) }; - | ^^^^^^^^^^^^^^ this borrow of an interior mutable value may end up in the final value + | ^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary | = help: to fix this, the value can be extracted to a separate `static` item and then referenced -error[E0492]: constants cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/refs-to-cell-in-final.rs:15:53 | LL | const RAW_SYNC_C: SyncPtr> = SyncPtr { x: &Cell::new(42) }; - | ^^^^^^^^^^^^^^ this borrow of an interior mutable value may end up in the final value + | ^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary -error[E0492]: constants cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/refs-to-cell-in-final.rs:41:57 | LL | const INTERIOR_MUT_VARIANT: &Option> = &{ @@ -23,7 +23,7 @@ LL | | assert!(x.is_none()); LL | | x = Some(UnsafeCell::new(false)); LL | | x LL | | }; - | |_^ this borrow of an interior mutable value may end up in the final value + | |_^ this borrow of an interior mutable value refers to a lifetime-extended temporary error: aborting due to 3 previous errors diff --git a/tests/ui/consts/write_to_static_via_mut_ref.rs b/tests/ui/consts/write_to_static_via_mut_ref.rs index 82ac85bd2509a..6d3ddf01a2d21 100644 --- a/tests/ui/consts/write_to_static_via_mut_ref.rs +++ b/tests/ui/consts/write_to_static_via_mut_ref.rs @@ -1,4 +1,4 @@ -static OH_NO: &mut i32 = &mut 42; //~ ERROR mutable references are not allowed +static OH_NO: &mut i32 = &mut 42; //~ ERROR mutable borrows of lifetime-extended temporaries fn main() { assert_eq!(*OH_NO, 42); *OH_NO = 43; //~ ERROR cannot assign to `*OH_NO`, as `OH_NO` is an immutable static diff --git a/tests/ui/consts/write_to_static_via_mut_ref.stderr b/tests/ui/consts/write_to_static_via_mut_ref.stderr index 63ef788032f3c..76926e6949177 100644 --- a/tests/ui/consts/write_to_static_via_mut_ref.stderr +++ b/tests/ui/consts/write_to_static_via_mut_ref.stderr @@ -1,4 +1,4 @@ -error[E0764]: mutable references are not allowed in the final value of statics +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed --> $DIR/write_to_static_via_mut_ref.rs:1:26 | LL | static OH_NO: &mut i32 = &mut 42; diff --git a/tests/ui/error-codes/E0017.rs b/tests/ui/error-codes/E0017.rs index 8c685aad0308b..52b81c8a09d55 100644 --- a/tests/ui/error-codes/E0017.rs +++ b/tests/ui/error-codes/E0017.rs @@ -5,12 +5,12 @@ static X: i32 = 1; const C: i32 = 2; static mut M: i32 = 3; -const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed +const CR: &'static mut i32 = &mut C; //~ ERROR mutable borrows of lifetime-extended temporaries //~| WARN taking a mutable static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR cannot borrow immutable static item `X` as mutable -static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed +static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable borrows of lifetime-extended temporaries //~| WARN taking a mutable fn main() {} diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr index 285d363592f8b..b1a94ca3e9da0 100644 --- a/tests/ui/error-codes/E0017.stderr +++ b/tests/ui/error-codes/E0017.stderr @@ -13,7 +13,7 @@ LL | const C: i32 = 2; | ^^^^^^^^^^^^ = note: `#[warn(const_item_mutation)]` on by default -error[E0764]: mutable references are not allowed in the final value of constants +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/E0017.rs:8:30 | LL | const CR: &'static mut i32 = &mut C; @@ -39,7 +39,7 @@ note: `const` item defined here LL | const C: i32 = 2; | ^^^^^^^^^^^^ -error[E0764]: mutable references are not allowed in the final value of statics +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed --> $DIR/E0017.rs:13:38 | LL | static CONST_REF: &'static mut i32 = &mut C; diff --git a/tests/ui/error-codes/E0492.stderr b/tests/ui/error-codes/E0492.stderr index 557c977e87d9c..fbbcf8f7d9285 100644 --- a/tests/ui/error-codes/E0492.stderr +++ b/tests/ui/error-codes/E0492.stderr @@ -1,14 +1,14 @@ -error[E0492]: constants cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed --> $DIR/E0492.rs:4:33 | LL | const B: &'static AtomicUsize = &A; - | ^^ this borrow of an interior mutable value may end up in the final value + | ^^ this borrow of an interior mutable value refers to a lifetime-extended temporary -error[E0492]: statics cannot refer to interior mutable data +error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed --> $DIR/E0492.rs:5:34 | LL | static C: &'static AtomicUsize = &A; - | ^^ this borrow of an interior mutable value may end up in the final value + | ^^ this borrow of an interior mutable value refers to a lifetime-extended temporary | = help: to fix this, the value can be extracted to a separate `static` item and then referenced diff --git a/tests/ui/issues/issue-46604.rs b/tests/ui/issues/issue-46604.rs index 6ec6e7bdcb81e..03960941b2e5f 100644 --- a/tests/ui/issues/issue-46604.rs +++ b/tests/ui/issues/issue-46604.rs @@ -1,4 +1,4 @@ -static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR mutable references are not allowed +static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR mutable borrows of lifetime-extended temporaries fn write>(buffer: T) { } fn main() { diff --git a/tests/ui/issues/issue-46604.stderr b/tests/ui/issues/issue-46604.stderr index 7faa2d79ba483..f00f3f0d23fe6 100644 --- a/tests/ui/issues/issue-46604.stderr +++ b/tests/ui/issues/issue-46604.stderr @@ -1,4 +1,4 @@ -error[E0764]: mutable references are not allowed in the final value of statics +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed --> $DIR/issue-46604.rs:1:25 | LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; diff --git a/tests/ui/statics/check-immutable-mut-slices.rs b/tests/ui/statics/check-immutable-mut-slices.rs index 8f9680778aa03..9e5ca5059d6a8 100644 --- a/tests/ui/statics/check-immutable-mut-slices.rs +++ b/tests/ui/statics/check-immutable-mut-slices.rs @@ -1,6 +1,6 @@ // Checks that immutable static items can't have mutable slices static TEST: &'static mut [isize] = &mut []; -//~^ ERROR mutable references are not allowed +//~^ ERROR mutable borrows of lifetime-extended temporaries pub fn main() { } diff --git a/tests/ui/statics/check-immutable-mut-slices.stderr b/tests/ui/statics/check-immutable-mut-slices.stderr index 5cb35a7c21eb6..3552175565040 100644 --- a/tests/ui/statics/check-immutable-mut-slices.stderr +++ b/tests/ui/statics/check-immutable-mut-slices.stderr @@ -1,4 +1,4 @@ -error[E0764]: mutable references are not allowed in the final value of statics +error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed --> $DIR/check-immutable-mut-slices.rs:3:37 | LL | static TEST: &'static mut [isize] = &mut [];