diff --git a/compiler/rustc_error_codes/src/error_codes/E0492.md b/compiler/rustc_error_codes/src/error_codes/E0492.md index 1caa59999ae1e..30235b0aeb0b3 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0492.md +++ b/compiler/rustc_error_codes/src/error_codes/E0492.md @@ -3,10 +3,11 @@ A borrow of a constant containing interior mutability was attempted. Erroneous code example: ```compile_fail,E0492 +#![feature(const_refs_to_cell)] use std::sync::atomic::AtomicUsize; const A: AtomicUsize = AtomicUsize::new(0); -static B: &'static AtomicUsize = &A; +const B: &'static AtomicUsize = &A; // error: cannot borrow a constant which may contain interior mutability, // create a static instead ``` @@ -18,7 +19,7 @@ can't be changed via a shared `&` pointer, but interior mutability would allow it. That is, a constant value could be mutated. On the other hand, a `static` is explicitly a single memory location, which can be mutated at will. -So, in order to solve this error, either use statics which are `Sync`: +So, in order to solve this error, use statics which are `Sync`: ``` use std::sync::atomic::AtomicUsize; @@ -30,6 +31,7 @@ static B: &'static AtomicUsize = &A; // ok! You can also have this error while using a cell type: ```compile_fail,E0492 +#![feature(const_refs_to_cell)] use std::cell::Cell; const A: Cell = Cell::new(1); diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 845e03150d71a..54c3e6451e6c2 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -623,6 +623,9 @@ declare_features! ( /// Allows arbitrary expressions in key-value attributes at parse time. (active, extended_key_value_attributes, "1.50.0", Some(78835), None), + /// Allows references to types with interior mutability within constants + (active, const_refs_to_cell, "1.51.0", Some(80384), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 598e28c1a3ab0..a76de89933bee 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -697,6 +697,7 @@ impl<'hir> Map<'hir> { | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(..), .. }) | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(..), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(..), .. }) + | Node::AnonConst(..) | Node::Block(_) = node { return Some(hir_id); diff --git a/compiler/rustc_mir/src/dataflow/framework/fmt.rs b/compiler/rustc_mir/src/dataflow/framework/fmt.rs index 0140a75054433..12c6ae27581d1 100644 --- a/compiler/rustc_mir/src/dataflow/framework/fmt.rs +++ b/compiler/rustc_mir/src/dataflow/framework/fmt.rs @@ -33,7 +33,7 @@ pub trait DebugWithContext: Eq + fmt::Debug { } write!(f, "\u{001f}-")?; - self.fmt_with(ctxt, f) + old.fmt_with(ctxt, f) } } @@ -133,6 +133,28 @@ where } } +impl DebugWithContext for rustc_index::vec::IndexVec +where + T: Idx + DebugWithContext, + V: DebugWithContext + Eq, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set() + .entries(self.iter_enumerated().map(|this| DebugWithAdapter { this, ctxt })) + .finish() + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + assert_eq!(self.len(), old.len()); + + for (new, old) in self.iter_enumerated().zip(old.iter_enumerated()) { + write!(f, "{:?}", DebugDiffWithAdapter { new, old, ctxt })?; + } + + Ok(()) + } +} + impl DebugWithContext for &'_ T where T: DebugWithContext, @@ -146,6 +168,40 @@ where } } +impl DebugWithContext for Option +where + T: DebugWithContext, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + None => Ok(()), + Some(v) => v.fmt_with(ctxt, f), + } + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match (self, old) { + (None, None) => Ok(()), + (Some(a), Some(b)) => a.fmt_diff_with(b, ctxt, f), + (Some(a), None) => { + write!(f, "\u{001f}+")?; + a.fmt_with(ctxt, f) + } + (None, Some(b)) => { + write!(f, "\u{001f}-")?; + b.fmt_with(ctxt, f) + } + } + } +} + +impl DebugWithContext for (T, U) +where + T: DebugWithContext, + U: DebugWithContext, +{ +} + impl DebugWithContext for rustc_middle::mir::Local {} impl DebugWithContext for crate::dataflow::move_paths::InitIndex {} diff --git a/compiler/rustc_mir/src/dataflow/framework/lattice.rs b/compiler/rustc_mir/src/dataflow/framework/lattice.rs index e7ef9267db5e5..1d7bec3ebdad0 100644 --- a/compiler/rustc_mir/src/dataflow/framework/lattice.rs +++ b/compiler/rustc_mir/src/dataflow/framework/lattice.rs @@ -89,6 +89,34 @@ impl JoinSemiLattice for bool { } } +/// Just for completion, we implement `JoinSemiLattice` for `()`, where top and bottom are +/// the same value. +impl JoinSemiLattice for () { + fn join(&mut self, _: &Self) -> bool { + false + } +} + +/// An `Option` is a "two-point" lattice with `Some as the top element and `None` as the bottom: +/// +/// ```text +/// Some(T) +/// | +/// None +/// ``` +impl JoinSemiLattice for Option { + fn join(&mut self, other: &Self) -> bool { + match (self, other) { + (None, None) | (Some(_), None) => false, + (this @ None, Some(val)) => { + *this = Some(val.clone()); + true + } + (Some(a), Some(b)) => a.join(b), + } + } +} + impl MeetSemiLattice for bool { fn meet(&mut self, other: &Self) -> bool { if let (true, false) = (*self, *other) { diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index ba7bea4ac54e1..9044451d54815 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -11,7 +11,7 @@ use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; -pub use self::qualifs::Qualif; +pub(super) use self::qualifs::Qualif; mod ops; pub mod post_drop_elaboration; diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index d2e65abfbc7ee..1ee6615f6f000 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -208,9 +208,29 @@ impl NonConstOp for LiveDrop { } } +#[derive(Debug)] +pub struct CellBorrowBehindRef; +impl NonConstOp for CellBorrowBehindRef { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_refs_to_cell) + } + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_refs_to_cell, + span, + "cannot borrow here, since the borrowed element may contain interior mutability", + ) + } +} + #[derive(Debug)] pub struct CellBorrow; impl NonConstOp for CellBorrow { + fn importance(&self) -> DiagnosticImportance { + // The problematic cases will already emit a `CellBorrowBehindRef` + DiagnosticImportance::Secondary + } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { struct_span_err!( ccx.tcx.sess, diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index 1a2d932ba1905..c737467c5674a 100644 --- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -78,7 +78,7 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> { match &terminator.kind { mir::TerminatorKind::Drop { place: dropped_place, .. } => { let dropped_ty = dropped_place.ty(self.body, self.tcx).ty; - if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) { + if NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty).is_none() { return; } @@ -87,7 +87,7 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> { return; } - if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) { + if self.qualifs.needs_drop(self.ccx, dropped_place.local, location).is_some() { // Use the span where the dropped local was declared for the error. let span = self.body.local_decls[dropped_place.local].source_info.span; self.check_live_drop(span); diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs index c66d3ed76df90..b9ef704c62081 100644 --- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs @@ -2,7 +2,10 @@ //! //! See the `Qualif` trait for more info. +use crate::dataflow::{fmt::DebugWithContext, JoinSemiLattice}; use rustc_errors::ErrorReported; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_span::DUMMY_SP; @@ -16,9 +19,9 @@ pub fn in_any_value_of_ty( error_occured: Option, ) -> ConstQualifs { ConstQualifs { - has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty), - needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty), - custom_eq: CustomEq::in_any_value_of_ty(cx, ty), + has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty).is_some(), + needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty).is_some(), + custom_eq: CustomEq::in_any_value_of_ty(cx, ty).is_some(), error_occured, } } @@ -34,15 +37,21 @@ pub fn in_any_value_of_ty( /// To accomplish this, const-checking and promotion use a value-based analysis (as opposed to a /// type-based one). Qualifications propagate structurally across variables: If a local (or a /// projection of a local) is assigned a qualifed value, that local itself becomes qualifed. -pub trait Qualif { +pub(crate) trait Qualif { /// The name of the file used to debug the dataflow analysis that computes this qualif. const ANALYSIS_NAME: &'static str; + /// The dataflow result type. If it's just qualified/not qualified, then + /// you can just use a `()` (most qualifs do that). But if you need more state, use a + /// custom enum. + type Result: SetChoice + std::fmt::Debug = (); + type Set: QualifsPerLocal = ::Set; + /// Whether this `Qualif` is cleared when a local is moved from. const IS_CLEARED_ON_MOVE: bool = false; /// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`. - fn in_qualifs(qualifs: &ConstQualifs) -> bool; + fn in_qualifs(qualifs: &ConstQualifs) -> Option; /// Returns `true` if *any* value of the given type could possibly have this `Qualif`. /// @@ -51,7 +60,17 @@ pub trait Qualif { /// from a call to another function. /// /// It also determines the `Qualif`s for primitive types. - fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool; + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> Option; + + /// Sometimes const fn calls cannot possibly contain the qualif, so we can treat function + /// calls special here. + fn in_any_function_call( + cx: &ConstCx<'_, 'tcx>, + ty: Ty<'tcx>, + _args: Option, + ) -> Option { + Self::in_any_value_of_ty(cx, ty) + } /// Returns `true` if this `Qualif` is inherent to the given struct or enum. /// @@ -65,7 +84,65 @@ pub trait Qualif { cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, substs: SubstsRef<'tcx>, - ) -> bool; + ) -> Option; + + fn in_value_behind_ref(qualif: Option) -> Option { + qualif + } +} + +pub(crate) trait SetChoice: Sized + Clone + JoinSemiLattice { + type Set: QualifsPerLocal = IndexVec>; +} + +impl SetChoice for () { + type Set = BitSet; +} + +pub(crate) trait QualifsPerLocal: Sized + Clone + JoinSemiLattice { + fn new_empty(n: usize) -> Self; + fn insert(&mut self, local: Local, val: Value); + fn remove(&mut self, local: Local); + fn clear(&mut self); + fn get(&self, local: Local) -> Option; +} + +impl QualifsPerLocal<()> for BitSet { + fn new_empty(n: usize) -> Self { + BitSet::new_empty(n) + } + fn insert(&mut self, local: Local, _: ()) { + BitSet::insert(self, local); + } + fn remove(&mut self, local: Local) { + BitSet::remove(self, local); + } + fn clear(&mut self) { + BitSet::clear(self) + } + fn get(&self, local: Local) -> Option<()> { + self.contains(local).then_some(()) + } +} + +impl QualifsPerLocal for IndexVec> { + fn new_empty(n: usize) -> Self { + IndexVec::from_elem_n(None, n) + } + fn insert(&mut self, local: Local, val: T) { + self[local].join(&Some(val)); + } + fn remove(&mut self, local: Local) { + self[local] = None; + } + fn clear(&mut self) { + for elem in self.iter_mut() { + *elem = None; + } + } + fn get(&self, local: Local) -> Option { + self[local].clone() + } } /// Constant containing interior mutability (`UnsafeCell`). @@ -78,18 +155,102 @@ pub struct HasMutInterior; impl Qualif for HasMutInterior { const ANALYSIS_NAME: &'static str = "flow_has_mut_interior"; - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.has_mut_interior + fn in_qualifs(qualifs: &ConstQualifs) -> Option<()> { + qualifs.has_mut_interior.then_some(()) } - fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> Option<()> { + (!ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)).then_some(()) } - fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool { + fn in_adt_inherently( + cx: &ConstCx<'_, 'tcx>, + adt: &'tcx AdtDef, + _: SubstsRef<'tcx>, + ) -> Option<()> { // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently. // It arises structurally for all other types. - Some(adt.did) == cx.tcx.lang_items().unsafe_cell_type() + (Some(adt.did) == cx.tcx.lang_items().unsafe_cell_type()).then_some(()) + } +} + +/// Constant containing interior mutability (`UnsafeCell`) behind a reference. +/// This must be ruled out to make sure that evaluating the constant at compile-time +/// and at *any point* during the run-time would produce the same result. In particular, +/// promotion of temporaries must not change program behavior; if the promoted could be +/// written to, that would be a problem. +pub struct HasMutInteriorBehindRef; + +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum HasMutInteriorBehindRefState { + Yes, + /// As long as we haven't encountered a reference yet, we use this state + /// which is equivalent to the `HasMutInterior` qualif. + OnlyHasMutInterior, +} +impl SetChoice for HasMutInteriorBehindRefState {} +impl DebugWithContext for HasMutInteriorBehindRefState {} + +impl JoinSemiLattice for HasMutInteriorBehindRefState { + fn join(&mut self, other: &Self) -> bool { + match (&self, other) { + (Self::Yes, _) => false, + (Self::OnlyHasMutInterior, Self::Yes) => { + *self = Self::Yes; + true + } + (Self::OnlyHasMutInterior, Self::OnlyHasMutInterior) => false, + } + } +} + +impl Qualif for HasMutInteriorBehindRef { + const ANALYSIS_NAME: &'static str = "flow_has_mut_interior_behind_ref"; + type Result = HasMutInteriorBehindRefState; + + fn in_qualifs(qualifs: &ConstQualifs) -> Option { + HasMutInterior::in_qualifs(qualifs) + .map(|()| HasMutInteriorBehindRefState::OnlyHasMutInterior) + } + + fn in_any_value_of_ty( + cx: &ConstCx<'_, 'tcx>, + ty: Ty<'tcx>, + ) -> Option { + match ty.builtin_deref(false) { + None => HasMutInterior::in_any_value_of_ty(cx, ty) + .map(|()| HasMutInteriorBehindRefState::OnlyHasMutInterior), + Some(tam) => HasMutInterior::in_any_value_of_ty(cx, tam.ty) + .map(|()| HasMutInteriorBehindRefState::Yes), + } + } + + #[instrument(skip(cx))] + fn in_any_function_call( + cx: &ConstCx<'_, 'tcx>, + ty: Ty<'tcx>, + mut args: Option, + ) -> Option { + args.join( + &HasMutInterior::in_any_value_of_ty(cx, ty) + .map(|()| HasMutInteriorBehindRefState::OnlyHasMutInterior), + ); + args + } + + fn in_adt_inherently( + cx: &ConstCx<'_, 'tcx>, + adt: &'tcx AdtDef, + substs: SubstsRef<'tcx>, + ) -> Option { + HasMutInterior::in_adt_inherently(cx, adt, substs) + .map(|()| HasMutInteriorBehindRefState::OnlyHasMutInterior) + } + + fn in_value_behind_ref( + qualif: Option, + ) -> Option { + qualif.map(|_| HasMutInteriorBehindRefState::Yes) } } @@ -103,16 +264,20 @@ impl Qualif for NeedsDrop { const ANALYSIS_NAME: &'static str = "flow_needs_drop"; const IS_CLEARED_ON_MOVE: bool = true; - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.needs_drop + fn in_qualifs(qualifs: &ConstQualifs) -> Option<()> { + qualifs.needs_drop.then_some(()) } - fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.needs_drop(cx.tcx, cx.param_env) + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> Option<()> { + ty.needs_drop(cx.tcx, cx.param_env).then_some(()) } - fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool { - adt.has_dtor(cx.tcx) + fn in_adt_inherently( + cx: &ConstCx<'_, 'tcx>, + adt: &'tcx AdtDef, + _: SubstsRef<'tcx>, + ) -> Option<()> { + adt.has_dtor(cx.tcx).then_some(()) } } @@ -122,37 +287,42 @@ pub struct CustomEq; impl Qualif for CustomEq { const ANALYSIS_NAME: &'static str = "flow_custom_eq"; - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.custom_eq + fn in_qualifs(qualifs: &ConstQualifs) -> Option<()> { + qualifs.custom_eq.then_some(()) } - fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> Option<()> { // If *any* component of a composite data type does not implement `Structural{Partial,}Eq`, // we know that at least some values of that type are not structural-match. I say "some" // because that component may be part of an enum variant (e.g., // `Option::::Some`), in which case some values of this type may be // structural-match (`Option::None`). let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id()); - traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some() + traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).map(drop) } fn in_adt_inherently( cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, substs: SubstsRef<'tcx>, - ) -> bool { + ) -> Option<()> { let ty = cx.tcx.mk_ty(ty::Adt(adt, substs)); - !ty.is_structural_eq_shallow(cx.tcx) + (!ty.is_structural_eq_shallow(cx.tcx)).then_some(()) } } // FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return. /// Returns `true` if this `Rvalue` contains qualif `Q`. -pub fn in_rvalue(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, rvalue: &Rvalue<'tcx>) -> bool +#[instrument(skip(cx, in_local), fields(Q=std::any::type_name::()))] +pub(crate) fn in_rvalue( + cx: &ConstCx<'_, 'tcx>, + in_local: &mut F, + rvalue: &Rvalue<'tcx>, +) -> Option where Q: Qualif, - F: FnMut(Local) -> bool, + F: FnMut(Local) -> Option, { match rvalue { Rvalue::ThreadLocalRef(_) | Rvalue::NullaryOp(..) => { @@ -169,7 +339,9 @@ where | Rvalue::Cast(_, operand, _) => in_operand::(cx, in_local, operand), Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { - in_operand::(cx, in_local, lhs) || in_operand::(cx, in_local, rhs) + let mut res = in_operand::(cx, in_local, lhs); + res.join(&in_operand::(cx, in_local, rhs)); + res } Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { @@ -185,61 +357,75 @@ where } } - in_place::(cx, in_local, place.as_ref()) + Q::in_value_behind_ref(in_place::(cx, in_local, place.as_ref())) } Rvalue::Aggregate(kind, operands) => { - // Return early if we know that the struct or enum being constructed is always - // qualified. + // Check if we know that the struct or enum being constructed is always qualified. + let mut result = None; if let AggregateKind::Adt(def, _, substs, ..) = **kind { - if Q::in_adt_inherently(cx, def, substs) { - return true; - } + result.join(&Q::in_adt_inherently(cx, def, substs)); } // Otherwise, proceed structurally... - operands.iter().any(|o| in_operand::(cx, in_local, o)) + for o in operands { + result.join(&in_operand::(cx, in_local, o)); + } + result } } } /// Returns `true` if this `Place` contains qualif `Q`. -pub fn in_place(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, place: PlaceRef<'tcx>) -> bool +#[instrument(skip(cx, in_local), fields(Q=std::any::type_name::()))] +pub(crate) fn in_place( + cx: &ConstCx<'_, 'tcx>, + in_local: &mut F, + place: PlaceRef<'tcx>, +) -> Option where Q: Qualif, - F: FnMut(Local) -> bool, + F: FnMut(Local) -> Option, { let mut projection = place.projection; + let mut result = None; while let &[ref proj_base @ .., proj_elem] = projection { match proj_elem { - ProjectionElem::Index(index) if in_local(index) => return true, + ProjectionElem::Index(index) => { + result.join(&in_local(index)); + } ProjectionElem::Deref | ProjectionElem::Field(_, _) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(_, _) - | ProjectionElem::Index(_) => {} + | ProjectionElem::Downcast(_, _) => {} } let base_ty = Place::ty_from(place.local, proj_base, cx.body, cx.tcx); let proj_ty = base_ty.projection_ty(cx.tcx, proj_elem).ty; - if !Q::in_any_value_of_ty(cx, proj_ty) { - return false; + if Q::in_any_value_of_ty(cx, proj_ty).is_none() { + return result; } projection = proj_base; } assert!(projection.is_empty()); - in_local(place.local) + result.join(&in_local(place.local)); + result } /// Returns `true` if this `Operand` contains qualif `Q`. -pub fn in_operand(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, operand: &Operand<'tcx>) -> bool +#[instrument(skip(cx, in_local), fields(Q=std::any::type_name::()))] +pub(crate) fn in_operand( + cx: &ConstCx<'_, 'tcx>, + in_local: &mut F, + operand: &Operand<'tcx>, +) -> Option where Q: Qualif, - F: FnMut(Local) -> bool, + F: FnMut(Local) -> Option, { let constant = match operand { Operand::Copy(place) | Operand::Move(place) => { @@ -260,9 +446,10 @@ where cx.tcx.at(constant.span).mir_const_qualif(def.did) }; - if !Q::in_qualifs(&qualifs) { - return false; - } + // Since this comes from a constant's qualifs, there can only + // be `Option<()>` style qualifs, so we are allowed to early + // return here and not try to join the results. + Q::in_qualifs(&qualifs)?; // Just in case the type is more specific than // the definition, e.g., impl associated const diff --git a/compiler/rustc_mir/src/transform/check_consts/resolver.rs b/compiler/rustc_mir/src/transform/check_consts/resolver.rs index a00301952b328..476b8a40d4ae6 100644 --- a/compiler/rustc_mir/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_mir/src/transform/check_consts/resolver.rs @@ -2,14 +2,14 @@ //! //! This contains the dataflow analysis used to track `Qualif`s on complex control-flow graphs. -use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, BasicBlock, Local, Location}; +use rustc_middle::mir::{self, BasicBlock, Location}; use std::marker::PhantomData; +use super::qualifs::QualifsPerLocal; use super::{qualifs, ConstCx, Qualif}; -use crate::dataflow; +use crate::dataflow::{self, JoinSemiLattice}; /// A `Visitor` that propagates qualifs between locals. This defines the transfer function of /// `FlowSensitiveAnalysis`. @@ -17,9 +17,9 @@ use crate::dataflow; /// This transfer does nothing when encountering an indirect assignment. Consumers should rely on /// the `MaybeMutBorrowedLocals` dataflow pass to see if a `Local` may have become qualified via /// an indirect assignment or function call. -struct TransferFunction<'a, 'mir, 'tcx, Q> { +struct TransferFunction<'a, 'mir, 'tcx, Q: Qualif> { ccx: &'a ConstCx<'mir, 'tcx>, - qualifs_per_local: &'a mut BitSet, + qualifs_per_local: &'a mut Q::Set, _qualif: PhantomData, } @@ -28,7 +28,7 @@ impl TransferFunction<'a, 'mir, 'tcx, Q> where Q: Qualif, { - fn new(ccx: &'a ConstCx<'mir, 'tcx>, qualifs_per_local: &'a mut BitSet) -> Self { + fn new(ccx: &'a ConstCx<'mir, 'tcx>, qualifs_per_local: &'a mut Q::Set) -> Self { TransferFunction { ccx, qualifs_per_local, _qualif: PhantomData } } @@ -37,25 +37,26 @@ where for arg in self.ccx.body.args_iter() { let arg_ty = self.ccx.body.local_decls[arg].ty; - if Q::in_any_value_of_ty(self.ccx, arg_ty) { - self.qualifs_per_local.insert(arg); + if let Some(val) = Q::in_any_value_of_ty(self.ccx, arg_ty) { + self.qualifs_per_local.insert(arg, val); } } } - fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) { + #[instrument(skip(self))] + fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: Option) { debug_assert!(!place.is_indirect()); match (value, place.as_ref()) { - (true, mir::PlaceRef { local, .. }) => { - self.qualifs_per_local.insert(local); + (Some(value), mir::PlaceRef { local, .. }) => { + self.qualifs_per_local.insert(local, value); } // For now, we do not clear the qualif if a local is overwritten in full by // an unqualified rvalue (e.g. `y = 5`). This is to be consistent // with aggregates where we overwrite all fields with assignments, which would not // get this feature. - (false, mir::PlaceRef { local: _, projection: &[] }) => { + (None, mir::PlaceRef { local: _, projection: &[] }) => { // self.qualifs_per_local.remove(*local); } @@ -67,13 +68,22 @@ where &mut self, _block: BasicBlock, _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], + args: &[mir::Operand<'tcx>], return_place: mir::Place<'tcx>, ) { // We cannot reason about another function's internals, so use conservative type-based // qualification for the result of a function call. let return_ty = return_place.ty(self.ccx.body, self.ccx.tcx).ty; - let qualif = Q::in_any_value_of_ty(self.ccx, return_ty); + + // Though some qualifs merge the call arguments' qualifs into the result qualif. + let mut args_qualif = None; + for arg in args { + let arg = + qualifs::in_operand::(self.ccx, &mut |l| self.qualifs_per_local.get(l), arg); + args_qualif.join(&arg); + } + + let qualif = Q::in_any_function_call(self.ccx, return_ty, args_qualif); if !return_place.is_indirect() { self.assign_qualif_direct(&return_place, qualif); @@ -107,11 +117,8 @@ where rvalue: &mir::Rvalue<'tcx>, location: Location, ) { - let qualif = qualifs::in_rvalue::( - self.ccx, - &mut |l| self.qualifs_per_local.contains(l), - rvalue, - ); + let qualif = + qualifs::in_rvalue::(self.ccx, &mut |l| self.qualifs_per_local.get(l), rvalue); if !place.is_indirect() { self.assign_qualif_direct(place, qualif); } @@ -128,7 +135,7 @@ where if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind { let qualif = qualifs::in_operand::( self.ccx, - &mut |l| self.qualifs_per_local.contains(l), + &mut |l| self.qualifs_per_local.get(l), value, ); @@ -157,10 +164,7 @@ where FlowSensitiveAnalysis { ccx, _qualif: PhantomData } } - fn transfer_function( - &self, - state: &'a mut BitSet, - ) -> TransferFunction<'a, 'mir, 'tcx, Q> { + fn transfer_function(&self, state: &'a mut Q::Set) -> TransferFunction<'a, 'mir, 'tcx, Q> { TransferFunction::::new(self.ccx, state) } } @@ -169,12 +173,12 @@ impl dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q where Q: Qualif, { - type Domain = BitSet; + type Domain = Q::Set; const NAME: &'static str = Q::ANALYSIS_NAME; fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - BitSet::new_empty(body.local_decls.len()) + Q::Set::new_empty(body.local_decls.len()) } fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) { diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 90688ebbd0acb..01f0be3020264 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -21,12 +21,15 @@ use std::mem; use std::ops::Deref; use super::ops::{self, NonConstOp, Status}; -use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop}; +use super::qualifs::{ + self, CustomEq, HasMutInterior, HasMutInteriorBehindRef, HasMutInteriorBehindRefState, + NeedsDrop, QualifsPerLocal, +}; use super::resolver::FlowSensitiveAnalysis; use super::{is_lang_panic_fn, ConstCx, Qualif}; use crate::const_eval::is_unstable_const_fn; use crate::dataflow::impls::MaybeMutBorrowedLocals; -use crate::dataflow::{self, Analysis}; +use crate::dataflow::{self, lattice::JoinSemiLattice, Analysis}; // We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated // through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals` @@ -40,12 +43,13 @@ type QualifResults<'mir, 'tcx, Q> = #[derive(Default)] pub struct Qualifs<'mir, 'tcx> { has_mut_interior: Option>, + has_mut_interior_behind_ref: Option>, needs_drop: Option>, indirectly_mutable: Option>, } impl Qualifs<'mir, 'tcx> { - pub fn indirectly_mutable( + fn indirectly_mutable( &mut self, ccx: &'mir ConstCx<'mir, 'tcx>, local: Local, @@ -79,11 +83,9 @@ impl Qualifs<'mir, 'tcx> { ccx: &'mir ConstCx<'mir, 'tcx>, local: Local, location: Location, - ) -> bool { + ) -> Option<()> { let ty = ccx.body.local_decls[local].ty; - if !NeedsDrop::in_any_value_of_ty(ccx, ty) { - return false; - } + NeedsDrop::in_any_value_of_ty(ccx, ty)?; let needs_drop = self.needs_drop.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; @@ -95,7 +97,36 @@ impl Qualifs<'mir, 'tcx> { }); needs_drop.seek_before_primary_effect(location); - needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location) + let mut result = needs_drop.get().get(local); + result.join(&self.indirectly_mutable(ccx, local, location).then_some(())); + result + } + + /// Returns `true` if `RETURN_PLACE` is `HasMutInteriorBehindRef` + /// + /// Only updates the cursor if absolutely necessary. + pub fn return_place_has_mut_interior_behind_ref( + &mut self, + ccx: &'mir ConstCx<'mir, 'tcx>, + ) -> Option { + let location = match self.return_loc(ccx) { + Some(location) => location, + // Diverging constants do not have any relevant qualifs. + None => return None, + }; + + let has_mut_interior_behind_ref = + self.has_mut_interior_behind_ref.get_or_insert_with(|| { + let ConstCx { tcx, body, .. } = *ccx; + + FlowSensitiveAnalysis::new(HasMutInteriorBehindRef, ccx) + .into_engine(tcx, &body) + .iterate_to_fixpoint() + .into_results_cursor(&body) + }); + + has_mut_interior_behind_ref.seek_before_primary_effect(location); + has_mut_interior_behind_ref.get()[RETURN_PLACE].clone() } /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. @@ -106,11 +137,9 @@ impl Qualifs<'mir, 'tcx> { ccx: &'mir ConstCx<'mir, 'tcx>, local: Local, location: Location, - ) -> bool { + ) -> Option<()> { let ty = ccx.body.local_decls[local].ty; - if !HasMutInterior::in_any_value_of_ty(ccx, ty) { - return false; - } + HasMutInterior::in_any_value_of_ty(ccx, ty)?; let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; @@ -122,18 +151,16 @@ impl Qualifs<'mir, 'tcx> { }); has_mut_interior.seek_before_primary_effect(location); - has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location) + let mut result = has_mut_interior.get().get(local); + result.join(&self.indirectly_mutable(ccx, local, location).then_some(())); + result } - fn in_return_place( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - error_occured: Option, - ) -> ConstQualifs { - // Find the `Return` terminator if one exists. - // - // If no `Return` terminator exists, this MIR is divergent. Just return the conservative - // qualifs for the return type. + /// Find the `Return` terminator if one exists. + /// + /// If no `Return` terminator exists, this MIR is divergent. Just return the conservative + /// qualifs for the return type. + fn return_loc(&self, ccx: &'mir ConstCx<'mir, 'tcx>) -> Option { let return_block = ccx .body .basic_blocks() @@ -141,16 +168,22 @@ impl Qualifs<'mir, 'tcx> { .find(|(_, block)| match block.terminator().kind { TerminatorKind::Return => true, _ => false, - }) - .map(|(bb, _)| bb); + })? + .0; + + Some(ccx.body.terminator_loc(return_block)) + } - let return_block = match return_block { + fn in_return_place( + &mut self, + ccx: &'mir ConstCx<'mir, 'tcx>, + error_occured: Option, + ) -> ConstQualifs { + let return_loc = match self.return_loc(ccx) { None => return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), error_occured), - Some(bb) => bb, + Some(loc) => loc, }; - let return_loc = ccx.body.terminator_loc(return_block); - let custom_eq = match ccx.const_kind() { // We don't care whether a `const fn` returns a value that is not structurally // matchable. Functions calls are opaque and always use type-based qualification, so @@ -159,7 +192,7 @@ impl Qualifs<'mir, 'tcx> { // If we know that all values of the return type are structurally matchable, there's no // need to run dataflow. - _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false, + _ if CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()).is_none() => false, hir::ConstContext::Const | hir::ConstContext::Static(_) => { let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx) @@ -173,8 +206,8 @@ impl Qualifs<'mir, 'tcx> { }; ConstQualifs { - needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), - has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), + needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc).is_some(), + has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc).is_some(), custom_eq, error_occured, } @@ -258,6 +291,17 @@ impl Validator<'mir, 'tcx> { self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE); } + if let hir::ConstContext::Const = self.const_kind() { + // Ensure that we do not produce references with interior mutability behind them + if let Some(HasMutInteriorBehindRefState::Yes) = + self.qualifs.return_place_has_mut_interior_behind_ref(self.ccx) + { + // FIXME: Trace the source of the `Yes` in dataflow + self.span = body.local_decls[RETURN_PLACE].source_info.span; + self.check_op(ops::CellBorrow) + } + } + self.visit_body(&body); // Ensure that the end result is `Sync` in a non-thread local `static`. @@ -555,8 +599,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { place.as_ref(), ); - if borrowed_place_has_mut_interior { - self.check_op(ops::CellBorrow); + if borrowed_place_has_mut_interior.is_some() { + self.check_op(ops::CellBorrowBehindRef); } } @@ -907,10 +951,10 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { err_span = self.body.local_decls[local].source_info.span; self.qualifs.needs_drop(self.ccx, local, location) } else { - true + Some(()) }; - if needs_drop { + if needs_drop.is_some() { self.check_op_spanned( ops::LiveDrop { dropped_at: Some(terminator.source_info.span) }, err_span, diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 8d5ed747c3f8f..f0323b74db945 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -326,14 +326,14 @@ impl<'tcx> Validator<'_, 'tcx> { if place.projection.contains(&ProjectionElem::Deref) { return Err(Unpromotable); } - if self.qualif_local::(place.local) { + if self.qualif_local::(place.local).is_some() { return Err(Unpromotable); } // FIXME(eddyb) this duplicates part of `validate_rvalue`. let has_mut_interior = self.qualif_local::(place.local); - if has_mut_interior { + if has_mut_interior.is_some() { return Err(Unpromotable); } @@ -398,7 +398,7 @@ impl<'tcx> Validator<'_, 'tcx> { } // FIXME(eddyb) maybe cache this? - fn qualif_local(&self, local: Local) -> bool { + fn qualif_local(&self, local: Local) -> Option { if let TempState::Defined { location: loc, .. } = self.temps[local] { let num_stmts = self.body[loc.block].statements.len(); @@ -668,7 +668,7 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_place(place)?; let has_mut_interior = self.qualif_local::(place.local); - if has_mut_interior { + if has_mut_interior.is_some() { return Err(Unpromotable); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 99a523c3f3bb4..c6ae53b7c056f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -380,6 +380,7 @@ symbols! { const_ptr, const_raw_ptr_deref, const_raw_ptr_to_usize_cast, + const_refs_to_cell, const_slice_ptr, const_trait_bound_opt_out, const_trait_impl, diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr index d9bb7386565fa..ef7b45b0dae31 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr @@ -1,43 +1,20 @@ -error[E0391]: cycle detected when simplifying constant for the type system `IMPL_REF_BAR` - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 +error[E0391]: cycle detected when const checking `IMPL_REF_BAR` + --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:27 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 +note: ...which requires const checking `::BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:22 | -LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... +LL | const BAR: u32 = IMPL_REF_BAR; + | ^^^^^^^^^^^^ + = note: ...which again requires const checking `IMPL_REF_BAR`, completing the cycle +note: cycle used when processing `IMPL_REF_BAR` --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires normalizing `::BAR`... -note: ...which requires simplifying constant for the type system `::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 - | -LL | const BAR: u32 = IMPL_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 - | -LL | const BAR: u32 = IMPL_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 - | -LL | const BAR: u32 = IMPL_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires optimizing MIR for `::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 - | -LL | const BAR: u32 = IMPL_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires normalizing `IMPL_REF_BAR`... - = note: ...which again requires simplifying constant for the type system `IMPL_REF_BAR`, completing the cycle - = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/consts/const-address-of-interior-mut.stderr b/src/test/ui/consts/const-address-of-interior-mut.stderr index f15174c33b3a0..93120753b1a08 100644 --- a/src/test/ui/consts/const-address-of-interior-mut.stderr +++ b/src/test/ui/consts/const-address-of-interior-mut.stderr @@ -1,27 +1,39 @@ -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability --> $DIR/const-address-of-interior-mut.rs:5:39 | LL | const A: () = { let x = Cell::new(2); &raw const x; }; | ^^^^^^^^^^^^ + | + = note: see issue #80384 for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability --> $DIR/const-address-of-interior-mut.rs:7:40 | LL | static B: () = { let x = Cell::new(2); &raw const x; }; | ^^^^^^^^^^^^ + | + = note: see issue #80384 for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability --> $DIR/const-address-of-interior-mut.rs:9:44 | LL | static mut C: () = { let x = Cell::new(2); &raw const x; }; | ^^^^^^^^^^^^ + | + = note: see issue #80384 for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability --> $DIR/const-address-of-interior-mut.rs:13:13 | LL | let y = &raw const x; | ^^^^^^^^^^^^ + | + = note: see issue #80384 for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0492`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-multi-ref.rs b/src/test/ui/consts/const-multi-ref.rs index 18645efc88715..7e0f1a812fd9c 100644 --- a/src/test/ui/consts/const-multi-ref.rs +++ b/src/test/ui/consts/const-multi-ref.rs @@ -13,7 +13,7 @@ const _: i32 = { const _: std::cell::Cell = { let mut a = std::cell::Cell::new(5); - let p = &a; //~ ERROR cannot borrow a constant which may contain interior mutability + let p = &a; //~ ERROR borrowed element may contain interior mutability let reborrow = {p}; let pp = &reborrow; diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr index 9a7914b458874..c0a320d46cbf9 100644 --- a/src/test/ui/consts/const-multi-ref.stderr +++ b/src/test/ui/consts/const-multi-ref.stderr @@ -4,13 +4,16 @@ error[E0764]: mutable references are not allowed in constants LL | let p = &mut a; | ^^^^^^ `&mut` is only allowed in `const fn` -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability --> $DIR/const-multi-ref.rs:16:13 | LL | let p = &a; | ^^ + | + = note: see issue #80384 for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable error: aborting due to 2 previous errors -Some errors have detailed explanations: E0492, E0764. -For more information about an error, try `rustc --explain E0492`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr index e5cd86b3d6c2f..e0088a7f7c40f 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -18,6 +18,11 @@ LL | READ_MUT; warning: skipping const checks | +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:11:28 + | +LL | const MUTATE_INTERIOR_MUT: usize = { + | ^^^^^ help: skipping check that does not even have a feature gate --> $DIR/const_refers_to_static.rs:13:5 | diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index c6180c1e0041c..b5174f24ff024 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -21,7 +21,7 @@ help: skipping check that does not even have a feature gate | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^ -help: skipping check that does not even have a feature gate +help: skipping check for `const_refs_to_cell` feature --> $DIR/mutable_references.rs:26:8 | LL | x: &UnsafeCell::new(42), diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr index 0c206dd51aaab..dcbba2c597567 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr @@ -27,11 +27,21 @@ LL | const BLUNT: &mut i32 = &mut 42; warning: skipping const checks | help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:16:12 + | +LL | const MUH: Meh = Meh { + | ^^^ +help: skipping check for `const_refs_to_cell` feature --> $DIR/mutable_references_err.rs:17:8 | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:26:15 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^ +help: skipping check for `const_refs_to_cell` feature --> $DIR/mutable_references_err.rs:26:27 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; diff --git a/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr b/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr index b5b5a965295a7..7242afed95d7b 100644 --- a/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr +++ b/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr @@ -7,6 +7,11 @@ LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *m warning: skipping const checks | help: skipping check that does not even have a feature gate + --> $DIR/raw_mutable_const.rs:7:27 + | +LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^ +help: skipping check for `const_refs_to_cell` feature --> $DIR/raw_mutable_const.rs:7:38 | LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; diff --git a/src/test/ui/consts/partial_qualif.rs b/src/test/ui/consts/partial_qualif.rs index 32c68e69f4bed..ff76b26b38c32 100644 --- a/src/test/ui/consts/partial_qualif.rs +++ b/src/test/ui/consts/partial_qualif.rs @@ -1,9 +1,11 @@ +#![feature(const_refs_to_cell)] + use std::cell::Cell; -const FOO: &(Cell, bool) = { +const FOO: &(Cell, bool) = { //~ ERROR may contain interior mutability let mut a = (Cell::new(0), false); a.1 = true; // sets `qualif(a)` to `qualif(a) | qualif(true)` - &{a} //~ ERROR cannot borrow a constant which may contain interior mutability + &{a} }; fn main() {} diff --git a/src/test/ui/consts/partial_qualif.stderr b/src/test/ui/consts/partial_qualif.stderr index 221e449b6f9a9..77787c29dd231 100644 --- a/src/test/ui/consts/partial_qualif.stderr +++ b/src/test/ui/consts/partial_qualif.stderr @@ -1,8 +1,8 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead - --> $DIR/partial_qualif.rs:6:5 + --> $DIR/partial_qualif.rs:5:12 | -LL | &{a} - | ^^^^ +LL | const FOO: &(Cell, bool) = { + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/qualif_overwrite.rs b/src/test/ui/consts/qualif_overwrite.rs index 430eea37de73c..c2a4a910cd14f 100644 --- a/src/test/ui/consts/qualif_overwrite.rs +++ b/src/test/ui/consts/qualif_overwrite.rs @@ -1,13 +1,15 @@ +#![feature(const_refs_to_cell)] + use std::cell::Cell; // this is overly conservative. The reset to `None` should clear `a` of all qualifications // while we could fix this, it would be inconsistent with `qualif_overwrite_2.rs`. // We can fix this properly in the future by allowing constants that do not depend on generics // to be checked by an analysis on the final value instead of looking at the body. -const FOO: &Option> = { +const FOO: &Option> = { //~ ERROR may contain interior mutability let mut a = Some(Cell::new(0)); a = None; // sets `qualif(a)` to `qualif(a) | qualif(None)` - &{a} //~ ERROR cannot borrow a constant which may contain interior mutability + &{a} }; fn main() {} diff --git a/src/test/ui/consts/qualif_overwrite.stderr b/src/test/ui/consts/qualif_overwrite.stderr index fbaae711d7c06..48c9bb283a4a5 100644 --- a/src/test/ui/consts/qualif_overwrite.stderr +++ b/src/test/ui/consts/qualif_overwrite.stderr @@ -1,8 +1,8 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead - --> $DIR/qualif_overwrite.rs:10:5 + --> $DIR/qualif_overwrite.rs:9:12 | -LL | &{a} - | ^^^^ +LL | const FOO: &Option> = { + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/qualif_overwrite_2.rs b/src/test/ui/consts/qualif_overwrite_2.rs index fa79b5c14a736..2a1272d3d1d03 100644 --- a/src/test/ui/consts/qualif_overwrite_2.rs +++ b/src/test/ui/consts/qualif_overwrite_2.rs @@ -1,11 +1,13 @@ +#![feature(const_refs_to_cell)] + use std::cell::Cell; // const qualification is not smart enough to know about fields and always assumes that there might // be other fields that caused the qualification -const FOO: &Option> = { +const FOO: &Option> = { //~ ERROR may contain interior mutability let mut a = (Some(Cell::new(0)),); a.0 = None; // sets `qualif(a)` to `qualif(a) | qualif(None)` - &{a.0} //~ ERROR cannot borrow a constant which may contain interior mutability + &{a.0} }; fn main() {} diff --git a/src/test/ui/consts/qualif_overwrite_2.stderr b/src/test/ui/consts/qualif_overwrite_2.stderr index a393c4e336d64..1318f30de5a14 100644 --- a/src/test/ui/consts/qualif_overwrite_2.stderr +++ b/src/test/ui/consts/qualif_overwrite_2.stderr @@ -1,8 +1,8 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead - --> $DIR/qualif_overwrite_2.rs:8:5 + --> $DIR/qualif_overwrite_2.rs:7:12 | -LL | &{a.0} - | ^^^^^^ +LL | const FOO: &Option> = { + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/std/cell.rs b/src/test/ui/consts/std/cell.rs index cf6c0f2379d1e..05dc705d91db0 100644 --- a/src/test/ui/consts/std/cell.rs +++ b/src/test/ui/consts/std/cell.rs @@ -1,18 +1,24 @@ +#![feature(const_refs_to_cell)] + use std::cell::*; -// not ok, because this would create a silent constant with interior mutability. -// the rules could be relaxed in the future static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); -//~^ ERROR cannot borrow a constant which may contain interior mutability +// not ok in a constant, because this would create a silent constant with interior mutability. +const FOO_CONST: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); +//~^ ERROR may contain interior mutability static FOO3: Wrap> = Wrap(Cell::new(42)); +const FOO3_CONST: Wrap> = Wrap(Cell::new(42)); + // ok static FOO4: Wrap<*mut u32> = Wrap(FOO3.0.as_ptr()); +const FOO4_CONST: Wrap<*mut u32> = Wrap(FOO3_CONST.0.as_ptr()); +//~^ ERROR may contain interior mutability // not ok, because the `as_ptr` call takes a reference to a type with interior mutability // which is not allowed in constants const FOO2: *mut u32 = Cell::new(42).as_ptr(); -//~^ ERROR cannot borrow a constant which may contain interior mutability +//~^ ERROR may contain interior mutability struct IMSafeTrustMe(UnsafeCell); unsafe impl Send for IMSafeTrustMe {} @@ -21,6 +27,7 @@ unsafe impl Sync for IMSafeTrustMe {} static BAR: IMSafeTrustMe = IMSafeTrustMe(UnsafeCell::new(5)); + struct Wrap(T); unsafe impl Send for Wrap {} unsafe impl Sync for Wrap {} diff --git a/src/test/ui/consts/std/cell.stderr b/src/test/ui/consts/std/cell.stderr index f75aadff6d5ea..cac5f9f590f3d 100644 --- a/src/test/ui/consts/std/cell.stderr +++ b/src/test/ui/consts/std/cell.stderr @@ -1,15 +1,21 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead - --> $DIR/cell.rs:5:35 + --> $DIR/cell.rs:7:18 | -LL | static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); - | ^^^^^^^^^^^^^ +LL | const FOO_CONST: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); + | ^^^^^^^^^^^^^^ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead - --> $DIR/cell.rs:14:24 + --> $DIR/cell.rs:15:19 + | +LL | const FOO4_CONST: Wrap<*mut u32> = Wrap(FOO3_CONST.0.as_ptr()); + | ^^^^^^^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead + --> $DIR/cell.rs:20:13 | LL | const FOO2: *mut u32 = Cell::new(42).as_ptr(); - | ^^^^^^^^^^^^^ + | ^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0492`. diff --git a/src/test/ui/error-codes/E0492.rs b/src/test/ui/error-codes/E0492.rs index 2de4c12eb64fb..5e3824a4b0d36 100644 --- a/src/test/ui/error-codes/E0492.rs +++ b/src/test/ui/error-codes/E0492.rs @@ -1,7 +1,13 @@ +#![feature(const_refs_to_cell)] + use std::sync::atomic::AtomicUsize; const A: AtomicUsize = AtomicUsize::new(0); -static B: &'static AtomicUsize = &A; //~ ERROR E0492 +const B: &'static AtomicUsize = &A; //~ ERROR E0492 +// We allow this, because we would allow it *anyway* if `A` were a `static`. +static C: &'static AtomicUsize = &A; + +const NONE: &'static Option = &None; fn main() { } diff --git a/src/test/ui/error-codes/E0492.stderr b/src/test/ui/error-codes/E0492.stderr index 5f337dd7f422d..d349cfc4f54c6 100644 --- a/src/test/ui/error-codes/E0492.stderr +++ b/src/test/ui/error-codes/E0492.stderr @@ -1,8 +1,8 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead - --> $DIR/E0492.rs:4:34 + --> $DIR/E0492.rs:6:10 | -LL | static B: &'static AtomicUsize = &A; - | ^^ +LL | const B: &'static AtomicUsize = &A; + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs b/src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs new file mode 100644 index 0000000000000..63159ed05532f --- /dev/null +++ b/src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs @@ -0,0 +1,12 @@ +// check-pass + +#![feature(const_refs_to_cell)] + +const FOO: () = { + let x = std::cell::Cell::new(42); + let y = &x; +}; + +fn main() { + FOO; +} diff --git a/src/test/ui/impl-trait/issues/issue-78722.rs b/src/test/ui/impl-trait/issues/issue-78722.rs index 58734d3a44554..1167af90a4a6a 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.rs +++ b/src/test/ui/impl-trait/issues/issue-78722.rs @@ -5,6 +5,7 @@ //~^ WARN the feature `impl_trait_in_bindings` is incomplete type F = impl core::future::Future; +//~^ ERROR type mismatch struct Bug { V1: [(); { diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr index 0e1e92b912080..cc8c7f7fcf59f 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.stderr +++ b/src/test/ui/impl-trait/issues/issue-78722.stderr @@ -7,14 +7,20 @@ LL | #![feature(impl_trait_in_bindings)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #63065 for more information +error[E0271]: type mismatch resolving `::Output == u8` + --> $DIR/issue-78722.rs:7:10 + | +LL | type F = impl core::future::Future; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `u8` + error: `async` blocks are not allowed in constants - --> $DIR/issue-78722.rs:14:20 + --> $DIR/issue-78722.rs:15:20 | LL | let f: F = async { 1 }; | ^^^^^^^^^^^ error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/issue-78722.rs:14:13 + --> $DIR/issue-78722.rs:15:13 | LL | let f: F = async { 1 }; | ^ constants cannot evaluate destructors @@ -22,6 +28,7 @@ LL | let f: F = async { 1 }; LL | }], | - value is dropped here -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0271, E0493. +For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr index 1148577016ab4..54177b688d40c 100644 --- a/src/test/ui/issues/issue-17252.stderr +++ b/src/test/ui/issues/issue-17252.stderr @@ -1,22 +1,11 @@ -error[E0391]: cycle detected when normalizing `FOO` - | -note: ...which requires simplifying constant for the type system `FOO`... - --> $DIR/issue-17252.rs:1:1 - | -LL | const FOO: usize = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `FOO`... - --> $DIR/issue-17252.rs:1:1 +error[E0391]: cycle detected when const checking `FOO` + --> $DIR/issue-17252.rs:1:20 | LL | const FOO: usize = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `FOO`... - --> $DIR/issue-17252.rs:1:1 + | ^^^ | -LL | const FOO: usize = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires normalizing `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `main::{constant#0}` + = note: ...which again requires const checking `FOO`, completing the cycle +note: cycle used when const checking `main::{constant#0}` --> $DIR/issue-17252.rs:4:18 | LL | let _x: [u8; FOO]; // caused stack overflow prior to fix diff --git a/src/test/ui/issues/issue-17718-const-borrow.rs b/src/test/ui/issues/issue-17718-const-borrow.rs index 8a31bd0c66af6..7bde2361f6126 100644 --- a/src/test/ui/issues/issue-17718-const-borrow.rs +++ b/src/test/ui/issues/issue-17718-const-borrow.rs @@ -1,14 +1,16 @@ +#![feature(const_refs_to_cell)] + use std::cell::UnsafeCell; const A: UnsafeCell = UnsafeCell::new(1); const B: &'static UnsafeCell = &A; -//~^ ERROR: cannot borrow a constant which may contain interior mutability +//~^ ERROR: may contain interior mutability struct C { a: UnsafeCell } const D: C = C { a: UnsafeCell::new(1) }; const E: &'static UnsafeCell = &D.a; -//~^ ERROR: cannot borrow a constant which may contain interior mutability +//~^ ERROR: may contain interior mutability const F: &'static C = &D; -//~^ ERROR: cannot borrow a constant which may contain interior mutability +//~^ ERROR: may contain interior mutability fn main() {} diff --git a/src/test/ui/issues/issue-17718-const-borrow.stderr b/src/test/ui/issues/issue-17718-const-borrow.stderr index b4330049689e5..3b2c5bba85c35 100644 --- a/src/test/ui/issues/issue-17718-const-borrow.stderr +++ b/src/test/ui/issues/issue-17718-const-borrow.stderr @@ -1,20 +1,20 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead - --> $DIR/issue-17718-const-borrow.rs:4:39 + --> $DIR/issue-17718-const-borrow.rs:6:10 | LL | const B: &'static UnsafeCell = &A; - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead - --> $DIR/issue-17718-const-borrow.rs:9:39 + --> $DIR/issue-17718-const-borrow.rs:11:10 | LL | const E: &'static UnsafeCell = &D.a; - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead - --> $DIR/issue-17718-const-borrow.rs:11:23 + --> $DIR/issue-17718-const-borrow.rs:13:10 | LL | const F: &'static C = &D; - | ^^ + | ^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr index d3a1993536a00..e4bbb12af0364 100644 --- a/src/test/ui/issues/issue-23302-1.stderr +++ b/src/test/ui/issues/issue-23302-1.stderr @@ -1,26 +1,15 @@ -error[E0391]: cycle detected when simplifying constant for the type system `X::A::{constant#0}` +error[E0391]: cycle detected when const checking `X::A::{constant#0}` --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `X::A::{constant#0}`... + = note: ...which again requires const checking `X::A::{constant#0}`, completing the cycle +note: cycle used when const-evaluating + checking `X::A::{constant#0}` --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `X::A::{constant#0}`... - --> $DIR/issue-23302-1.rs:4:9 - | -LL | A = X::A as isize, - | ^^^^^^^^^^^^^ - = note: ...which requires normalizing `X::A as isize`... - = note: ...which again requires simplifying constant for the type system `X::A::{constant#0}`, completing the cycle -note: cycle used when collecting item types in top-level module - --> $DIR/issue-23302-1.rs:3:1 - | -LL | enum X { - | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr index d3b78ea1af5f5..944c5a624fd4d 100644 --- a/src/test/ui/issues/issue-23302-2.stderr +++ b/src/test/ui/issues/issue-23302-2.stderr @@ -1,26 +1,15 @@ -error[E0391]: cycle detected when simplifying constant for the type system `Y::A::{constant#0}` +error[E0391]: cycle detected when const checking `Y::A::{constant#0}` --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `Y::A::{constant#0}`... + = note: ...which again requires const checking `Y::A::{constant#0}`, completing the cycle +note: cycle used when const-evaluating + checking `Y::A::{constant#0}` --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Y::A::{constant#0}`... - --> $DIR/issue-23302-2.rs:4:9 - | -LL | A = Y::B as isize, - | ^^^^^^^^^^^^^ - = note: ...which requires normalizing `Y::B as isize`... - = note: ...which again requires simplifying constant for the type system `Y::A::{constant#0}`, completing the cycle -note: cycle used when collecting item types in top-level module - --> $DIR/issue-23302-2.rs:3:1 - | -LL | enum Y { - | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23302-3.stderr b/src/test/ui/issues/issue-23302-3.stderr index 5233b832ecc79..0229469f04140 100644 --- a/src/test/ui/issues/issue-23302-3.stderr +++ b/src/test/ui/issues/issue-23302-3.stderr @@ -1,38 +1,20 @@ -error[E0391]: cycle detected when simplifying constant for the type system `A` - --> $DIR/issue-23302-3.rs:1:1 +error[E0391]: cycle detected when const checking `A` + --> $DIR/issue-23302-3.rs:1:16 | LL | const A: i32 = B; - | ^^^^^^^^^^^^^^^^^ + | ^ | -note: ...which requires simplifying constant for the type system `A`... - --> $DIR/issue-23302-3.rs:1:1 +note: ...which requires const checking `B`... + --> $DIR/issue-23302-3.rs:3:16 | -LL | const A: i32 = B; - | ^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `A`... +LL | const B: i32 = A; + | ^ + = note: ...which again requires const checking `A`, completing the cycle +note: cycle used when processing `A` --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ - = note: ...which requires normalizing `B`... -note: ...which requires simplifying constant for the type system `B`... - --> $DIR/issue-23302-3.rs:3:1 - | -LL | const B: i32 = A; - | ^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `B`... - --> $DIR/issue-23302-3.rs:3:1 - | -LL | const B: i32 = A; - | ^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `B`... - --> $DIR/issue-23302-3.rs:3:1 - | -LL | const B: i32 = A; - | ^^^^^^^^^^^^^^^^^ - = note: ...which requires normalizing `A`... - = note: ...which again requires simplifying constant for the type system `A`, completing the cycle - = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36163.stderr b/src/test/ui/issues/issue-36163.stderr index 113f86cf0f99f..e17f8438e6719 100644 --- a/src/test/ui/issues/issue-36163.stderr +++ b/src/test/ui/issues/issue-36163.stderr @@ -1,48 +1,20 @@ -error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}` +error[E0391]: cycle detected when const checking `Foo::B::{constant#0}` --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ | -note: ...which requires simplifying constant for the type system `Foo::B::{constant#0}`... - --> $DIR/issue-36163.rs:4:9 +note: ...which requires const checking `A`... + --> $DIR/issue-36163.rs:1:18 | -LL | B = A, - | ^ -note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`... +LL | const A: isize = Foo::B as isize; + | ^^^^^^^^^^^^^^^ + = note: ...which again requires const checking `Foo::B::{constant#0}`, completing the cycle +note: cycle used when const-evaluating + checking `Foo::B::{constant#0}` --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ - = note: ...which requires normalizing `A`... -note: ...which requires simplifying constant for the type system `A`... - --> $DIR/issue-36163.rs:1:1 - | -LL | const A: isize = Foo::B as isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `A`... - --> $DIR/issue-36163.rs:1:1 - | -LL | const A: isize = Foo::B as isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `A`... - --> $DIR/issue-36163.rs:1:1 - | -LL | const A: isize = Foo::B as isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires normalizing `A`... - = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle -note: cycle used when collecting item types in top-level module - --> $DIR/issue-36163.rs:1:1 - | -LL | / const A: isize = Foo::B as isize; -LL | | -LL | | enum Foo { -LL | | B = A, -LL | | } -LL | | -LL | | fn main() {} - | |____________^ error: aborting due to previous error diff --git a/src/test/ui/unsafe/ranged_ints3_const.rs b/src/test/ui/unsafe/ranged_ints3_const.rs index 7b03d8eda9380..c069ae7da0212 100644 --- a/src/test/ui/unsafe/ranged_ints3_const.rs +++ b/src/test/ui/unsafe/ranged_ints3_const.rs @@ -9,13 +9,13 @@ fn main() {} const fn foo() -> NonZero> { let mut x = unsafe { NonZero(Cell::new(1)) }; - let y = &x.0; //~ ERROR cannot borrow a constant which may contain interior mutability + let y = &x.0; //~ ERROR the borrowed element may contain interior mutability //~^ ERROR borrow of layout constrained field with interior mutability unsafe { NonZero(Cell::new(1)) } } const fn bar() -> NonZero> { let mut x = unsafe { NonZero(Cell::new(1)) }; - let y = unsafe { &x.0 }; //~ ERROR cannot borrow a constant which may contain interior mut + let y = unsafe { &x.0 }; //~ ERROR the borrowed element may contain interior mutability unsafe { NonZero(Cell::new(1)) } } diff --git a/src/test/ui/unsafe/ranged_ints3_const.stderr b/src/test/ui/unsafe/ranged_ints3_const.stderr index d2eb3bc536008..215005571f6d7 100644 --- a/src/test/ui/unsafe/ranged_ints3_const.stderr +++ b/src/test/ui/unsafe/ranged_ints3_const.stderr @@ -1,14 +1,20 @@ -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability --> $DIR/ranged_ints3_const.rs:12:13 | LL | let y = &x.0; | ^^^^ + | + = note: see issue #80384 for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability --> $DIR/ranged_ints3_const.rs:19:22 | LL | let y = unsafe { &x.0 }; | ^^^^ + | + = note: see issue #80384 for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block --> $DIR/ranged_ints3_const.rs:12:13 @@ -20,5 +26,5 @@ LL | let y = &x.0; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0133, E0492. +Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`.