compile-time evaluation: emit a lint when a write through an immutable pointer occurs
This commit is contained in:
parent
cb86303342
commit
4d93590d59
16 changed files with 380 additions and 185 deletions
|
@ -461,6 +461,9 @@ const_eval_validation_uninhabited_val = {$front_matter}: encountered a value of
|
||||||
const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected}
|
const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected}
|
||||||
const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const`
|
const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const`
|
||||||
|
|
||||||
|
const_eval_write_through_immutable_pointer =
|
||||||
|
writing through a pointer that was derived from a shared (immutable) reference
|
||||||
|
|
||||||
const_eval_write_to_read_only =
|
const_eval_write_to_read_only =
|
||||||
writing to {$allocation} which is read-only
|
writing to {$allocation} which is read-only
|
||||||
const_eval_zst_pointer_out_of_bounds =
|
const_eval_zst_pointer_out_of_bounds =
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg};
|
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg};
|
||||||
|
use rustc_hir::CRATE_HIR_ID;
|
||||||
use rustc_middle::mir::AssertKind;
|
use rustc_middle::mir::AssertKind;
|
||||||
|
use rustc_middle::query::TyCtxtAt;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_middle::ty::{layout::LayoutError, ConstInt};
|
use rustc_middle::ty::{layout::LayoutError, ConstInt};
|
||||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP};
|
use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP};
|
||||||
|
|
||||||
use super::InterpCx;
|
use super::{CompileTimeInterpreter, InterpCx};
|
||||||
use crate::errors::{self, FrameNote, ReportErrorExt};
|
use crate::errors::{self, FrameNote, ReportErrorExt};
|
||||||
use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, Machine, MachineStopType};
|
use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, MachineStopType};
|
||||||
|
|
||||||
/// The CTFE machine has some custom error kinds.
|
/// The CTFE machine has some custom error kinds.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -57,16 +59,20 @@ impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_span_and_frames<'tcx, 'mir, M: Machine<'mir, 'tcx>>(
|
pub fn get_span_and_frames<'tcx, 'mir>(
|
||||||
ecx: &InterpCx<'mir, 'tcx, M>,
|
tcx: TyCtxtAt<'tcx>,
|
||||||
|
machine: &CompileTimeInterpreter<'mir, 'tcx>,
|
||||||
) -> (Span, Vec<errors::FrameNote>)
|
) -> (Span, Vec<errors::FrameNote>)
|
||||||
where
|
where
|
||||||
'tcx: 'mir,
|
'tcx: 'mir,
|
||||||
{
|
{
|
||||||
let mut stacktrace = ecx.generate_stacktrace();
|
let mut stacktrace =
|
||||||
|
InterpCx::<CompileTimeInterpreter<'mir, 'tcx>>::generate_stacktrace_from_stack(
|
||||||
|
&machine.stack,
|
||||||
|
);
|
||||||
// Filter out `requires_caller_location` frames.
|
// Filter out `requires_caller_location` frames.
|
||||||
stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx));
|
stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx));
|
||||||
let span = stacktrace.first().map(|f| f.span).unwrap_or(ecx.tcx.span);
|
let span = stacktrace.first().map(|f| f.span).unwrap_or(tcx.span);
|
||||||
|
|
||||||
let mut frames = Vec::new();
|
let mut frames = Vec::new();
|
||||||
|
|
||||||
|
@ -87,7 +93,7 @@ where
|
||||||
|
|
||||||
let mut last_frame: Option<errors::FrameNote> = None;
|
let mut last_frame: Option<errors::FrameNote> = None;
|
||||||
for frame_info in &stacktrace {
|
for frame_info in &stacktrace {
|
||||||
let frame = frame_info.as_note(*ecx.tcx);
|
let frame = frame_info.as_note(*tcx);
|
||||||
match last_frame.as_mut() {
|
match last_frame.as_mut() {
|
||||||
Some(last_frame)
|
Some(last_frame)
|
||||||
if last_frame.span == frame.span
|
if last_frame.span == frame.span
|
||||||
|
@ -156,3 +162,25 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emit a lint from a const-eval situation.
|
||||||
|
// Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future!
|
||||||
|
pub(super) fn lint<'tcx, 'mir, L>(
|
||||||
|
tcx: TyCtxtAt<'tcx>,
|
||||||
|
machine: &CompileTimeInterpreter<'mir, 'tcx>,
|
||||||
|
lint: &'static rustc_session::lint::Lint,
|
||||||
|
decorator: impl FnOnce(Vec<errors::FrameNote>) -> L,
|
||||||
|
) where
|
||||||
|
L: for<'a> rustc_errors::DecorateLint<'a, ()>,
|
||||||
|
{
|
||||||
|
let (span, frames) = get_span_and_frames(tcx, machine);
|
||||||
|
|
||||||
|
tcx.emit_spanned_lint(
|
||||||
|
lint,
|
||||||
|
// We use the root frame for this so the crate that defines the const defines whether the
|
||||||
|
// lint is emitted.
|
||||||
|
machine.stack.first().and_then(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
|
||||||
|
span,
|
||||||
|
decorator(frames),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -338,7 +338,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
|
||||||
*ecx.tcx,
|
*ecx.tcx,
|
||||||
error,
|
error,
|
||||||
None,
|
None,
|
||||||
|| super::get_span_and_frames(&ecx),
|
|| super::get_span_and_frames(ecx.tcx, &ecx.machine),
|
||||||
|span, frames| ConstEvalError {
|
|span, frames| ConstEvalError {
|
||||||
span,
|
span,
|
||||||
error_kind: kind,
|
error_kind: kind,
|
||||||
|
@ -419,7 +419,7 @@ pub fn const_report_error<'mir, 'tcx>(
|
||||||
*ecx.tcx,
|
*ecx.tcx,
|
||||||
error,
|
error,
|
||||||
None,
|
None,
|
||||||
|| crate::const_eval::get_span_and_frames(ecx),
|
|| crate::const_eval::get_span_and_frames(ecx.tcx, &ecx.machine),
|
||||||
move |span, frames| errors::UndefinedBehavior { span, ub_note, frames, raw_bytes },
|
move |span, frames| errors::UndefinedBehavior { span, ub_note, frames, raw_bytes },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
use rustc_hir::def::DefKind;
|
|
||||||
use rustc_hir::LangItem;
|
|
||||||
use rustc_middle::mir;
|
|
||||||
use rustc_middle::mir::interpret::PointerArithmetic;
|
|
||||||
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
|
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
|
||||||
use rustc_span::Span;
|
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
use std::fmt;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use rustc_ast::Mutability;
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_data_structures::fx::IndexEntry;
|
use rustc_data_structures::fx::IndexEntry;
|
||||||
use std::fmt;
|
use rustc_hir::def::DefKind;
|
||||||
|
|
||||||
use rustc_ast::Mutability;
|
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_hir::LangItem;
|
||||||
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::AssertMessage;
|
use rustc_middle::mir::AssertMessage;
|
||||||
|
use rustc_middle::query::TyCtxtAt;
|
||||||
|
use rustc_middle::ty;
|
||||||
|
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
|
||||||
|
use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER;
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Align, Size};
|
||||||
use rustc_target::spec::abi::Abi as CallAbi;
|
use rustc_target::spec::abi::Abi as CallAbi;
|
||||||
|
|
||||||
use crate::errors::{LongRunning, LongRunningWarn};
|
use crate::errors::{LongRunning, LongRunningWarn};
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
use crate::interpret::{
|
use crate::interpret::{
|
||||||
self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx,
|
self, compile_time_machine, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal,
|
||||||
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
|
Frame, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, PointerArithmetic, Scalar,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::error::*;
|
use super::error::*;
|
||||||
|
@ -671,7 +671,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn before_access_global(
|
fn before_access_global(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
machine: &Self,
|
machine: &Self,
|
||||||
alloc_id: AllocId,
|
alloc_id: AllocId,
|
||||||
alloc: ConstAllocation<'tcx>,
|
alloc: ConstAllocation<'tcx>,
|
||||||
|
@ -708,6 +708,45 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn retag_ptr_value(
|
||||||
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
|
_kind: mir::RetagKind,
|
||||||
|
val: &ImmTy<'tcx, CtfeProvenance>,
|
||||||
|
) -> InterpResult<'tcx, ImmTy<'tcx, CtfeProvenance>> {
|
||||||
|
if let ty::Ref(_, ty, mutbl) = val.layout.ty.kind()
|
||||||
|
&& *mutbl == Mutability::Not
|
||||||
|
&& ty.is_freeze(*ecx.tcx, ecx.param_env)
|
||||||
|
{
|
||||||
|
// This is a frozen shared reference, mark it immutable.
|
||||||
|
let place = ecx.ref_to_mplace(val)?;
|
||||||
|
let new_place = place.map_provenance(|p| p.map(CtfeProvenance::as_immutable));
|
||||||
|
Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout))
|
||||||
|
} else {
|
||||||
|
Ok(val.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_memory_write(
|
||||||
|
tcx: TyCtxtAt<'tcx>,
|
||||||
|
machine: &mut Self,
|
||||||
|
_alloc_extra: &mut Self::AllocExtra,
|
||||||
|
(_alloc_id, immutable): (AllocId, bool),
|
||||||
|
range: AllocRange,
|
||||||
|
) -> InterpResult<'tcx> {
|
||||||
|
if range.size == Size::ZERO {
|
||||||
|
// Nothing to check.
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
// Reject writes through immutable pointers.
|
||||||
|
if immutable {
|
||||||
|
super::lint(tcx, machine, WRITES_THROUGH_IMMUTABLE_POINTER, |frames| {
|
||||||
|
crate::errors::WriteThroughImmutablePointer { frames }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Everything else is fine.
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups
|
// Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups
|
||||||
|
|
|
@ -402,6 +402,13 @@ pub struct ConstEvalError {
|
||||||
pub frame_notes: Vec<FrameNote>,
|
pub frame_notes: Vec<FrameNote>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(const_eval_write_through_immutable_pointer)]
|
||||||
|
pub struct WriteThroughImmutablePointer {
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub frames: Vec<FrameNote>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(const_eval_nullary_intrinsic_fail)]
|
#[diag(const_eval_nullary_intrinsic_fail)]
|
||||||
pub struct NullaryIntrinsicError {
|
pub struct NullaryIntrinsicError {
|
||||||
|
|
|
@ -9,8 +9,9 @@ use std::hash::Hash;
|
||||||
use rustc_apfloat::{Float, FloatConvert};
|
use rustc_apfloat::{Float, FloatConvert};
|
||||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
|
use rustc_middle::query::TyCtxtAt;
|
||||||
|
use rustc_middle::ty;
|
||||||
use rustc_middle::ty::layout::TyAndLayout;
|
use rustc_middle::ty::layout::TyAndLayout;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Align, Size};
|
||||||
use rustc_target::spec::abi::Abi as CallAbi;
|
use rustc_target::spec::abi::Abi as CallAbi;
|
||||||
|
@ -293,7 +294,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
||||||
/// `def_id` is `Some` if this is the "lazy" allocation of a static.
|
/// `def_id` is `Some` if this is the "lazy" allocation of a static.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn before_access_global(
|
fn before_access_global(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
_machine: &Self,
|
_machine: &Self,
|
||||||
_alloc_id: AllocId,
|
_alloc_id: AllocId,
|
||||||
_allocation: ConstAllocation<'tcx>,
|
_allocation: ConstAllocation<'tcx>,
|
||||||
|
@ -388,7 +389,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
||||||
/// need to mutate.
|
/// need to mutate.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn before_memory_read(
|
fn before_memory_read(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
_machine: &Self,
|
_machine: &Self,
|
||||||
_alloc_extra: &Self::AllocExtra,
|
_alloc_extra: &Self::AllocExtra,
|
||||||
_prov: (AllocId, Self::ProvenanceExtra),
|
_prov: (AllocId, Self::ProvenanceExtra),
|
||||||
|
@ -400,7 +401,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
||||||
/// Hook for performing extra checks on a memory write access.
|
/// Hook for performing extra checks on a memory write access.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn before_memory_write(
|
fn before_memory_write(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
_machine: &mut Self,
|
_machine: &mut Self,
|
||||||
_alloc_extra: &mut Self::AllocExtra,
|
_alloc_extra: &mut Self::AllocExtra,
|
||||||
_prov: (AllocId, Self::ProvenanceExtra),
|
_prov: (AllocId, Self::ProvenanceExtra),
|
||||||
|
@ -412,7 +413,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
||||||
/// Hook for performing extra operations on a memory deallocation.
|
/// Hook for performing extra operations on a memory deallocation.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn before_memory_deallocation(
|
fn before_memory_deallocation(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
_machine: &mut Self,
|
_machine: &mut Self,
|
||||||
_alloc_extra: &mut Self::AllocExtra,
|
_alloc_extra: &mut Self::AllocExtra,
|
||||||
_prov: (AllocId, Self::ProvenanceExtra),
|
_prov: (AllocId, Self::ProvenanceExtra),
|
||||||
|
@ -515,7 +516,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
||||||
/// (CTFE and ConstProp) use the same instance. Here, we share that code.
|
/// (CTFE and ConstProp) use the same instance. Here, we share that code.
|
||||||
pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||||
type Provenance = CtfeProvenance;
|
type Provenance = CtfeProvenance;
|
||||||
type ProvenanceExtra = (); // FIXME extract the "immutable" bool?
|
type ProvenanceExtra = bool; // the "immutable" flag
|
||||||
|
|
||||||
type ExtraFnVal = !;
|
type ExtraFnVal = !;
|
||||||
|
|
||||||
|
@ -597,6 +598,6 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||||
) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
|
) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
|
||||||
// We know `offset` is relative to the allocation, so we can use `into_parts`.
|
// We know `offset` is relative to the allocation, so we can use `into_parts`.
|
||||||
let (prov, offset) = ptr.into_parts();
|
let (prov, offset) = ptr.into_parts();
|
||||||
Some((prov.alloc_id(), offset, ()))
|
Some((prov.alloc_id(), offset, prov.immutable()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -339,7 +339,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
// Let the machine take some extra action
|
// Let the machine take some extra action
|
||||||
let size = alloc.size();
|
let size = alloc.size();
|
||||||
M::before_memory_deallocation(
|
M::before_memory_deallocation(
|
||||||
*self.tcx,
|
self.tcx,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
&mut alloc.extra,
|
&mut alloc.extra,
|
||||||
(alloc_id, prov),
|
(alloc_id, prov),
|
||||||
|
@ -561,7 +561,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
(val, Some(def_id))
|
(val, Some(def_id))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
M::before_access_global(*self.tcx, &self.machine, id, alloc, def_id, is_write)?;
|
M::before_access_global(self.tcx, &self.machine, id, alloc, def_id, is_write)?;
|
||||||
// We got tcx memory. Let the machine initialize its "extra" stuff.
|
// We got tcx memory. Let the machine initialize its "extra" stuff.
|
||||||
M::adjust_allocation(
|
M::adjust_allocation(
|
||||||
self,
|
self,
|
||||||
|
@ -626,7 +626,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
)?;
|
)?;
|
||||||
if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc {
|
if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc {
|
||||||
let range = alloc_range(offset, size);
|
let range = alloc_range(offset, size);
|
||||||
M::before_memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?;
|
M::before_memory_read(self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?;
|
||||||
Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id }))
|
Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id }))
|
||||||
} else {
|
} else {
|
||||||
// Even in this branch we have to be sure that we actually access the allocation, in
|
// Even in this branch we have to be sure that we actually access the allocation, in
|
||||||
|
@ -687,13 +687,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
{
|
{
|
||||||
let parts = self.get_ptr_access(ptr, size)?;
|
let parts = self.get_ptr_access(ptr, size)?;
|
||||||
if let Some((alloc_id, offset, prov)) = parts {
|
if let Some((alloc_id, offset, prov)) = parts {
|
||||||
let tcx = *self.tcx;
|
let tcx = self.tcx;
|
||||||
// FIXME: can we somehow avoid looking up the allocation twice here?
|
// FIXME: can we somehow avoid looking up the allocation twice here?
|
||||||
// We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
|
// We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
|
||||||
let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?;
|
let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?;
|
||||||
let range = alloc_range(offset, size);
|
let range = alloc_range(offset, size);
|
||||||
M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?;
|
M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?;
|
||||||
Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id }))
|
Ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id }))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -1133,7 +1133,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
let src_alloc = self.get_alloc_raw(src_alloc_id)?;
|
let src_alloc = self.get_alloc_raw(src_alloc_id)?;
|
||||||
let src_range = alloc_range(src_offset, size);
|
let src_range = alloc_range(src_offset, size);
|
||||||
M::before_memory_read(
|
M::before_memory_read(
|
||||||
*tcx,
|
tcx,
|
||||||
&self.machine,
|
&self.machine,
|
||||||
&src_alloc.extra,
|
&src_alloc.extra,
|
||||||
(src_alloc_id, src_prov),
|
(src_alloc_id, src_prov),
|
||||||
|
@ -1163,7 +1163,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
|
let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
|
||||||
let dest_range = alloc_range(dest_offset, size * num_copies);
|
let dest_range = alloc_range(dest_offset, size * num_copies);
|
||||||
M::before_memory_write(
|
M::before_memory_write(
|
||||||
*tcx,
|
tcx,
|
||||||
extra,
|
extra,
|
||||||
&mut dest_alloc.extra,
|
&mut dest_alloc.extra,
|
||||||
(dest_alloc_id, dest_prov),
|
(dest_alloc_id, dest_prov),
|
||||||
|
|
|
@ -8,6 +8,135 @@ use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
|
declare_lint_pass! {
|
||||||
|
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||||
|
/// that are used by other parts of the compiler.
|
||||||
|
HardwiredLints => [
|
||||||
|
// tidy-alphabetical-start
|
||||||
|
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
|
||||||
|
AMBIGUOUS_ASSOCIATED_ITEMS,
|
||||||
|
AMBIGUOUS_GLOB_IMPORTS,
|
||||||
|
AMBIGUOUS_GLOB_REEXPORTS,
|
||||||
|
ARITHMETIC_OVERFLOW,
|
||||||
|
ASM_SUB_REGISTER,
|
||||||
|
BAD_ASM_STYLE,
|
||||||
|
BARE_TRAIT_OBJECTS,
|
||||||
|
BINDINGS_WITH_VARIANT_NAME,
|
||||||
|
BREAK_WITH_LABEL_AND_LOOP,
|
||||||
|
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
||||||
|
CENUM_IMPL_DROP_CAST,
|
||||||
|
COHERENCE_LEAK_CHECK,
|
||||||
|
COINDUCTIVE_OVERLAP_IN_COHERENCE,
|
||||||
|
CONFLICTING_REPR_HINTS,
|
||||||
|
CONST_EVALUATABLE_UNCHECKED,
|
||||||
|
CONST_ITEM_MUTATION,
|
||||||
|
CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
|
||||||
|
DEAD_CODE,
|
||||||
|
DEPRECATED,
|
||||||
|
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
||||||
|
DEPRECATED_IN_FUTURE,
|
||||||
|
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||||
|
DUPLICATE_MACRO_ATTRIBUTES,
|
||||||
|
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
||||||
|
ELIDED_LIFETIMES_IN_PATHS,
|
||||||
|
EXPORTED_PRIVATE_DEPENDENCIES,
|
||||||
|
FFI_UNWIND_CALLS,
|
||||||
|
FORBIDDEN_LINT_GROUPS,
|
||||||
|
FUNCTION_ITEM_REFERENCES,
|
||||||
|
FUZZY_PROVENANCE_CASTS,
|
||||||
|
HIDDEN_GLOB_REEXPORTS,
|
||||||
|
ILL_FORMED_ATTRIBUTE_INPUT,
|
||||||
|
ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||||
|
IMPLIED_BOUNDS_ENTAILMENT,
|
||||||
|
INCOMPLETE_INCLUDE,
|
||||||
|
INDIRECT_STRUCTURAL_MATCH,
|
||||||
|
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
|
||||||
|
INLINE_NO_SANITIZE,
|
||||||
|
INVALID_DOC_ATTRIBUTES,
|
||||||
|
INVALID_MACRO_EXPORT_ARGUMENTS,
|
||||||
|
INVALID_TYPE_PARAM_DEFAULT,
|
||||||
|
IRREFUTABLE_LET_PATTERNS,
|
||||||
|
LARGE_ASSIGNMENTS,
|
||||||
|
LATE_BOUND_LIFETIME_ARGUMENTS,
|
||||||
|
LEGACY_DERIVE_HELPERS,
|
||||||
|
LONG_RUNNING_CONST_EVAL,
|
||||||
|
LOSSY_PROVENANCE_CASTS,
|
||||||
|
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
|
||||||
|
MACRO_USE_EXTERN_CRATE,
|
||||||
|
META_VARIABLE_MISUSE,
|
||||||
|
MISSING_ABI,
|
||||||
|
MISSING_FRAGMENT_SPECIFIER,
|
||||||
|
MUST_NOT_SUSPEND,
|
||||||
|
NAMED_ARGUMENTS_USED_POSITIONALLY,
|
||||||
|
NON_EXHAUSTIVE_OMITTED_PATTERNS,
|
||||||
|
NONTRIVIAL_STRUCTURAL_MATCH,
|
||||||
|
ORDER_DEPENDENT_TRAIT_OBJECTS,
|
||||||
|
OVERLAPPING_RANGE_ENDPOINTS,
|
||||||
|
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||||
|
POINTER_STRUCTURAL_MATCH,
|
||||||
|
PRIVATE_BOUNDS,
|
||||||
|
PRIVATE_INTERFACES,
|
||||||
|
PROC_MACRO_BACK_COMPAT,
|
||||||
|
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
||||||
|
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
||||||
|
REFINING_IMPL_TRAIT,
|
||||||
|
RENAMED_AND_REMOVED_LINTS,
|
||||||
|
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
|
||||||
|
RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
|
||||||
|
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
|
||||||
|
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
|
||||||
|
RUST_2021_PRELUDE_COLLISIONS,
|
||||||
|
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
||||||
|
SINGLE_USE_LIFETIMES,
|
||||||
|
SOFT_UNSTABLE,
|
||||||
|
STABLE_FEATURES,
|
||||||
|
SUSPICIOUS_AUTO_TRAIT_IMPLS,
|
||||||
|
TEST_UNSTABLE_LINT,
|
||||||
|
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
|
||||||
|
TRIVIAL_CASTS,
|
||||||
|
TRIVIAL_NUMERIC_CASTS,
|
||||||
|
TYVAR_BEHIND_RAW_POINTER,
|
||||||
|
UNCONDITIONAL_PANIC,
|
||||||
|
UNCONDITIONAL_RECURSION,
|
||||||
|
UNDEFINED_NAKED_FUNCTION_ABI,
|
||||||
|
UNEXPECTED_CFGS,
|
||||||
|
UNFULFILLED_LINT_EXPECTATIONS,
|
||||||
|
UNINHABITED_STATIC,
|
||||||
|
UNKNOWN_CRATE_TYPES,
|
||||||
|
UNKNOWN_LINTS,
|
||||||
|
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||||
|
UNNAMEABLE_TEST_ITEMS,
|
||||||
|
UNNAMEABLE_TYPES,
|
||||||
|
UNREACHABLE_CODE,
|
||||||
|
UNREACHABLE_PATTERNS,
|
||||||
|
UNSAFE_OP_IN_UNSAFE_FN,
|
||||||
|
UNSTABLE_NAME_COLLISIONS,
|
||||||
|
UNSTABLE_SYNTAX_PRE_EXPANSION,
|
||||||
|
UNSUPPORTED_CALLING_CONVENTIONS,
|
||||||
|
UNUSED_ASSIGNMENTS,
|
||||||
|
UNUSED_ASSOCIATED_TYPE_BOUNDS,
|
||||||
|
UNUSED_ATTRIBUTES,
|
||||||
|
UNUSED_CRATE_DEPENDENCIES,
|
||||||
|
UNUSED_EXTERN_CRATES,
|
||||||
|
UNUSED_FEATURES,
|
||||||
|
UNUSED_IMPORTS,
|
||||||
|
UNUSED_LABELS,
|
||||||
|
UNUSED_LIFETIMES,
|
||||||
|
UNUSED_MACRO_RULES,
|
||||||
|
UNUSED_MACROS,
|
||||||
|
UNUSED_MUT,
|
||||||
|
UNUSED_QUALIFICATIONS,
|
||||||
|
UNUSED_TUPLE_STRUCT_FIELDS,
|
||||||
|
UNUSED_UNSAFE,
|
||||||
|
UNUSED_VARIABLES,
|
||||||
|
USELESS_DEPRECATED,
|
||||||
|
WARNINGS,
|
||||||
|
WHERE_CLAUSES_OBJECT_SAFETY,
|
||||||
|
WRITES_THROUGH_IMMUTABLE_POINTER,
|
||||||
|
// tidy-alphabetical-end
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `forbidden_lint_groups` lint detects violations of
|
/// The `forbidden_lint_groups` lint detects violations of
|
||||||
/// `forbid` applied to a lint group. Due to a bug in the compiler,
|
/// `forbid` applied to a lint group. Due to a bug in the compiler,
|
||||||
|
@ -3348,134 +3477,6 @@ declare_lint! {
|
||||||
"name introduced by a private item shadows a name introduced by a public glob re-export",
|
"name introduced by a private item shadows a name introduced by a public glob re-export",
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint_pass! {
|
|
||||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
|
||||||
/// that are used by other parts of the compiler.
|
|
||||||
HardwiredLints => [
|
|
||||||
// tidy-alphabetical-start
|
|
||||||
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
|
|
||||||
AMBIGUOUS_ASSOCIATED_ITEMS,
|
|
||||||
AMBIGUOUS_GLOB_IMPORTS,
|
|
||||||
AMBIGUOUS_GLOB_REEXPORTS,
|
|
||||||
ARITHMETIC_OVERFLOW,
|
|
||||||
ASM_SUB_REGISTER,
|
|
||||||
BAD_ASM_STYLE,
|
|
||||||
BARE_TRAIT_OBJECTS,
|
|
||||||
BINDINGS_WITH_VARIANT_NAME,
|
|
||||||
BREAK_WITH_LABEL_AND_LOOP,
|
|
||||||
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
|
||||||
CENUM_IMPL_DROP_CAST,
|
|
||||||
COHERENCE_LEAK_CHECK,
|
|
||||||
COINDUCTIVE_OVERLAP_IN_COHERENCE,
|
|
||||||
CONFLICTING_REPR_HINTS,
|
|
||||||
CONST_EVALUATABLE_UNCHECKED,
|
|
||||||
CONST_ITEM_MUTATION,
|
|
||||||
CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
|
|
||||||
DEAD_CODE,
|
|
||||||
DEPRECATED,
|
|
||||||
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
|
||||||
DEPRECATED_IN_FUTURE,
|
|
||||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
|
||||||
DUPLICATE_MACRO_ATTRIBUTES,
|
|
||||||
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
|
||||||
ELIDED_LIFETIMES_IN_PATHS,
|
|
||||||
EXPORTED_PRIVATE_DEPENDENCIES,
|
|
||||||
FFI_UNWIND_CALLS,
|
|
||||||
FORBIDDEN_LINT_GROUPS,
|
|
||||||
FUNCTION_ITEM_REFERENCES,
|
|
||||||
FUZZY_PROVENANCE_CASTS,
|
|
||||||
HIDDEN_GLOB_REEXPORTS,
|
|
||||||
ILL_FORMED_ATTRIBUTE_INPUT,
|
|
||||||
ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
|
||||||
IMPLIED_BOUNDS_ENTAILMENT,
|
|
||||||
INCOMPLETE_INCLUDE,
|
|
||||||
INDIRECT_STRUCTURAL_MATCH,
|
|
||||||
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
|
|
||||||
INLINE_NO_SANITIZE,
|
|
||||||
INVALID_DOC_ATTRIBUTES,
|
|
||||||
INVALID_MACRO_EXPORT_ARGUMENTS,
|
|
||||||
INVALID_TYPE_PARAM_DEFAULT,
|
|
||||||
IRREFUTABLE_LET_PATTERNS,
|
|
||||||
LARGE_ASSIGNMENTS,
|
|
||||||
LATE_BOUND_LIFETIME_ARGUMENTS,
|
|
||||||
LEGACY_DERIVE_HELPERS,
|
|
||||||
LONG_RUNNING_CONST_EVAL,
|
|
||||||
LOSSY_PROVENANCE_CASTS,
|
|
||||||
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
|
|
||||||
MACRO_USE_EXTERN_CRATE,
|
|
||||||
META_VARIABLE_MISUSE,
|
|
||||||
MISSING_ABI,
|
|
||||||
MISSING_FRAGMENT_SPECIFIER,
|
|
||||||
MUST_NOT_SUSPEND,
|
|
||||||
NAMED_ARGUMENTS_USED_POSITIONALLY,
|
|
||||||
NON_EXHAUSTIVE_OMITTED_PATTERNS,
|
|
||||||
NONTRIVIAL_STRUCTURAL_MATCH,
|
|
||||||
ORDER_DEPENDENT_TRAIT_OBJECTS,
|
|
||||||
OVERLAPPING_RANGE_ENDPOINTS,
|
|
||||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
|
||||||
POINTER_STRUCTURAL_MATCH,
|
|
||||||
PRIVATE_BOUNDS,
|
|
||||||
PRIVATE_INTERFACES,
|
|
||||||
PROC_MACRO_BACK_COMPAT,
|
|
||||||
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
|
||||||
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
|
||||||
REFINING_IMPL_TRAIT,
|
|
||||||
RENAMED_AND_REMOVED_LINTS,
|
|
||||||
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
|
|
||||||
RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
|
|
||||||
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
|
|
||||||
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
|
|
||||||
RUST_2021_PRELUDE_COLLISIONS,
|
|
||||||
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
|
||||||
SINGLE_USE_LIFETIMES,
|
|
||||||
SOFT_UNSTABLE,
|
|
||||||
STABLE_FEATURES,
|
|
||||||
SUSPICIOUS_AUTO_TRAIT_IMPLS,
|
|
||||||
TEST_UNSTABLE_LINT,
|
|
||||||
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
|
|
||||||
TRIVIAL_CASTS,
|
|
||||||
TRIVIAL_NUMERIC_CASTS,
|
|
||||||
TYVAR_BEHIND_RAW_POINTER,
|
|
||||||
UNCONDITIONAL_PANIC,
|
|
||||||
UNCONDITIONAL_RECURSION,
|
|
||||||
UNDEFINED_NAKED_FUNCTION_ABI,
|
|
||||||
UNEXPECTED_CFGS,
|
|
||||||
UNFULFILLED_LINT_EXPECTATIONS,
|
|
||||||
UNINHABITED_STATIC,
|
|
||||||
UNKNOWN_CRATE_TYPES,
|
|
||||||
UNKNOWN_LINTS,
|
|
||||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
|
||||||
UNNAMEABLE_TEST_ITEMS,
|
|
||||||
UNNAMEABLE_TYPES,
|
|
||||||
UNREACHABLE_CODE,
|
|
||||||
UNREACHABLE_PATTERNS,
|
|
||||||
UNSAFE_OP_IN_UNSAFE_FN,
|
|
||||||
UNSTABLE_NAME_COLLISIONS,
|
|
||||||
UNSTABLE_SYNTAX_PRE_EXPANSION,
|
|
||||||
UNSUPPORTED_CALLING_CONVENTIONS,
|
|
||||||
UNUSED_ASSIGNMENTS,
|
|
||||||
UNUSED_ASSOCIATED_TYPE_BOUNDS,
|
|
||||||
UNUSED_ATTRIBUTES,
|
|
||||||
UNUSED_CRATE_DEPENDENCIES,
|
|
||||||
UNUSED_EXTERN_CRATES,
|
|
||||||
UNUSED_FEATURES,
|
|
||||||
UNUSED_IMPORTS,
|
|
||||||
UNUSED_LABELS,
|
|
||||||
UNUSED_LIFETIMES,
|
|
||||||
UNUSED_MACRO_RULES,
|
|
||||||
UNUSED_MACROS,
|
|
||||||
UNUSED_MUT,
|
|
||||||
UNUSED_QUALIFICATIONS,
|
|
||||||
UNUSED_TUPLE_STRUCT_FIELDS,
|
|
||||||
UNUSED_UNSAFE,
|
|
||||||
UNUSED_VARIABLES,
|
|
||||||
USELESS_DEPRECATED,
|
|
||||||
WARNINGS,
|
|
||||||
WHERE_CLAUSES_OBJECT_SAFETY,
|
|
||||||
// tidy-alphabetical-end
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `long_running_const_eval` lint is emitted when const
|
/// The `long_running_const_eval` lint is emitted when const
|
||||||
/// eval is running for a long time to ensure rustc terminates
|
/// eval is running for a long time to ensure rustc terminates
|
||||||
|
@ -4620,3 +4621,37 @@ declare_lint! {
|
||||||
reference: "issue #115010 <https://github.com/rust-lang/rust/issues/115010>",
|
reference: "issue #115010 <https://github.com/rust-lang/rust/issues/115010>",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `writes_through_immutable_pointer` lint detects writes through pointers derived from
|
||||||
|
/// shared references.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust,compile_fail
|
||||||
|
/// #![feature(const_mut_refs)]
|
||||||
|
/// const WRITE_AFTER_CAST: () = unsafe {
|
||||||
|
/// let mut x = 0;
|
||||||
|
/// let ptr = &x as *const i32 as *mut i32;
|
||||||
|
/// *ptr = 0;
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Shared references are immutable (when there is no `UnsafeCell` involved),
|
||||||
|
/// and writing through them or through pointers derived from them is Undefined Behavior.
|
||||||
|
/// The compiler recently learned to detect such Undefined Behavior during compile-time
|
||||||
|
/// evaluation, and in the future this will raise a hard error.
|
||||||
|
///
|
||||||
|
/// [future-incompatible]: ../index.md#future-incompatible-lints
|
||||||
|
pub WRITES_THROUGH_IMMUTABLE_POINTER,
|
||||||
|
Warn,
|
||||||
|
"shared references are immutable, and pointers derived from them must not be written to",
|
||||||
|
@future_incompatible = FutureIncompatibleInfo {
|
||||||
|
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
|
||||||
|
reference: "issue #X <https://github.com/rust-lang/rust/issues/X>",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ use rustc_middle::mir::visit::{
|
||||||
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
|
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
|
||||||
};
|
};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
|
use rustc_middle::query::TyCtxtAt;
|
||||||
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
|
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
|
||||||
use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_span::{def_id::DefId, Span};
|
use rustc_span::{def_id::DefId, Span};
|
||||||
|
@ -220,7 +221,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn before_access_global(
|
fn before_access_global(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
_machine: &Self,
|
_machine: &Self,
|
||||||
_alloc_id: AllocId,
|
_alloc_id: AllocId,
|
||||||
alloc: ConstAllocation<'tcx>,
|
alloc: ConstAllocation<'tcx>,
|
||||||
|
|
|
@ -8,6 +8,7 @@ use rustc_hir::def::DefKind;
|
||||||
use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
|
use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
|
||||||
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
|
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
|
use rustc_middle::query::TyCtxtAt;
|
||||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_mir_dataflow::value_analysis::{
|
use rustc_mir_dataflow::value_analysis::{
|
||||||
|
@ -876,7 +877,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
|
||||||
}
|
}
|
||||||
|
|
||||||
fn before_access_global(
|
fn before_access_global(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
_machine: &Self,
|
_machine: &Self,
|
||||||
_alloc_id: AllocId,
|
_alloc_id: AllocId,
|
||||||
alloc: ConstAllocation<'tcx>,
|
alloc: ConstAllocation<'tcx>,
|
||||||
|
|
|
@ -17,6 +17,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::static_assert_size;
|
use rustc_data_structures::static_assert_size;
|
||||||
use rustc_middle::{
|
use rustc_middle::{
|
||||||
mir,
|
mir,
|
||||||
|
query::TyCtxtAt,
|
||||||
ty::{
|
ty::{
|
||||||
self,
|
self,
|
||||||
layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout},
|
layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout},
|
||||||
|
@ -1251,7 +1252,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn before_memory_read(
|
fn before_memory_read(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
machine: &Self,
|
machine: &Self,
|
||||||
alloc_extra: &AllocExtra<'tcx>,
|
alloc_extra: &AllocExtra<'tcx>,
|
||||||
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
|
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
|
||||||
|
@ -1271,7 +1272,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn before_memory_write(
|
fn before_memory_write(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
machine: &mut Self,
|
machine: &mut Self,
|
||||||
alloc_extra: &mut AllocExtra<'tcx>,
|
alloc_extra: &mut AllocExtra<'tcx>,
|
||||||
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
|
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
|
||||||
|
@ -1291,7 +1292,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn before_memory_deallocation(
|
fn before_memory_deallocation(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
machine: &mut Self,
|
machine: &mut Self,
|
||||||
alloc_extra: &mut AllocExtra<'tcx>,
|
alloc_extra: &mut AllocExtra<'tcx>,
|
||||||
(alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra),
|
(alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra),
|
||||||
|
|
30
tests/ui/consts/const-eval/ub-write-through-immutable.rs
Normal file
30
tests/ui/consts/const-eval/ub-write-through-immutable.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//! Ensure we catch UB due to writing through a shared reference.
|
||||||
|
#![feature(const_mut_refs, const_refs_to_cell)]
|
||||||
|
#![deny(writes_through_immutable_pointer)]
|
||||||
|
#![allow(invalid_reference_casting)]
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::cell::UnsafeCell;
|
||||||
|
|
||||||
|
const WRITE_AFTER_CAST: () = unsafe {
|
||||||
|
let mut x = 0;
|
||||||
|
let ptr = &x as *const i32 as *mut i32;
|
||||||
|
*ptr = 0; //~ERROR: writes_through_immutable_pointer
|
||||||
|
//~^ previously accepted
|
||||||
|
};
|
||||||
|
|
||||||
|
const WRITE_AFTER_TRANSMUTE: () = unsafe {
|
||||||
|
let mut x = 0;
|
||||||
|
let ptr: *mut i32 = mem::transmute(&x);
|
||||||
|
*ptr = 0; //~ERROR: writes_through_immutable_pointer
|
||||||
|
//~^ previously accepted
|
||||||
|
};
|
||||||
|
|
||||||
|
// it's okay when there is interior mutability;
|
||||||
|
const WRITE_INTERIOR_MUT: () = unsafe {
|
||||||
|
let x = UnsafeCell::new(0);
|
||||||
|
let ptr = &x as *const _ as *mut i32;
|
||||||
|
*ptr = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {}
|
55
tests/ui/consts/const-eval/ub-write-through-immutable.stderr
Normal file
55
tests/ui/consts/const-eval/ub-write-through-immutable.stderr
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
error: writing through a pointer that was derived from a shared (immutable) reference
|
||||||
|
--> $DIR/ub-write-through-immutable.rs:12:5
|
||||||
|
|
|
||||||
|
LL | *ptr = 0;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= 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 #X <https://github.com/rust-lang/rust/issues/X>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/ub-write-through-immutable.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(writes_through_immutable_pointer)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: writing through a pointer that was derived from a shared (immutable) reference
|
||||||
|
--> $DIR/ub-write-through-immutable.rs:19:5
|
||||||
|
|
|
||||||
|
LL | *ptr = 0;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= 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 #X <https://github.com/rust-lang/rust/issues/X>
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Future incompatibility report: Future breakage diagnostic:
|
||||||
|
error: writing through a pointer that was derived from a shared (immutable) reference
|
||||||
|
--> $DIR/ub-write-through-immutable.rs:12:5
|
||||||
|
|
|
||||||
|
LL | *ptr = 0;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= 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 #X <https://github.com/rust-lang/rust/issues/X>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/ub-write-through-immutable.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(writes_through_immutable_pointer)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Future breakage diagnostic:
|
||||||
|
error: writing through a pointer that was derived from a shared (immutable) reference
|
||||||
|
--> $DIR/ub-write-through-immutable.rs:19:5
|
||||||
|
|
|
||||||
|
LL | *ptr = 0;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= 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 #X <https://github.com/rust-lang/rust/issues/X>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/ub-write-through-immutable.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(writes_through_immutable_pointer)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0080]: it is undefined behavior to use this value
|
error[E0080]: it is undefined behavior to use this value
|
||||||
--> $DIR/invalid-union.rs:41:1
|
--> $DIR/invalid-union.rs:35:1
|
||||||
|
|
|
|
||||||
LL | fn main() {
|
LL | fn main() {
|
||||||
| ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const`
|
| ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const`
|
||||||
|
@ -10,13 +10,13 @@ LL | fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
note: erroneous constant encountered
|
note: erroneous constant encountered
|
||||||
--> $DIR/invalid-union.rs:43:25
|
--> $DIR/invalid-union.rs:37:25
|
||||||
|
|
|
|
||||||
LL | let _: &'static _ = &C;
|
LL | let _: &'static _ = &C;
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
note: erroneous constant encountered
|
note: erroneous constant encountered
|
||||||
--> $DIR/invalid-union.rs:43:25
|
--> $DIR/invalid-union.rs:37:25
|
||||||
|
|
|
|
||||||
LL | let _: &'static _ = &C;
|
LL | let _: &'static _ = &C;
|
||||||
| ^^
|
| ^^
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0080]: it is undefined behavior to use this value
|
error[E0080]: it is undefined behavior to use this value
|
||||||
--> $DIR/invalid-union.rs:41:1
|
--> $DIR/invalid-union.rs:35:1
|
||||||
|
|
|
|
||||||
LL | fn main() {
|
LL | fn main() {
|
||||||
| ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const`
|
| ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const`
|
||||||
|
@ -10,13 +10,13 @@ LL | fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
note: erroneous constant encountered
|
note: erroneous constant encountered
|
||||||
--> $DIR/invalid-union.rs:43:25
|
--> $DIR/invalid-union.rs:37:25
|
||||||
|
|
|
|
||||||
LL | let _: &'static _ = &C;
|
LL | let _: &'static _ = &C;
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
note: erroneous constant encountered
|
note: erroneous constant encountered
|
||||||
--> $DIR/invalid-union.rs:43:25
|
--> $DIR/invalid-union.rs:37:25
|
||||||
|
|
|
|
||||||
LL | let _: &'static _ = &C;
|
LL | let _: &'static _ = &C;
|
||||||
| ^^
|
| ^^
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
// Check that constants with interior mutability inside unions are rejected
|
// Check that constants with interior mutability inside unions are rejected
|
||||||
// during validation.
|
// during validation.
|
||||||
//
|
//
|
||||||
// Note that this test case relies on undefined behaviour to construct a
|
|
||||||
// constant with interior mutability that is "invisible" to the static checks.
|
|
||||||
// If for some reason this approach no longer works, it is should be fine to
|
|
||||||
// remove the test case.
|
|
||||||
//
|
|
||||||
// build-fail
|
// build-fail
|
||||||
// stderr-per-bitwidth
|
// stderr-per-bitwidth
|
||||||
#![feature(const_mut_refs)]
|
#![feature(const_mut_refs)]
|
||||||
|
@ -30,10 +25,9 @@ union U {
|
||||||
}
|
}
|
||||||
|
|
||||||
const C: S = {
|
const C: S = {
|
||||||
let s = S { x: 0, y: E::A };
|
let mut s = S { x: 0, y: E::A };
|
||||||
// Go through an &u32 reference which is definitely not allowed to mutate anything.
|
let p = &mut s.x as *mut u32;
|
||||||
let p = &s.x as *const u32 as *mut u32;
|
// Change enum tag to E::B. Now there's interior mutability here.
|
||||||
// Change enum tag to E::B.
|
|
||||||
unsafe { *p.add(1) = 1 };
|
unsafe { *p.add(1) = 1 };
|
||||||
s
|
s
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue