Auto merge of #125691 - jieyouxu:rollup-0i3wrc4, r=jieyouxu
Rollup of 8 pull requests Successful merges: - #124251 (Add an intrinsic for `ptr::metadata`) - #124320 (Add `--print=check-cfg` to get the expected configs) - #125226 (Make more of the test suite run on Mac Catalyst) - #125381 (Silence some resolve errors when there have been glob import errors) - #125633 (miri: avoid making a full copy of all new allocations) - #125638 (Rewrite `lto-smoke`, `simple-rlib` and `mixing-deps` `run-make` tests in `rmake.rs` format) - #125639 (Support `./x doc run-make-support --open`) - #125664 (Tweak relations to no longer rely on `TypeTrace`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
751691271d
@ -616,22 +616,34 @@ fn codegen_stmt<'tcx>(
|
|||||||
Rvalue::UnaryOp(un_op, ref operand) => {
|
Rvalue::UnaryOp(un_op, ref operand) => {
|
||||||
let operand = codegen_operand(fx, operand);
|
let operand = codegen_operand(fx, operand);
|
||||||
let layout = operand.layout();
|
let layout = operand.layout();
|
||||||
let val = operand.load_scalar(fx);
|
|
||||||
let res = match un_op {
|
let res = match un_op {
|
||||||
UnOp::Not => match layout.ty.kind() {
|
UnOp::Not => {
|
||||||
ty::Bool => {
|
let val = operand.load_scalar(fx);
|
||||||
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
|
match layout.ty.kind() {
|
||||||
CValue::by_val(res, layout)
|
ty::Bool => {
|
||||||
|
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
|
||||||
|
CValue::by_val(res, layout)
|
||||||
|
}
|
||||||
|
ty::Uint(_) | ty::Int(_) => {
|
||||||
|
CValue::by_val(fx.bcx.ins().bnot(val), layout)
|
||||||
|
}
|
||||||
|
_ => unreachable!("un op Not for {:?}", layout.ty),
|
||||||
}
|
}
|
||||||
ty::Uint(_) | ty::Int(_) => {
|
}
|
||||||
CValue::by_val(fx.bcx.ins().bnot(val), layout)
|
UnOp::Neg => {
|
||||||
|
let val = operand.load_scalar(fx);
|
||||||
|
match layout.ty.kind() {
|
||||||
|
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
|
||||||
|
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
|
||||||
|
_ => unreachable!("un op Neg for {:?}", layout.ty),
|
||||||
}
|
}
|
||||||
_ => unreachable!("un op Not for {:?}", layout.ty),
|
}
|
||||||
},
|
UnOp::PtrMetadata => match layout.abi {
|
||||||
UnOp::Neg => match layout.ty.kind() {
|
Abi::Scalar(_) => CValue::zst(dest_layout),
|
||||||
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
|
Abi::ScalarPair(_, _) => {
|
||||||
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
|
CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout)
|
||||||
_ => unreachable!("un op Neg for {:?}", layout.ty),
|
}
|
||||||
|
_ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
lval.write_cvalue(fx, res);
|
lval.write_cvalue(fx, res);
|
||||||
|
@ -100,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>(
|
|||||||
assert!(layout.is_sized(), "unsized const value");
|
assert!(layout.is_sized(), "unsized const value");
|
||||||
|
|
||||||
if layout.is_zst() {
|
if layout.is_zst() {
|
||||||
return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout);
|
return CValue::zst(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
match const_val {
|
match const_val {
|
||||||
|
@ -95,6 +95,14 @@ impl<'tcx> CValue<'tcx> {
|
|||||||
CValue(CValueInner::ByValPair(value, extra), layout)
|
CValue(CValueInner::ByValPair(value, extra), layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create an instance of a ZST
|
||||||
|
///
|
||||||
|
/// The is represented by a dangling pointer of suitable alignment.
|
||||||
|
pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> {
|
||||||
|
assert!(layout.is_zst());
|
||||||
|
CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
|
pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
|
||||||
self.1
|
self.1
|
||||||
}
|
}
|
||||||
|
@ -565,6 +565,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
for elem in place_ref.projection.iter() {
|
for elem in place_ref.projection.iter() {
|
||||||
match elem {
|
match elem {
|
||||||
mir::ProjectionElem::Field(ref f, _) => {
|
mir::ProjectionElem::Field(ref f, _) => {
|
||||||
|
debug_assert!(
|
||||||
|
!o.layout.ty.is_any_ptr(),
|
||||||
|
"Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
|
||||||
|
but tried to access field {f:?} of pointer {o:?}",
|
||||||
|
);
|
||||||
o = o.extract_field(bx, f.index());
|
o = o.extract_field(bx, f.index());
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::Index(_)
|
mir::ProjectionElem::Index(_)
|
||||||
|
@ -480,6 +480,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
cg_base = match *elem {
|
cg_base = match *elem {
|
||||||
mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
|
mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
|
||||||
mir::ProjectionElem::Field(ref field, _) => {
|
mir::ProjectionElem::Field(ref field, _) => {
|
||||||
|
debug_assert!(
|
||||||
|
!cg_base.layout.ty.is_any_ptr(),
|
||||||
|
"Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
|
||||||
|
but tried to access field {field:?} of pointer {cg_base:?}",
|
||||||
|
);
|
||||||
cg_base.project_field(bx, field.index())
|
cg_base.project_field(bx, field.index())
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::OpaqueCast(ty) => {
|
mir::ProjectionElem::OpaqueCast(ty) => {
|
||||||
|
@ -623,19 +623,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
|
|
||||||
mir::Rvalue::UnaryOp(op, ref operand) => {
|
mir::Rvalue::UnaryOp(op, ref operand) => {
|
||||||
let operand = self.codegen_operand(bx, operand);
|
let operand = self.codegen_operand(bx, operand);
|
||||||
let lloperand = operand.immediate();
|
|
||||||
let is_float = operand.layout.ty.is_floating_point();
|
let is_float = operand.layout.ty.is_floating_point();
|
||||||
let llval = match op {
|
let (val, layout) = match op {
|
||||||
mir::UnOp::Not => bx.not(lloperand),
|
mir::UnOp::Not => {
|
||||||
|
let llval = bx.not(operand.immediate());
|
||||||
|
(OperandValue::Immediate(llval), operand.layout)
|
||||||
|
}
|
||||||
mir::UnOp::Neg => {
|
mir::UnOp::Neg => {
|
||||||
if is_float {
|
let llval = if is_float {
|
||||||
bx.fneg(lloperand)
|
bx.fneg(operand.immediate())
|
||||||
} else {
|
} else {
|
||||||
bx.neg(lloperand)
|
bx.neg(operand.immediate())
|
||||||
|
};
|
||||||
|
(OperandValue::Immediate(llval), operand.layout)
|
||||||
|
}
|
||||||
|
mir::UnOp::PtrMetadata => {
|
||||||
|
debug_assert!(operand.layout.ty.is_unsafe_ptr());
|
||||||
|
let (_, meta) = operand.val.pointer_parts();
|
||||||
|
assert_eq!(operand.layout.fields.count() > 1, meta.is_some());
|
||||||
|
if let Some(meta) = meta {
|
||||||
|
(OperandValue::Immediate(meta), operand.layout.field(self.cx, 1))
|
||||||
|
} else {
|
||||||
|
(OperandValue::ZeroSized, bx.cx().layout_of(bx.tcx().types.unit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
OperandRef { val: OperandValue::Immediate(llval), layout: operand.layout }
|
debug_assert!(
|
||||||
|
val.is_expected_variant_for_type(self.cx, layout),
|
||||||
|
"Made wrong variant {val:?} for type {layout:?}",
|
||||||
|
);
|
||||||
|
OperandRef { val, layout }
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::Rvalue::Discriminant(ref place) => {
|
mir::Rvalue::Discriminant(ref place) => {
|
||||||
@ -718,8 +735,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
let values = op.val.immediates_or_place().left_or_else(|p| {
|
let values = op.val.immediates_or_place().left_or_else(|p| {
|
||||||
bug!("Field {field_idx:?} is {p:?} making {layout:?}");
|
bug!("Field {field_idx:?} is {p:?} making {layout:?}");
|
||||||
});
|
});
|
||||||
inputs.extend(values);
|
|
||||||
let scalars = self.value_kind(op.layout).scalars().unwrap();
|
let scalars = self.value_kind(op.layout).scalars().unwrap();
|
||||||
|
debug_assert_eq!(values.len(), scalars.len());
|
||||||
|
inputs.extend(values);
|
||||||
input_scalars.extend(scalars);
|
input_scalars.extend(scalars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_frame_extra(
|
fn init_frame(
|
||||||
_ecx: &mut InterpCx<'tcx, Self>,
|
_ecx: &mut InterpCx<'tcx, Self>,
|
||||||
_frame: interpret::Frame<'tcx, Self::Provenance>,
|
_frame: interpret::Frame<'tcx, Self::Provenance>,
|
||||||
) -> interpret::InterpResult<'tcx, interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>>
|
) -> interpret::InterpResult<'tcx, interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>>
|
||||||
|
@ -643,7 +643,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn init_frame_extra(
|
fn init_frame(
|
||||||
ecx: &mut InterpCx<'tcx, Self>,
|
ecx: &mut InterpCx<'tcx, Self>,
|
||||||
frame: Frame<'tcx>,
|
frame: Frame<'tcx>,
|
||||||
) -> InterpResult<'tcx, Frame<'tcx>> {
|
) -> InterpResult<'tcx, Frame<'tcx>> {
|
||||||
|
@ -207,7 +207,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
assert!(cast_to.ty.is_unsafe_ptr());
|
assert!(cast_to.ty.is_unsafe_ptr());
|
||||||
// Handle casting any ptr to raw ptr (might be a fat ptr).
|
// Handle casting any ptr to raw ptr (might be a fat ptr).
|
||||||
if cast_to.size == src.layout.size {
|
if cast_to.size == src.layout.size {
|
||||||
// Thin or fat pointer that just hast the ptr kind of target type changed.
|
// Thin or fat pointer that just has the ptr kind of target type changed.
|
||||||
return Ok(ImmTy::from_immediate(**src, cast_to));
|
return Ok(ImmTy::from_immediate(**src, cast_to));
|
||||||
} else {
|
} else {
|
||||||
// Casting the metadata away from a fat ptr.
|
// Casting the metadata away from a fat ptr.
|
||||||
|
@ -819,7 +819,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
tracing_span: SpanGuard::new(),
|
tracing_span: SpanGuard::new(),
|
||||||
extra: (),
|
extra: (),
|
||||||
};
|
};
|
||||||
let frame = M::init_frame_extra(self, pre_frame)?;
|
let frame = M::init_frame(self, pre_frame)?;
|
||||||
self.stack_mut().push(frame);
|
self.stack_mut().push(frame);
|
||||||
|
|
||||||
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
|
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
|
||||||
|
@ -329,27 +329,41 @@ pub trait Machine<'tcx>: Sized {
|
|||||||
ptr: Pointer<Self::Provenance>,
|
ptr: Pointer<Self::Provenance>,
|
||||||
) -> Option<(AllocId, Size, Self::ProvenanceExtra)>;
|
) -> Option<(AllocId, Size, Self::ProvenanceExtra)>;
|
||||||
|
|
||||||
/// Called to adjust allocations to the Provenance and AllocExtra of this machine.
|
/// Called to adjust global allocations to the Provenance and AllocExtra of this machine.
|
||||||
///
|
///
|
||||||
/// If `alloc` contains pointers, then they are all pointing to globals.
|
/// If `alloc` contains pointers, then they are all pointing to globals.
|
||||||
///
|
///
|
||||||
/// The way we construct allocations is to always first construct it without extra and then add
|
|
||||||
/// the extra. This keeps uniform code paths for handling both allocations created by CTFE for
|
|
||||||
/// globals, and allocations created by Miri during evaluation.
|
|
||||||
///
|
|
||||||
/// `kind` is the kind of the allocation being adjusted; it can be `None` when
|
|
||||||
/// it's a global and `GLOBAL_KIND` is `None`.
|
|
||||||
///
|
|
||||||
/// This should avoid copying if no work has to be done! If this returns an owned
|
/// This should avoid copying if no work has to be done! If this returns an owned
|
||||||
/// allocation (because a copy had to be done to adjust things), machine memory will
|
/// allocation (because a copy had to be done to adjust things), machine memory will
|
||||||
/// cache the result. (This relies on `AllocMap::get_or` being able to add the
|
/// cache the result. (This relies on `AllocMap::get_or` being able to add the
|
||||||
/// owned allocation to the map even when the map is shared.)
|
/// owned allocation to the map even when the map is shared.)
|
||||||
fn adjust_allocation<'b>(
|
fn adjust_global_allocation<'b>(
|
||||||
ecx: &InterpCx<'tcx, Self>,
|
ecx: &InterpCx<'tcx, Self>,
|
||||||
id: AllocId,
|
id: AllocId,
|
||||||
alloc: Cow<'b, Allocation>,
|
alloc: &'b Allocation,
|
||||||
kind: Option<MemoryKind<Self::MemoryKind>>,
|
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
|
||||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>;
|
{
|
||||||
|
// The default implementation does a copy; CTFE machines have a more efficient implementation
|
||||||
|
// based on their particular choice for `Provenance`, `AllocExtra`, and `Bytes`.
|
||||||
|
let kind = Self::GLOBAL_KIND
|
||||||
|
.expect("if GLOBAL_KIND is None, adjust_global_allocation must be overwritten");
|
||||||
|
let alloc = alloc.adjust_from_tcx(&ecx.tcx, |ptr| ecx.global_root_pointer(ptr))?;
|
||||||
|
let extra =
|
||||||
|
Self::init_alloc_extra(ecx, id, MemoryKind::Machine(kind), alloc.size(), alloc.align)?;
|
||||||
|
Ok(Cow::Owned(alloc.with_extra(extra)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize the extra state of an allocation.
|
||||||
|
///
|
||||||
|
/// This is guaranteed to be called exactly once on all allocations that are accessed by the
|
||||||
|
/// program.
|
||||||
|
fn init_alloc_extra(
|
||||||
|
ecx: &InterpCx<'tcx, Self>,
|
||||||
|
id: AllocId,
|
||||||
|
kind: MemoryKind<Self::MemoryKind>,
|
||||||
|
size: Size,
|
||||||
|
align: Align,
|
||||||
|
) -> InterpResult<'tcx, Self::AllocExtra>;
|
||||||
|
|
||||||
/// Return a "root" pointer for the given allocation: the one that is used for direct
|
/// Return a "root" pointer for the given allocation: the one that is used for direct
|
||||||
/// accesses to this static/const/fn allocation, or the one returned from the heap allocator.
|
/// accesses to this static/const/fn allocation, or the one returned from the heap allocator.
|
||||||
@ -473,7 +487,7 @@ pub trait Machine<'tcx>: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Called immediately before a new stack frame gets pushed.
|
/// Called immediately before a new stack frame gets pushed.
|
||||||
fn init_frame_extra(
|
fn init_frame(
|
||||||
ecx: &mut InterpCx<'tcx, Self>,
|
ecx: &mut InterpCx<'tcx, Self>,
|
||||||
frame: Frame<'tcx, Self::Provenance>,
|
frame: Frame<'tcx, Self::Provenance>,
|
||||||
) -> InterpResult<'tcx, Frame<'tcx, Self::Provenance, Self::FrameExtra>>;
|
) -> InterpResult<'tcx, Frame<'tcx, Self::Provenance, Self::FrameExtra>>;
|
||||||
@ -590,13 +604,23 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn adjust_allocation<'b>(
|
fn adjust_global_allocation<'b>(
|
||||||
_ecx: &InterpCx<$tcx, Self>,
|
_ecx: &InterpCx<$tcx, Self>,
|
||||||
_id: AllocId,
|
_id: AllocId,
|
||||||
alloc: Cow<'b, Allocation>,
|
alloc: &'b Allocation,
|
||||||
_kind: Option<MemoryKind<Self::MemoryKind>>,
|
|
||||||
) -> InterpResult<$tcx, Cow<'b, Allocation<Self::Provenance>>> {
|
) -> InterpResult<$tcx, Cow<'b, Allocation<Self::Provenance>>> {
|
||||||
Ok(alloc)
|
// Overwrite default implementation: no need to adjust anything.
|
||||||
|
Ok(Cow::Borrowed(alloc))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_alloc_extra(
|
||||||
|
_ecx: &InterpCx<$tcx, Self>,
|
||||||
|
_id: AllocId,
|
||||||
|
_kind: MemoryKind<Self::MemoryKind>,
|
||||||
|
_size: Size,
|
||||||
|
_align: Align,
|
||||||
|
) -> InterpResult<$tcx, Self::AllocExtra> {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extern_static_pointer(
|
fn extern_static_pointer(
|
||||||
|
@ -239,7 +239,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
|
|
||||||
pub fn allocate_raw_ptr(
|
pub fn allocate_raw_ptr(
|
||||||
&mut self,
|
&mut self,
|
||||||
alloc: Allocation,
|
alloc: Allocation<M::Provenance, (), M::Bytes>,
|
||||||
kind: MemoryKind<M::MemoryKind>,
|
kind: MemoryKind<M::MemoryKind>,
|
||||||
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
|
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
|
||||||
let id = self.tcx.reserve_alloc_id();
|
let id = self.tcx.reserve_alloc_id();
|
||||||
@ -248,8 +248,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
M::GLOBAL_KIND.map(MemoryKind::Machine),
|
M::GLOBAL_KIND.map(MemoryKind::Machine),
|
||||||
"dynamically allocating global memory"
|
"dynamically allocating global memory"
|
||||||
);
|
);
|
||||||
let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
|
// We have set things up so we don't need to call `adjust_from_tcx` here,
|
||||||
self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
|
// so we avoid copying the entire allocation contents.
|
||||||
|
let extra = M::init_alloc_extra(self, id, kind, alloc.size(), alloc.align)?;
|
||||||
|
let alloc = alloc.with_extra(extra);
|
||||||
|
self.memory.alloc_map.insert(id, (kind, alloc));
|
||||||
M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind))
|
M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,11 +586,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
};
|
};
|
||||||
M::before_access_global(self.tcx, &self.machine, id, alloc, def_id, is_write)?;
|
M::before_access_global(self.tcx, &self.machine, id, alloc, def_id, is_write)?;
|
||||||
// We got tcx memory. Let the machine initialize its "extra" stuff.
|
// We got tcx memory. Let the machine initialize its "extra" stuff.
|
||||||
M::adjust_allocation(
|
M::adjust_global_allocation(
|
||||||
self,
|
self,
|
||||||
id, // always use the ID we got as input, not the "hidden" one.
|
id, // always use the ID we got as input, not the "hidden" one.
|
||||||
Cow::Borrowed(alloc.inner()),
|
alloc.inner(),
|
||||||
M::GLOBAL_KIND.map(MemoryKind::Machine),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use rustc_middle::{bug, span_bug};
|
|||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine};
|
use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta};
|
||||||
|
|
||||||
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> {
|
fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> {
|
||||||
@ -415,11 +415,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
use rustc_middle::mir::UnOp::*;
|
use rustc_middle::mir::UnOp::*;
|
||||||
|
|
||||||
let layout = val.layout;
|
let layout = val.layout;
|
||||||
let val = val.to_scalar();
|
|
||||||
trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty);
|
trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty);
|
||||||
|
|
||||||
match layout.ty.kind() {
|
match layout.ty.kind() {
|
||||||
ty::Bool => {
|
ty::Bool => {
|
||||||
|
let val = val.to_scalar();
|
||||||
let val = val.to_bool()?;
|
let val = val.to_bool()?;
|
||||||
let res = match un_op {
|
let res = match un_op {
|
||||||
Not => !val,
|
Not => !val,
|
||||||
@ -428,6 +428,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
Ok(ImmTy::from_bool(res, *self.tcx))
|
Ok(ImmTy::from_bool(res, *self.tcx))
|
||||||
}
|
}
|
||||||
ty::Float(fty) => {
|
ty::Float(fty) => {
|
||||||
|
let val = val.to_scalar();
|
||||||
// No NaN adjustment here, `-` is a bitwise operation!
|
// No NaN adjustment here, `-` is a bitwise operation!
|
||||||
let res = match (un_op, fty) {
|
let res = match (un_op, fty) {
|
||||||
(Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?),
|
(Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?),
|
||||||
@ -436,8 +437,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
};
|
};
|
||||||
Ok(ImmTy::from_scalar(res, layout))
|
Ok(ImmTy::from_scalar(res, layout))
|
||||||
}
|
}
|
||||||
_ => {
|
_ if layout.ty.is_integral() => {
|
||||||
assert!(layout.ty.is_integral());
|
let val = val.to_scalar();
|
||||||
let val = val.to_bits(layout.size)?;
|
let val = val.to_bits(layout.size)?;
|
||||||
let res = match un_op {
|
let res = match un_op {
|
||||||
Not => self.truncate(!val, layout), // bitwise negation, then truncate
|
Not => self.truncate(!val, layout), // bitwise negation, then truncate
|
||||||
@ -450,9 +451,28 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
// Truncate to target type.
|
// Truncate to target type.
|
||||||
self.truncate(res, layout)
|
self.truncate(res, layout)
|
||||||
}
|
}
|
||||||
|
_ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op),
|
||||||
};
|
};
|
||||||
Ok(ImmTy::from_uint(res, layout))
|
Ok(ImmTy::from_uint(res, layout))
|
||||||
}
|
}
|
||||||
|
ty::RawPtr(..) => {
|
||||||
|
assert_eq!(un_op, PtrMetadata);
|
||||||
|
let (_, meta) = val.to_scalar_and_meta();
|
||||||
|
Ok(match meta {
|
||||||
|
MemPlaceMeta::Meta(scalar) => {
|
||||||
|
let ty = un_op.ty(*self.tcx, val.layout.ty);
|
||||||
|
let layout = self.layout_of(ty)?;
|
||||||
|
ImmTy::from_scalar(scalar, layout)
|
||||||
|
}
|
||||||
|
MemPlaceMeta::None => {
|
||||||
|
let unit_layout = self.layout_of(self.tcx.types.unit)?;
|
||||||
|
ImmTy::uninit(unit_layout)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
bug!("Unexpected unary op argument {val:?}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -804,6 +804,39 @@ fn print_crate_info(
|
|||||||
println_info!("{cfg}");
|
println_info!("{cfg}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CheckCfg => {
|
||||||
|
let mut check_cfgs: Vec<String> = Vec::with_capacity(410);
|
||||||
|
|
||||||
|
// INSTABILITY: We are sorting the output below.
|
||||||
|
#[allow(rustc::potential_query_instability)]
|
||||||
|
for (name, expected_values) in &sess.psess.check_config.expecteds {
|
||||||
|
use crate::config::ExpectedValues;
|
||||||
|
match expected_values {
|
||||||
|
ExpectedValues::Any => check_cfgs.push(format!("{name}=any()")),
|
||||||
|
ExpectedValues::Some(values) => {
|
||||||
|
check_cfgs.extend(values.iter().map(|value| {
|
||||||
|
if let Some(value) = value {
|
||||||
|
format!("{name}=\"{value}\"")
|
||||||
|
} else {
|
||||||
|
name.to_string()
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check_cfgs.sort_unstable();
|
||||||
|
if !sess.psess.check_config.exhaustive_names {
|
||||||
|
if !sess.psess.check_config.exhaustive_values {
|
||||||
|
println_info!("any()=any()");
|
||||||
|
} else {
|
||||||
|
println_info!("any()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for check_cfg in check_cfgs {
|
||||||
|
println_info!("{check_cfg}");
|
||||||
|
}
|
||||||
|
}
|
||||||
CallingConventions => {
|
CallingConventions => {
|
||||||
let mut calling_conventions = rustc_target::spec::abi::all_names();
|
let mut calling_conventions = rustc_target::spec::abi::all_names();
|
||||||
calling_conventions.sort_unstable();
|
calling_conventions.sort_unstable();
|
||||||
|
@ -130,6 +130,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
|
|||||||
| sym::is_val_statically_known
|
| sym::is_val_statically_known
|
||||||
| sym::ptr_mask
|
| sym::ptr_mask
|
||||||
| sym::aggregate_raw_ptr
|
| sym::aggregate_raw_ptr
|
||||||
|
| sym::ptr_metadata
|
||||||
| sym::ub_checks
|
| sym::ub_checks
|
||||||
| sym::fadd_algebraic
|
| sym::fadd_algebraic
|
||||||
| sym::fsub_algebraic
|
| sym::fsub_algebraic
|
||||||
@ -576,6 +577,7 @@ pub fn check_intrinsic_type(
|
|||||||
// This type check is not particularly useful, but the `where` bounds
|
// This type check is not particularly useful, but the `where` bounds
|
||||||
// on the definition in `core` do the heavy lifting for checking it.
|
// on the definition in `core` do the heavy lifting for checking it.
|
||||||
sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)),
|
sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)),
|
||||||
|
sym::ptr_metadata => (2, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)),
|
||||||
|
|
||||||
sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool),
|
sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool),
|
||||||
|
|
||||||
|
@ -1158,7 +1158,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig));
|
let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig));
|
||||||
let sig = self
|
let sig = self
|
||||||
.at(cause, self.param_env)
|
.at(cause, self.param_env)
|
||||||
.trace(prev_ty, new_ty)
|
|
||||||
.lub(DefineOpaqueTypes::Yes, a_sig, b_sig)
|
.lub(DefineOpaqueTypes::Yes, a_sig, b_sig)
|
||||||
.map(|ok| self.register_infer_ok_obligations(ok))?;
|
.map(|ok| self.register_infer_ok_obligations(ok))?;
|
||||||
|
|
||||||
|
@ -48,11 +48,6 @@ pub struct At<'a, 'tcx> {
|
|||||||
pub param_env: ty::ParamEnv<'tcx>,
|
pub param_env: ty::ParamEnv<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Trace<'a, 'tcx> {
|
|
||||||
at: At<'a, 'tcx>,
|
|
||||||
trace: TypeTrace<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> InferCtxt<'tcx> {
|
impl<'tcx> InferCtxt<'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn at<'a>(
|
pub fn at<'a>(
|
||||||
@ -109,9 +104,6 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
/// call like `foo(x)`, where `foo: fn(i32)`, you might have
|
/// call like `foo(x)`, where `foo: fn(i32)`, you might have
|
||||||
/// `sup(i32, x)`, since the "expected" type is the type that
|
/// `sup(i32, x)`, since the "expected" type is the type that
|
||||||
/// appears in the signature.
|
/// appears in the signature.
|
||||||
///
|
|
||||||
/// See [`At::trace`] and [`Trace::sub`] for a version of
|
|
||||||
/// this method that only requires `T: Relate<'tcx>`
|
|
||||||
pub fn sup<T>(
|
pub fn sup<T>(
|
||||||
self,
|
self,
|
||||||
define_opaque_types: DefineOpaqueTypes,
|
define_opaque_types: DefineOpaqueTypes,
|
||||||
@ -121,13 +113,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
where
|
where
|
||||||
T: ToTrace<'tcx>,
|
T: ToTrace<'tcx>,
|
||||||
{
|
{
|
||||||
self.trace(expected, actual).sup(define_opaque_types, expected, actual)
|
let mut fields = CombineFields::new(
|
||||||
|
self.infcx,
|
||||||
|
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||||
|
self.param_env,
|
||||||
|
define_opaque_types,
|
||||||
|
);
|
||||||
|
fields
|
||||||
|
.sup()
|
||||||
|
.relate(expected, actual)
|
||||||
|
.map(|_| InferOk { value: (), obligations: fields.obligations })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes `expected <: actual`.
|
/// Makes `expected <: actual`.
|
||||||
///
|
|
||||||
/// See [`At::trace`] and [`Trace::sub`] for a version of
|
|
||||||
/// this method that only requires `T: Relate<'tcx>`
|
|
||||||
pub fn sub<T>(
|
pub fn sub<T>(
|
||||||
self,
|
self,
|
||||||
define_opaque_types: DefineOpaqueTypes,
|
define_opaque_types: DefineOpaqueTypes,
|
||||||
@ -137,13 +135,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
where
|
where
|
||||||
T: ToTrace<'tcx>,
|
T: ToTrace<'tcx>,
|
||||||
{
|
{
|
||||||
self.trace(expected, actual).sub(define_opaque_types, expected, actual)
|
let mut fields = CombineFields::new(
|
||||||
|
self.infcx,
|
||||||
|
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||||
|
self.param_env,
|
||||||
|
define_opaque_types,
|
||||||
|
);
|
||||||
|
fields
|
||||||
|
.sub()
|
||||||
|
.relate(expected, actual)
|
||||||
|
.map(|_| InferOk { value: (), obligations: fields.obligations })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes `expected <: actual`.
|
/// Makes `expected == actual`.
|
||||||
///
|
|
||||||
/// See [`At::trace`] and [`Trace::eq`] for a version of
|
|
||||||
/// this method that only requires `T: Relate<'tcx>`
|
|
||||||
pub fn eq<T>(
|
pub fn eq<T>(
|
||||||
self,
|
self,
|
||||||
define_opaque_types: DefineOpaqueTypes,
|
define_opaque_types: DefineOpaqueTypes,
|
||||||
@ -153,7 +157,40 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
where
|
where
|
||||||
T: ToTrace<'tcx>,
|
T: ToTrace<'tcx>,
|
||||||
{
|
{
|
||||||
self.trace(expected, actual).eq(define_opaque_types, expected, actual)
|
let mut fields = CombineFields::new(
|
||||||
|
self.infcx,
|
||||||
|
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||||
|
self.param_env,
|
||||||
|
define_opaque_types,
|
||||||
|
);
|
||||||
|
fields
|
||||||
|
.equate(StructurallyRelateAliases::No)
|
||||||
|
.relate(expected, actual)
|
||||||
|
.map(|_| InferOk { value: (), obligations: fields.obligations })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Equates `expected` and `found` while structurally relating aliases.
|
||||||
|
/// This should only be used inside of the next generation trait solver
|
||||||
|
/// when relating rigid aliases.
|
||||||
|
pub fn eq_structurally_relating_aliases<T>(
|
||||||
|
self,
|
||||||
|
expected: T,
|
||||||
|
actual: T,
|
||||||
|
) -> InferResult<'tcx, ()>
|
||||||
|
where
|
||||||
|
T: ToTrace<'tcx>,
|
||||||
|
{
|
||||||
|
assert!(self.infcx.next_trait_solver());
|
||||||
|
let mut fields = CombineFields::new(
|
||||||
|
self.infcx,
|
||||||
|
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||||
|
self.param_env,
|
||||||
|
DefineOpaqueTypes::Yes,
|
||||||
|
);
|
||||||
|
fields
|
||||||
|
.equate(StructurallyRelateAliases::Yes)
|
||||||
|
.relate(expected, actual)
|
||||||
|
.map(|_| InferOk { value: (), obligations: fields.obligations })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn relate<T>(
|
pub fn relate<T>(
|
||||||
@ -185,9 +222,6 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
/// this can result in an error (e.g., if asked to compute LUB of
|
/// this can result in an error (e.g., if asked to compute LUB of
|
||||||
/// u32 and i32), it is meaningful to call one of them the
|
/// u32 and i32), it is meaningful to call one of them the
|
||||||
/// "expected type".
|
/// "expected type".
|
||||||
///
|
|
||||||
/// See [`At::trace`] and [`Trace::lub`] for a version of
|
|
||||||
/// this method that only requires `T: Relate<'tcx>`
|
|
||||||
pub fn lub<T>(
|
pub fn lub<T>(
|
||||||
self,
|
self,
|
||||||
define_opaque_types: DefineOpaqueTypes,
|
define_opaque_types: DefineOpaqueTypes,
|
||||||
@ -197,15 +231,21 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
where
|
where
|
||||||
T: ToTrace<'tcx>,
|
T: ToTrace<'tcx>,
|
||||||
{
|
{
|
||||||
self.trace(expected, actual).lub(define_opaque_types, expected, actual)
|
let mut fields = CombineFields::new(
|
||||||
|
self.infcx,
|
||||||
|
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||||
|
self.param_env,
|
||||||
|
define_opaque_types,
|
||||||
|
);
|
||||||
|
fields
|
||||||
|
.lub()
|
||||||
|
.relate(expected, actual)
|
||||||
|
.map(|value| InferOk { value, obligations: fields.obligations })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the greatest-lower-bound, or mutual subtype, of two
|
/// Computes the greatest-lower-bound, or mutual subtype, of two
|
||||||
/// values. As with `lub` order doesn't matter, except for error
|
/// values. As with `lub` order doesn't matter, except for error
|
||||||
/// cases.
|
/// cases.
|
||||||
///
|
|
||||||
/// See [`At::trace`] and [`Trace::glb`] for a version of
|
|
||||||
/// this method that only requires `T: Relate<'tcx>`
|
|
||||||
pub fn glb<T>(
|
pub fn glb<T>(
|
||||||
self,
|
self,
|
||||||
define_opaque_types: DefineOpaqueTypes,
|
define_opaque_types: DefineOpaqueTypes,
|
||||||
@ -215,105 +255,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
where
|
where
|
||||||
T: ToTrace<'tcx>,
|
T: ToTrace<'tcx>,
|
||||||
{
|
{
|
||||||
self.trace(expected, actual).glb(define_opaque_types, expected, actual)
|
let mut fields = CombineFields::new(
|
||||||
}
|
self.infcx,
|
||||||
|
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||||
/// Sets the "trace" values that will be used for
|
self.param_env,
|
||||||
/// error-reporting, but doesn't actually perform any operation
|
define_opaque_types,
|
||||||
/// yet (this is useful when you want to set the trace using
|
);
|
||||||
/// distinct values from those you wish to operate upon).
|
|
||||||
pub fn trace<T>(self, expected: T, actual: T) -> Trace<'a, 'tcx>
|
|
||||||
where
|
|
||||||
T: ToTrace<'tcx>,
|
|
||||||
{
|
|
||||||
let trace = ToTrace::to_trace(self.cause, true, expected, actual);
|
|
||||||
Trace { at: self, trace }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> Trace<'a, 'tcx> {
|
|
||||||
/// Makes `a <: b`.
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
|
||||||
pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
|
||||||
where
|
|
||||||
T: Relate<'tcx>,
|
|
||||||
{
|
|
||||||
let Trace { at, trace } = self;
|
|
||||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
|
||||||
fields
|
|
||||||
.sub()
|
|
||||||
.relate(a, b)
|
|
||||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes `a :> b`.
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
|
||||||
pub fn sup<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
|
||||||
where
|
|
||||||
T: Relate<'tcx>,
|
|
||||||
{
|
|
||||||
let Trace { at, trace } = self;
|
|
||||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
|
||||||
fields
|
|
||||||
.sup()
|
|
||||||
.relate(a, b)
|
|
||||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes `a == b`.
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
|
||||||
pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
|
||||||
where
|
|
||||||
T: Relate<'tcx>,
|
|
||||||
{
|
|
||||||
let Trace { at, trace } = self;
|
|
||||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
|
||||||
fields
|
|
||||||
.equate(StructurallyRelateAliases::No)
|
|
||||||
.relate(a, b)
|
|
||||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Equates `a` and `b` while structurally relating aliases. This should only
|
|
||||||
/// be used inside of the next generation trait solver when relating rigid aliases.
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
|
||||||
pub fn eq_structurally_relating_aliases<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
|
|
||||||
where
|
|
||||||
T: Relate<'tcx>,
|
|
||||||
{
|
|
||||||
let Trace { at, trace } = self;
|
|
||||||
debug_assert!(at.infcx.next_trait_solver());
|
|
||||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::Yes);
|
|
||||||
fields
|
|
||||||
.equate(StructurallyRelateAliases::Yes)
|
|
||||||
.relate(a, b)
|
|
||||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
|
||||||
pub fn lub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
|
|
||||||
where
|
|
||||||
T: Relate<'tcx>,
|
|
||||||
{
|
|
||||||
let Trace { at, trace } = self;
|
|
||||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
|
||||||
fields
|
|
||||||
.lub()
|
|
||||||
.relate(a, b)
|
|
||||||
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
|
||||||
pub fn glb<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
|
|
||||||
where
|
|
||||||
T: Relate<'tcx>,
|
|
||||||
{
|
|
||||||
let Trace { at, trace } = self;
|
|
||||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
|
||||||
fields
|
fields
|
||||||
.glb()
|
.glb()
|
||||||
.relate(a, b)
|
.relate(expected, actual)
|
||||||
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
.map(|value| InferOk { value, obligations: fields.obligations })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -836,21 +836,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn combine_fields<'a>(
|
|
||||||
&'a self,
|
|
||||||
trace: TypeTrace<'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
define_opaque_types: DefineOpaqueTypes,
|
|
||||||
) -> CombineFields<'a, 'tcx> {
|
|
||||||
CombineFields {
|
|
||||||
infcx: self,
|
|
||||||
trace,
|
|
||||||
param_env,
|
|
||||||
obligations: PredicateObligations::new(),
|
|
||||||
define_opaque_types,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool
|
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool
|
||||||
where
|
where
|
||||||
T: at::ToTrace<'tcx>,
|
T: at::ToTrace<'tcx>,
|
||||||
|
@ -42,6 +42,17 @@ pub struct CombineFields<'infcx, 'tcx> {
|
|||||||
pub define_opaque_types: DefineOpaqueTypes,
|
pub define_opaque_types: DefineOpaqueTypes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||||
|
pub fn new(
|
||||||
|
infcx: &'infcx InferCtxt<'tcx>,
|
||||||
|
trace: TypeTrace<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
define_opaque_types: DefineOpaqueTypes,
|
||||||
|
) -> Self {
|
||||||
|
Self { infcx, trace, param_env, define_opaque_types, obligations: vec![] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> InferCtxt<'tcx> {
|
impl<'tcx> InferCtxt<'tcx> {
|
||||||
pub fn super_combine_tys<R>(
|
pub fn super_combine_tys<R>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -266,19 +266,6 @@ impl AllocRange {
|
|||||||
|
|
||||||
// The constructors are all without extra; the extra gets added by a machine hook later.
|
// The constructors are all without extra; the extra gets added by a machine hook later.
|
||||||
impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
||||||
/// Creates an allocation from an existing `Bytes` value - this is needed for miri FFI support
|
|
||||||
pub fn from_raw_bytes(bytes: Bytes, align: Align, mutability: Mutability) -> Self {
|
|
||||||
let size = Size::from_bytes(bytes.len());
|
|
||||||
Self {
|
|
||||||
bytes,
|
|
||||||
provenance: ProvenanceMap::new(),
|
|
||||||
init_mask: InitMask::new(size, true),
|
|
||||||
align,
|
|
||||||
mutability,
|
|
||||||
extra: (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an allocation initialized by the given bytes
|
/// Creates an allocation initialized by the given bytes
|
||||||
pub fn from_bytes<'a>(
|
pub fn from_bytes<'a>(
|
||||||
slice: impl Into<Cow<'a, [u8]>>,
|
slice: impl Into<Cow<'a, [u8]>>,
|
||||||
@ -342,18 +329,30 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
|||||||
Err(x) => x,
|
Err(x) => x,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add the extra.
|
||||||
|
pub fn with_extra<Extra>(self, extra: Extra) -> Allocation<Prov, Extra, Bytes> {
|
||||||
|
Allocation {
|
||||||
|
bytes: self.bytes,
|
||||||
|
provenance: self.provenance,
|
||||||
|
init_mask: self.init_mask,
|
||||||
|
align: self.align,
|
||||||
|
mutability: self.mutability,
|
||||||
|
extra,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocation {
|
impl Allocation {
|
||||||
/// Adjust allocation from the ones in `tcx` to a custom Machine instance
|
/// Adjust allocation from the ones in `tcx` to a custom Machine instance
|
||||||
/// with a different `Provenance`, `Extra` and `Byte` type.
|
/// with a different `Provenance` and `Byte` type.
|
||||||
pub fn adjust_from_tcx<Prov: Provenance, Extra, Bytes: AllocBytes, Err>(
|
pub fn adjust_from_tcx<Prov: Provenance, Bytes: AllocBytes, Err>(
|
||||||
self,
|
&self,
|
||||||
cx: &impl HasDataLayout,
|
cx: &impl HasDataLayout,
|
||||||
extra: Extra,
|
|
||||||
mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> Result<Pointer<Prov>, Err>,
|
mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> Result<Pointer<Prov>, Err>,
|
||||||
) -> Result<Allocation<Prov, Extra, Bytes>, Err> {
|
) -> Result<Allocation<Prov, (), Bytes>, Err> {
|
||||||
let mut bytes = self.bytes;
|
// Copy the data.
|
||||||
|
let mut bytes = Bytes::from_bytes(Cow::Borrowed(&*self.bytes), self.align);
|
||||||
// Adjust provenance of pointers stored in this allocation.
|
// Adjust provenance of pointers stored in this allocation.
|
||||||
let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len());
|
let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len());
|
||||||
let ptr_size = cx.data_layout().pointer_size.bytes_usize();
|
let ptr_size = cx.data_layout().pointer_size.bytes_usize();
|
||||||
@ -369,12 +368,12 @@ impl Allocation {
|
|||||||
}
|
}
|
||||||
// Create allocation.
|
// Create allocation.
|
||||||
Ok(Allocation {
|
Ok(Allocation {
|
||||||
bytes: AllocBytes::from_bytes(Cow::Owned(Vec::from(bytes)), self.align),
|
bytes,
|
||||||
provenance: ProvenanceMap::from_presorted_ptrs(new_provenance),
|
provenance: ProvenanceMap::from_presorted_ptrs(new_provenance),
|
||||||
init_mask: self.init_mask,
|
init_mask: self.init_mask.clone(),
|
||||||
align: self.align,
|
align: self.align,
|
||||||
mutability: self.mutability,
|
mutability: self.mutability,
|
||||||
extra,
|
extra: self.extra,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1434,6 +1434,13 @@ pub enum UnOp {
|
|||||||
Not,
|
Not,
|
||||||
/// The `-` operator for negation
|
/// The `-` operator for negation
|
||||||
Neg,
|
Neg,
|
||||||
|
/// Get the metadata `M` from a `*const/mut impl Pointee<Metadata = M>`.
|
||||||
|
///
|
||||||
|
/// For example, this will give a `()` from `*const i32`, a `usize` from
|
||||||
|
/// `*mut [u8]`, or a pointer to a vtable from a `*const dyn Foo`.
|
||||||
|
///
|
||||||
|
/// Allowed only in [`MirPhase::Runtime`]; earlier it's an intrinsic.
|
||||||
|
PtrMetadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
|
||||||
|
@ -180,7 +180,10 @@ impl<'tcx> Rvalue<'tcx> {
|
|||||||
let rhs_ty = rhs.ty(local_decls, tcx);
|
let rhs_ty = rhs.ty(local_decls, tcx);
|
||||||
op.ty(tcx, lhs_ty, rhs_ty)
|
op.ty(tcx, lhs_ty, rhs_ty)
|
||||||
}
|
}
|
||||||
Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
|
Rvalue::UnaryOp(op, ref operand) => {
|
||||||
|
let arg_ty = operand.ty(local_decls, tcx);
|
||||||
|
op.ty(tcx, arg_ty)
|
||||||
|
}
|
||||||
Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
|
Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
|
||||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
|
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
|
||||||
tcx.types.usize
|
tcx.types.usize
|
||||||
@ -282,6 +285,27 @@ impl<'tcx> BinOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> UnOp {
|
||||||
|
pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
match self {
|
||||||
|
UnOp::Not | UnOp::Neg => arg_ty,
|
||||||
|
UnOp::PtrMetadata => {
|
||||||
|
let pointee_ty = arg_ty
|
||||||
|
.builtin_deref(true)
|
||||||
|
.unwrap_or_else(|| bug!("PtrMetadata of non-dereferenceable ty {arg_ty:?}"));
|
||||||
|
if pointee_ty.is_trivially_sized(tcx) {
|
||||||
|
tcx.types.unit
|
||||||
|
} else {
|
||||||
|
let Some(metadata_def_id) = tcx.lang_items().metadata_type() else {
|
||||||
|
bug!("No metadata_type lang item while looking at {arg_ty:?}")
|
||||||
|
};
|
||||||
|
Ty::new_projection(tcx, metadata_def_id, [pointee_ty])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BorrowKind {
|
impl BorrowKind {
|
||||||
pub fn to_mutbl_lossy(self) -> hir::Mutability {
|
pub fn to_mutbl_lossy(self) -> hir::Mutability {
|
||||||
match self {
|
match self {
|
||||||
|
@ -1579,8 +1579,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||||||
let formatted_op = match op {
|
let formatted_op = match op {
|
||||||
UnOp::Not => "!",
|
UnOp::Not => "!",
|
||||||
UnOp::Neg => "-",
|
UnOp::Neg => "-",
|
||||||
|
UnOp::PtrMetadata => "PtrMetadata",
|
||||||
};
|
};
|
||||||
let parenthesized = match ct.kind() {
|
let parenthesized = match ct.kind() {
|
||||||
|
_ if op == UnOp::PtrMetadata => true,
|
||||||
ty::ConstKind::Expr(Expr::UnOp(c_op, ..)) => c_op != op,
|
ty::ConstKind::Expr(Expr::UnOp(c_op, ..)) => c_op != op,
|
||||||
ty::ConstKind::Expr(_) => true,
|
ty::ConstKind::Expr(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -212,6 +212,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
|||||||
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
|
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
|
||||||
},
|
},
|
||||||
@call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
|
@call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
|
||||||
|
@call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)),
|
||||||
@call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
|
@call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
|
||||||
ExprKind::Borrow { borrow_kind, arg } => Ok(
|
ExprKind::Borrow { borrow_kind, arg } => Ok(
|
||||||
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
|
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
|
||||||
|
@ -316,6 +316,23 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
|||||||
|
|
||||||
terminator.kind = TerminatorKind::Goto { target };
|
terminator.kind = TerminatorKind::Goto { target };
|
||||||
}
|
}
|
||||||
|
sym::ptr_metadata => {
|
||||||
|
let Ok([ptr]) = <[_; 1]>::try_from(std::mem::take(args)) else {
|
||||||
|
span_bug!(
|
||||||
|
terminator.source_info.span,
|
||||||
|
"Wrong number of arguments for ptr_metadata intrinsic",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
let target = target.unwrap();
|
||||||
|
block.statements.push(Statement {
|
||||||
|
source_info: terminator.source_info,
|
||||||
|
kind: StatementKind::Assign(Box::new((
|
||||||
|
*destination,
|
||||||
|
Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node),
|
||||||
|
))),
|
||||||
|
});
|
||||||
|
terminator.kind = TerminatorKind::Goto { target };
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,7 +464,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||||||
Rvalue::UnaryOp(op, operand) => {
|
Rvalue::UnaryOp(op, operand) => {
|
||||||
match op {
|
match op {
|
||||||
// These operations can never fail.
|
// These operations can never fail.
|
||||||
UnOp::Neg | UnOp::Not => {}
|
UnOp::Neg | UnOp::Not | UnOp::PtrMetadata => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.validate_operand(operand)?;
|
self.validate_operand(operand)?;
|
||||||
|
@ -1109,6 +1109,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||||||
ty::Int(..) | ty::Uint(..) | ty::Bool
|
ty::Int(..) | ty::Uint(..) | ty::Bool
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
UnOp::PtrMetadata => {
|
||||||
|
if !matches!(self.mir_phase, MirPhase::Runtime(_)) {
|
||||||
|
// It would probably be fine to support this in earlier phases,
|
||||||
|
// but at the time of writing it's only ever introduced from intrinsic lowering,
|
||||||
|
// so earlier things can just `bug!` on it.
|
||||||
|
self.fail(location, "PtrMetadata should be in runtime MIR only");
|
||||||
|
}
|
||||||
|
|
||||||
|
check_kinds!(a, "Cannot PtrMetadata non-pointer type {:?}", ty::RawPtr(..));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rvalue::ShallowInitBox(operand, _) => {
|
Rvalue::ShallowInitBox(operand, _) => {
|
||||||
|
@ -537,6 +537,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
let determined_imports = mem::take(&mut self.determined_imports);
|
let determined_imports = mem::take(&mut self.determined_imports);
|
||||||
let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
|
let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
|
||||||
|
|
||||||
|
let mut glob_error = false;
|
||||||
for (is_indeterminate, import) in determined_imports
|
for (is_indeterminate, import) in determined_imports
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| (false, i))
|
.map(|i| (false, i))
|
||||||
@ -548,6 +549,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
self.import_dummy_binding(*import, is_indeterminate);
|
self.import_dummy_binding(*import, is_indeterminate);
|
||||||
|
|
||||||
if let Some(err) = unresolved_import_error {
|
if let Some(err) = unresolved_import_error {
|
||||||
|
glob_error |= import.is_glob();
|
||||||
|
|
||||||
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
|
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
|
||||||
if source.name == kw::SelfLower {
|
if source.name == kw::SelfLower {
|
||||||
// Silence `unresolved import` error if E0429 is already emitted
|
// Silence `unresolved import` error if E0429 is already emitted
|
||||||
@ -563,7 +566,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
// In the case of a new import line, throw a diagnostic message
|
// In the case of a new import line, throw a diagnostic message
|
||||||
// for the previous line.
|
// for the previous line.
|
||||||
self.throw_unresolved_import_error(errors);
|
self.throw_unresolved_import_error(errors, glob_error);
|
||||||
errors = vec![];
|
errors = vec![];
|
||||||
}
|
}
|
||||||
if seen_spans.insert(err.span) {
|
if seen_spans.insert(err.span) {
|
||||||
@ -574,7 +577,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
self.throw_unresolved_import_error(errors);
|
self.throw_unresolved_import_error(errors, glob_error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,9 +603,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !errors.is_empty() {
|
self.throw_unresolved_import_error(errors, glob_error);
|
||||||
self.throw_unresolved_import_error(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn check_hidden_glob_reexports(
|
pub(crate) fn check_hidden_glob_reexports(
|
||||||
@ -672,7 +673,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn throw_unresolved_import_error(&mut self, errors: Vec<(Import<'_>, UnresolvedImportError)>) {
|
fn throw_unresolved_import_error(
|
||||||
|
&mut self,
|
||||||
|
errors: Vec<(Import<'_>, UnresolvedImportError)>,
|
||||||
|
glob_error: bool,
|
||||||
|
) {
|
||||||
if errors.is_empty() {
|
if errors.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -751,7 +756,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diag.emit();
|
let guar = diag.emit();
|
||||||
|
if glob_error {
|
||||||
|
self.glob_error = Some(guar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to resolve the given import, returning:
|
/// Attempts to resolve the given import, returning:
|
||||||
|
@ -4033,9 +4033,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items.
|
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items or
|
||||||
|
// an invalid `use foo::*;` was found, which can cause unbounded ammounts of "item not found"
|
||||||
|
// errors. We silence them all.
|
||||||
fn should_report_errs(&self) -> bool {
|
fn should_report_errs(&self) -> bool {
|
||||||
!(self.r.tcx.sess.opts.actually_rustdoc && self.in_func_body)
|
!(self.r.tcx.sess.opts.actually_rustdoc && self.in_func_body)
|
||||||
|
&& !self.r.glob_error.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve in alternative namespaces if resolution in the primary namespace fails.
|
// Resolve in alternative namespaces if resolution in the primary namespace fails.
|
||||||
|
@ -32,7 +32,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
|||||||
use rustc_data_structures::intern::Interned;
|
use rustc_data_structures::intern::Interned;
|
||||||
use rustc_data_structures::steal::Steal;
|
use rustc_data_structures::steal::Steal;
|
||||||
use rustc_data_structures::sync::{FreezeReadGuard, Lrc};
|
use rustc_data_structures::sync::{FreezeReadGuard, Lrc};
|
||||||
use rustc_errors::{Applicability, Diag, ErrCode};
|
use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed};
|
||||||
use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
|
use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
|
||||||
use rustc_feature::BUILTIN_ATTRIBUTES;
|
use rustc_feature::BUILTIN_ATTRIBUTES;
|
||||||
use rustc_hir::def::Namespace::{self, *};
|
use rustc_hir::def::Namespace::{self, *};
|
||||||
@ -1048,6 +1048,7 @@ pub struct Resolver<'a, 'tcx> {
|
|||||||
|
|
||||||
/// Maps glob imports to the names of items actually imported.
|
/// Maps glob imports to the names of items actually imported.
|
||||||
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
|
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
|
||||||
|
glob_error: Option<ErrorGuaranteed>,
|
||||||
visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
|
visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
|
||||||
used_imports: FxHashSet<NodeId>,
|
used_imports: FxHashSet<NodeId>,
|
||||||
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
|
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
|
||||||
@ -1417,6 +1418,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
ast_transform_scopes: FxHashMap::default(),
|
ast_transform_scopes: FxHashMap::default(),
|
||||||
|
|
||||||
glob_map: Default::default(),
|
glob_map: Default::default(),
|
||||||
|
glob_error: None,
|
||||||
visibilities_for_hashing: Default::default(),
|
visibilities_for_hashing: Default::default(),
|
||||||
used_imports: FxHashSet::default(),
|
used_imports: FxHashSet::default(),
|
||||||
maybe_unused_trait_imports: Default::default(),
|
maybe_unused_trait_imports: Default::default(),
|
||||||
|
@ -773,6 +773,7 @@ pub enum PrintKind {
|
|||||||
TargetLibdir,
|
TargetLibdir,
|
||||||
CrateName,
|
CrateName,
|
||||||
Cfg,
|
Cfg,
|
||||||
|
CheckCfg,
|
||||||
CallingConventions,
|
CallingConventions,
|
||||||
TargetList,
|
TargetList,
|
||||||
TargetCPUs,
|
TargetCPUs,
|
||||||
@ -1443,7 +1444,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
|
|||||||
"",
|
"",
|
||||||
"print",
|
"print",
|
||||||
"Compiler information to print on stdout",
|
"Compiler information to print on stdout",
|
||||||
"[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
|
"[crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|\
|
||||||
target-list|target-cpus|target-features|relocation-models|code-models|\
|
target-list|target-cpus|target-features|relocation-models|code-models|\
|
||||||
tls-models|target-spec-json|all-target-specs-json|native-static-libs|\
|
tls-models|target-spec-json|all-target-specs-json|native-static-libs|\
|
||||||
stack-protector-strategies|link-args|deployment-target]",
|
stack-protector-strategies|link-args|deployment-target]",
|
||||||
@ -1859,6 +1860,7 @@ fn collect_print_requests(
|
|||||||
("all-target-specs-json", PrintKind::AllTargetSpecs),
|
("all-target-specs-json", PrintKind::AllTargetSpecs),
|
||||||
("calling-conventions", PrintKind::CallingConventions),
|
("calling-conventions", PrintKind::CallingConventions),
|
||||||
("cfg", PrintKind::Cfg),
|
("cfg", PrintKind::Cfg),
|
||||||
|
("check-cfg", PrintKind::CheckCfg),
|
||||||
("code-models", PrintKind::CodeModels),
|
("code-models", PrintKind::CodeModels),
|
||||||
("crate-name", PrintKind::CrateName),
|
("crate-name", PrintKind::CrateName),
|
||||||
("deployment-target", PrintKind::DeploymentTarget),
|
("deployment-target", PrintKind::DeploymentTarget),
|
||||||
@ -1908,6 +1910,16 @@ fn collect_print_requests(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some((_, PrintKind::CheckCfg)) => {
|
||||||
|
if unstable_opts.unstable_options {
|
||||||
|
PrintKind::CheckCfg
|
||||||
|
} else {
|
||||||
|
early_dcx.early_fatal(
|
||||||
|
"the `-Z unstable-options` flag must also be passed to \
|
||||||
|
enable the check-cfg print option",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some(&(_, print_kind)) => print_kind,
|
Some(&(_, print_kind)) => print_kind,
|
||||||
None => {
|
None => {
|
||||||
let prints =
|
let prints =
|
||||||
|
@ -10,7 +10,7 @@ use rustc_span::Symbol;
|
|||||||
use stable_mir::abi::Layout;
|
use stable_mir::abi::Layout;
|
||||||
use stable_mir::mir::alloc::AllocId;
|
use stable_mir::mir::alloc::AllocId;
|
||||||
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
|
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
|
||||||
use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety};
|
use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety, UnOp};
|
||||||
use stable_mir::ty::{
|
use stable_mir::ty::{
|
||||||
Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
|
Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
|
||||||
DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
|
DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
|
||||||
@ -582,6 +582,18 @@ impl RustcInternal for BinOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RustcInternal for UnOp {
|
||||||
|
type T<'tcx> = rustc_middle::mir::UnOp;
|
||||||
|
|
||||||
|
fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
||||||
|
match self {
|
||||||
|
UnOp::Not => rustc_middle::mir::UnOp::Not,
|
||||||
|
UnOp::Neg => rustc_middle::mir::UnOp::Neg,
|
||||||
|
UnOp::PtrMetadata => rustc_middle::mir::UnOp::PtrMetadata,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> RustcInternal for &T
|
impl<T> RustcInternal for &T
|
||||||
where
|
where
|
||||||
T: RustcInternal,
|
T: RustcInternal,
|
||||||
|
@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape};
|
|||||||
use stable_mir::compiler_interface::Context;
|
use stable_mir::compiler_interface::Context;
|
||||||
use stable_mir::mir::alloc::GlobalAlloc;
|
use stable_mir::mir::alloc::GlobalAlloc;
|
||||||
use stable_mir::mir::mono::{InstanceDef, StaticDef};
|
use stable_mir::mir::mono::{InstanceDef, StaticDef};
|
||||||
use stable_mir::mir::{BinOp, Body, Place};
|
use stable_mir::mir::{BinOp, Body, Place, UnOp};
|
||||||
use stable_mir::target::{MachineInfo, MachineSize};
|
use stable_mir::target::{MachineInfo, MachineSize};
|
||||||
use stable_mir::ty::{
|
use stable_mir::ty::{
|
||||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
||||||
@ -700,6 +700,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||||||
let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal);
|
let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal);
|
||||||
ty.stable(&mut *tables)
|
ty.stable(&mut *tables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
let tcx = tables.tcx;
|
||||||
|
let arg_internal = arg.internal(&mut *tables, tcx);
|
||||||
|
let ty = un_op.internal(&mut *tables, tcx).ty(tcx, arg_internal);
|
||||||
|
ty.stable(&mut *tables)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
|
pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
|
||||||
|
@ -526,6 +526,7 @@ impl<'tcx> Stable<'tcx> for mir::UnOp {
|
|||||||
match self {
|
match self {
|
||||||
UnOp::Not => stable_mir::mir::UnOp::Not,
|
UnOp::Not => stable_mir::mir::UnOp::Not,
|
||||||
UnOp::Neg => stable_mir::mir::UnOp::Neg,
|
UnOp::Neg => stable_mir::mir::UnOp::Neg,
|
||||||
|
UnOp::PtrMetadata => stable_mir::mir::UnOp::PtrMetadata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1179,6 +1179,7 @@ symbols! {
|
|||||||
mir_make_place,
|
mir_make_place,
|
||||||
mir_move,
|
mir_move,
|
||||||
mir_offset,
|
mir_offset,
|
||||||
|
mir_ptr_metadata,
|
||||||
mir_retag,
|
mir_retag,
|
||||||
mir_return,
|
mir_return,
|
||||||
mir_return_to,
|
mir_return_to,
|
||||||
@ -1433,6 +1434,7 @@ symbols! {
|
|||||||
ptr_guaranteed_cmp,
|
ptr_guaranteed_cmp,
|
||||||
ptr_is_null,
|
ptr_is_null,
|
||||||
ptr_mask,
|
ptr_mask,
|
||||||
|
ptr_metadata,
|
||||||
ptr_null,
|
ptr_null,
|
||||||
ptr_null_mut,
|
ptr_null_mut,
|
||||||
ptr_offset_from,
|
ptr_offset_from,
|
||||||
|
@ -363,7 +363,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
|||||||
for (&orig, response) in iter::zip(original_values, var_values.var_values) {
|
for (&orig, response) in iter::zip(original_values, var_values.var_values) {
|
||||||
let InferOk { value: (), obligations } = infcx
|
let InferOk { value: (), obligations } = infcx
|
||||||
.at(&cause, param_env)
|
.at(&cause, param_env)
|
||||||
.trace(orig, response)
|
|
||||||
.eq_structurally_relating_aliases(orig, response)
|
.eq_structurally_relating_aliases(orig, response)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(obligations.is_empty());
|
assert!(obligations.is_empty());
|
||||||
|
@ -776,7 +776,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
|||||||
let InferOk { value: (), obligations } = self
|
let InferOk { value: (), obligations } = self
|
||||||
.infcx
|
.infcx
|
||||||
.at(&ObligationCause::dummy(), param_env)
|
.at(&ObligationCause::dummy(), param_env)
|
||||||
.trace(term, ctor_term)
|
|
||||||
.eq_structurally_relating_aliases(term, ctor_term)?;
|
.eq_structurally_relating_aliases(term, ctor_term)?;
|
||||||
debug_assert!(obligations.is_empty());
|
debug_assert!(obligations.is_empty());
|
||||||
self.relate(param_env, alias, variance, rigid_ctor)
|
self.relate(param_env, alias, variance, rigid_ctor)
|
||||||
@ -796,11 +795,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
|||||||
rhs: T,
|
rhs: T,
|
||||||
) -> Result<(), NoSolution> {
|
) -> Result<(), NoSolution> {
|
||||||
let cause = ObligationCause::dummy();
|
let cause = ObligationCause::dummy();
|
||||||
let InferOk { value: (), obligations } = self
|
let InferOk { value: (), obligations } =
|
||||||
.infcx
|
self.infcx.at(&cause, param_env).eq_structurally_relating_aliases(lhs, rhs)?;
|
||||||
.at(&cause, param_env)
|
|
||||||
.trace(lhs, rhs)
|
|
||||||
.eq_structurally_relating_aliases(lhs, rhs)?;
|
|
||||||
assert!(obligations.is_empty());
|
assert!(obligations.is_empty());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -566,10 +566,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
if let Ok(new_obligations) = infcx
|
if let Ok(new_obligations) = infcx
|
||||||
.at(&obligation.cause, obligation.param_env)
|
.at(&obligation.cause, obligation.param_env)
|
||||||
.trace(c1, c2)
|
|
||||||
// Can define opaque types as this is only reachable with
|
// Can define opaque types as this is only reachable with
|
||||||
// `generic_const_exprs`
|
// `generic_const_exprs`
|
||||||
.eq(DefineOpaqueTypes::Yes, a.args, b.args)
|
.eq(
|
||||||
|
DefineOpaqueTypes::Yes,
|
||||||
|
ty::AliasTerm::from(a),
|
||||||
|
ty::AliasTerm::from(b),
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return ProcessResult::Changed(mk_pending(
|
return ProcessResult::Changed(mk_pending(
|
||||||
new_obligations.into_obligations(),
|
new_obligations.into_obligations(),
|
||||||
|
@ -910,10 +910,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
if let Ok(InferOk { obligations, value: () }) = self
|
if let Ok(InferOk { obligations, value: () }) = self
|
||||||
.infcx
|
.infcx
|
||||||
.at(&obligation.cause, obligation.param_env)
|
.at(&obligation.cause, obligation.param_env)
|
||||||
.trace(c1, c2)
|
|
||||||
// Can define opaque types as this is only reachable with
|
// Can define opaque types as this is only reachable with
|
||||||
// `generic_const_exprs`
|
// `generic_const_exprs`
|
||||||
.eq(DefineOpaqueTypes::Yes, a.args, b.args)
|
.eq(
|
||||||
|
DefineOpaqueTypes::Yes,
|
||||||
|
ty::AliasTerm::from(a),
|
||||||
|
ty::AliasTerm::from(b),
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return self.evaluate_predicates_recursively(
|
return self.evaluate_predicates_recursively(
|
||||||
previous_stack,
|
previous_stack,
|
||||||
|
@ -94,7 +94,7 @@ fn check_binop(op: mir::BinOp) -> bool {
|
|||||||
fn check_unop(op: mir::UnOp) -> bool {
|
fn check_unop(op: mir::UnOp) -> bool {
|
||||||
use mir::UnOp::*;
|
use mir::UnOp::*;
|
||||||
match op {
|
match op {
|
||||||
Not | Neg => true,
|
Not | Neg | PtrMetadata => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use std::cell::Cell;
|
|||||||
use crate::abi::{FnAbi, Layout, LayoutShape};
|
use crate::abi::{FnAbi, Layout, LayoutShape};
|
||||||
use crate::mir::alloc::{AllocId, GlobalAlloc};
|
use crate::mir::alloc::{AllocId, GlobalAlloc};
|
||||||
use crate::mir::mono::{Instance, InstanceDef, StaticDef};
|
use crate::mir::mono::{Instance, InstanceDef, StaticDef};
|
||||||
use crate::mir::{BinOp, Body, Place};
|
use crate::mir::{BinOp, Body, Place, UnOp};
|
||||||
use crate::target::MachineInfo;
|
use crate::target::MachineInfo;
|
||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
||||||
@ -226,6 +226,9 @@ pub trait Context {
|
|||||||
|
|
||||||
/// Get the resulting type of binary operation.
|
/// Get the resulting type of binary operation.
|
||||||
fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty;
|
fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty;
|
||||||
|
|
||||||
|
/// Get the resulting type of unary operation.
|
||||||
|
fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
|
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
|
||||||
|
@ -346,6 +346,15 @@ impl BinOp {
|
|||||||
pub enum UnOp {
|
pub enum UnOp {
|
||||||
Not,
|
Not,
|
||||||
Neg,
|
Neg,
|
||||||
|
PtrMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnOp {
|
||||||
|
/// Return the type of this operation for the given input Ty.
|
||||||
|
/// This function does not perform type checking, and it currently doesn't handle SIMD.
|
||||||
|
pub fn ty(&self, arg_ty: Ty) -> Ty {
|
||||||
|
with(|ctx| ctx.unop_ty(*self, arg_ty))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@ -580,7 +589,10 @@ impl Rvalue {
|
|||||||
let ty = op.ty(lhs_ty, rhs_ty);
|
let ty = op.ty(lhs_ty, rhs_ty);
|
||||||
Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
|
Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
|
||||||
}
|
}
|
||||||
Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => operand.ty(locals),
|
Rvalue::UnaryOp(op, operand) => {
|
||||||
|
let arg_ty = operand.ty(locals)?;
|
||||||
|
Ok(op.ty(arg_ty))
|
||||||
|
}
|
||||||
Rvalue::Discriminant(place) => {
|
Rvalue::Discriminant(place) => {
|
||||||
let place_ty = place.ty(locals)?;
|
let place_ty = place.ty(locals)?;
|
||||||
place_ty
|
place_ty
|
||||||
|
@ -2821,6 +2821,21 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
|
|||||||
type Metadata = <P as ptr::Pointee>::Metadata;
|
type Metadata = <P as ptr::Pointee>::Metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lowers in MIR to `Rvalue::UnaryOp` with `UnOp::PtrMetadata`.
|
||||||
|
///
|
||||||
|
/// This is used to implement functions like `ptr::metadata`.
|
||||||
|
#[rustc_nounwind]
|
||||||
|
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||||
|
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M {
|
||||||
|
// To implement a fallback we'd have to assume the layout of the pointer,
|
||||||
|
// but the whole point of this intrinsic is that we shouldn't do that.
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
// Some functions are defined here because they accidentally got made
|
// Some functions are defined here because they accidentally got made
|
||||||
// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
|
// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
|
||||||
// (`transmute` also falls into this category, but it cannot be wrapped due to the
|
// (`transmute` also falls into this category, but it cannot be wrapped due to the
|
||||||
|
@ -360,6 +360,10 @@ define!("mir_assume", fn Assume(operand: bool));
|
|||||||
define!("mir_deinit", fn Deinit<T>(place: T));
|
define!("mir_deinit", fn Deinit<T>(place: T));
|
||||||
define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
|
define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
|
||||||
define!("mir_len", fn Len<T>(place: T) -> usize);
|
define!("mir_len", fn Len<T>(place: T) -> usize);
|
||||||
|
define!(
|
||||||
|
"mir_ptr_metadata",
|
||||||
|
fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata
|
||||||
|
);
|
||||||
define!("mir_copy_for_deref", fn CopyForDeref<T>(place: T) -> T);
|
define!("mir_copy_for_deref", fn CopyForDeref<T>(place: T) -> T);
|
||||||
define!("mir_retag", fn Retag<T>(place: T));
|
define!("mir_retag", fn Retag<T>(place: T));
|
||||||
define!("mir_move", fn Move<T>(place: T) -> T);
|
define!("mir_move", fn Move<T>(place: T) -> T);
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::hash::{Hash, Hasher};
|
use crate::hash::{Hash, Hasher};
|
||||||
use crate::intrinsics::aggregate_raw_ptr;
|
use crate::intrinsics::aggregate_raw_ptr;
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
use crate::intrinsics::ptr_metadata;
|
||||||
use crate::marker::Freeze;
|
use crate::marker::Freeze;
|
||||||
|
|
||||||
/// Provides the pointer metadata type of any pointed-to type.
|
/// Provides the pointer metadata type of any pointed-to type.
|
||||||
@ -94,10 +96,17 @@ pub trait Thin = Pointee<Metadata = ()>;
|
|||||||
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
|
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
|
pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
|
||||||
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
|
#[cfg(bootstrap)]
|
||||||
// and PtrComponents<T> have the same memory layouts. Only std can make this
|
{
|
||||||
// guarantee.
|
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
|
||||||
unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
|
// and PtrComponents<T> have the same memory layouts. Only std can make this
|
||||||
|
// guarantee.
|
||||||
|
unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
|
||||||
|
}
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
{
|
||||||
|
ptr_metadata(ptr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forms a (possibly-wide) raw pointer from a data pointer and metadata.
|
/// Forms a (possibly-wide) raw pointer from a data pointer and metadata.
|
||||||
@ -132,6 +141,7 @@ pub const fn from_raw_parts_mut<T: ?Sized>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
#[cfg(bootstrap)]
|
||||||
union PtrRepr<T: ?Sized> {
|
union PtrRepr<T: ?Sized> {
|
||||||
const_ptr: *const T,
|
const_ptr: *const T,
|
||||||
mut_ptr: *mut T,
|
mut_ptr: *mut T,
|
||||||
@ -139,15 +149,18 @@ union PtrRepr<T: ?Sized> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
#[cfg(bootstrap)]
|
||||||
struct PtrComponents<T: ?Sized> {
|
struct PtrComponents<T: ?Sized> {
|
||||||
data_pointer: *const (),
|
data_pointer: *const (),
|
||||||
metadata: <T as Pointee>::Metadata,
|
metadata: <T as Pointee>::Metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manual impl needed to avoid `T: Copy` bound.
|
// Manual impl needed to avoid `T: Copy` bound.
|
||||||
|
#[cfg(bootstrap)]
|
||||||
impl<T: ?Sized> Copy for PtrComponents<T> {}
|
impl<T: ?Sized> Copy for PtrComponents<T> {}
|
||||||
|
|
||||||
// Manual impl needed to avoid `T: Clone` bound.
|
// Manual impl needed to avoid `T: Clone` bound.
|
||||||
|
#[cfg(bootstrap)]
|
||||||
impl<T: ?Sized> Clone for PtrComponents<T> {
|
impl<T: ?Sized> Clone for PtrComponents<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
*self
|
*self
|
||||||
|
@ -1171,3 +1171,15 @@ fn test_ptr_from_raw_parts_in_const() {
|
|||||||
assert_eq!(EMPTY_SLICE_PTR.addr(), 123);
|
assert_eq!(EMPTY_SLICE_PTR.addr(), 123);
|
||||||
assert_eq!(EMPTY_SLICE_PTR.len(), 456);
|
assert_eq!(EMPTY_SLICE_PTR.len(), 456);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ptr_metadata_in_const() {
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
const ARRAY_META: () = std::ptr::metadata::<[u16; 3]>(&[1, 2, 3]);
|
||||||
|
const SLICE_META: usize = std::ptr::metadata::<[u16]>(&[1, 2, 3]);
|
||||||
|
const DYN_META: DynMetadata<dyn Debug> = std::ptr::metadata::<dyn Debug>(&[0_u8; 42]);
|
||||||
|
assert_eq!(ARRAY_META, ());
|
||||||
|
assert_eq!(SLICE_META, 3);
|
||||||
|
assert_eq!(DYN_META.size_of(), 42);
|
||||||
|
}
|
||||||
|
@ -1431,7 +1431,7 @@ fn metadata_access_times() {
|
|||||||
assert_eq!(check!(a.modified()), check!(a.modified()));
|
assert_eq!(check!(a.modified()), check!(a.modified()));
|
||||||
assert_eq!(check!(b.accessed()), check!(b.modified()));
|
assert_eq!(check!(b.accessed()), check!(b.modified()));
|
||||||
|
|
||||||
if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
|
if cfg!(target_vendor = "apple") || cfg!(target_os = "windows") {
|
||||||
check!(a.created());
|
check!(a.created());
|
||||||
check!(b.created());
|
check!(b.created());
|
||||||
}
|
}
|
||||||
|
@ -491,6 +491,14 @@ mod imp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is intentionally not enabled on iOS/tvOS/watchOS/visionOS, as it uses
|
||||||
|
// several symbols that might lead to rejections from the App Store, namely
|
||||||
|
// `sigaction`, `sigaltstack`, `sysctlbyname`, `mmap`, `munmap` and `mprotect`.
|
||||||
|
//
|
||||||
|
// This might be overly cautious, though it is also what Swift does (and they
|
||||||
|
// usually have fewer qualms about forwards compatibility, since the runtime
|
||||||
|
// is shipped with the OS):
|
||||||
|
// <https://github.com/apple/swift/blob/swift-5.10-RELEASE/stdlib/public/runtime/CrashHandlerMacOS.cpp>
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
target_os = "linux",
|
target_os = "linux",
|
||||||
target_os = "freebsd",
|
target_os = "freebsd",
|
||||||
|
@ -1028,6 +1028,14 @@ tool_doc!(
|
|||||||
is_library = true,
|
is_library = true,
|
||||||
crates = ["bootstrap"]
|
crates = ["bootstrap"]
|
||||||
);
|
);
|
||||||
|
tool_doc!(
|
||||||
|
RunMakeSupport,
|
||||||
|
"run_make_support",
|
||||||
|
"src/tools/run-make-support",
|
||||||
|
rustc_tool = false,
|
||||||
|
is_library = true,
|
||||||
|
crates = ["run_make_support"]
|
||||||
|
);
|
||||||
|
|
||||||
#[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)]
|
#[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct ErrorIndex {
|
pub struct ErrorIndex {
|
||||||
|
@ -888,6 +888,7 @@ impl<'a> Builder<'a> {
|
|||||||
doc::Tidy,
|
doc::Tidy,
|
||||||
doc::Bootstrap,
|
doc::Bootstrap,
|
||||||
doc::Releases,
|
doc::Releases,
|
||||||
|
doc::RunMakeSupport,
|
||||||
),
|
),
|
||||||
Kind::Dist => describe!(
|
Kind::Dist => describe!(
|
||||||
dist::Docs,
|
dist::Docs,
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
pub fn dylib_path_var() -> &'static str {
|
pub fn dylib_path_var() -> &'static str {
|
||||||
if cfg!(target_os = "windows") {
|
if cfg!(target_os = "windows") {
|
||||||
"PATH"
|
"PATH"
|
||||||
} else if cfg!(target_os = "macos") {
|
} else if cfg!(target_vendor = "apple") {
|
||||||
"DYLD_LIBRARY_PATH"
|
"DYLD_LIBRARY_PATH"
|
||||||
} else if cfg!(target_os = "haiku") {
|
} else if cfg!(target_os = "haiku") {
|
||||||
"LIBRARY_PATH"
|
"LIBRARY_PATH"
|
||||||
|
25
src/doc/unstable-book/src/compiler-flags/print-check-cfg.md
Normal file
25
src/doc/unstable-book/src/compiler-flags/print-check-cfg.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# `print=check-cfg`
|
||||||
|
|
||||||
|
The tracking issue for this feature is: [#XXXXXX](https://github.com/rust-lang/rust/issues/XXXXXX).
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
This option of the `--print` flag print the list of expected cfgs.
|
||||||
|
|
||||||
|
This is related to the `--check-cfg` flag which allows specifying arbitrary expected
|
||||||
|
names and values.
|
||||||
|
|
||||||
|
This print option works similarly to `--print=cfg` (modulo check-cfg specifics):
|
||||||
|
- *check_cfg syntax*: *output of --print=check-cfg*
|
||||||
|
- `cfg(windows)`: `windows`
|
||||||
|
- `cfg(feature, values("foo", "bar"))`: `feature="foo"` and `feature="bar"`
|
||||||
|
- `cfg(feature, values(none(), ""))`: `feature` and `feature=""`
|
||||||
|
- `cfg(feature, values(any()))`: `feature=any()`
|
||||||
|
- `cfg(any())`: `any()`
|
||||||
|
- *nothing*: `any()=any()`
|
||||||
|
|
||||||
|
To be used like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rustc --print=check-cfg -Zunstable-options lib.rs
|
||||||
|
```
|
@ -747,6 +747,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
|||||||
"ignore-aarch64",
|
"ignore-aarch64",
|
||||||
"ignore-aarch64-unknown-linux-gnu",
|
"ignore-aarch64-unknown-linux-gnu",
|
||||||
"ignore-android",
|
"ignore-android",
|
||||||
|
"ignore-apple",
|
||||||
"ignore-arm",
|
"ignore-arm",
|
||||||
"ignore-avr",
|
"ignore-avr",
|
||||||
"ignore-beta",
|
"ignore-beta",
|
||||||
@ -829,7 +830,6 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
|||||||
"ignore-x32",
|
"ignore-x32",
|
||||||
"ignore-x86",
|
"ignore-x86",
|
||||||
"ignore-x86_64",
|
"ignore-x86_64",
|
||||||
"ignore-x86_64-apple-darwin",
|
|
||||||
"ignore-x86_64-unknown-linux-gnu",
|
"ignore-x86_64-unknown-linux-gnu",
|
||||||
"incremental",
|
"incremental",
|
||||||
"known-bug",
|
"known-bug",
|
||||||
@ -876,6 +876,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
|||||||
"only-32bit",
|
"only-32bit",
|
||||||
"only-64bit",
|
"only-64bit",
|
||||||
"only-aarch64",
|
"only-aarch64",
|
||||||
|
"only-apple",
|
||||||
"only-arm",
|
"only-arm",
|
||||||
"only-avr",
|
"only-avr",
|
||||||
"only-beta",
|
"only-beta",
|
||||||
|
@ -159,6 +159,12 @@ pub(super) fn parse_cfg_name_directive<'a>(
|
|||||||
message: "when the architecture is part of the Thumb family"
|
message: "when the architecture is part of the Thumb family"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
condition! {
|
||||||
|
name: "apple",
|
||||||
|
condition: config.target.contains("apple"),
|
||||||
|
message: "when the target vendor is Apple"
|
||||||
|
}
|
||||||
|
|
||||||
// Technically the locally built compiler uses the "dev" channel rather than the "nightly"
|
// Technically the locally built compiler uses the "dev" channel rather than the "nightly"
|
||||||
// channel, even though most people don't know or won't care about it. To avoid confusion, we
|
// channel, even though most people don't know or won't care about it. To avoid confusion, we
|
||||||
// treat the "dev" channel as the "nightly" channel when processing the directive.
|
// treat the "dev" channel as the "nightly" channel when processing the directive.
|
||||||
|
@ -98,7 +98,7 @@ fn get_lib_name(lib: &str, aux_type: AuxType) -> Option<String> {
|
|||||||
AuxType::Lib => Some(format!("lib{}.rlib", lib)),
|
AuxType::Lib => Some(format!("lib{}.rlib", lib)),
|
||||||
AuxType::Dylib => Some(if cfg!(windows) {
|
AuxType::Dylib => Some(if cfg!(windows) {
|
||||||
format!("{}.dll", lib)
|
format!("{}.dll", lib)
|
||||||
} else if cfg!(target_os = "macos") {
|
} else if cfg!(target_vendor = "apple") {
|
||||||
format!("lib{}.dylib", lib)
|
format!("lib{}.dylib", lib)
|
||||||
} else {
|
} else {
|
||||||
format!("lib{}.so", lib)
|
format!("lib{}.so", lib)
|
||||||
|
@ -57,7 +57,7 @@ impl PathBufExt for PathBuf {
|
|||||||
pub fn dylib_env_var() -> &'static str {
|
pub fn dylib_env_var() -> &'static str {
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
"PATH"
|
"PATH"
|
||||||
} else if cfg!(target_os = "macos") {
|
} else if cfg!(target_vendor = "apple") {
|
||||||
"DYLD_LIBRARY_PATH"
|
"DYLD_LIBRARY_PATH"
|
||||||
} else if cfg!(target_os = "haiku") {
|
} else if cfg!(target_os = "haiku") {
|
||||||
"LIBRARY_PATH"
|
"LIBRARY_PATH"
|
||||||
|
@ -862,14 +862,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
if tcx.is_foreign_item(def_id) {
|
if tcx.is_foreign_item(def_id) {
|
||||||
throw_unsup_format!("foreign thread-local statics are not supported");
|
throw_unsup_format!("foreign thread-local statics are not supported");
|
||||||
}
|
}
|
||||||
let allocation = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
let alloc = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
||||||
let mut allocation = allocation.inner().clone();
|
// We make a full copy of this allocation.
|
||||||
|
let mut alloc = alloc.inner().adjust_from_tcx(&this.tcx, |ptr| this.global_root_pointer(ptr))?;
|
||||||
// This allocation will be deallocated when the thread dies, so it is not in read-only memory.
|
// This allocation will be deallocated when the thread dies, so it is not in read-only memory.
|
||||||
allocation.mutability = Mutability::Mut;
|
alloc.mutability = Mutability::Mut;
|
||||||
// Create a fresh allocation with this content.
|
// Create a fresh allocation with this content.
|
||||||
let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into())?;
|
let ptr = this.allocate_raw_ptr(alloc, MiriMemoryKind::Tls.into())?;
|
||||||
this.machine.threads.set_thread_local_alloc(def_id, new_alloc);
|
this.machine.threads.set_thread_local_alloc(def_id, ptr);
|
||||||
Ok(new_alloc)
|
Ok(ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
//! Global machine state as well as implementation of the interpreter engine
|
//! Global machine state as well as implementation of the interpreter engine
|
||||||
//! `Machine` trait.
|
//! `Machine` trait.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -1086,40 +1085,33 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adjust_allocation<'b>(
|
fn init_alloc_extra(
|
||||||
ecx: &MiriInterpCx<'tcx>,
|
ecx: &MiriInterpCx<'tcx>,
|
||||||
id: AllocId,
|
id: AllocId,
|
||||||
alloc: Cow<'b, Allocation>,
|
kind: MemoryKind,
|
||||||
kind: Option<MemoryKind>,
|
size: Size,
|
||||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
|
align: Align,
|
||||||
{
|
) -> InterpResult<'tcx, Self::AllocExtra> {
|
||||||
let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
|
|
||||||
if ecx.machine.tracked_alloc_ids.contains(&id) {
|
if ecx.machine.tracked_alloc_ids.contains(&id) {
|
||||||
ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(
|
ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id, size, align, kind));
|
||||||
id,
|
|
||||||
alloc.size(),
|
|
||||||
alloc.align,
|
|
||||||
kind,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let alloc = alloc.into_owned();
|
|
||||||
let borrow_tracker = ecx
|
let borrow_tracker = ecx
|
||||||
.machine
|
.machine
|
||||||
.borrow_tracker
|
.borrow_tracker
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|bt| bt.borrow_mut().new_allocation(id, alloc.size(), kind, &ecx.machine));
|
.map(|bt| bt.borrow_mut().new_allocation(id, size, kind, &ecx.machine));
|
||||||
|
|
||||||
let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| {
|
let data_race = ecx.machine.data_race.as_ref().map(|data_race| {
|
||||||
data_race::AllocState::new_allocation(
|
data_race::AllocState::new_allocation(
|
||||||
data_race,
|
data_race,
|
||||||
&ecx.machine.threads,
|
&ecx.machine.threads,
|
||||||
alloc.size(),
|
size,
|
||||||
kind,
|
kind,
|
||||||
ecx.machine.current_span(),
|
ecx.machine.current_span(),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let buffer_alloc = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation);
|
let weak_memory = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation);
|
||||||
|
|
||||||
// If an allocation is leaked, we want to report a backtrace to indicate where it was
|
// If an allocation is leaked, we want to report a backtrace to indicate where it was
|
||||||
// allocated. We don't need to record a backtrace for allocations which are allowed to
|
// allocated. We don't need to record a backtrace for allocations which are allowed to
|
||||||
@ -1130,17 +1122,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||||||
Some(ecx.generate_stacktrace())
|
Some(ecx.generate_stacktrace())
|
||||||
};
|
};
|
||||||
|
|
||||||
let alloc: Allocation<Provenance, Self::AllocExtra, Self::Bytes> = alloc.adjust_from_tcx(
|
|
||||||
&ecx.tcx,
|
|
||||||
AllocExtra {
|
|
||||||
borrow_tracker,
|
|
||||||
data_race: race_alloc,
|
|
||||||
weak_memory: buffer_alloc,
|
|
||||||
backtrace,
|
|
||||||
},
|
|
||||||
|ptr| ecx.global_root_pointer(ptr),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if matches!(kind, MemoryKind::Machine(kind) if kind.should_save_allocation_span()) {
|
if matches!(kind, MemoryKind::Machine(kind) if kind.should_save_allocation_span()) {
|
||||||
ecx.machine
|
ecx.machine
|
||||||
.allocation_spans
|
.allocation_spans
|
||||||
@ -1148,7 +1129,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||||||
.insert(id, (ecx.machine.current_span(), None));
|
.insert(id, (ecx.machine.current_span(), None));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Cow::Owned(alloc))
|
Ok(AllocExtra { borrow_tracker, data_race, weak_memory, backtrace })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adjust_alloc_root_pointer(
|
fn adjust_alloc_root_pointer(
|
||||||
@ -1357,7 +1338,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn init_frame_extra(
|
fn init_frame(
|
||||||
ecx: &mut InterpCx<'tcx, Self>,
|
ecx: &mut InterpCx<'tcx, Self>,
|
||||||
frame: Frame<'tcx, Provenance>,
|
frame: Frame<'tcx, Provenance>,
|
||||||
) -> InterpResult<'tcx, Frame<'tcx, Provenance, FrameExtra<'tcx>>> {
|
) -> InterpResult<'tcx, Frame<'tcx, Provenance, FrameExtra<'tcx>>> {
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
//@compile-flags: -Zmiri-disable-validation
|
||||||
|
#![feature(core_intrinsics, custom_mir)]
|
||||||
|
use std::intrinsics::mir::*;
|
||||||
|
|
||||||
|
// This disables validation and uses custom MIR hit exactly the UB in the intrinsic,
|
||||||
|
// rather than getting UB from the typed load or parameter passing.
|
||||||
|
|
||||||
|
#[custom_mir(dialect = "runtime")]
|
||||||
|
pub unsafe fn deref_meta(p: *const *const [i32]) -> usize {
|
||||||
|
mir!({
|
||||||
|
RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
|
||||||
|
Return()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut p = std::mem::MaybeUninit::<*const [i32]>::uninit();
|
||||||
|
unsafe {
|
||||||
|
(*p.as_mut_ptr().cast::<[usize; 2]>())[1] = 4;
|
||||||
|
let _meta = deref_meta(p.as_ptr().cast());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
|
||||||
|
--> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | RET = PtrMetadata(*p);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
||||||
|
|
|
||||||
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||||
|
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||||
|
= note: BACKTRACE:
|
||||||
|
= note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC
|
||||||
|
note: inside `main`
|
||||||
|
--> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | let _meta = deref_meta(p.as_ptr().cast());
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
@ -0,0 +1,22 @@
|
|||||||
|
//@compile-flags: -Zmiri-disable-validation
|
||||||
|
#![feature(core_intrinsics, custom_mir)]
|
||||||
|
use std::intrinsics::mir::*;
|
||||||
|
|
||||||
|
// This disables validation and uses custom MIR hit exactly the UB in the intrinsic,
|
||||||
|
// rather than getting UB from the typed load or parameter passing.
|
||||||
|
|
||||||
|
#[custom_mir(dialect = "runtime")]
|
||||||
|
pub unsafe fn deref_meta(p: *const *const [i32]) -> usize {
|
||||||
|
mir!({
|
||||||
|
RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
|
||||||
|
Return()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut p = std::mem::MaybeUninit::<*const [i32]>::uninit();
|
||||||
|
unsafe {
|
||||||
|
(*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32;
|
||||||
|
let _meta = deref_meta(p.as_ptr().cast());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
warning: integer-to-pointer cast
|
||||||
|
--> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
||||||
|
|
|
||||||
|
= help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
|
||||||
|
= help: which means that Miri might miss pointer bugs in this program.
|
||||||
|
= help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
|
||||||
|
= help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
|
||||||
|
= help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
|
||||||
|
= help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
|
||||||
|
= note: BACKTRACE:
|
||||||
|
= note: inside `main` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
|
||||||
|
|
||||||
|
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
|
||||||
|
--> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | RET = PtrMetadata(*p);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
||||||
|
|
|
||||||
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||||
|
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||||
|
= note: BACKTRACE:
|
||||||
|
= note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
|
||||||
|
note: inside `main`
|
||||||
|
--> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | let _meta = deref_meta(p.as_ptr().cast());
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error; 1 warning emitted
|
||||||
|
|
@ -0,0 +1,23 @@
|
|||||||
|
//@compile-flags: -Zmiri-disable-validation
|
||||||
|
#![feature(core_intrinsics, custom_mir)]
|
||||||
|
use std::intrinsics::mir::*;
|
||||||
|
|
||||||
|
// This disables validation and uses custom MIR hit exactly the UB in the intrinsic,
|
||||||
|
// rather than getting UB from the typed load or parameter passing.
|
||||||
|
|
||||||
|
#[custom_mir(dialect = "runtime")]
|
||||||
|
pub unsafe fn deref_meta(p: *const *const i32) -> () {
|
||||||
|
mir!({
|
||||||
|
RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
|
||||||
|
Return()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Even though the meta is the trivially-valid `()`, this is still UB
|
||||||
|
|
||||||
|
let p = std::mem::MaybeUninit::<*const i32>::uninit();
|
||||||
|
unsafe {
|
||||||
|
let _meta = deref_meta(p.as_ptr());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
|
||||||
|
--> $DIR/ptr_metadata_uninit_thin.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | RET = PtrMetadata(*p);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
||||||
|
|
|
||||||
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||||
|
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||||
|
= note: BACKTRACE:
|
||||||
|
= note: inside `deref_meta` at $DIR/ptr_metadata_uninit_thin.rs:LL:CC
|
||||||
|
note: inside `main`
|
||||||
|
--> $DIR/ptr_metadata_uninit_thin.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | let _meta = deref_meta(p.as_ptr());
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
//@compile-flags: -Zmiri-permissive-provenance
|
//@compile-flags: -Zmiri-permissive-provenance
|
||||||
#![feature(core_intrinsics, layout_for_ptr)]
|
#![feature(core_intrinsics, layout_for_ptr, ptr_metadata)]
|
||||||
//! Tests for various intrinsics that do not fit anywhere else.
|
//! Tests for various intrinsics that do not fit anywhere else.
|
||||||
|
|
||||||
use std::intrinsics;
|
use std::intrinsics;
|
||||||
@ -57,4 +57,10 @@ fn main() {
|
|||||||
// Make sure that even if the discriminant is stored together with data, the intrinsic returns
|
// Make sure that even if the discriminant is stored together with data, the intrinsic returns
|
||||||
// only the discriminant, nothing about the data.
|
// only the discriminant, nothing about the data.
|
||||||
assert_eq!(discriminant(&Some(false)), discriminant(&Some(true)));
|
assert_eq!(discriminant(&Some(false)), discriminant(&Some(true)));
|
||||||
|
|
||||||
|
let () = intrinsics::ptr_metadata(&[1, 2, 3]);
|
||||||
|
let len = intrinsics::ptr_metadata(&[1, 2, 3][..]);
|
||||||
|
assert_eq!(len, 3);
|
||||||
|
let dyn_meta = intrinsics::ptr_metadata(&[1, 2, 3] as &dyn std::fmt::Debug);
|
||||||
|
assert_eq!(dyn_meta.size_of(), 12);
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ macro_rules! impl_common_helpers {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inspect what the underlying [`Command`][::std::process::Command] is up to the
|
/// Inspect what the underlying [`Command`] is up to the
|
||||||
/// current construction.
|
/// current construction.
|
||||||
pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
|
pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
|
||||||
where
|
where
|
||||||
|
@ -203,7 +203,7 @@ impl Rustc {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the [`Output`][::std::process::Output] of the finished process.
|
/// Get the [`Output`] of the finished process.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn command_output(&mut self) -> ::std::process::Output {
|
pub fn command_output(&mut self) -> ::std::process::Output {
|
||||||
// let's make sure we piped all the input and outputs
|
// let's make sure we piped all the input and outputs
|
||||||
|
@ -94,7 +94,7 @@ impl Rustdoc {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the [`Output`][::std::process::Output] of the finished process.
|
/// Get the [`Output`] of the finished process.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn command_output(&mut self) -> ::std::process::Output {
|
pub fn command_output(&mut self) -> ::std::process::Output {
|
||||||
// let's make sure we piped all the input and outputs
|
// let's make sure we piped all the input and outputs
|
||||||
|
@ -144,7 +144,6 @@ run-make/lto-linkage-used-attr/Makefile
|
|||||||
run-make/lto-no-link-whole-rlib/Makefile
|
run-make/lto-no-link-whole-rlib/Makefile
|
||||||
run-make/lto-readonly-lib/Makefile
|
run-make/lto-readonly-lib/Makefile
|
||||||
run-make/lto-smoke-c/Makefile
|
run-make/lto-smoke-c/Makefile
|
||||||
run-make/lto-smoke/Makefile
|
|
||||||
run-make/macos-deployment-target/Makefile
|
run-make/macos-deployment-target/Makefile
|
||||||
run-make/macos-fat-archive/Makefile
|
run-make/macos-fat-archive/Makefile
|
||||||
run-make/manual-crate-name/Makefile
|
run-make/manual-crate-name/Makefile
|
||||||
@ -156,7 +155,6 @@ run-make/min-global-align/Makefile
|
|||||||
run-make/mingw-export-call-convention/Makefile
|
run-make/mingw-export-call-convention/Makefile
|
||||||
run-make/mismatching-target-triples/Makefile
|
run-make/mismatching-target-triples/Makefile
|
||||||
run-make/missing-crate-dependency/Makefile
|
run-make/missing-crate-dependency/Makefile
|
||||||
run-make/mixing-deps/Makefile
|
|
||||||
run-make/mixing-formats/Makefile
|
run-make/mixing-formats/Makefile
|
||||||
run-make/mixing-libs/Makefile
|
run-make/mixing-libs/Makefile
|
||||||
run-make/msvc-opt-minsize/Makefile
|
run-make/msvc-opt-minsize/Makefile
|
||||||
@ -238,7 +236,6 @@ run-make/short-ice/Makefile
|
|||||||
run-make/silly-file-names/Makefile
|
run-make/silly-file-names/Makefile
|
||||||
run-make/simd-ffi/Makefile
|
run-make/simd-ffi/Makefile
|
||||||
run-make/simple-dylib/Makefile
|
run-make/simple-dylib/Makefile
|
||||||
run-make/simple-rlib/Makefile
|
|
||||||
run-make/split-debuginfo/Makefile
|
run-make/split-debuginfo/Makefile
|
||||||
run-make/stable-symbol-names/Makefile
|
run-make/stable-symbol-names/Makefile
|
||||||
run-make/static-dylib-by-default/Makefile
|
run-make/static-dylib-by-default/Makefile
|
||||||
|
@ -2122,7 +2122,6 @@ ui/issues/issue-33687.rs
|
|||||||
ui/issues/issue-33770.rs
|
ui/issues/issue-33770.rs
|
||||||
ui/issues/issue-3389.rs
|
ui/issues/issue-3389.rs
|
||||||
ui/issues/issue-33941.rs
|
ui/issues/issue-33941.rs
|
||||||
ui/issues/issue-33992.rs
|
|
||||||
ui/issues/issue-34047.rs
|
ui/issues/issue-34047.rs
|
||||||
ui/issues/issue-34074.rs
|
ui/issues/issue-34074.rs
|
||||||
ui/issues/issue-34209.rs
|
ui/issues/issue-34209.rs
|
||||||
|
@ -15,7 +15,7 @@ use std::path::{Path, PathBuf};
|
|||||||
const ENTRY_LIMIT: u32 = 900;
|
const ENTRY_LIMIT: u32 = 900;
|
||||||
// FIXME: The following limits should be reduced eventually.
|
// FIXME: The following limits should be reduced eventually.
|
||||||
|
|
||||||
const ISSUES_ENTRY_LIMIT: u32 = 1676;
|
const ISSUES_ENTRY_LIMIT: u32 = 1674;
|
||||||
|
|
||||||
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
|
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
|
||||||
"rs", // test source files
|
"rs", // test source files
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//@ revisions: all strong basic none missing
|
//@ revisions: all strong basic none missing
|
||||||
//@ assembly-output: emit-asm
|
//@ assembly-output: emit-asm
|
||||||
//@ ignore-macos slightly different policy on stack protection of arrays
|
//@ ignore-apple slightly different policy on stack protection of arrays
|
||||||
//@ ignore-msvc stack check code uses different function names
|
//@ ignore-msvc stack check code uses different function names
|
||||||
//@ ignore-nvptx64 stack protector is not supported
|
//@ ignore-nvptx64 stack protector is not supported
|
||||||
//@ ignore-wasm32-bare
|
//@ ignore-wasm32-bare
|
||||||
@ -17,12 +17,9 @@
|
|||||||
// See comments on https://github.com/rust-lang/rust/issues/114903.
|
// See comments on https://github.com/rust-lang/rust/issues/114903.
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
#![feature(unsized_locals, unsized_fn_params)]
|
#![feature(unsized_locals, unsized_fn_params)]
|
||||||
|
|
||||||
|
|
||||||
// CHECK-LABEL: emptyfn:
|
// CHECK-LABEL: emptyfn:
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn emptyfn() {
|
pub fn emptyfn() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
|
//@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
|
||||||
//@ only-x86_64
|
//@ only-x86_64
|
||||||
//@ ignore-sgx
|
//@ ignore-sgx
|
||||||
//@ ignore-macos (manipulates rsp too)
|
//@ ignore-apple (manipulates rsp too)
|
||||||
|
|
||||||
// Depending on various codegen choices, this might end up copying
|
// Depending on various codegen choices, this might end up copying
|
||||||
// a `<2 x i8>`, an `i16`, or two `i8`s.
|
// a `<2 x i8>`, an `i16`, or two `i8`s.
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
//@ [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern
|
//@ [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern
|
||||||
//@ [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep
|
//@ [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep
|
||||||
//@ only-x86_64
|
//@ only-x86_64
|
||||||
//@ ignore-x86_64-apple-darwin Symbol is called `___x86_return_thunk` (Darwin's extra underscore)
|
//@ ignore-apple Symbol is called `___x86_return_thunk` (Darwin's extra underscore)
|
||||||
//@ ignore-sgx Tests incompatible with LVI mitigations
|
//@ ignore-sgx Tests incompatible with LVI mitigations
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//
|
//
|
||||||
//@ ignore-windows
|
//@ ignore-windows
|
||||||
//@ ignore-macos
|
//@ ignore-apple
|
||||||
//@ ignore-wasm
|
//@ ignore-wasm
|
||||||
//@ ignore-emscripten
|
//@ ignore-emscripten
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVFUN=__llvm_covfun
|
//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVFUN=__llvm_covfun
|
||||||
//@ [LINUX] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat'
|
//@ [LINUX] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat'
|
||||||
|
|
||||||
//@ [DARWIN] only-macos
|
//@ [DARWIN] only-apple
|
||||||
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_DATA=__DATA,__llvm_prf_data,regular,live_support
|
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_DATA=__DATA,__llvm_prf_data,regular,live_support
|
||||||
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_NAME=__DATA,__llvm_prf_names
|
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_NAME=__DATA,__llvm_prf_names
|
||||||
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_CNTS=__DATA,__llvm_prf_cnts
|
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_CNTS=__DATA,__llvm_prf_cnts
|
||||||
@ -49,7 +49,7 @@ where
|
|||||||
|
|
||||||
pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
|
pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(&T)
|
F: FnOnce(&T),
|
||||||
{
|
{
|
||||||
if should_wrap {
|
if should_wrap {
|
||||||
wrapper(&inner)
|
wrapper(&inner)
|
||||||
|
36
tests/codegen/intrinsics/ptr_metadata.rs
Normal file
36
tests/codegen/intrinsics/ptr_metadata.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//@ compile-flags: -O -C no-prepopulate-passes -Z inline-mir
|
||||||
|
//@ only-64bit (so I don't need to worry about usize)
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(core_intrinsics)]
|
||||||
|
|
||||||
|
use std::intrinsics::ptr_metadata;
|
||||||
|
|
||||||
|
// CHECK-LABEL: @thin_metadata(
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn thin_metadata(p: *const ()) {
|
||||||
|
// CHECK: start
|
||||||
|
// CHECK-NEXT: ret void
|
||||||
|
ptr_metadata(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @slice_metadata(
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn slice_metadata(p: *const [u8]) -> usize {
|
||||||
|
// CHECK: start
|
||||||
|
// CHECK-NEXT: ret i64 %p.1
|
||||||
|
ptr_metadata(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @dyn_byte_offset(
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn dyn_byte_offset(
|
||||||
|
p: *const dyn std::fmt::Debug,
|
||||||
|
n: usize,
|
||||||
|
) -> *const dyn std::fmt::Debug {
|
||||||
|
// CHECK: %[[Q:.+]] = getelementptr inbounds i8, ptr %p.0, i64 %n
|
||||||
|
// CHECK: %[[TEMP1:.+]] = insertvalue { ptr, ptr } poison, ptr %[[Q]], 0
|
||||||
|
// CHECK: %[[TEMP2:.+]] = insertvalue { ptr, ptr } %[[TEMP1]], ptr %p.1, 1
|
||||||
|
// CHECK: ret { ptr, ptr } %[[TEMP2]]
|
||||||
|
p.byte_add(n)
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
//@ only-macos
|
//@ only-apple
|
||||||
//@ compile-flags: -O
|
//@ compile-flags: -O
|
||||||
|
|
||||||
#![crate_type = "rlib"]
|
#![crate_type = "rlib"]
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// before 4.0, formerly backported to the Rust LLVM fork.
|
// before 4.0, formerly backported to the Rust LLVM fork.
|
||||||
|
|
||||||
//@ ignore-windows
|
//@ ignore-windows
|
||||||
//@ ignore-macos
|
//@ ignore-apple
|
||||||
//@ ignore-wasi
|
//@ ignore-wasi
|
||||||
|
|
||||||
//@ compile-flags: -g -C no-prepopulate-passes
|
//@ compile-flags: -g -C no-prepopulate-passes
|
||||||
@ -10,5 +10,4 @@
|
|||||||
// CHECK-LABEL: @main
|
// CHECK-LABEL: @main
|
||||||
// CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}}
|
// CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {}
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//@ ignore-windows
|
//@ ignore-windows
|
||||||
//@ ignore-macos
|
//@ ignore-apple
|
||||||
//@ ignore-wasi wasi codegens the main symbol differently
|
//@ ignore-wasi wasi codegens the main symbol differently
|
||||||
|
|
||||||
//@ compile-flags: -g -C no-prepopulate-passes
|
//@ compile-flags: -g -C no-prepopulate-passes
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Test that __llvm_profile_counter_bias does not get internalized by lto.
|
// Test that __llvm_profile_counter_bias does not get internalized by lto.
|
||||||
|
|
||||||
//@ ignore-macos -runtime-counter-relocation not honored on Mach-O
|
//@ ignore-apple -runtime-counter-relocation not honored on Mach-O
|
||||||
//@ compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat
|
//@ compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat
|
||||||
//@ needs-profiler-support
|
//@ needs-profiler-support
|
||||||
//@ no-prefer-dynamic
|
//@ no-prefer-dynamic
|
||||||
|
13
tests/mir-opt/building/custom/operators.g.runtime.after.mir
Normal file
13
tests/mir-opt/building/custom/operators.g.runtime.after.mir
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// MIR for `g` after runtime
|
||||||
|
|
||||||
|
fn g(_1: *const i32, _2: *const [i32]) -> () {
|
||||||
|
let mut _0: ();
|
||||||
|
let mut _3: ();
|
||||||
|
let mut _4: usize;
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
_3 = PtrMetadata(_1);
|
||||||
|
_4 = PtrMetadata(_2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
@ -30,3 +30,13 @@ pub fn f(a: i32, b: bool) -> i32 {
|
|||||||
Return()
|
Return()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EMIT_MIR operators.g.runtime.after.mir
|
||||||
|
#[custom_mir(dialect = "runtime")]
|
||||||
|
pub fn g(p: *const i32, q: *const [i32]) {
|
||||||
|
mir!({
|
||||||
|
let a = PtrMetadata(p);
|
||||||
|
let b = PtrMetadata(q);
|
||||||
|
Return()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
- // MIR for `get_metadata` before LowerIntrinsics
|
||||||
|
+ // MIR for `get_metadata` after LowerIntrinsics
|
||||||
|
|
||||||
|
fn get_metadata(_1: *const i32, _2: *const [u8], _3: *const dyn Debug) -> () {
|
||||||
|
debug a => _1;
|
||||||
|
debug b => _2;
|
||||||
|
debug c => _3;
|
||||||
|
let mut _0: ();
|
||||||
|
let _4: ();
|
||||||
|
let mut _5: *const i32;
|
||||||
|
let mut _7: *const [u8];
|
||||||
|
let mut _9: *const dyn std::fmt::Debug;
|
||||||
|
scope 1 {
|
||||||
|
debug _unit => _4;
|
||||||
|
let _6: usize;
|
||||||
|
scope 2 {
|
||||||
|
debug _usize => _6;
|
||||||
|
let _8: std::ptr::DynMetadata<dyn std::fmt::Debug>;
|
||||||
|
scope 3 {
|
||||||
|
debug _vtable => _8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_4);
|
||||||
|
StorageLive(_5);
|
||||||
|
_5 = _1;
|
||||||
|
- _4 = ptr_metadata::<i32, ()>(move _5) -> [return: bb1, unwind unreachable];
|
||||||
|
+ _4 = PtrMetadata(move _5);
|
||||||
|
+ goto -> bb1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
StorageDead(_5);
|
||||||
|
StorageLive(_6);
|
||||||
|
StorageLive(_7);
|
||||||
|
_7 = _2;
|
||||||
|
- _6 = ptr_metadata::<[u8], usize>(move _7) -> [return: bb2, unwind unreachable];
|
||||||
|
+ _6 = PtrMetadata(move _7);
|
||||||
|
+ goto -> bb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
StorageDead(_7);
|
||||||
|
StorageLive(_8);
|
||||||
|
StorageLive(_9);
|
||||||
|
_9 = _3;
|
||||||
|
- _8 = ptr_metadata::<dyn Debug, DynMetadata<dyn Debug>>(move _9) -> [return: bb3, unwind unreachable];
|
||||||
|
+ _8 = PtrMetadata(move _9);
|
||||||
|
+ goto -> bb3;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb3: {
|
||||||
|
StorageDead(_9);
|
||||||
|
_0 = const ();
|
||||||
|
StorageDead(_8);
|
||||||
|
StorageDead(_6);
|
||||||
|
StorageDead(_4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
|||||||
|
- // MIR for `get_metadata` before LowerIntrinsics
|
||||||
|
+ // MIR for `get_metadata` after LowerIntrinsics
|
||||||
|
|
||||||
|
fn get_metadata(_1: *const i32, _2: *const [u8], _3: *const dyn Debug) -> () {
|
||||||
|
debug a => _1;
|
||||||
|
debug b => _2;
|
||||||
|
debug c => _3;
|
||||||
|
let mut _0: ();
|
||||||
|
let _4: ();
|
||||||
|
let mut _5: *const i32;
|
||||||
|
let mut _7: *const [u8];
|
||||||
|
let mut _9: *const dyn std::fmt::Debug;
|
||||||
|
scope 1 {
|
||||||
|
debug _unit => _4;
|
||||||
|
let _6: usize;
|
||||||
|
scope 2 {
|
||||||
|
debug _usize => _6;
|
||||||
|
let _8: std::ptr::DynMetadata<dyn std::fmt::Debug>;
|
||||||
|
scope 3 {
|
||||||
|
debug _vtable => _8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_4);
|
||||||
|
StorageLive(_5);
|
||||||
|
_5 = _1;
|
||||||
|
- _4 = ptr_metadata::<i32, ()>(move _5) -> [return: bb1, unwind unreachable];
|
||||||
|
+ _4 = PtrMetadata(move _5);
|
||||||
|
+ goto -> bb1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
StorageDead(_5);
|
||||||
|
StorageLive(_6);
|
||||||
|
StorageLive(_7);
|
||||||
|
_7 = _2;
|
||||||
|
- _6 = ptr_metadata::<[u8], usize>(move _7) -> [return: bb2, unwind unreachable];
|
||||||
|
+ _6 = PtrMetadata(move _7);
|
||||||
|
+ goto -> bb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
StorageDead(_7);
|
||||||
|
StorageLive(_8);
|
||||||
|
StorageLive(_9);
|
||||||
|
_9 = _3;
|
||||||
|
- _8 = ptr_metadata::<dyn Debug, DynMetadata<dyn Debug>>(move _9) -> [return: bb3, unwind unreachable];
|
||||||
|
+ _8 = PtrMetadata(move _9);
|
||||||
|
+ goto -> bb3;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb3: {
|
||||||
|
StorageDead(_9);
|
||||||
|
_0 = const ();
|
||||||
|
StorageDead(_8);
|
||||||
|
StorageDead(_6);
|
||||||
|
StorageDead(_4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -258,3 +258,12 @@ pub fn make_pointers(a: *const u8, b: *mut (), n: usize) {
|
|||||||
let _slice_const: *const [u16] = aggregate_raw_ptr(a, n);
|
let _slice_const: *const [u16] = aggregate_raw_ptr(a, n);
|
||||||
let _slice_mut: *mut [u64] = aggregate_raw_ptr(b, n);
|
let _slice_mut: *mut [u64] = aggregate_raw_ptr(b, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EMIT_MIR lower_intrinsics.get_metadata.LowerIntrinsics.diff
|
||||||
|
pub fn get_metadata(a: *const i32, b: *const [u8], c: *const dyn std::fmt::Debug) {
|
||||||
|
use std::intrinsics::ptr_metadata;
|
||||||
|
|
||||||
|
let _unit = ptr_metadata(a);
|
||||||
|
let _usize = ptr_metadata(b);
|
||||||
|
let _vtable = ptr_metadata(c);
|
||||||
|
}
|
||||||
|
@ -13,9 +13,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
|
|||||||
}
|
}
|
||||||
scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) {
|
scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) {
|
||||||
let mut _5: *const ();
|
let mut _5: *const ();
|
||||||
let mut _7: usize;
|
let mut _6: usize;
|
||||||
scope 5 (inlined std::ptr::metadata::<[u32]>) {
|
scope 5 (inlined std::ptr::metadata::<[u32]>) {
|
||||||
let mut _6: std::ptr::metadata::PtrRepr<[u32]>;
|
|
||||||
}
|
}
|
||||||
scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) {
|
scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) {
|
||||||
}
|
}
|
||||||
@ -30,13 +29,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
|
|||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = _4 as *const () (PtrToPtr);
|
_5 = _4 as *const () (PtrToPtr);
|
||||||
StorageLive(_7);
|
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 };
|
_6 = PtrMetadata(_1);
|
||||||
_7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize);
|
_0 = *const [u32] from (_5, _6);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
_0 = *const [u32] from (_5, _7);
|
|
||||||
StorageDead(_7);
|
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
return;
|
return;
|
||||||
|
@ -13,9 +13,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
|
|||||||
}
|
}
|
||||||
scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) {
|
scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) {
|
||||||
let mut _5: *const ();
|
let mut _5: *const ();
|
||||||
let mut _7: usize;
|
let mut _6: usize;
|
||||||
scope 5 (inlined std::ptr::metadata::<[u32]>) {
|
scope 5 (inlined std::ptr::metadata::<[u32]>) {
|
||||||
let mut _6: std::ptr::metadata::PtrRepr<[u32]>;
|
|
||||||
}
|
}
|
||||||
scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) {
|
scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) {
|
||||||
}
|
}
|
||||||
@ -30,13 +29,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
|
|||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = _4 as *const () (PtrToPtr);
|
_5 = _4 as *const () (PtrToPtr);
|
||||||
StorageLive(_7);
|
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 };
|
_6 = PtrMetadata(_1);
|
||||||
_7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize);
|
_0 = *const [u32] from (_5, _6);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
_0 = *const [u32] from (_5, _7);
|
|
||||||
StorageDead(_7);
|
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
return;
|
return;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# ignore-cross-compile
|
# ignore-cross-compile
|
||||||
include ../tools.mk
|
include ../tools.mk
|
||||||
|
|
||||||
# ignore-macos
|
# ignore-apple
|
||||||
#
|
#
|
||||||
# This hits an assertion in the linker on older versions of osx apparently
|
# This hits an assertion in the linker on older versions of osx apparently
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# ignore-cross-compile
|
# ignore-cross-compile
|
||||||
include ../tools.mk
|
include ../tools.mk
|
||||||
|
|
||||||
# ignore-macos
|
# ignore-apple
|
||||||
#
|
#
|
||||||
# This hits an assertion in the linker on older versions of osx apparently
|
# This hits an assertion in the linker on older versions of osx apparently
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
include ../tools.mk
|
include ../tools.mk
|
||||||
|
|
||||||
# ignore-windows
|
# ignore-windows
|
||||||
# ignore-macos
|
# ignore-apple
|
||||||
#
|
#
|
||||||
# This feature only works when the output object format is ELF so we ignore
|
# This feature only works when the output object format is ELF so we ignore
|
||||||
# macOS and Windows
|
# Apple and Windows
|
||||||
|
|
||||||
# check that the .stack_sizes section is generated
|
# check that the .stack_sizes section is generated
|
||||||
all:
|
all:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
include ../tools.mk
|
include ../tools.mk
|
||||||
|
|
||||||
# ignore-windows
|
# ignore-windows
|
||||||
# ignore-macos
|
# ignore-apple
|
||||||
|
|
||||||
# Test for #39529.
|
# Test for #39529.
|
||||||
# `-z text` causes ld to error if there are any non-PIC sections
|
# `-z text` causes ld to error if there are any non-PIC sections
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# only-macos
|
# only-apple
|
||||||
#
|
#
|
||||||
# Check that linking to a framework actually makes it to the linker.
|
# Check that linking to a framework actually makes it to the linker.
|
||||||
|
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
# ignore-cross-compile
|
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all: noparam bool_true bool_false thin fat
|
|
||||||
|
|
||||||
noparam:
|
|
||||||
$(RUSTC) lib.rs
|
|
||||||
$(RUSTC) main.rs -C lto
|
|
||||||
$(call RUN,main)
|
|
||||||
|
|
||||||
bool_true:
|
|
||||||
$(RUSTC) lib.rs
|
|
||||||
$(RUSTC) main.rs -C lto=yes
|
|
||||||
$(call RUN,main)
|
|
||||||
|
|
||||||
|
|
||||||
bool_false:
|
|
||||||
$(RUSTC) lib.rs
|
|
||||||
$(RUSTC) main.rs -C lto=off
|
|
||||||
$(call RUN,main)
|
|
||||||
|
|
||||||
thin:
|
|
||||||
$(RUSTC) lib.rs
|
|
||||||
$(RUSTC) main.rs -C lto=thin
|
|
||||||
$(call RUN,main)
|
|
||||||
|
|
||||||
fat:
|
|
||||||
$(RUSTC) lib.rs
|
|
||||||
$(RUSTC) main.rs -C lto=fat
|
|
||||||
$(call RUN,main)
|
|
||||||
|
|
16
tests/run-make/lto-smoke/rmake.rs
Normal file
16
tests/run-make/lto-smoke/rmake.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// A simple smoke test to check that link time optimization
|
||||||
|
// (LTO) is accepted by the compiler, and that
|
||||||
|
// passing its various flags still results in successful compilation.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/10741
|
||||||
|
|
||||||
|
//@ ignore-cross-compile
|
||||||
|
|
||||||
|
use run_make_support::rustc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let lto_flags = ["-Clto", "-Clto=yes", "-Clto=off", "-Clto=thin", "-Clto=fat"];
|
||||||
|
for flag in lto_flags {
|
||||||
|
rustc().input("lib.rs").run();
|
||||||
|
rustc().input("main.rs").arg(flag).run();
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
# only-macos
|
# only-apple
|
||||||
|
|
||||||
include ../tools.mk
|
include ../tools.mk
|
||||||
|
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
# ignore-cross-compile
|
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTC) both.rs -C prefer-dynamic
|
|
||||||
$(RUSTC) dylib.rs -C prefer-dynamic
|
|
||||||
$(RUSTC) prog.rs
|
|
||||||
$(call RUN,prog)
|
|
13
tests/run-make/mixing-deps/rmake.rs
Normal file
13
tests/run-make/mixing-deps/rmake.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// This test invokes the main function in prog.rs, which has dependencies
|
||||||
|
// in both an rlib and a dylib. This test checks that these different library
|
||||||
|
// types can be successfully mixed.
|
||||||
|
//@ ignore-cross-compile
|
||||||
|
|
||||||
|
use run_make_support::{run, rustc};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
rustc().input("both.rs").arg("-Cprefer-dynamic").run();
|
||||||
|
rustc().input("dylib.rs").arg("-Cprefer-dynamic").run();
|
||||||
|
rustc().input("prog.rs").run();
|
||||||
|
run("prog");
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
# ignore-cross-compile
|
# ignore-cross-compile
|
||||||
# ignore-macos
|
# ignore-apple
|
||||||
|
|
||||||
include ../tools.mk
|
include ../tools.mk
|
||||||
|
|
||||||
|
1
tests/run-make/print-check-cfg/lib.rs
Normal file
1
tests/run-make/print-check-cfg/lib.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
// empty crate
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user