Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Downgrade const eval dangling ptr in final to future incompat lint #122204

7 changes: 5 additions & 2 deletions compiler/rustc_const_eval/src/errors.rs
Expand Up @@ -25,10 +25,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,
}
Expand Down
12 changes: 8 additions & 4 deletions compiler/rustc_const_eval/src/interpret/intern.rs
Expand Up @@ -21,6 +21,7 @@ use rustc_hir as hir;
use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::sym;

Expand Down Expand Up @@ -262,10 +263,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(())
Expand Down
46 changes: 46 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Expand Up @@ -30,6 +30,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,
DEAD_CODE,
Expand Down Expand Up @@ -2796,6 +2797,51 @@ 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<bool>),
/// }
///
/// impl ::std::ops::Drop for JsValue {
/// fn drop(&mut self) {}
/// }
///
/// const UNDEFINED: &JsValue = &JsValue::Undefined;
///
/// fn main() {
/// }
/// ```
///
wesleywiser marked this conversation as resolved.
Show resolved Hide resolved
/// {{produces}}
///
/// ### Explanation
///
/// In the 1.77 release, the const evaluation machinery adopted some
/// stricter rules to reject expressions with values that could
/// end up holding mutable references to state stored in static memory
/// (which is inherently immutable).
///
/// 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
pnkfelix marked this conversation as resolved.
Show resolved Hide resolved
/// [future-incompatible]: ../index.md#future-incompatible-lints
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 <https://github.com/rust-lang/rust/issues/122153>",
};
}

declare_lint! {
/// The `const_evaluatable_unchecked` lint detects a generic constant used
/// in a type.
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs
@@ -1,9 +1,11 @@
#![feature(core_intrinsics)]
#![feature(const_heap)]
#![feature(const_mut_refs)]
#![deny(const_eval_mutable_ptr_in_final_value)]
use std::intrinsics;

const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
//~^ error: mutable pointer in final value of constant
//~| WARNING this was previously accepted by the compiler

fn main() {}
25 changes: 24 additions & 1 deletion tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr
@@ -1,8 +1,31 @@
error: encountered mutable pointer in final value of constant
--> $DIR/alloc_intrinsic_untyped.rs:6:1
--> $DIR/alloc_intrinsic_untyped.rs:7:1
|
LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
| ^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/alloc_intrinsic_untyped.rs:4:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

Future incompatibility report: Future breakage diagnostic:
error: encountered mutable pointer in final value of constant
--> $DIR/alloc_intrinsic_untyped.rs:7:1
|
LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
| ^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/alloc_intrinsic_untyped.rs:4:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

@@ -0,0 +1,18 @@
//@ check-pass
use std::cell::Cell;

pub enum JsValue {
Undefined,
Object(Cell<bool>),
}

impl ::std::ops::Drop for JsValue {
fn drop(&mut self) {}
}

const UNDEFINED: &JsValue = &JsValue::Undefined;
//~^ WARN encountered mutable pointer in final value of constant
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

fn main() {
}
@@ -0,0 +1,23 @@
warning: encountered mutable pointer in final value of constant
--> $DIR/future-incompat-mutable-in-final-value-issue-121610.rs:13:1
|
LL | const UNDEFINED: &JsValue = &JsValue::Undefined;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
= note: `#[warn(const_eval_mutable_ptr_in_final_value)]` on by default

warning: 1 warning emitted

Future incompatibility report: Future breakage diagnostic:
warning: encountered mutable pointer in final value of constant
--> $DIR/future-incompat-mutable-in-final-value-issue-121610.rs:13:1
|
LL | const UNDEFINED: &JsValue = &JsValue::Undefined;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
= note: `#[warn(const_eval_mutable_ptr_in_final_value)]` on by default

9 changes: 9 additions & 0 deletions tests/ui/consts/miri_unleashed/mutable_references.rs
@@ -1,29 +1,38 @@
//@ compile-flags: -Zunleash-the-miri-inside-of-you
//@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
//@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"

#![deny(const_eval_mutable_ptr_in_final_value)]
use std::cell::UnsafeCell;

// a test demonstrating what things we could allow with a smarter const qualification

static FOO: &&mut u32 = &&mut 42;
//~^ ERROR encountered mutable pointer in final value of static
//~| WARNING this was previously accepted by the compiler

static BAR: &mut () = &mut ();
//~^ ERROR encountered mutable pointer in final value of static
//~| WARNING this was previously accepted by the compiler

struct Foo<T>(T);

static BOO: &mut Foo<()> = &mut Foo(());
//~^ ERROR encountered mutable pointer in final value of static
//~| WARNING this was previously accepted by the compiler

struct Meh {
x: &'static UnsafeCell<i32>,
}
unsafe impl Sync for Meh {}
static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
//~^ ERROR encountered mutable pointer in final value of static
//~| WARNING this was previously accepted by the compiler

static OH_YES: &mut i32 = &mut 42;
//~^ ERROR encountered mutable pointer in final value of static
//~| WARNING this was previously accepted by the compiler
//~| ERROR it is undefined behavior to use this value

fn main() {
unsafe {
Expand Down