Auto merge of #118324 - RalfJung:ctfe-read-only-pointers, r=saethlin

compile-time evaluation: detect writes through immutable pointers

This has two motivations:
- it unblocks https://github.com/rust-lang/rust/pull/116745 (and therefore takes a big step towards `const_mut_refs` stabilization), because we can now detect if the memory that we find in `const` can be interned as "immutable"
- it would detect the UB that was uncovered in https://github.com/rust-lang/rust/pull/117905, which was caused by accidental stabilization of `copy` functions in `const` that can only be called with UB

When UB is detected, we emit a future-compat warn-by-default lint. This is not a breaking change, so completely in line with [the const-UB RFC](https://rust-lang.github.io/rfcs/3016-const-ub.html), meaning we don't need t-lang FCP here. I made the lint immediately show up for dependencies since it is nearly impossible to even trigger this lint without `const_mut_refs` -- the accidentally stabilized `copy` functions are the only way this can happen, so the crates that popped up in #117905 are the only causes of such UB (in the code that crater covers), and the three cases of UB that we know about have all been fixed in their respective crates already.

The way this is implemented is by making use of the fact that our interpreter is already generic over the notion of provenance. For CTFE we now use the new `CtfeProvenance` type which is conceptually an `AllocId` plus a boolean `immutable` flag (but packed for a more efficient representation). This means we can mark a pointer as immutable when it is created as a shared reference. The flag will be propagated to all pointers derived from this one. We can then check the immutable flag on each write to reject writes through immutable pointers.

I just hope perf works out.
This commit is contained in:
bors 2023-12-07 18:11:01 +00:00
commit 0e7f91b75e
86 changed files with 784 additions and 462 deletions

View File

@ -126,7 +126,8 @@ pub(crate) fn codegen_const_value<'tcx>(
}
}
Scalar::Ptr(ptr, _size) => {
let (alloc_id, offset) = ptr.into_parts(); // we know the `offset` is relative
let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative
let alloc_id = prov.alloc_id();
let base_addr = match fx.tcx.global_alloc(alloc_id) {
GlobalAlloc::Memory(alloc) => {
let data_id = data_id_for_alloc_id(
@ -374,7 +375,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
data.define(bytes.into_boxed_slice());
for &(offset, alloc_id) in alloc.provenance().ptrs().iter() {
for &(offset, prov) in alloc.provenance().ptrs().iter() {
let alloc_id = prov.alloc_id();
let addend = {
let endianness = tcx.data_layout.endian;
let offset = offset.bytes() as usize;

View File

@ -199,7 +199,8 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}
}
Scalar::Ptr(ptr, _size) => {
let (alloc_id, offset) = ptr.into_parts();
let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative
let alloc_id = prov.alloc_id();
let base_addr =
match self.tcx.global_alloc(alloc_id) {
GlobalAlloc::Memory(alloc) => {

View File

@ -285,7 +285,8 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
let pointer_size = dl.pointer_size.bytes() as usize;
let mut next_offset = 0;
for &(offset, alloc_id) in alloc.provenance().ptrs().iter() {
for &(offset, prov) in alloc.provenance().ptrs().iter() {
let alloc_id = prov.alloc_id();
let offset = offset.bytes();
assert_eq!(offset as usize as u64, offset);
let offset = offset as usize;
@ -313,7 +314,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
llvals.push(cx.scalar_to_backend(
InterpScalar::from_pointer(
interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
interpret::Pointer::new(prov, Size::from_bytes(ptr_offset)),
&cx.tcx,
),
abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) },

View File

@ -246,8 +246,8 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
Scalar::Ptr(ptr, _size) => {
let (alloc_id, offset) = ptr.into_parts();
let (base_addr, base_addr_space) = match self.tcx.global_alloc(alloc_id) {
let (prov, offset) = ptr.into_parts();
let (base_addr, base_addr_space) = match self.tcx.global_alloc(prov.alloc_id()) {
GlobalAlloc::Memory(alloc) => {
let init = const_alloc_to_llvm(self, alloc);
let alloc = alloc.inner();

View File

@ -72,7 +72,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
}
let mut next_offset = 0;
for &(offset, alloc_id) in alloc.provenance().ptrs().iter() {
for &(offset, prov) in alloc.provenance().ptrs().iter() {
let offset = offset.bytes();
assert_eq!(offset as usize as u64, offset);
let offset = offset as usize;
@ -92,13 +92,10 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
.expect("const_alloc_to_llvm: could not read relocation pointer")
as u64;
let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
let address_space = cx.tcx.global_alloc(prov.alloc_id()).address_space(cx);
llvals.push(cx.scalar_to_backend(
InterpScalar::from_pointer(
Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
&cx.tcx,
),
InterpScalar::from_pointer(Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx),
Scalar::Initialized {
value: Primitive::Pointer(address_space),
valid_range: WrappingRange::full(dl.pointer_size),

View File

@ -105,7 +105,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
};
let a = Scalar::from_pointer(
Pointer::new(bx.tcx().reserve_and_set_memory_alloc(data), Size::ZERO),
Pointer::new(bx.tcx().reserve_and_set_memory_alloc(data).into(), Size::ZERO),
&bx.tcx(),
);
let a_llval = bx.scalar_to_backend(

View File

@ -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_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 =
writing to {$allocation} which is read-only
const_eval_zst_pointer_out_of_bounds =

View File

@ -1,14 +1,16 @@
use std::mem;
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg};
use rustc_hir::CRATE_HIR_ID;
use rustc_middle::mir::AssertKind;
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{layout::LayoutError, ConstInt};
use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP};
use super::InterpCx;
use super::{CompileTimeInterpreter, InterpCx};
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.
#[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>>(
ecx: &InterpCx<'mir, 'tcx, M>,
pub fn get_span_and_frames<'tcx, 'mir>(
tcx: TyCtxtAt<'tcx>,
machine: &CompileTimeInterpreter<'mir, 'tcx>,
) -> (Span, Vec<errors::FrameNote>)
where
'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.
stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx));
let span = stacktrace.first().map(|f| f.span).unwrap_or(ecx.tcx.span);
stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx));
let span = stacktrace.first().map(|f| f.span).unwrap_or(tcx.span);
let mut frames = Vec::new();
@ -87,7 +93,7 @@ where
let mut last_frame: Option<errors::FrameNote> = None;
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() {
Some(last_frame)
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),
);
}

View File

@ -155,8 +155,8 @@ pub(super) fn op_to_const<'tcx>(
match immediate {
Left(ref mplace) => {
// We know `offset` is relative to the allocation, so we can use `into_parts`.
let (alloc_id, offset) = mplace.ptr().into_parts();
let alloc_id = alloc_id.expect("cannot have `fake` place fot non-ZST type");
let (prov, offset) = mplace.ptr().into_parts();
let alloc_id = prov.expect("cannot have `fake` place for non-ZST type").alloc_id();
ConstValue::Indirect { alloc_id, offset }
}
// see comment on `let force_as_immediate` above
@ -178,8 +178,8 @@ pub(super) fn op_to_const<'tcx>(
);
let msg = "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation";
// We know `offset` is relative to the allocation, so we can use `into_parts`.
let (alloc_id, offset) = a.to_pointer(ecx).expect(msg).into_parts();
let alloc_id = alloc_id.expect(msg);
let (prov, offset) = a.to_pointer(ecx).expect(msg).into_parts();
let alloc_id = prov.expect(msg).alloc_id();
let data = ecx.tcx.global_alloc(alloc_id).unwrap_memory();
assert!(offset == abi::Size::ZERO, "{}", msg);
let meta = b.to_target_usize(ecx).expect(msg);
@ -338,7 +338,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
*ecx.tcx,
error,
None,
|| super::get_span_and_frames(&ecx),
|| super::get_span_and_frames(ecx.tcx, &ecx.machine),
|span, frames| ConstEvalError {
span,
error_kind: kind,
@ -353,7 +353,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
let validation =
const_validate_mplace(&ecx, &mplace, is_static, cid.promoted.is_some());
let alloc_id = mplace.ptr().provenance.unwrap();
let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
// Validation failed, report an error.
if let Err(error) = validation {
@ -419,7 +419,7 @@ pub fn const_report_error<'mir, 'tcx>(
*ecx.tcx,
error,
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 },
)
}

View File

@ -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::fmt;
use std::hash::Hash;
use std::ops::ControlFlow;
use rustc_ast::Mutability;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::fx::IndexEntry;
use std::fmt;
use rustc_ast::Mutability;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::LangItem;
use rustc_middle::mir;
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::Span;
use rustc_target::abi::{Align, Size};
use rustc_target::spec::abi::Abi as CallAbi;
use crate::errors::{LongRunning, LongRunningWarn};
use crate::fluent_generated as fluent;
use crate::interpret::{
self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx,
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
self, compile_time_machine, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal,
Frame, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, PointerArithmetic, Scalar,
};
use super::error::*;
@ -49,7 +49,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
pub(super) num_evaluated_steps: usize,
/// The virtual call stack.
pub(super) stack: Vec<Frame<'mir, 'tcx, AllocId, ()>>,
pub(super) stack: Vec<Frame<'mir, 'tcx>>,
/// We need to make sure consts never point to anything mutable, even recursively. That is
/// relied on for pattern matching on consts with references.
@ -638,10 +638,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
}
#[inline(always)]
fn expose_ptr(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_ptr: Pointer<AllocId>,
) -> InterpResult<'tcx> {
fn expose_ptr(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> {
// This is only reachable with -Zunleash-the-miri-inside-of-you.
throw_unsup_format!("exposing pointers is not possible at compile-time")
}
@ -674,7 +671,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
}
fn before_access_global(
_tcx: TyCtxt<'tcx>,
_tcx: TyCtxtAt<'tcx>,
machine: &Self,
alloc_id: AllocId,
alloc: ConstAllocation<'tcx>,
@ -711,6 +708,48 @@ 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 it's a frozen shared reference that's not already immutable, make it immutable.
// (Do nothing on `None` provenance, that cannot store immutability anyway.)
if let ty::Ref(_, ty, mutbl) = val.layout.ty.kind()
&& *mutbl == Mutability::Not
&& val.to_scalar_and_meta().0.to_pointer(ecx)?.provenance.is_some_and(|p| !p.immutable())
// That next check is expensive, that's why we have all the guards above.
&& ty.is_freeze(*ecx.tcx, ecx.param_env)
{
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

View File

@ -402,6 +402,13 @@ pub struct ConstEvalError {
pub frame_notes: Vec<FrameNote>,
}
#[derive(LintDiagnostic)]
#[diag(const_eval_write_through_immutable_pointer)]
pub struct WriteThroughImmutablePointer {
#[subdiagnostic]
pub frames: Vec<FrameNote>,
}
#[derive(Diagnostic)]
#[diag(const_eval_nullary_intrinsic_fail)]
pub struct NullaryIntrinsicError {

View File

@ -7,7 +7,9 @@ use hir::CRATE_HIR_ID;
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
use rustc_index::IndexVec;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
use rustc_middle::mir::interpret::{
CtfeProvenance, ErrorHandled, InvalidMetaKind, ReportedErrorInfo,
};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
@ -20,9 +22,9 @@ use rustc_span::Span;
use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};
use super::{
AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
MemPlaceMeta, Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic,
Projectable, Provenance, Scalar, StackPopJump,
GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta,
Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable,
Provenance, Scalar, StackPopJump,
};
use crate::errors;
use crate::util;
@ -84,7 +86,7 @@ impl Drop for SpanGuard {
}
/// A stack frame.
pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> {
pub struct Frame<'mir, 'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
////////////////////////////////////////////////////////////////////////////////
// Function and callsite information
////////////////////////////////////////////////////////////////////////////////
@ -156,7 +158,7 @@ pub enum StackPopCleanup {
/// State of a local variable including a memoized layout
#[derive(Clone)]
pub struct LocalState<'tcx, Prov: Provenance = AllocId> {
pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
value: LocalValue<Prov>,
/// Don't modify if `Some`, this is only used to prevent computing the layout twice.
/// Avoids computing the layout of locals that are never actually initialized.
@ -177,7 +179,7 @@ impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> {
/// This does not store the type of the local; the type is given by `body.local_decls` and can never
/// change, so by not storing here we avoid having to maintain that as an invariant.
#[derive(Copy, Clone, Debug)] // Miri debug-prints these
pub(super) enum LocalValue<Prov: Provenance = AllocId> {
pub(super) enum LocalValue<Prov: Provenance = CtfeProvenance> {
/// This local is not currently alive, and cannot be used at all.
Dead,
/// A normal, live local.

View File

@ -18,7 +18,7 @@ use super::validity::RefTracking;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_middle::mir::interpret::InterpResult;
use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult};
use rustc_middle::ty::{self, layout::TyAndLayout, Ty};
use rustc_ast::Mutability;
@ -34,7 +34,7 @@ pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
'mir,
'tcx,
MemoryKind = T,
Provenance = AllocId,
Provenance = CtfeProvenance,
ExtraFnVal = !,
FrameExtra = (),
AllocExtra = (),
@ -135,7 +135,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
alloc.mutability = Mutability::Not;
};
// link the alloc id to the actual allocation
leftover_allocations.extend(alloc.provenance().ptrs().iter().map(|&(_, alloc_id)| alloc_id));
leftover_allocations.extend(alloc.provenance().ptrs().iter().map(|&(_, prov)| prov.alloc_id()));
let alloc = tcx.mk_const_alloc(alloc);
tcx.set_alloc_id_memory(alloc_id, alloc);
None
@ -178,10 +178,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind()
{
let ptr = mplace.meta().unwrap_meta().to_pointer(&tcx)?;
if let Some(alloc_id) = ptr.provenance {
if let Some(prov) = ptr.provenance {
// Explicitly choose const mode here, since vtables are immutable, even
// if the reference of the fat pointer is mutable.
self.intern_shallow(alloc_id, InternMode::Const, None);
self.intern_shallow(prov.alloc_id(), InternMode::Const, None);
} else {
// Validation will error (with a better message) on an invalid vtable pointer.
// Let validation show the error message, but make sure it *does* error.
@ -191,7 +191,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
}
// Check if we have encountered this pointer+layout combination before.
// Only recurse for allocation-backed pointers.
if let Some(alloc_id) = mplace.ptr().provenance {
if let Some(prov) = mplace.ptr().provenance {
// Compute the mode with which we intern this. Our goal here is to make as many
// statics as we can immutable so they can be placed in read-only memory by LLVM.
let ref_mode = match self.mode {
@ -234,7 +234,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
InternMode::Const
}
};
match self.intern_shallow(alloc_id, ref_mode, Some(referenced_ty)) {
match self.intern_shallow(prov.alloc_id(), ref_mode, Some(referenced_ty)) {
// No need to recurse, these are interned already and statics may have
// cycles, so we don't want to recurse there
Some(IsStaticOrFn) => {}
@ -353,7 +353,7 @@ pub fn intern_const_alloc_recursive<
leftover_allocations,
// The outermost allocation must exist, because we allocated it with
// `Memory::allocate`.
ret.ptr().provenance.unwrap(),
ret.ptr().provenance.unwrap().alloc_id(),
base_intern_mode,
Some(ret.layout.ty),
);
@ -431,7 +431,8 @@ pub fn intern_const_alloc_recursive<
}
let alloc = tcx.mk_const_alloc(alloc);
tcx.set_alloc_id_memory(alloc_id, alloc);
for &(_, alloc_id) in alloc.inner().provenance().ptrs().iter() {
for &(_, prov) in alloc.inner().provenance().ptrs().iter() {
let alloc_id = prov.alloc_id();
if leftover_allocations.insert(alloc_id) {
todo.push(alloc_id);
}
@ -503,10 +504,11 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
// `allocate` picks a fresh AllocId that we will associate with its data below.
let dest = self.allocate(layout, MemoryKind::Stack)?;
f(self, &dest.clone().into())?;
let mut alloc = self.memory.alloc_map.remove(&dest.ptr().provenance.unwrap()).unwrap().1;
let mut alloc =
self.memory.alloc_map.remove(&dest.ptr().provenance.unwrap().alloc_id()).unwrap().1;
alloc.mutability = Mutability::Not;
let alloc = self.tcx.mk_const_alloc(alloc);
let alloc_id = dest.ptr().provenance.unwrap(); // this was just allocated, it must have provenance
let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance
self.tcx.set_alloc_id_memory(alloc_id, alloc);
Ok(alloc_id)
}

View File

@ -9,15 +9,17 @@ use std::hash::Hash;
use rustc_apfloat::{Float, FloatConvert};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_middle::mir;
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_target::abi::{Align, Size};
use rustc_target::spec::abi::Abi as CallAbi;
use super::{
AllocBytes, AllocId, AllocKind, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy,
InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance,
AllocBytes, AllocId, AllocKind, AllocRange, Allocation, ConstAllocation, CtfeProvenance, FnArg,
Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy,
Pointer, Provenance,
};
/// Data returned by Machine::stack_pop,
@ -292,7 +294,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// `def_id` is `Some` if this is the "lazy" allocation of a static.
#[inline]
fn before_access_global(
_tcx: TyCtxt<'tcx>,
_tcx: TyCtxtAt<'tcx>,
_machine: &Self,
_alloc_id: AllocId,
_allocation: ConstAllocation<'tcx>,
@ -387,7 +389,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// need to mutate.
#[inline(always)]
fn before_memory_read(
_tcx: TyCtxt<'tcx>,
_tcx: TyCtxtAt<'tcx>,
_machine: &Self,
_alloc_extra: &Self::AllocExtra,
_prov: (AllocId, Self::ProvenanceExtra),
@ -399,7 +401,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// Hook for performing extra checks on a memory write access.
#[inline(always)]
fn before_memory_write(
_tcx: TyCtxt<'tcx>,
_tcx: TyCtxtAt<'tcx>,
_machine: &mut Self,
_alloc_extra: &mut Self::AllocExtra,
_prov: (AllocId, Self::ProvenanceExtra),
@ -411,7 +413,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// Hook for performing extra operations on a memory deallocation.
#[inline(always)]
fn before_memory_deallocation(
_tcx: TyCtxt<'tcx>,
_tcx: TyCtxtAt<'tcx>,
_machine: &mut Self,
_alloc_extra: &mut Self::AllocExtra,
_prov: (AllocId, Self::ProvenanceExtra),
@ -513,8 +515,8 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
/// (CTFE and ConstProp) use the same instance. Here, we share that code.
pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
type Provenance = AllocId;
type ProvenanceExtra = ();
type Provenance = CtfeProvenance;
type ProvenanceExtra = bool; // the "immutable" flag
type ExtraFnVal = !;
@ -567,14 +569,14 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
def_id: DefId,
) -> InterpResult<$tcx, Pointer> {
// Use the `AllocId` associated with the `DefId`. Any actual *access* will fail.
Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id), Size::ZERO))
Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO))
}
#[inline(always)]
fn adjust_alloc_base_pointer(
_ecx: &InterpCx<$mir, $tcx, Self>,
ptr: Pointer<AllocId>,
) -> InterpResult<$tcx, Pointer<AllocId>> {
ptr: Pointer<CtfeProvenance>,
) -> InterpResult<$tcx, Pointer<CtfeProvenance>> {
Ok(ptr)
}
@ -582,7 +584,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
fn ptr_from_addr_cast(
_ecx: &InterpCx<$mir, $tcx, Self>,
addr: u64,
) -> InterpResult<$tcx, Pointer<Option<AllocId>>> {
) -> InterpResult<$tcx, Pointer<Option<CtfeProvenance>>> {
// Allow these casts, but make the pointer not dereferenceable.
// (I.e., they behave like transmutation.)
// This is correct because no pointers can ever be exposed in compile-time evaluation.
@ -592,10 +594,10 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
#[inline(always)]
fn ptr_get_alloc(
_ecx: &InterpCx<$mir, $tcx, Self>,
ptr: Pointer<AllocId>,
ptr: Pointer<CtfeProvenance>,
) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
// We know `offset` is relative to the allocation, so we can use `into_parts`.
let (alloc_id, offset) = ptr.into_parts();
Some((alloc_id, offset, ()))
let (prov, offset) = ptr.into_parts();
Some((prov.alloc_id(), offset, prov.immutable()))
}
}

View File

@ -22,8 +22,8 @@ use crate::fluent_generated as fluent;
use super::{
alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg,
CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
PointerArithmetic, Provenance, Scalar,
CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak,
Misalignment, Pointer, PointerArithmetic, Provenance, Scalar,
};
#[derive(Debug, PartialEq, Copy, Clone)]
@ -159,9 +159,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
#[inline]
pub fn global_base_pointer(
&self,
ptr: Pointer<AllocId>,
ptr: Pointer<CtfeProvenance>,
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
let alloc_id = ptr.provenance;
let alloc_id = ptr.provenance.alloc_id();
// We need to handle `extern static`.
match self.tcx.try_get_global_alloc(alloc_id) {
Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => {
@ -339,7 +339,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Let the machine take some extra action
let size = alloc.size();
M::before_memory_deallocation(
*self.tcx,
self.tcx,
&mut self.machine,
&mut alloc.extra,
(alloc_id, prov),
@ -561,7 +561,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
(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.
M::adjust_allocation(
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 {
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 }))
} else {
// 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)?;
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?
// 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 range = alloc_range(offset, size);
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 {
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_range = alloc_range(src_offset, size);
M::before_memory_read(
*tcx,
tcx,
&self.machine,
&src_alloc.extra,
(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_range = alloc_range(dest_offset, size * num_copies);
M::before_memory_write(
*tcx,
tcx,
extra,
&mut dest_alloc.extra,
(dest_alloc_id, dest_prov),

View File

@ -13,9 +13,9 @@ use rustc_middle::{mir, ty};
use rustc_target::abi::{self, Abi, HasDataLayout, Size};
use super::{
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, Frame, InterpCx, InterpResult,
MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable,
Provenance, Scalar,
alloc_range, from_known_layout, mir_assign_valid_types, CtfeProvenance, Frame, InterpCx,
InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer,
Projectable, Provenance, Scalar,
};
/// An `Immediate` represents a single immediate self-contained Rust value.
@ -26,7 +26,7 @@ use super::{
/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
/// defined on `Immediate`, and do not have to work with a `Place`.
#[derive(Copy, Clone, Debug)]
pub enum Immediate<Prov: Provenance = AllocId> {
pub enum Immediate<Prov: Provenance = CtfeProvenance> {
/// A single scalar value (must have *initialized* `Scalar` ABI).
Scalar(Scalar<Prov>),
/// A pair of two scalar value (must have `ScalarPair` ABI where both fields are
@ -93,12 +93,23 @@ impl<Prov: Provenance> Immediate<Prov> {
Immediate::Uninit => bug!("Got uninit where a scalar pair was expected"),
}
}
/// Returns the scalar from the first component and optionally the 2nd component as metadata.
#[inline]
#[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
pub fn to_scalar_and_meta(self) -> (Scalar<Prov>, MemPlaceMeta<Prov>) {
match self {
Immediate::ScalarPair(val1, val2) => (val1, MemPlaceMeta::Meta(val2)),
Immediate::Scalar(val) => (val, MemPlaceMeta::None),
Immediate::Uninit => bug!("Got uninit where a scalar or scalar pair was expected"),
}
}
}
// ScalarPair needs a type to interpret, so we often have an immediate and a type together
// as input for binary and cast operations.
#[derive(Clone)]
pub struct ImmTy<'tcx, Prov: Provenance = AllocId> {
pub struct ImmTy<'tcx, Prov: Provenance = CtfeProvenance> {
imm: Immediate<Prov>,
pub layout: TyAndLayout<'tcx>,
}
@ -334,13 +345,13 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> {
/// or still in memory. The latter is an optimization, to delay reading that chunk of
/// memory and to avoid having to store arbitrary-sized data here.
#[derive(Copy, Clone, Debug)]
pub(super) enum Operand<Prov: Provenance = AllocId> {
pub(super) enum Operand<Prov: Provenance = CtfeProvenance> {
Immediate(Immediate<Prov>),
Indirect(MemPlace<Prov>),
}
#[derive(Clone)]
pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
pub struct OpTy<'tcx, Prov: Provenance = CtfeProvenance> {
op: Operand<Prov>, // Keep this private; it helps enforce invariants.
pub layout: TyAndLayout<'tcx>,
}
@ -750,17 +761,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?;
let imm = match val_val {
mir::ConstValue::Indirect { alloc_id, offset } => {
// We rely on mutability being set correctly in that allocation to prevent writes
// where none should happen.
let ptr = self.global_base_pointer(Pointer::new(alloc_id, offset))?;
// This is const data, no mutation allowed.
let ptr = self.global_base_pointer(Pointer::new(
CtfeProvenance::from(alloc_id).as_immutable(),
offset,
))?;
return Ok(self.ptr_to_mplace(ptr.into(), layout).into());
}
mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(),
mir::ConstValue::ZeroSized => Immediate::Uninit,
mir::ConstValue::Slice { data, meta } => {
// We rely on mutability being set correctly in `data` to prevent writes
// where none should happen.
let ptr = Pointer::new(self.tcx.reserve_and_set_memory_alloc(data), Size::ZERO);
// This is const data, no mutation allowed.
let alloc_id = self.tcx.reserve_and_set_memory_alloc(data);
let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO);
Immediate::new_slice(self.global_base_pointer(ptr)?.into(), meta, self)
}
};

View File

@ -14,14 +14,14 @@ use rustc_middle::ty::Ty;
use rustc_target::abi::{Abi, Align, HasDataLayout, Size};
use super::{
alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckAlignMsg, ImmTy,
Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy,
alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance,
ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy,
Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable, Scalar,
};
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
/// Information required for the sound usage of a `MemPlace`.
pub enum MemPlaceMeta<Prov: Provenance = AllocId> {
pub enum MemPlaceMeta<Prov: Provenance = CtfeProvenance> {
/// The unsized payload (e.g. length for slices or vtable pointer for trait objects).
Meta(Scalar<Prov>),
/// `Sized` types or unsized `extern type`
@ -49,7 +49,7 @@ impl<Prov: Provenance> MemPlaceMeta<Prov> {
}
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
pub(super) struct MemPlace<Prov: Provenance = AllocId> {
pub(super) struct MemPlace<Prov: Provenance = CtfeProvenance> {
/// The pointer can be a pure integer, with the `None` provenance.
pub ptr: Pointer<Option<Prov>>,
/// Metadata for unsized places. Interpretation is up to the type.
@ -100,7 +100,7 @@ impl<Prov: Provenance> MemPlace<Prov> {
/// A MemPlace with its layout. Constructing it is only possible in this module.
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
pub struct MPlaceTy<'tcx, Prov: Provenance = CtfeProvenance> {
mplace: MemPlace<Prov>,
pub layout: TyAndLayout<'tcx>,
}
@ -179,7 +179,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
}
#[derive(Copy, Clone, Debug)]
pub(super) enum Place<Prov: Provenance = AllocId> {
pub(super) enum Place<Prov: Provenance = CtfeProvenance> {
/// A place referring to a value allocated in the `Memory` system.
Ptr(MemPlace<Prov>),
@ -195,7 +195,7 @@ pub(super) enum Place<Prov: Provenance = AllocId> {
}
#[derive(Clone)]
pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
pub struct PlaceTy<'tcx, Prov: Provenance = CtfeProvenance> {
place: Place<Prov>, // Keep this private; it helps enforce invariants.
pub layout: TyAndLayout<'tcx>,
}
@ -406,11 +406,7 @@ where
let pointee_type =
val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty;
let layout = self.layout_of(pointee_type)?;
let (ptr, meta) = match **val {
Immediate::Scalar(ptr) => (ptr, MemPlaceMeta::None),
Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta)),
Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
};
let (ptr, meta) = val.to_scalar_and_meta();
// `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced;
// we hence can't call `size_and_align_of` since that asserts more validity than we want.

View File

@ -18,14 +18,14 @@ use rustc_target::abi::{
use rustc_target::spec::abi::Abi;
use super::{
AllocId, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable,
Provenance, Scalar, StackPopCleanup,
CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy,
Projectable, Provenance, Scalar, StackPopCleanup,
};
use crate::fluent_generated as fluent;
/// An argment passed to a function.
#[derive(Clone, Debug)]
pub enum FnArg<'tcx, Prov: Provenance = AllocId> {
pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
/// Pass a copy of the given operand.
Copy(OpTy<'tcx, Prov>),
/// Allow for the argument to be passed in-place: destroy the value originally stored at that place and

View File

@ -8,6 +8,135 @@ use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
use rustc_span::edition::Edition;
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! {
/// The `forbidden_lint_groups` lint detects violations of
/// `forbid` applied to a lint group. Due to a bug in the compiler,
@ -3349,134 +3478,6 @@ declare_lint! {
"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! {
/// The `long_running_const_eval` lint is emitted when const
/// eval is running for a long time to ensure rustc terminates
@ -4621,3 +4622,37 @@ declare_lint! {
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>",
};
}

View File

@ -75,7 +75,7 @@ static_assert_size!(ConstValue<'_>, 24);
impl<'tcx> ConstValue<'tcx> {
#[inline]
pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
pub fn try_to_scalar(&self) -> Option<Scalar> {
match *self {
ConstValue::Indirect { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None,
ConstValue::Scalar(val) => Some(val),
@ -161,8 +161,8 @@ impl<'tcx> ConstValue<'tcx> {
return Some(&[]);
}
// Non-empty slice, must have memory. We know this is a relative pointer.
let (inner_alloc_id, offset) = ptr.into_parts();
let data = tcx.global_alloc(inner_alloc_id?).unwrap_memory();
let (inner_prov, offset) = ptr.into_parts();
let data = tcx.global_alloc(inner_prov?.alloc_id()).unwrap_memory();
(data, offset.bytes(), offset.bytes() + len)
}
};

View File

@ -18,9 +18,9 @@ use rustc_span::DUMMY_SP;
use rustc_target::abi::{Align, HasDataLayout, Size};
use super::{
read_target_uint, write_target_uint, AllocId, BadBytesAccess, InterpError, InterpResult,
Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch,
UndefinedBehaviorInfo, UnsupportedOpInfo,
read_target_uint, write_target_uint, AllocId, BadBytesAccess, CtfeProvenance, InterpError,
InterpResult, Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar,
ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo,
};
use crate::ty;
use init_mask::*;
@ -63,7 +63,7 @@ impl AllocBytes for Box<[u8]> {
// hashed. (see the `Hash` impl below for more details), so the impl is not derived.
#[derive(Clone, Eq, PartialEq, TyEncodable, TyDecodable)]
#[derive(HashStable)]
pub struct Allocation<Prov: Provenance = AllocId, Extra = (), Bytes = Box<[u8]>> {
pub struct Allocation<Prov: Provenance = CtfeProvenance, Extra = (), Bytes = Box<[u8]>> {
/// The actual bytes of the allocation.
/// Note that the bytes of a pointer represent the offset of the pointer.
bytes: Bytes,
@ -336,14 +336,14 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
}
}
impl<Bytes: AllocBytes> Allocation<AllocId, (), Bytes> {
/// Adjust allocation from the ones in tcx to a custom Machine instance
/// with a different Provenance and Extra type.
impl<Bytes: AllocBytes> Allocation<CtfeProvenance, (), Bytes> {
/// Adjust allocation from the ones in `tcx` to a custom Machine instance
/// with a different `Provenance` and `Extra` type.
pub fn adjust_from_tcx<Prov: Provenance, Extra, Err>(
self,
cx: &impl HasDataLayout,
extra: Extra,
mut adjust_ptr: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Prov>, Err>,
mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> Result<Pointer<Prov>, Err>,
) -> Result<Allocation<Prov, Extra, Bytes>, Err> {
let mut bytes = self.bytes;
// Adjust provenance of pointers stored in this allocation.

View File

@ -6,14 +6,14 @@ use std::cmp;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_target::abi::{HasDataLayout, Size};
use super::{alloc_range, AllocError, AllocId, AllocRange, AllocResult, Provenance};
use super::{alloc_range, AllocError, AllocRange, AllocResult, CtfeProvenance, Provenance};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
/// Stores the provenance information of pointers stored in memory.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[derive(HashStable)]
pub struct ProvenanceMap<Prov = AllocId> {
/// Provenance in this map applies from the given offset for an entire pointer-size worth of
pub struct ProvenanceMap<Prov = CtfeProvenance> {
/// `Provenance` in this map applies from the given offset for an entire pointer-size worth of
/// bytes. Two entries in this map are always at least a pointer size apart.
ptrs: SortedMap<Size, Prov>,
/// Provenance in this map only applies to the given single byte.
@ -22,18 +22,19 @@ pub struct ProvenanceMap<Prov = AllocId> {
bytes: Option<Box<SortedMap<Size, Prov>>>,
}
// These impls are generic over `Prov` since `CtfeProvenance` is only decodable/encodable
// for some particular `D`/`S`.
impl<D: Decoder, Prov: Provenance + Decodable<D>> Decodable<D> for ProvenanceMap<Prov> {
fn decode(d: &mut D) -> Self {
assert!(!Prov::OFFSET_IS_ADDR); // only `AllocId` is ever serialized
assert!(!Prov::OFFSET_IS_ADDR); // only `CtfeProvenance` is ever serialized
Self { ptrs: Decodable::decode(d), bytes: None }
}
}
impl<S: Encoder, Prov: Provenance + Encodable<S>> Encodable<S> for ProvenanceMap<Prov> {
fn encode(&self, s: &mut S) {
let Self { ptrs, bytes } = self;
assert!(!Prov::OFFSET_IS_ADDR); // only `AllocId` is ever serialized
debug_assert!(bytes.is_none());
assert!(!Prov::OFFSET_IS_ADDR); // only `CtfeProvenance` is ever serialized
debug_assert!(bytes.is_none()); // without `OFFSET_IS_ADDR`, this is always empty
ptrs.encode(s)
}
}
@ -54,10 +55,10 @@ impl ProvenanceMap {
/// Give access to the ptr-sized provenances (which can also be thought of as relocations, and
/// indeed that is how codegen treats them).
///
/// Only exposed with `AllocId` provenance, since it panics if there is bytewise provenance.
/// Only exposed with `CtfeProvenance` provenance, since it panics if there is bytewise provenance.
#[inline]
pub fn ptrs(&self) -> &SortedMap<Size, AllocId> {
debug_assert!(self.bytes.is_none()); // `AllocId::OFFSET_IS_ADDR` is false so this cannot fail
pub fn ptrs(&self) -> &SortedMap<Size, CtfeProvenance> {
debug_assert!(self.bytes.is_none()); // `CtfeProvenance::OFFSET_IS_ADDR` is false so this cannot fail
&self.ptrs
}
}

View File

@ -290,7 +290,7 @@ macro_rules! impl_into_diagnostic_arg_through_debug {
// These types have nice `Debug` output so we can just use them in diagnostics.
impl_into_diagnostic_arg_through_debug! {
AllocId,
Pointer,
Pointer<AllocId>,
AllocRange,
}
@ -323,7 +323,7 @@ pub enum UndefinedBehaviorInfo<'tcx> {
/// Invalid metadata in a wide pointer
InvalidMeta(InvalidMetaKind),
/// Reading a C string that does not end within its allocation.
UnterminatedCString(Pointer),
UnterminatedCString(Pointer<AllocId>),
/// Using a pointer after it got freed.
PointerUseAfterFree(AllocId, CheckInAllocMsg),
/// Used a pointer outside the bounds it is valid for.
@ -350,11 +350,11 @@ pub enum UndefinedBehaviorInfo<'tcx> {
/// Using a non-character `u32` as character.
InvalidChar(u32),
/// The tag of an enum does not encode an actual discriminant.
InvalidTag(Scalar),
InvalidTag(Scalar<AllocId>),
/// Using a pointer-not-to-a-function as function pointer.
InvalidFunctionPointer(Pointer),
InvalidFunctionPointer(Pointer<AllocId>),
/// Using a pointer-not-to-a-vtable as vtable pointer.
InvalidVTablePointer(Pointer),
InvalidVTablePointer(Pointer<AllocId>),
/// Using a string that is not valid UTF-8,
InvalidStr(std::str::Utf8Error),
/// Using uninitialized data where it is not allowed.

View File

@ -157,7 +157,7 @@ pub use self::allocation::{
InitChunk, InitChunkIter,
};
pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
/// Uniquely identifies one of the following:
/// - A constant

View File

@ -3,7 +3,7 @@ use super::{AllocId, InterpResult};
use rustc_macros::HashStable;
use rustc_target::abi::{HasDataLayout, Size};
use std::fmt;
use std::{fmt, num::NonZeroU64};
////////////////////////////////////////////////////////////////////////////////
// Pointer arithmetic
@ -114,22 +114,7 @@ pub trait Provenance: Copy + fmt::Debug + 'static {
const OFFSET_IS_ADDR: bool;
/// Determines how a pointer should be printed.
///
/// Default impl is only good for when `OFFSET_IS_ADDR == true`.
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
where
Self: Sized,
{
assert!(Self::OFFSET_IS_ADDR);
let (prov, addr) = ptr.into_parts(); // address is absolute
write!(f, "{:#x}", addr.bytes())?;
if f.alternate() {
write!(f, "{prov:#?}")?;
} else {
write!(f, "{prov:?}")?;
}
Ok(())
}
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
/// If `OFFSET_IS_ADDR == false`, provenance must always be able to
/// identify the allocation this ptr points to (i.e., this must return `Some`).
@ -141,6 +126,80 @@ pub trait Provenance: Copy + fmt::Debug + 'static {
fn join(left: Option<Self>, right: Option<Self>) -> Option<Self>;
}
/// The type of provenance in the compile-time interpreter.
/// This is a packed representation of an `AllocId` and an `immutable: bool`.
#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct CtfeProvenance(NonZeroU64);
impl From<AllocId> for CtfeProvenance {
fn from(value: AllocId) -> Self {
let prov = CtfeProvenance(value.0);
assert!(!prov.immutable(), "`AllocId` with the highest bit set cannot be used in CTFE");
prov
}
}
impl fmt::Debug for CtfeProvenance {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.alloc_id(), f)?; // propagates `alternate` flag
if self.immutable() {
write!(f, "<imm>")?;
}
Ok(())
}
}
const IMMUTABLE_MASK: u64 = 1 << 63; // the highest bit
impl CtfeProvenance {
/// Returns the `AllocId` of this provenance.
#[inline(always)]
pub fn alloc_id(self) -> AllocId {
AllocId(NonZeroU64::new(self.0.get() & !IMMUTABLE_MASK).unwrap())
}
/// Returns whether this provenance is immutable.
#[inline]
pub fn immutable(self) -> bool {
self.0.get() & IMMUTABLE_MASK != 0
}
/// Returns an immutable version of this provenance.
#[inline]
pub fn as_immutable(self) -> Self {
CtfeProvenance(self.0 | IMMUTABLE_MASK)
}
}
impl Provenance for CtfeProvenance {
// With the `AllocId` as provenance, the `offset` is interpreted *relative to the allocation*,
// so ptr-to-int casts are not possible (since we do not know the global physical offset).
const OFFSET_IS_ADDR: bool = false;
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Print AllocId.
fmt::Debug::fmt(&ptr.provenance.alloc_id(), f)?; // propagates `alternate` flag
// Print offset only if it is non-zero.
if ptr.offset.bytes() > 0 {
write!(f, "+{:#x}", ptr.offset.bytes())?;
}
// Print immutable status.
if ptr.provenance.immutable() {
write!(f, "<imm>")?;
}
Ok(())
}
fn get_alloc_id(self) -> Option<AllocId> {
Some(self.alloc_id())
}
fn join(_left: Option<Self>, _right: Option<Self>) -> Option<Self> {
panic!("merging provenance is not supported when `OFFSET_IS_ADDR` is false")
}
}
// We also need this impl so that one can debug-print `Pointer<AllocId>`
impl Provenance for AllocId {
// With the `AllocId` as provenance, the `offset` is interpreted *relative to the allocation*,
// so ptr-to-int casts are not possible (since we do not know the global physical offset).
@ -174,7 +233,7 @@ impl Provenance for AllocId {
/// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable, Hash)]
#[derive(HashStable)]
pub struct Pointer<Prov = AllocId> {
pub struct Pointer<Prov = CtfeProvenance> {
pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Prov` type)
pub provenance: Prov,
}
@ -182,7 +241,7 @@ pub struct Pointer<Prov = AllocId> {
static_assert_size!(Pointer, 16);
// `Option<Prov>` pointers are also passed around quite a bit
// (but not stored in permanent machine state).
static_assert_size!(Pointer<Option<AllocId>>, 16);
static_assert_size!(Pointer<Option<CtfeProvenance>>, 16);
// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
// all the Miri types.
@ -215,7 +274,7 @@ impl<Prov: Provenance> fmt::Display for Pointer<Option<Prov>> {
impl From<AllocId> for Pointer {
#[inline(always)]
fn from(alloc_id: AllocId) -> Self {
Pointer::new(alloc_id, Size::ZERO)
Pointer::new(alloc_id.into(), Size::ZERO)
}
}

View File

@ -11,7 +11,10 @@ use rustc_target::abi::{HasDataLayout, Size};
use crate::ty::ScalarInt;
use super::{AllocId, InterpResult, Pointer, PointerArithmetic, Provenance, ScalarSizeMismatch};
use super::{
AllocId, CtfeProvenance, InterpResult, Pointer, PointerArithmetic, Provenance,
ScalarSizeMismatch,
};
/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of an `Allocation`, up to 16 bytes in
@ -22,7 +25,7 @@ use super::{AllocId, InterpResult, Pointer, PointerArithmetic, Provenance, Scala
/// Do *not* match on a `Scalar`! Use the various `to_*` methods instead.
#[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, Hash)]
#[derive(HashStable)]
pub enum Scalar<Prov = AllocId> {
pub enum Scalar<Prov = CtfeProvenance> {
/// The raw bytes of a simple value.
Int(ScalarInt),
@ -267,6 +270,9 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
/// Will perform ptr-to-int casts if needed and possible.
/// If that fails, we know the offset is relative, so we return an "erased" Scalar
/// (which is useful for error messages but not much else).
///
/// The error type is `AllocId`, not `CtfeProvenance`, since `AllocId` is the "minimal"
/// component all provenance types must have.
#[inline]
pub fn try_to_int(self) -> Result<ScalarInt, Scalar<AllocId>> {
match self {

View File

@ -1337,13 +1337,13 @@ pub fn write_allocations<'tcx>(
fn alloc_ids_from_alloc(
alloc: ConstAllocation<'_>,
) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
alloc.inner().provenance().ptrs().values().copied()
alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id())
}
fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
match val {
ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
Either::Left(std::iter::once(ptr.provenance))
Either::Left(std::iter::once(ptr.provenance.alloc_id()))
}
ConstValue::Scalar(interpret::Scalar::Int { .. }) => Either::Right(std::iter::empty()),
ConstValue::ZeroSized => Either::Right(std::iter::empty()),

View File

@ -381,7 +381,7 @@ impl<'tcx> Operand<'tcx> {
impl<'tcx> ConstOperand<'tcx> {
pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
match self.const_.try_to_scalar() {
Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance.alloc_id()) {
GlobalAlloc::Static(def_id) => {
assert!(!tcx.is_thread_local_static(def_id));
Some(def_id)

View File

@ -264,6 +264,7 @@ trivial! {
rustc_middle::middle::stability::DeprecationEntry,
rustc_middle::mir::ConstQualifs,
rustc_middle::mir::interpret::AllocId,
rustc_middle::mir::interpret::CtfeProvenance,
rustc_middle::mir::interpret::ErrorHandled,
rustc_middle::mir::interpret::LitToConstError,
rustc_middle::thir::ExprId,

View File

@ -8,6 +8,7 @@
use crate::arena::ArenaAllocatable;
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use crate::mir::interpret::CtfeProvenance;
use crate::mir::{
self,
interpret::{AllocId, ConstAllocation},
@ -164,6 +165,13 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AllocId {
}
}
impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for CtfeProvenance {
fn encode(&self, e: &mut E) {
self.alloc_id().encode(e);
self.immutable().encode(e);
}
}
impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::ParamEnv<'tcx> {
fn encode(&self, e: &mut E) {
self.caller_bounds().encode(e);
@ -295,6 +303,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AllocId {
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for CtfeProvenance {
fn decode(decoder: &mut D) -> Self {
let alloc_id: AllocId = Decodable::decode(decoder);
let prov = CtfeProvenance::from(alloc_id);
let immutable: bool = Decodable::decode(decoder);
if immutable { prov.as_immutable() } else { prov }
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::SymbolName<'tcx> {
fn decode(decoder: &mut D) -> Self {
ty::SymbolName::new(decoder.interner(), decoder.read_str())

View File

@ -1,5 +1,5 @@
use crate::middle::resolve_bound_vars as rbv;
use crate::mir::interpret::{AllocId, ErrorHandled, LitToConstInput, Scalar};
use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
use rustc_data_structures::intern::Interned;
use rustc_error_messages::MultiSpan;
@ -413,7 +413,7 @@ impl<'tcx> Const<'tcx> {
}
#[inline]
pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
pub fn try_to_scalar(self) -> Option<Scalar> {
self.try_to_valtree()?.try_to_scalar()
}

View File

@ -1,5 +1,5 @@
use super::ScalarInt;
use crate::mir::interpret::{AllocId, Scalar};
use crate::mir::interpret::Scalar;
use crate::ty::{self, Ty, TyCtxt};
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
@ -67,7 +67,7 @@ impl<'tcx> ValTree<'tcx> {
Self::Leaf(i)
}
pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
pub fn try_to_scalar(self) -> Option<Scalar> {
self.try_to_scalar_int().map(Scalar::Int)
}

View File

@ -84,6 +84,14 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
}
}
// CtfeProvenance is an AllocId and a bool.
impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::CtfeProvenance {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.alloc_id().hash_stable(hcx, hasher);
self.immutable().hash_stable(hcx, hasher);
}
}
impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope {
type KeyType = region::Scope;

View File

@ -1410,14 +1410,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
) -> Result<(), PrintError> {
define_scoped_cx!(self);
let (alloc_id, offset) = ptr.into_parts();
let (prov, offset) = ptr.into_parts();
match ty.kind() {
// Byte strings (&[u8; N])
ty::Ref(_, inner, _) => {
if let ty::Array(elem, len) = inner.kind() {
if let ty::Uint(ty::UintTy::U8) = elem.kind() {
if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() {
match self.tcx().try_get_global_alloc(alloc_id) {
match self.tcx().try_get_global_alloc(prov.alloc_id()) {
Some(GlobalAlloc::Memory(alloc)) => {
let len = int.assert_bits(self.tcx().data_layout.pointer_size);
let range =
@ -1447,7 +1447,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
// FIXME: We should probably have a helper method to share code with the "Byte strings"
// printing above (which also has to handle pointers to all sorts of things).
if let Some(GlobalAlloc::Function(instance)) =
self.tcx().try_get_global_alloc(alloc_id)
self.tcx().try_get_global_alloc(prov.alloc_id())
{
self.typed_value(
|this| this.print_value_path(instance.def_id(), instance.args),

View File

@ -440,8 +440,9 @@ TrivialTypeTraversalAndLiftImpls! {
crate::ty::ClosureKind,
crate::ty::ParamConst,
crate::ty::ParamTy,
interpret::Scalar,
interpret::AllocId,
interpret::CtfeProvenance,
interpret::Scalar,
rustc_target::abi::Size,
}

View File

@ -11,6 +11,7 @@ use rustc_middle::mir::visit::{
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
};
use rustc_middle::mir::*;
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
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(
_tcx: TyCtxt<'tcx>,
_tcx: TyCtxtAt<'tcx>,
_machine: &Self,
_alloc_id: AllocId,
alloc: ConstAllocation<'tcx>,
@ -240,10 +241,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
}
#[inline(always)]
fn expose_ptr(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_ptr: Pointer<AllocId>,
) -> InterpResult<'tcx> {
fn expose_ptr(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> {
throw_machine_stop_str!("exposing pointers isn't supported in ConstProp")
}

View File

@ -8,6 +8,7 @@ use rustc_hir::def::DefKind;
use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
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(
_tcx: TyCtxt<'tcx>,
_tcx: TyCtxtAt<'tcx>,
_machine: &Self,
_alloc_id: AllocId,
alloc: ConstAllocation<'tcx>,

View File

@ -388,7 +388,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
self.ecx.copy_op(op, &field_dest, /*allow_transmute*/ false).ok()?;
}
self.ecx.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest).ok()?;
self.ecx.alloc_mark_immutable(dest.ptr().provenance.unwrap()).ok()?;
self.ecx
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
.ok()?;
dest.into()
} else {
return None;
@ -928,7 +930,8 @@ fn op_to_prop_const<'tcx>(
}
let pointer = mplace.ptr().into_pointer_or_addr().ok()?;
let (alloc_id, offset) = pointer.into_parts();
let (prov, offset) = pointer.into_parts();
let alloc_id = prov.alloc_id();
intern_const_alloc_for_constprop(ecx, alloc_id).ok()?;
if matches!(ecx.tcx.global_alloc(alloc_id), GlobalAlloc::Memory(_)) {
// `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything

View File

@ -385,8 +385,8 @@ fn collect_items_rec<'tcx>(
recursion_depth_reset = None;
if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
for &id in alloc.inner().provenance().ptrs().values() {
collect_alloc(tcx, id, &mut used_items);
for &prov in alloc.inner().provenance().ptrs().values() {
collect_alloc(tcx, prov.alloc_id(), &mut used_items);
}
}
@ -1363,9 +1363,9 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
}
GlobalAlloc::Memory(alloc) => {
trace!("collecting {:?} with {:#?}", alloc_id, alloc);
for &inner in alloc.inner().provenance().ptrs().values() {
for &prov in alloc.inner().provenance().ptrs().values() {
rustc_data_structures::stack::ensure_sufficient_stack(|| {
collect_alloc(tcx, inner, output);
collect_alloc(tcx, prov.alloc_id(), output);
});
}
}
@ -1440,12 +1440,12 @@ fn collect_const_value<'tcx>(
) {
match value {
mir::ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => {
collect_alloc(tcx, ptr.provenance, output)
collect_alloc(tcx, ptr.provenance.alloc_id(), output)
}
mir::ConstValue::Indirect { alloc_id, .. } => collect_alloc(tcx, alloc_id, output),
mir::ConstValue::Slice { data, meta: _ } => {
for &id in data.inner().provenance().ptrs().values() {
collect_alloc(tcx, id, output);
for &prov in data.inner().provenance().ptrs().values() {
collect_alloc(tcx, prov.alloc_id(), output);
}
}
_ => {}

View File

@ -47,7 +47,7 @@ pub fn new_allocation<'tcx>(
}
ConstValue::Slice { data, meta } => {
let alloc_id = tables.tcx.reserve_and_set_memory_alloc(data);
let ptr = Pointer::new(alloc_id, rustc_target::abi::Size::ZERO);
let ptr = Pointer::new(alloc_id.into(), rustc_target::abi::Size::ZERO);
let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
let scalar_meta =
rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
@ -112,7 +112,10 @@ pub(super) fn allocation_filter<'tcx>(
.iter()
.filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end())
{
ptrs.push((offset.bytes_usize() - alloc_range.start.bytes_usize(), tables.prov(*prov)));
ptrs.push((
offset.bytes_usize() - alloc_range.start.bytes_usize(),
tables.prov(prov.alloc_id()),
));
}
Allocation {
bytes: bytes,

View File

@ -4288,15 +4288,18 @@ impl<'test> TestCx<'test> {
let mut seen_allocs = indexmap::IndexSet::new();
// The alloc-id appears in pretty-printed allocations.
let re = Regex::new(r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?─*╼").unwrap();
let re =
Regex::new(r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?(<imm>)?( \([0-9]+ ptr bytes\))?─*╼")
.unwrap();
normalized = re
.replace_all(&normalized, |caps: &Captures<'_>| {
// Renumber the captured index.
let index = caps.get(2).unwrap().as_str().to_string();
let (index, _) = seen_allocs.insert_full(index);
let offset = caps.get(3).map_or("", |c| c.as_str());
let imm = caps.get(4).map_or("", |c| c.as_str());
// Do not bother keeping it pretty, just make it deterministic.
format!("╾ALLOC{index}{offset}")
format!("╾ALLOC{index}{offset}{imm}")
})
.into_owned();

View File

@ -44,7 +44,7 @@ pub enum TerminationInfo {
},
DataRace {
involves_non_atomic: bool,
ptr: Pointer,
ptr: Pointer<AllocId>,
op1: RacingOp,
op2: RacingOp,
extra: Option<&'static str>,

View File

@ -256,12 +256,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// Convert a relative (tcx) pointer to a Miri pointer.
fn ptr_from_rel_ptr(
&self,
ptr: Pointer<AllocId>,
ptr: Pointer<CtfeProvenance>,
tag: BorTag,
) -> InterpResult<'tcx, Pointer<Provenance>> {
let ecx = self.eval_context_ref();
let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
let alloc_id = prov.alloc_id();
let base_addr = ecx.addr_from_alloc_id(alloc_id)?;
// Add offset with the right kind of pointer-overflowing arithmetic.

View File

@ -17,6 +17,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::static_assert_size;
use rustc_middle::{
mir,
query::TyCtxtAt,
ty::{
self,
layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout},
@ -259,6 +260,17 @@ impl interpret::Provenance for Provenance {
}
}
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (prov, addr) = ptr.into_parts(); // address is absolute
write!(f, "{:#x}", addr.bytes())?;
if f.alternate() {
write!(f, "{prov:#?}")?;
} else {
write!(f, "{prov:?}")?;
}
Ok(())
}
fn join(left: Option<Self>, right: Option<Self>) -> Option<Self> {
match (left, right) {
// If both are the *same* concrete tag, that is the result.
@ -1170,11 +1182,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
fn adjust_alloc_base_pointer(
ecx: &MiriInterpCx<'mir, 'tcx>,
ptr: Pointer<AllocId>,
ptr: Pointer<CtfeProvenance>,
) -> InterpResult<'tcx, Pointer<Provenance>> {
let alloc_id = ptr.provenance.alloc_id();
if cfg!(debug_assertions) {
// The machine promises to never call us on thread-local or extern statics.
let alloc_id = ptr.provenance;
match ecx.tcx.try_get_global_alloc(alloc_id) {
Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => {
panic!("adjust_alloc_base_pointer called on thread-local static")
@ -1185,8 +1197,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
_ => {}
}
}
// FIXME: can we somehow preserve the immutability of `ptr`?
let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
borrow_tracker.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine)
borrow_tracker.borrow_mut().base_ptr_tag(alloc_id, &ecx.machine)
} else {
// Value does not matter, SB is disabled
BorTag::default()
@ -1245,7 +1258,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
#[inline(always)]
fn before_memory_read(
_tcx: TyCtxt<'tcx>,
_tcx: TyCtxtAt<'tcx>,
machine: &Self,
alloc_extra: &AllocExtra<'tcx>,
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
@ -1265,7 +1278,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
#[inline(always)]
fn before_memory_write(
_tcx: TyCtxt<'tcx>,
_tcx: TyCtxtAt<'tcx>,
machine: &mut Self,
alloc_extra: &mut AllocExtra<'tcx>,
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
@ -1285,7 +1298,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
#[inline(always)]
fn before_memory_deallocation(
_tcx: TyCtxt<'tcx>,
_tcx: TyCtxtAt<'tcx>,
machine: &mut Self,
alloc_extra: &mut AllocExtra<'tcx>,
(alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra),

View File

@ -18,19 +18,19 @@ fn main() -> () {
}
ALLOC9 (static: FOO, size: 8, align: 4) {
ALLOC0 03 00 00 00 ....
ALLOC0<imm> 03 00 00 00 ....
}
ALLOC0 (size: 48, align: 4) {
0x00 00 00 00 00 __ __ __ __ ALLOC1 00 00 00 00 ........
0x10 00 00 00 00 __ __ __ __ ALLOC2 02 00 00 00 ........
0x20 01 00 00 00 2a 00 00 00 ALLOC3 03 00 00 00 ....*.......
0x00 00 00 00 00 __ __ __ __ ALLOC1<imm> 00 00 00 00 ........
0x10 00 00 00 00 __ __ __ __ ALLOC2<imm> 02 00 00 00 ........
0x20 01 00 00 00 2a 00 00 00 ALLOC3<imm> 03 00 00 00 ....*.......
}
ALLOC1 (size: 0, align: 4) {}
ALLOC2 (size: 16, align: 4) {
ALLOC4 03 00 00 00 ALLOC5 03 00 00 00 ........
ALLOC4<imm> 03 00 00 00 ALLOC5<imm> 03 00 00 00 ........
}
ALLOC4 (size: 3, align: 1) {
@ -42,8 +42,8 @@ ALLOC5 (size: 3, align: 1) {
}
ALLOC3 (size: 24, align: 4) {
0x00 ALLOC6 03 00 00 00 ALLOC7 03 00 00 00 ........
0x10 ALLOC8 04 00 00 00 ....
0x00 ALLOC6<imm> 03 00 00 00 ALLOC7<imm> 03 00 00 00 ........
0x10 ALLOC8<imm> 04 00 00 00 ....
}
ALLOC6 (size: 3, align: 1) {

View File

@ -18,22 +18,22 @@ fn main() -> () {
}
ALLOC9 (static: FOO, size: 16, align: 8) {
ALLOC0 03 00 00 00 00 00 00 00 ........
ALLOC0<imm> 03 00 00 00 00 00 00 00 ........
}
ALLOC0 (size: 72, align: 8) {
0x00 00 00 00 00 __ __ __ __ ALLOC1 ....
0x00 00 00 00 00 __ __ __ __ ALLOC1<imm> ....
0x10 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ ............
0x20 ALLOC2 02 00 00 00 00 00 00 00 ........
0x30 01 00 00 00 2a 00 00 00 ALLOC3 ....*...
0x20 ALLOC2<imm> 02 00 00 00 00 00 00 00 ........
0x30 01 00 00 00 2a 00 00 00 ALLOC3<imm> ....*...
0x40 03 00 00 00 00 00 00 00 ........
}
ALLOC1 (size: 0, align: 8) {}
ALLOC2 (size: 32, align: 8) {
0x00 ALLOC4 03 00 00 00 00 00 00 00 ........
0x10 ALLOC5 03 00 00 00 00 00 00 00 ........
0x00 ALLOC4<imm> 03 00 00 00 00 00 00 00 ........
0x10 ALLOC5<imm> 03 00 00 00 00 00 00 00 ........
}
ALLOC4 (size: 3, align: 1) {
@ -45,9 +45,9 @@ ALLOC5 (size: 3, align: 1) {
}
ALLOC3 (size: 48, align: 8) {
0x00 ALLOC6 03 00 00 00 00 00 00 00 ........
0x10 ALLOC7 03 00 00 00 00 00 00 00 ........
0x20 ALLOC8 04 00 00 00 00 00 00 00 ........
0x00 ALLOC6<imm> 03 00 00 00 00 00 00 00 ........
0x10 ALLOC7<imm> 03 00 00 00 00 00 00 00 ........
0x20 ALLOC8<imm> 04 00 00 00 00 00 00 00 ........
}
ALLOC6 (size: 3, align: 1) {

View File

@ -18,19 +18,19 @@ fn main() -> () {
}
ALLOC9 (static: FOO, size: 8, align: 4) {
ALLOC0 03 00 00 00 ....
ALLOC0<imm> 03 00 00 00 ....
}
ALLOC0 (size: 48, align: 4) {
0x00 00 00 00 00 __ __ __ __ ALLOC1 00 00 00 00 ........
0x10 00 00 00 00 __ __ __ __ ALLOC2 02 00 00 00 ........
0x20 01 00 00 00 2a 00 00 00 ALLOC3 03 00 00 00 ....*.......
0x00 00 00 00 00 __ __ __ __ ALLOC1<imm> 00 00 00 00 ........
0x10 00 00 00 00 __ __ __ __ ALLOC2<imm> 02 00 00 00 ........
0x20 01 00 00 00 2a 00 00 00 ALLOC3<imm> 03 00 00 00 ....*.......
}
ALLOC1 (size: 0, align: 4) {}
ALLOC2 (size: 8, align: 4) {
ALLOC4 ALLOC5
ALLOC4<imm> ALLOC5<imm>
}
ALLOC4 (size: 1, align: 1) {
@ -42,7 +42,7 @@ ALLOC5 (size: 1, align: 1) {
}
ALLOC3 (size: 12, align: 4) {
ALLOC6+0x3 ALLOC7 ALLOC8+0x2
ALLOC6+0x3<imm> ALLOC7<imm> ALLOC8+0x2<imm>
}
ALLOC6 (size: 4, align: 1) {

View File

@ -18,21 +18,21 @@ fn main() -> () {
}
ALLOC9 (static: FOO, size: 16, align: 8) {
ALLOC0 03 00 00 00 00 00 00 00 ........
ALLOC0<imm> 03 00 00 00 00 00 00 00 ........
}
ALLOC0 (size: 72, align: 8) {
0x00 00 00 00 00 __ __ __ __ ALLOC1 ....
0x00 00 00 00 00 __ __ __ __ ALLOC1<imm> ....
0x10 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ ............
0x20 ALLOC2 02 00 00 00 00 00 00 00 ........
0x30 01 00 00 00 2a 00 00 00 ALLOC3 ....*...
0x20 ALLOC2<imm> 02 00 00 00 00 00 00 00 ........
0x30 01 00 00 00 2a 00 00 00 ALLOC3<imm> ....*...
0x40 03 00 00 00 00 00 00 00 ........
}
ALLOC1 (size: 0, align: 8) {}
ALLOC2 (size: 16, align: 8) {
ALLOC4 ALLOC5
ALLOC4<imm> ALLOC5<imm>
}
ALLOC4 (size: 1, align: 1) {
@ -44,8 +44,8 @@ ALLOC5 (size: 1, align: 1) {
}
ALLOC3 (size: 24, align: 8) {
0x00 ALLOC6+0x3 ALLOC7
0x10 ALLOC8+0x2
0x00 ALLOC6+0x3<imm> ALLOC7<imm>
0x10 ALLOC8+0x2<imm>
}
ALLOC6 (size: 4, align: 1) {

View File

@ -18,12 +18,12 @@ fn main() -> () {
}
ALLOC4 (static: FOO, size: 4, align: 4) {
ALLOC0
ALLOC0<imm>
}
ALLOC0 (size: 168, align: 1) {
0x00 ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ................
0x10 ab ab ab ab ab ab ab ab ab ab ab ab ALLOC1 ............
0x10 ab ab ab ab ab ab ab ab ab ab ab ab ALLOC1<imm> ............
0x20 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
@ -31,7 +31,7 @@ ALLOC0 (size: 168, align: 1) {
0x60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x80 00 00 00 00 00 00 00 00 00 00 ALLOC2 00 00 ............
0x90 ALLOC3+0x63 00 00 00 00 00 00 00 00 00 00 00 00 ............
0x90 ALLOC3+0x63<imm> 00 00 00 00 00 00 00 00 00 00 00 00 ............
0xa0 00 00 00 00 00 00 00 00 ........
}

View File

@ -18,12 +18,12 @@ fn main() -> () {
}
ALLOC2 (static: FOO, size: 8, align: 8) {
ALLOC0
ALLOC0<imm>
}
ALLOC0 (size: 180, align: 1) {
0x00 ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ................
0x10 ab ab ab ab ab ab ab ab ab ab ab ab ALLOC3 ............
0x10 ab ab ab ab ab ab ab ab ab ab ab ab ALLOC3<imm> (8 ptr bytes) ............
0x20 01 ef cd ab 00 00 00 00 00 00 00 00 ............
0x30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
@ -31,7 +31,7 @@ ALLOC0 (size: 180, align: 1) {
0x60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
0x90 ALLOC4 00 00 ALLOC1+0x63 ..
0x90 ALLOC4 00 00 ALLOC1+0x63<imm> ..
0xa0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0xb0 00 00 00 00 ....
}

View File

@ -118,7 +118,7 @@
}
ALLOC2 (static: RC, size: 4, align: 4) {
╾ALLOC0╼ │ ╾──╼
╾ALLOC0<imm>╼ │ ╾──╼
}
ALLOC0 (size: 8, align: 4) {

View File

@ -118,7 +118,7 @@
}
ALLOC2 (static: RC, size: 8, align: 8) {
╾ALLOC0╼ │ ╾──────╼
╾ALLOC0<imm>╼ │ ╾──────╼
}
ALLOC0 (size: 8, align: 4) {

View File

@ -220,11 +220,11 @@
}
ALLOC5 (static: BIG_STAT, size: 4, align: 4) {
╾ALLOC0╼ │ ╾──╼
╾ALLOC0<imm>╼ │ ╾──╼
}
ALLOC0 (size: 20, align: 4) {
0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ 02 00 00 00 │ ....#...╾──╼....
0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1<imm>╼ 02 00 00 00 │ ....#...╾──╼....
0x10 │ 00 00 a4 42 │ ...B
}
@ -233,11 +233,11 @@
}
ALLOC4 (static: SMALL_STAT, size: 4, align: 4) {
╾ALLOC2╼ │ ╾──╼
╾ALLOC2<imm>╼ │ ╾──╼
}
ALLOC2 (size: 20, align: 4) {
0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ 01 00 00 00 │ ....░░░░╾──╼....
0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3<imm>╼ 01 00 00 00 │ ....░░░░╾──╼....
0x10 │ 00 00 10 41 │ ...A
}

View File

@ -220,11 +220,11 @@
}
ALLOC5 (static: BIG_STAT, size: 8, align: 8) {
╾ALLOC0╼ │ ╾──────╼
╾ALLOC0<imm>╼ │ ╾──────╼
}
ALLOC0 (size: 32, align: 8) {
0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ │ ....#...╾──────╼
0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1<imm>╼ │ ....#...╾──────╼
0x10 │ 02 00 00 00 00 00 00 00 00 00 a4 42 __ __ __ __ │ ...........B░░░░
}
@ -233,11 +233,11 @@
}
ALLOC4 (static: SMALL_STAT, size: 8, align: 8) {
╾ALLOC2╼ │ ╾──────╼
╾ALLOC2<imm>╼ │ ╾──────╼
}
ALLOC2 (size: 32, align: 8) {
0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ │ ....░░░░╾──────╼
0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3<imm>╼ │ ....░░░░╾──────╼
0x10 │ 01 00 00 00 00 00 00 00 00 00 10 41 __ __ __ __ │ ...........A░░░░
}

View File

@ -78,7 +78,7 @@
StorageLive(_6);
_9 = const _;
- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable];
+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind unreachable];
+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind unreachable];
}
bb4: {

View File

@ -76,7 +76,7 @@
StorageLive(_6);
_9 = const _;
- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue];
+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb5, unwind continue];
+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb5, unwind continue];
}
bb5: {

View File

@ -78,7 +78,7 @@
StorageLive(_6);
_9 = const _;
- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable];
+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind unreachable];
+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind unreachable];
}
bb4: {

View File

@ -76,7 +76,7 @@
StorageLive(_6);
_9 = const _;
- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue];
+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue];
+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue];
}
bb5: {

View File

@ -1,6 +1,6 @@
// Strip out raw byte dumps to make comparison platform-independent:
// 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] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
#![feature(
slice_from_ptr_range,

View File

@ -6,7 +6,7 @@ LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
╾ALLOC0╼ │ ╾──╼
╾ALLOC0<imm>╼ │ ╾──╼
}
error: aborting due to 1 previous error

View File

@ -6,7 +6,7 @@ LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
╾ALLOC0╼ │ ╾──────╼
╾ALLOC0<imm>╼ │ ╾──────╼
}
error: aborting due to 1 previous error

View File

@ -211,7 +211,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:109:1
|
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a function pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
@ -385,7 +385,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:178:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
@ -396,7 +396,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:182:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
@ -418,7 +418,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:189:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
@ -451,7 +451,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:199:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {

View File

@ -211,7 +211,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:109:1
|
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a function pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
@ -385,7 +385,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:178:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
@ -396,7 +396,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:182:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
@ -418,7 +418,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:189:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
@ -451,7 +451,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:199:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {

View File

@ -1,7 +1,7 @@
// stderr-per-bitwidth
// ignore-endian-big
// ignore-tidy-linelength
// normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$1╼"
// normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼" -> "╾ALLOC_ID$1╼"
#![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)]
#![allow(invalid_value)]

View File

@ -2,55 +2,55 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:18:1
|
LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾ALLOC0╼ ╾ALLOC1╼ │ ╾──╼╾──╼
╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:23:1
|
LL | const INVALID_VTABLE_SIZE: &dyn Trait =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾ALLOC2╼ ╾ALLOC3╼ │ ╾──╼╾──╼
╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:33:1
|
LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾ALLOC4╼ ╾ALLOC5╼ │ ╾──╼╾──╼
╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:38:1
|
LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾ALLOC6╼ ╾ALLOC7╼ │ ╾──╼╾──╼
╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:44:1
|
LL | const INVALID_VTABLE_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾ALLOC8╼ ╾ALLOC9╼ │ ╾──╼╾──╼
╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
@ -61,7 +61,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾ALLOC10╼ ╾ALLOC11╼ │ ╾──╼╾──╼
╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──╼╾──╼
}
error: aborting due to 6 previous errors

View File

@ -2,55 +2,55 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:18:1
|
LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:23:1
|
LL | const INVALID_VTABLE_SIZE: &dyn Trait =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾ALLOC2╼ ╾ALLOC3╼ │ ╾──────╼╾──────╼
╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:33:1
|
LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾ALLOC4╼ ╾ALLOC5╼ │ ╾──────╼╾──────╼
╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:38:1
|
LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾ALLOC6╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼
╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:44:1
|
LL | const INVALID_VTABLE_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾ALLOC8╼ ╾ALLOC9╼ │ ╾──────╼╾──────╼
╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
@ -61,7 +61,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾ALLOC10╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼
╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼
}
error: aborting due to 6 previous errors

View File

@ -1,7 +1,7 @@
// ignore-tidy-linelength
// Strip out raw byte dumps to make comparison platform-independent:
// 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]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
#![allow(invalid_value)]
use std::mem;

View File

@ -141,7 +141,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref-ptr.rs:59:1
|
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC2, but expected a function pointer
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC2<imm>, but expected a function pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {

View File

@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾ALLOC0╼ ╾ALLOC1╼ │ ╾──╼╾──╼
╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──╼╾──╼
}
error: aborting due to 1 previous error

View File

@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
}
error: aborting due to 1 previous error

View File

@ -5,7 +5,7 @@ use std::mem;
// Strip out raw byte dumps to make comparison platform-independent:
// 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]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
// normalize-stderr-test "offset \d+" -> "offset N"
// normalize-stderr-test "size \d+" -> "size N"

View File

@ -189,7 +189,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:113:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC12, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC12<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@ -200,7 +200,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:117:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC14, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC14<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@ -222,7 +222,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:124:1
|
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC17, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC17<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@ -233,7 +233,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:127:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC19, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC19<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@ -244,7 +244,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:130:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC21, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC21<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@ -255,7 +255,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:133:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC23, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC23<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@ -288,7 +288,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:145:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC28, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC28<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@ -310,7 +310,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:154:1
|
LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC31, but expected a vtable pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC31<imm>, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {

View 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() {}

View 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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -6,7 +6,7 @@ LL | const TEST: &u8 = &MY_STATIC;
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
╾ALLOC0╼ │ ╾──╼
╾ALLOC0<imm>╼ │ ╾──╼
}
warning: skipping const checks

View File

@ -6,7 +6,7 @@ LL | const TEST: &u8 = &MY_STATIC;
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
╾ALLOC0╼ │ ╾──────╼
╾ALLOC0<imm>╼ │ ╾──────╼
}
warning: skipping const checks

View File

@ -1,5 +1,5 @@
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() {
| ^^^^^^^^^ 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
--> $DIR/invalid-union.rs:43:25
--> $DIR/invalid-union.rs:37:25
|
LL | let _: &'static _ = &C;
| ^^
note: erroneous constant encountered
--> $DIR/invalid-union.rs:43:25
--> $DIR/invalid-union.rs:37:25
|
LL | let _: &'static _ = &C;
| ^^

View File

@ -1,5 +1,5 @@
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() {
| ^^^^^^^^^ 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
--> $DIR/invalid-union.rs:43:25
--> $DIR/invalid-union.rs:37:25
|
LL | let _: &'static _ = &C;
| ^^
note: erroneous constant encountered
--> $DIR/invalid-union.rs:43:25
--> $DIR/invalid-union.rs:37:25
|
LL | let _: &'static _ = &C;
| ^^

View File

@ -1,11 +1,6 @@
// Check that constants with interior mutability inside unions are rejected
// 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
// stderr-per-bitwidth
#![feature(const_mut_refs)]
@ -30,10 +25,9 @@ union U {
}
const C: S = {
let s = S { x: 0, y: E::A };
// Go through an &u32 reference which is definitely not allowed to mutate anything.
let p = &s.x as *const u32 as *mut u32;
// Change enum tag to E::B.
let mut s = S { x: 0, y: E::A };
let p = &mut s.x as *mut u32;
// Change enum tag to E::B. Now there's interior mutability here.
unsafe { *p.add(1) = 1 };
s
};

View File

@ -6,7 +6,7 @@ LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾ALLOC0╼ ff ff ff ff │ ╾──╼....
╾ALLOC0<imm>╼ ff ff ff ff │ ╾──╼....
}
error: aborting due to 1 previous error

View File

@ -6,7 +6,7 @@ LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾ALLOC0╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
╾ALLOC0<imm>╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
}
error: aborting due to 1 previous error

View File

@ -6,7 +6,7 @@ LL | const G: Fat = unsafe { Transmute { t: FOO }.u };
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
}
error: aborting due to 1 previous error

View File

@ -24,7 +24,7 @@ LL | const REF_INTERIOR_MUT: &usize = {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
╾ALLOC0╼ │ ╾──╼
╾ALLOC0<imm>╼ │ ╾──╼
}
error[E0080]: it is undefined behavior to use this value
@ -35,7 +35,7 @@ LL | const READ_IMMUT: &usize = {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
╾ALLOC1╼ │ ╾──╼
╾ALLOC1<imm>╼ │ ╾──╼
}
warning: skipping const checks

View File

@ -24,7 +24,7 @@ LL | const REF_INTERIOR_MUT: &usize = {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
╾ALLOC0╼ │ ╾──────╼
╾ALLOC0<imm>╼ │ ╾──────╼
}
error[E0080]: it is undefined behavior to use this value
@ -35,7 +35,7 @@ LL | const READ_IMMUT: &usize = {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
╾ALLOC1╼ │ ╾──────╼
╾ALLOC1<imm>╼ │ ╾──────╼
}
warning: skipping const checks

View File

@ -6,7 +6,7 @@ LL | const SLICE_MUT: &[u8; 1] = {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
╾ALLOC0╼ │ ╾──╼
╾ALLOC0<imm>╼ │ ╾──╼
}
error: could not evaluate constant pattern
@ -23,7 +23,7 @@ LL | const U8_MUT: &u8 = {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
╾ALLOC0╼ │ ╾──╼
╾ALLOC0<imm>╼ │ ╾──╼
}
error: could not evaluate constant pattern

View File

@ -6,7 +6,7 @@ LL | const SLICE_MUT: &[u8; 1] = {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
╾ALLOC0╼ │ ╾──────╼
╾ALLOC0<imm>╼ │ ╾──────╼
}
error: could not evaluate constant pattern
@ -23,7 +23,7 @@ LL | const U8_MUT: &u8 = {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
╾ALLOC0╼ │ ╾──────╼
╾ALLOC0<imm>╼ │ ╾──────╼
}
error: could not evaluate constant pattern