diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 4d2b1ba3eec8..7736dc6d5c42 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -27,10 +27,13 @@ pub(crate) struct DanglingPtrInFinal { pub kind: InternKind, } -#[derive(Diagnostic)] +#[derive(LintDiagnostic)] #[diag(const_eval_mutable_ptr_in_final)] pub(crate) struct MutablePtrInFinal { - #[primary_span] + // rust-lang/rust#122153: This was marked as `#[primary_span]` under + // `derive(Diagnostic)`. Since we expect we may hard-error in future, we are + // keeping the field (and skipping it under `derive(LintDiagnostic)`). + #[skip_arg] pub span: Span, pub kind: InternKind, } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 751fbfacaad0..61f170620ea6 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -19,6 +19,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult}; use rustc_middle::ty::layout::TyAndLayout; +use rustc_session::lint; use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy}; use crate::const_eval; @@ -195,10 +196,13 @@ pub fn intern_const_alloc_recursive< })?; } if found_bad_mutable_pointer { - return Err(ecx - .tcx - .dcx() - .emit_err(MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind })); + let err_diag = MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }; + ecx.tcx.emit_node_span_lint( + lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, + ecx.best_lint_scope(), + err_diag.span, + err_diag, + ) } Ok(()) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f209e083d2de..050478149b0a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -27,6 +27,7 @@ declare_lint_pass! { CENUM_IMPL_DROP_CAST, COHERENCE_LEAK_CHECK, CONFLICTING_REPR_HINTS, + CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, CONST_EVALUATABLE_UNCHECKED, CONST_ITEM_MUTATION, CONST_PATTERNS_WITHOUT_PARTIAL_EQ, @@ -2905,6 +2906,41 @@ declare_lint! { @feature_gate = sym::strict_provenance; } +declare_lint! { + /// The `const_eval_mutable_ptr_in_final_value` lint detects if a mutable pointer + /// has leaked into the final value of a const expression. + /// + /// ### Example + /// + /// ```rust + /// pub enum JsValue { + /// Undefined, + /// Object(std::cell::Cell), + /// } + /// + /// impl ::std::ops::Drop for JsValue { + /// fn drop(&mut self) {} + /// } + /// + /// const UNDEFINED: &JsValue = &JsValue::Undefined; + /// + /// fn main() { + /// } + /// ``` + /// + /// This is a [future-incompatible] lint to ease the transition to an error. + /// See [issue #122153] for more details. + /// + /// [issue #122153]: https://github.com/rust-lang/rust/issues/122153 + pub CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, + Warn, + "detects a mutable pointer that has leaked into final value of a const expression", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reference: "issue #122153 ", + }; +} + declare_lint! { /// The `const_evaluatable_unchecked` lint detects a generic constant used /// in a type.