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) => {
|
||||
let operand = codegen_operand(fx, operand);
|
||||
let layout = operand.layout();
|
||||
let val = operand.load_scalar(fx);
|
||||
let res = match un_op {
|
||||
UnOp::Not => match layout.ty.kind() {
|
||||
ty::Bool => {
|
||||
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
|
||||
CValue::by_val(res, layout)
|
||||
UnOp::Not => {
|
||||
let val = operand.load_scalar(fx);
|
||||
match layout.ty.kind() {
|
||||
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::Neg => 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),
|
||||
}
|
||||
UnOp::PtrMetadata => match layout.abi {
|
||||
Abi::Scalar(_) => CValue::zst(dest_layout),
|
||||
Abi::ScalarPair(_, _) => {
|
||||
CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout)
|
||||
}
|
||||
_ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"),
|
||||
},
|
||||
};
|
||||
lval.write_cvalue(fx, res);
|
||||
|
@ -100,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>(
|
||||
assert!(layout.is_sized(), "unsized const value");
|
||||
|
||||
if layout.is_zst() {
|
||||
return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout);
|
||||
return CValue::zst(layout);
|
||||
}
|
||||
|
||||
match const_val {
|
||||
|
@ -95,6 +95,14 @@ impl<'tcx> CValue<'tcx> {
|
||||
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> {
|
||||
self.1
|
||||
}
|
||||
|
@ -565,6 +565,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
for elem in place_ref.projection.iter() {
|
||||
match elem {
|
||||
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());
|
||||
}
|
||||
mir::ProjectionElem::Index(_)
|
||||
|
@ -480,6 +480,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
cg_base = match *elem {
|
||||
mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
|
||||
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())
|
||||
}
|
||||
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) => {
|
||||
let operand = self.codegen_operand(bx, operand);
|
||||
let lloperand = operand.immediate();
|
||||
let is_float = operand.layout.ty.is_floating_point();
|
||||
let llval = match op {
|
||||
mir::UnOp::Not => bx.not(lloperand),
|
||||
let (val, layout) = match op {
|
||||
mir::UnOp::Not => {
|
||||
let llval = bx.not(operand.immediate());
|
||||
(OperandValue::Immediate(llval), operand.layout)
|
||||
}
|
||||
mir::UnOp::Neg => {
|
||||
if is_float {
|
||||
bx.fneg(lloperand)
|
||||
let llval = if is_float {
|
||||
bx.fneg(operand.immediate())
|
||||
} 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) => {
|
||||
@ -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| {
|
||||
bug!("Field {field_idx:?} is {p:?} making {layout:?}");
|
||||
});
|
||||
inputs.extend(values);
|
||||
let scalars = self.value_kind(op.layout).scalars().unwrap();
|
||||
debug_assert_eq!(values.len(), scalars.len());
|
||||
inputs.extend(values);
|
||||
input_scalars.extend(scalars);
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn init_frame_extra(
|
||||
fn init_frame(
|
||||
_ecx: &mut InterpCx<'tcx, Self>,
|
||||
_frame: interpret::Frame<'tcx, Self::Provenance>,
|
||||
) -> interpret::InterpResult<'tcx, interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>>
|
||||
|
@ -643,7 +643,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn init_frame_extra(
|
||||
fn init_frame(
|
||||
ecx: &mut InterpCx<'tcx, Self>,
|
||||
frame: 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());
|
||||
// Handle casting any ptr to raw ptr (might be a fat ptr).
|
||||
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));
|
||||
} else {
|
||||
// Casting the metadata away from a fat ptr.
|
||||
|
@ -819,7 +819,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
tracing_span: SpanGuard::new(),
|
||||
extra: (),
|
||||
};
|
||||
let frame = M::init_frame_extra(self, pre_frame)?;
|
||||
let frame = M::init_frame(self, pre_frame)?;
|
||||
self.stack_mut().push(frame);
|
||||
|
||||
// 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>,
|
||||
) -> 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.
|
||||
///
|
||||
/// 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
|
||||
/// 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
|
||||
/// owned allocation to the map even when the map is shared.)
|
||||
fn adjust_allocation<'b>(
|
||||
fn adjust_global_allocation<'b>(
|
||||
ecx: &InterpCx<'tcx, Self>,
|
||||
id: AllocId,
|
||||
alloc: Cow<'b, Allocation>,
|
||||
kind: Option<MemoryKind<Self::MemoryKind>>,
|
||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>;
|
||||
alloc: &'b Allocation,
|
||||
) -> 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
|
||||
/// 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.
|
||||
fn init_frame_extra(
|
||||
fn init_frame(
|
||||
ecx: &mut InterpCx<'tcx, Self>,
|
||||
frame: Frame<'tcx, Self::Provenance>,
|
||||
) -> InterpResult<'tcx, Frame<'tcx, Self::Provenance, Self::FrameExtra>>;
|
||||
@ -590,13 +604,23 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn adjust_allocation<'b>(
|
||||
fn adjust_global_allocation<'b>(
|
||||
_ecx: &InterpCx<$tcx, Self>,
|
||||
_id: AllocId,
|
||||
alloc: Cow<'b, Allocation>,
|
||||
_kind: Option<MemoryKind<Self::MemoryKind>>,
|
||||
alloc: &'b Allocation,
|
||||
) -> 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(
|
||||
|
@ -239,7 +239,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
|
||||
pub fn allocate_raw_ptr(
|
||||
&mut self,
|
||||
alloc: Allocation,
|
||||
alloc: Allocation<M::Provenance, (), M::Bytes>,
|
||||
kind: MemoryKind<M::MemoryKind>,
|
||||
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
|
||||
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),
|
||||
"dynamically allocating global memory"
|
||||
);
|
||||
let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
|
||||
self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
|
||||
// We have set things up so we don't need to call `adjust_from_tcx` here,
|
||||
// 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))
|
||||
}
|
||||
|
||||
@ -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)?;
|
||||
// We got tcx memory. Let the machine initialize its "extra" stuff.
|
||||
M::adjust_allocation(
|
||||
M::adjust_global_allocation(
|
||||
self,
|
||||
id, // always use the ID we got as input, not the "hidden" one.
|
||||
Cow::Borrowed(alloc.inner()),
|
||||
M::GLOBAL_KIND.map(MemoryKind::Machine),
|
||||
alloc.inner(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::symbol::sym;
|
||||
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> {
|
||||
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::*;
|
||||
|
||||
let layout = val.layout;
|
||||
let val = val.to_scalar();
|
||||
trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty);
|
||||
|
||||
match layout.ty.kind() {
|
||||
ty::Bool => {
|
||||
let val = val.to_scalar();
|
||||
let val = val.to_bool()?;
|
||||
let res = match un_op {
|
||||
Not => !val,
|
||||
@ -428,6 +428,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
Ok(ImmTy::from_bool(res, *self.tcx))
|
||||
}
|
||||
ty::Float(fty) => {
|
||||
let val = val.to_scalar();
|
||||
// No NaN adjustment here, `-` is a bitwise operation!
|
||||
let res = match (un_op, fty) {
|
||||
(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))
|
||||
}
|
||||
_ => {
|
||||
assert!(layout.ty.is_integral());
|
||||
_ if layout.ty.is_integral() => {
|
||||
let val = val.to_scalar();
|
||||
let val = val.to_bits(layout.size)?;
|
||||
let res = match un_op {
|
||||
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.
|
||||
self.truncate(res, layout)
|
||||
}
|
||||
_ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op),
|
||||
};
|
||||
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}");
|
||||
}
|
||||
}
|
||||
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 => {
|
||||
let mut calling_conventions = rustc_target::spec::abi::all_names();
|
||||
calling_conventions.sort_unstable();
|
||||
|
@ -130,6 +130,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
|
||||
| sym::is_val_statically_known
|
||||
| sym::ptr_mask
|
||||
| sym::aggregate_raw_ptr
|
||||
| sym::ptr_metadata
|
||||
| sym::ub_checks
|
||||
| sym::fadd_algebraic
|
||||
| sym::fsub_algebraic
|
||||
@ -576,6 +577,7 @@ pub fn check_intrinsic_type(
|
||||
// This type check is not particularly useful, but the `where` bounds
|
||||
// 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::ptr_metadata => (2, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)),
|
||||
|
||||
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 sig = self
|
||||
.at(cause, self.param_env)
|
||||
.trace(prev_ty, new_ty)
|
||||
.lub(DefineOpaqueTypes::Yes, a_sig, b_sig)
|
||||
.map(|ok| self.register_infer_ok_obligations(ok))?;
|
||||
|
||||
|
@ -48,11 +48,6 @@ pub struct At<'a, 'tcx> {
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
pub struct Trace<'a, 'tcx> {
|
||||
at: At<'a, 'tcx>,
|
||||
trace: TypeTrace<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
#[inline]
|
||||
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
|
||||
/// `sup(i32, x)`, since the "expected" type is the type that
|
||||
/// 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>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
@ -121,13 +113,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
where
|
||||
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`.
|
||||
///
|
||||
/// See [`At::trace`] and [`Trace::sub`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
pub fn sub<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
@ -137,13 +135,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
where
|
||||
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`.
|
||||
///
|
||||
/// See [`At::trace`] and [`Trace::eq`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
/// Makes `expected == actual`.
|
||||
pub fn eq<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
@ -153,7 +157,40 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
where
|
||||
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>(
|
||||
@ -185,9 +222,6 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
/// 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
|
||||
/// "expected type".
|
||||
///
|
||||
/// See [`At::trace`] and [`Trace::lub`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
pub fn lub<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
@ -197,15 +231,21 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
where
|
||||
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
|
||||
/// values. As with `lub` order doesn't matter, except for error
|
||||
/// cases.
|
||||
///
|
||||
/// See [`At::trace`] and [`Trace::glb`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
pub fn glb<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
@ -215,105 +255,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.trace(expected, actual).glb(define_opaque_types, expected, actual)
|
||||
}
|
||||
|
||||
/// Sets the "trace" values that will be used for
|
||||
/// error-reporting, but doesn't actually perform any operation
|
||||
/// 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);
|
||||
let mut fields = CombineFields::new(
|
||||
self.infcx,
|
||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||
self.param_env,
|
||||
define_opaque_types,
|
||||
);
|
||||
fields
|
||||
.glb()
|
||||
.relate(a, b)
|
||||
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
.relate(expected, actual)
|
||||
.map(|value| InferOk { value, obligations: fields.obligations })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -836,21 +836,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
.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
|
||||
where
|
||||
T: at::ToTrace<'tcx>,
|
||||
|
@ -42,6 +42,17 @@ pub struct CombineFields<'infcx, 'tcx> {
|
||||
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> {
|
||||
pub fn super_combine_tys<R>(
|
||||
&self,
|
||||
|
@ -266,19 +266,6 @@ impl AllocRange {
|
||||
|
||||
// The constructors are all without extra; the extra gets added by a machine hook later.
|
||||
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
|
||||
pub fn from_bytes<'a>(
|
||||
slice: impl Into<Cow<'a, [u8]>>,
|
||||
@ -342,18 +329,30 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
||||
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 {
|
||||
/// Adjust allocation from the ones in `tcx` to a custom Machine instance
|
||||
/// with a different `Provenance`, `Extra` and `Byte` type.
|
||||
pub fn adjust_from_tcx<Prov: Provenance, Extra, Bytes: AllocBytes, Err>(
|
||||
self,
|
||||
/// with a different `Provenance` and `Byte` type.
|
||||
pub fn adjust_from_tcx<Prov: Provenance, Bytes: AllocBytes, Err>(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
extra: Extra,
|
||||
mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> Result<Pointer<Prov>, Err>,
|
||||
) -> Result<Allocation<Prov, Extra, Bytes>, Err> {
|
||||
let mut bytes = self.bytes;
|
||||
) -> Result<Allocation<Prov, (), Bytes>, Err> {
|
||||
// Copy the data.
|
||||
let mut bytes = Bytes::from_bytes(Cow::Borrowed(&*self.bytes), self.align);
|
||||
// Adjust provenance of pointers stored in this allocation.
|
||||
let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len());
|
||||
let ptr_size = cx.data_layout().pointer_size.bytes_usize();
|
||||
@ -369,12 +368,12 @@ impl Allocation {
|
||||
}
|
||||
// Create allocation.
|
||||
Ok(Allocation {
|
||||
bytes: AllocBytes::from_bytes(Cow::Owned(Vec::from(bytes)), self.align),
|
||||
bytes,
|
||||
provenance: ProvenanceMap::from_presorted_ptrs(new_provenance),
|
||||
init_mask: self.init_mask,
|
||||
init_mask: self.init_mask.clone(),
|
||||
align: self.align,
|
||||
mutability: self.mutability,
|
||||
extra,
|
||||
extra: self.extra,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1434,6 +1434,13 @@ pub enum UnOp {
|
||||
Not,
|
||||
/// The `-` operator for negation
|
||||
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)]
|
||||
|
@ -180,7 +180,10 @@ impl<'tcx> Rvalue<'tcx> {
|
||||
let rhs_ty = rhs.ty(local_decls, tcx);
|
||||
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::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
|
||||
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 {
|
||||
pub fn to_mutbl_lossy(self) -> hir::Mutability {
|
||||
match self {
|
||||
|
@ -1579,8 +1579,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||
let formatted_op = match op {
|
||||
UnOp::Not => "!",
|
||||
UnOp::Neg => "-",
|
||||
UnOp::PtrMetadata => "PtrMetadata",
|
||||
};
|
||||
let parenthesized = match ct.kind() {
|
||||
_ if op == UnOp::PtrMetadata => true,
|
||||
ty::ConstKind::Expr(Expr::UnOp(c_op, ..)) => c_op != op,
|
||||
ty::ConstKind::Expr(_) => true,
|
||||
_ => false,
|
||||
|
@ -212,6 +212,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
|
||||
},
|
||||
@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])?)),
|
||||
ExprKind::Borrow { borrow_kind, arg } => Ok(
|
||||
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 };
|
||||
}
|
||||
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) => {
|
||||
match op {
|
||||
// These operations can never fail.
|
||||
UnOp::Neg | UnOp::Not => {}
|
||||
UnOp::Neg | UnOp::Not | UnOp::PtrMetadata => {}
|
||||
}
|
||||
|
||||
self.validate_operand(operand)?;
|
||||
|
@ -1109,6 +1109,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
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, _) => {
|
||||
|
@ -537,6 +537,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
let determined_imports = mem::take(&mut self.determined_imports);
|
||||
let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
|
||||
|
||||
let mut glob_error = false;
|
||||
for (is_indeterminate, import) in determined_imports
|
||||
.iter()
|
||||
.map(|i| (false, i))
|
||||
@ -548,6 +549,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
self.import_dummy_binding(*import, is_indeterminate);
|
||||
|
||||
if let Some(err) = unresolved_import_error {
|
||||
glob_error |= import.is_glob();
|
||||
|
||||
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
|
||||
if source.name == kw::SelfLower {
|
||||
// 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
|
||||
// for the previous line.
|
||||
self.throw_unresolved_import_error(errors);
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
errors = vec![];
|
||||
}
|
||||
if seen_spans.insert(err.span) {
|
||||
@ -574,7 +577,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
|
||||
if !errors.is_empty() {
|
||||
self.throw_unresolved_import_error(errors);
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -600,9 +603,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
if !errors.is_empty() {
|
||||
self.throw_unresolved_import_error(errors);
|
||||
}
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
}
|
||||
|
||||
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() {
|
||||
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:
|
||||
|
@ -4033,9 +4033,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
}
|
||||
|
||||
#[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 {
|
||||
!(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.
|
||||
|
@ -32,7 +32,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
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_feature::BUILTIN_ATTRIBUTES;
|
||||
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.
|
||||
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
|
||||
glob_error: Option<ErrorGuaranteed>,
|
||||
visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
|
||||
used_imports: FxHashSet<NodeId>,
|
||||
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
|
||||
@ -1417,6 +1418,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
ast_transform_scopes: FxHashMap::default(),
|
||||
|
||||
glob_map: Default::default(),
|
||||
glob_error: None,
|
||||
visibilities_for_hashing: Default::default(),
|
||||
used_imports: FxHashSet::default(),
|
||||
maybe_unused_trait_imports: Default::default(),
|
||||
|
@ -773,6 +773,7 @@ pub enum PrintKind {
|
||||
TargetLibdir,
|
||||
CrateName,
|
||||
Cfg,
|
||||
CheckCfg,
|
||||
CallingConventions,
|
||||
TargetList,
|
||||
TargetCPUs,
|
||||
@ -1443,7 +1444,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
|
||||
"",
|
||||
"print",
|
||||
"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|\
|
||||
tls-models|target-spec-json|all-target-specs-json|native-static-libs|\
|
||||
stack-protector-strategies|link-args|deployment-target]",
|
||||
@ -1859,6 +1860,7 @@ fn collect_print_requests(
|
||||
("all-target-specs-json", PrintKind::AllTargetSpecs),
|
||||
("calling-conventions", PrintKind::CallingConventions),
|
||||
("cfg", PrintKind::Cfg),
|
||||
("check-cfg", PrintKind::CheckCfg),
|
||||
("code-models", PrintKind::CodeModels),
|
||||
("crate-name", PrintKind::CrateName),
|
||||
("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,
|
||||
None => {
|
||||
let prints =
|
||||
|
@ -10,7 +10,7 @@ use rustc_span::Symbol;
|
||||
use stable_mir::abi::Layout;
|
||||
use stable_mir::mir::alloc::AllocId;
|
||||
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::{
|
||||
Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
|
||||
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
|
||||
where
|
||||
T: RustcInternal,
|
||||
|
@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape};
|
||||
use stable_mir::compiler_interface::Context;
|
||||
use stable_mir::mir::alloc::GlobalAlloc;
|
||||
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::ty::{
|
||||
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);
|
||||
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>>);
|
||||
|
@ -526,6 +526,7 @@ impl<'tcx> Stable<'tcx> for mir::UnOp {
|
||||
match self {
|
||||
UnOp::Not => stable_mir::mir::UnOp::Not,
|
||||
UnOp::Neg => stable_mir::mir::UnOp::Neg,
|
||||
UnOp::PtrMetadata => stable_mir::mir::UnOp::PtrMetadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1179,6 +1179,7 @@ symbols! {
|
||||
mir_make_place,
|
||||
mir_move,
|
||||
mir_offset,
|
||||
mir_ptr_metadata,
|
||||
mir_retag,
|
||||
mir_return,
|
||||
mir_return_to,
|
||||
@ -1433,6 +1434,7 @@ symbols! {
|
||||
ptr_guaranteed_cmp,
|
||||
ptr_is_null,
|
||||
ptr_mask,
|
||||
ptr_metadata,
|
||||
ptr_null,
|
||||
ptr_null_mut,
|
||||
ptr_offset_from,
|
||||
|
@ -363,7 +363,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
for (&orig, response) in iter::zip(original_values, var_values.var_values) {
|
||||
let InferOk { value: (), obligations } = infcx
|
||||
.at(&cause, param_env)
|
||||
.trace(orig, response)
|
||||
.eq_structurally_relating_aliases(orig, response)
|
||||
.unwrap();
|
||||
assert!(obligations.is_empty());
|
||||
|
@ -776,7 +776,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
let InferOk { value: (), obligations } = self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.trace(term, ctor_term)
|
||||
.eq_structurally_relating_aliases(term, ctor_term)?;
|
||||
debug_assert!(obligations.is_empty());
|
||||
self.relate(param_env, alias, variance, rigid_ctor)
|
||||
@ -796,11 +795,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
rhs: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
let cause = ObligationCause::dummy();
|
||||
let InferOk { value: (), obligations } = self
|
||||
.infcx
|
||||
.at(&cause, param_env)
|
||||
.trace(lhs, rhs)
|
||||
.eq_structurally_relating_aliases(lhs, rhs)?;
|
||||
let InferOk { value: (), obligations } =
|
||||
self.infcx.at(&cause, param_env).eq_structurally_relating_aliases(lhs, rhs)?;
|
||||
assert!(obligations.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
|
@ -566,10 +566,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||
{
|
||||
if let Ok(new_obligations) = infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.trace(c1, c2)
|
||||
// Can define opaque types as this is only reachable with
|
||||
// `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(
|
||||
new_obligations.into_obligations(),
|
||||
|
@ -910,10 +910,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
if let Ok(InferOk { obligations, value: () }) = self
|
||||
.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.trace(c1, c2)
|
||||
// Can define opaque types as this is only reachable with
|
||||
// `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(
|
||||
previous_stack,
|
||||
|
@ -94,7 +94,7 @@ fn check_binop(op: mir::BinOp) -> bool {
|
||||
fn check_unop(op: mir::UnOp) -> bool {
|
||||
use mir::UnOp::*;
|
||||
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::mir::alloc::{AllocId, GlobalAlloc};
|
||||
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::ty::{
|
||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
||||
@ -226,6 +226,9 @@ pub trait Context {
|
||||
|
||||
/// Get the resulting type of binary operation.
|
||||
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
|
||||
|
@ -346,6 +346,15 @@ impl BinOp {
|
||||
pub enum UnOp {
|
||||
Not,
|
||||
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)]
|
||||
@ -580,7 +589,10 @@ impl Rvalue {
|
||||
let ty = op.ty(lhs_ty, rhs_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) => {
|
||||
let place_ty = place.ty(locals)?;
|
||||
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;
|
||||
}
|
||||
|
||||
/// 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
|
||||
// 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
|
||||
|
@ -360,6 +360,10 @@ define!("mir_assume", fn Assume(operand: bool));
|
||||
define!("mir_deinit", fn Deinit<T>(place: T));
|
||||
define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
|
||||
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_retag", fn Retag<T>(place: T));
|
||||
define!("mir_move", fn Move<T>(place: T) -> T);
|
||||
|
@ -3,6 +3,8 @@
|
||||
use crate::fmt;
|
||||
use crate::hash::{Hash, Hasher};
|
||||
use crate::intrinsics::aggregate_raw_ptr;
|
||||
#[cfg(not(bootstrap))]
|
||||
use crate::intrinsics::ptr_metadata;
|
||||
use crate::marker::Freeze;
|
||||
|
||||
/// 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")]
|
||||
#[inline]
|
||||
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
|
||||
// and PtrComponents<T> have the same memory layouts. Only std can make this
|
||||
// guarantee.
|
||||
unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
|
||||
#[cfg(bootstrap)]
|
||||
{
|
||||
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
|
||||
// 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.
|
||||
@ -132,6 +141,7 @@ pub const fn from_raw_parts_mut<T: ?Sized>(
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(bootstrap)]
|
||||
union PtrRepr<T: ?Sized> {
|
||||
const_ptr: *const T,
|
||||
mut_ptr: *mut T,
|
||||
@ -139,15 +149,18 @@ union PtrRepr<T: ?Sized> {
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(bootstrap)]
|
||||
struct PtrComponents<T: ?Sized> {
|
||||
data_pointer: *const (),
|
||||
metadata: <T as Pointee>::Metadata,
|
||||
}
|
||||
|
||||
// Manual impl needed to avoid `T: Copy` bound.
|
||||
#[cfg(bootstrap)]
|
||||
impl<T: ?Sized> Copy for PtrComponents<T> {}
|
||||
|
||||
// Manual impl needed to avoid `T: Clone` bound.
|
||||
#[cfg(bootstrap)]
|
||||
impl<T: ?Sized> Clone for PtrComponents<T> {
|
||||
fn clone(&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.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!(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!(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(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
|
@ -1028,6 +1028,14 @@ tool_doc!(
|
||||
is_library = true,
|
||||
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)]
|
||||
pub struct ErrorIndex {
|
||||
|
@ -888,6 +888,7 @@ impl<'a> Builder<'a> {
|
||||
doc::Tidy,
|
||||
doc::Bootstrap,
|
||||
doc::Releases,
|
||||
doc::RunMakeSupport,
|
||||
),
|
||||
Kind::Dist => describe!(
|
||||
dist::Docs,
|
||||
|
@ -5,7 +5,7 @@
|
||||
pub fn dylib_path_var() -> &'static str {
|
||||
if cfg!(target_os = "windows") {
|
||||
"PATH"
|
||||
} else if cfg!(target_os = "macos") {
|
||||
} else if cfg!(target_vendor = "apple") {
|
||||
"DYLD_LIBRARY_PATH"
|
||||
} else if cfg!(target_os = "haiku") {
|
||||
"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-unknown-linux-gnu",
|
||||
"ignore-android",
|
||||
"ignore-apple",
|
||||
"ignore-arm",
|
||||
"ignore-avr",
|
||||
"ignore-beta",
|
||||
@ -829,7 +830,6 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
||||
"ignore-x32",
|
||||
"ignore-x86",
|
||||
"ignore-x86_64",
|
||||
"ignore-x86_64-apple-darwin",
|
||||
"ignore-x86_64-unknown-linux-gnu",
|
||||
"incremental",
|
||||
"known-bug",
|
||||
@ -876,6 +876,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
||||
"only-32bit",
|
||||
"only-64bit",
|
||||
"only-aarch64",
|
||||
"only-apple",
|
||||
"only-arm",
|
||||
"only-avr",
|
||||
"only-beta",
|
||||
|
@ -159,6 +159,12 @@ pub(super) fn parse_cfg_name_directive<'a>(
|
||||
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"
|
||||
// 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.
|
||||
|
@ -98,7 +98,7 @@ fn get_lib_name(lib: &str, aux_type: AuxType) -> Option<String> {
|
||||
AuxType::Lib => Some(format!("lib{}.rlib", lib)),
|
||||
AuxType::Dylib => Some(if cfg!(windows) {
|
||||
format!("{}.dll", lib)
|
||||
} else if cfg!(target_os = "macos") {
|
||||
} else if cfg!(target_vendor = "apple") {
|
||||
format!("lib{}.dylib", lib)
|
||||
} else {
|
||||
format!("lib{}.so", lib)
|
||||
|
@ -57,7 +57,7 @@ impl PathBufExt for PathBuf {
|
||||
pub fn dylib_env_var() -> &'static str {
|
||||
if cfg!(windows) {
|
||||
"PATH"
|
||||
} else if cfg!(target_os = "macos") {
|
||||
} else if cfg!(target_vendor = "apple") {
|
||||
"DYLD_LIBRARY_PATH"
|
||||
} else if cfg!(target_os = "haiku") {
|
||||
"LIBRARY_PATH"
|
||||
|
@ -862,14 +862,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
if tcx.is_foreign_item(def_id) {
|
||||
throw_unsup_format!("foreign thread-local statics are not supported");
|
||||
}
|
||||
let allocation = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
||||
let mut allocation = allocation.inner().clone();
|
||||
let alloc = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
||||
// 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.
|
||||
allocation.mutability = Mutability::Mut;
|
||||
alloc.mutability = Mutability::Mut;
|
||||
// Create a fresh allocation with this content.
|
||||
let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into())?;
|
||||
this.machine.threads.set_thread_local_alloc(def_id, new_alloc);
|
||||
Ok(new_alloc)
|
||||
let ptr = this.allocate_raw_ptr(alloc, MiriMemoryKind::Tls.into())?;
|
||||
this.machine.threads.set_thread_local_alloc(def_id, ptr);
|
||||
Ok(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
//! Global machine state as well as implementation of the interpreter engine
|
||||
//! `Machine` trait.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::hash_map::Entry;
|
||||
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>,
|
||||
id: AllocId,
|
||||
alloc: Cow<'b, Allocation>,
|
||||
kind: Option<MemoryKind>,
|
||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
|
||||
{
|
||||
let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
|
||||
kind: MemoryKind,
|
||||
size: Size,
|
||||
align: Align,
|
||||
) -> InterpResult<'tcx, Self::AllocExtra> {
|
||||
if ecx.machine.tracked_alloc_ids.contains(&id) {
|
||||
ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(
|
||||
id,
|
||||
alloc.size(),
|
||||
alloc.align,
|
||||
kind,
|
||||
));
|
||||
ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id, size, align, kind));
|
||||
}
|
||||
|
||||
let alloc = alloc.into_owned();
|
||||
let borrow_tracker = ecx
|
||||
.machine
|
||||
.borrow_tracker
|
||||
.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,
|
||||
&ecx.machine.threads,
|
||||
alloc.size(),
|
||||
size,
|
||||
kind,
|
||||
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
|
||||
// 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())
|
||||
};
|
||||
|
||||
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()) {
|
||||
ecx.machine
|
||||
.allocation_spans
|
||||
@ -1148,7 +1129,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
||||
.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(
|
||||
@ -1357,7 +1338,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn init_frame_extra(
|
||||
fn init_frame(
|
||||
ecx: &mut InterpCx<'tcx, Self>,
|
||||
frame: Frame<'tcx, Provenance>,
|
||||
) -> 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
|
||||
#![feature(core_intrinsics, layout_for_ptr)]
|
||||
#![feature(core_intrinsics, layout_for_ptr, ptr_metadata)]
|
||||
//! Tests for various intrinsics that do not fit anywhere else.
|
||||
|
||||
use std::intrinsics;
|
||||
@ -57,4 +57,10 @@ fn main() {
|
||||
// Make sure that even if the discriminant is stored together with data, the intrinsic returns
|
||||
// only the discriminant, nothing about the data.
|
||||
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
|
||||
}
|
||||
|
||||
/// Inspect what the underlying [`Command`][::std::process::Command] is up to the
|
||||
/// Inspect what the underlying [`Command`] is up to the
|
||||
/// current construction.
|
||||
pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
|
||||
where
|
||||
|
@ -203,7 +203,7 @@ impl Rustc {
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the [`Output`][::std::process::Output] of the finished process.
|
||||
/// Get the [`Output`] of the finished process.
|
||||
#[track_caller]
|
||||
pub fn command_output(&mut self) -> ::std::process::Output {
|
||||
// let's make sure we piped all the input and outputs
|
||||
|
@ -94,7 +94,7 @@ impl Rustdoc {
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the [`Output`][::std::process::Output] of the finished process.
|
||||
/// Get the [`Output`] of the finished process.
|
||||
#[track_caller]
|
||||
pub fn command_output(&mut self) -> ::std::process::Output {
|
||||
// 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-readonly-lib/Makefile
|
||||
run-make/lto-smoke-c/Makefile
|
||||
run-make/lto-smoke/Makefile
|
||||
run-make/macos-deployment-target/Makefile
|
||||
run-make/macos-fat-archive/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/mismatching-target-triples/Makefile
|
||||
run-make/missing-crate-dependency/Makefile
|
||||
run-make/mixing-deps/Makefile
|
||||
run-make/mixing-formats/Makefile
|
||||
run-make/mixing-libs/Makefile
|
||||
run-make/msvc-opt-minsize/Makefile
|
||||
@ -238,7 +236,6 @@ run-make/short-ice/Makefile
|
||||
run-make/silly-file-names/Makefile
|
||||
run-make/simd-ffi/Makefile
|
||||
run-make/simple-dylib/Makefile
|
||||
run-make/simple-rlib/Makefile
|
||||
run-make/split-debuginfo/Makefile
|
||||
run-make/stable-symbol-names/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-3389.rs
|
||||
ui/issues/issue-33941.rs
|
||||
ui/issues/issue-33992.rs
|
||||
ui/issues/issue-34047.rs
|
||||
ui/issues/issue-34074.rs
|
||||
ui/issues/issue-34209.rs
|
||||
|
@ -15,7 +15,7 @@ use std::path::{Path, PathBuf};
|
||||
const ENTRY_LIMIT: u32 = 900;
|
||||
// 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] = &[
|
||||
"rs", // test source files
|
||||
|
@ -1,6 +1,6 @@
|
||||
//@ revisions: all strong basic none missing
|
||||
//@ 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-nvptx64 stack protector is not supported
|
||||
//@ ignore-wasm32-bare
|
||||
@ -17,12 +17,9 @@
|
||||
// See comments on https://github.com/rust-lang/rust/issues/114903.
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
|
||||
|
||||
// CHECK-LABEL: emptyfn:
|
||||
#[no_mangle]
|
||||
pub fn emptyfn() {
|
||||
|
@ -2,7 +2,7 @@
|
||||
//@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
|
||||
//@ only-x86_64
|
||||
//@ ignore-sgx
|
||||
//@ ignore-macos (manipulates rsp too)
|
||||
//@ ignore-apple (manipulates rsp too)
|
||||
|
||||
// Depending on various codegen choices, this might end up copying
|
||||
// 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
|
||||
//@ [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep
|
||||
//@ 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
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
@ -1,6 +1,6 @@
|
||||
//
|
||||
//@ ignore-windows
|
||||
//@ ignore-macos
|
||||
//@ ignore-apple
|
||||
//@ ignore-wasm
|
||||
//@ ignore-emscripten
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVFUN=__llvm_covfun
|
||||
//@ [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_NAME=__DATA,__llvm_prf_names
|
||||
//@ [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)
|
||||
where
|
||||
F: FnOnce(&T)
|
||||
F: FnOnce(&T),
|
||||
{
|
||||
if should_wrap {
|
||||
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
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
@ -2,7 +2,7 @@
|
||||
// before 4.0, formerly backported to the Rust LLVM fork.
|
||||
|
||||
//@ ignore-windows
|
||||
//@ ignore-macos
|
||||
//@ ignore-apple
|
||||
//@ ignore-wasi
|
||||
|
||||
//@ compile-flags: -g -C no-prepopulate-passes
|
||||
@ -10,5 +10,4 @@
|
||||
// CHECK-LABEL: @main
|
||||
// CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}}
|
||||
|
||||
pub fn main() {
|
||||
}
|
||||
pub fn main() {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
//@ ignore-windows
|
||||
//@ ignore-macos
|
||||
//@ ignore-apple
|
||||
//@ ignore-wasi wasi codegens the main symbol differently
|
||||
|
||||
//@ compile-flags: -g -C no-prepopulate-passes
|
||||
|
@ -1,6 +1,6 @@
|
||||
// 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
|
||||
//@ needs-profiler-support
|
||||
//@ 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()
|
||||
})
|
||||
}
|
||||
|
||||
// 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_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]>) {
|
||||
let mut _5: *const ();
|
||||
let mut _7: usize;
|
||||
let mut _6: usize;
|
||||
scope 5 (inlined std::ptr::metadata::<[u32]>) {
|
||||
let mut _6: std::ptr::metadata::PtrRepr<[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);
|
||||
StorageLive(_5);
|
||||
_5 = _4 as *const () (PtrToPtr);
|
||||
StorageLive(_7);
|
||||
StorageLive(_6);
|
||||
_6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 };
|
||||
_7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize);
|
||||
_6 = PtrMetadata(_1);
|
||||
_0 = *const [u32] from (_5, _6);
|
||||
StorageDead(_6);
|
||||
_0 = *const [u32] from (_5, _7);
|
||||
StorageDead(_7);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
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]>) {
|
||||
let mut _5: *const ();
|
||||
let mut _7: usize;
|
||||
let mut _6: usize;
|
||||
scope 5 (inlined std::ptr::metadata::<[u32]>) {
|
||||
let mut _6: std::ptr::metadata::PtrRepr<[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);
|
||||
StorageLive(_5);
|
||||
_5 = _4 as *const () (PtrToPtr);
|
||||
StorageLive(_7);
|
||||
StorageLive(_6);
|
||||
_6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 };
|
||||
_7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize);
|
||||
_6 = PtrMetadata(_1);
|
||||
_0 = *const [u32] from (_5, _6);
|
||||
StorageDead(_6);
|
||||
_0 = *const [u32] from (_5, _7);
|
||||
StorageDead(_7);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
return;
|
||||
|
@ -4,7 +4,7 @@
|
||||
# ignore-cross-compile
|
||||
include ../tools.mk
|
||||
|
||||
# ignore-macos
|
||||
# ignore-apple
|
||||
#
|
||||
# This hits an assertion in the linker on older versions of osx apparently
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
# ignore-cross-compile
|
||||
include ../tools.mk
|
||||
|
||||
# ignore-macos
|
||||
# ignore-apple
|
||||
#
|
||||
# This hits an assertion in the linker on older versions of osx apparently
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
include ../tools.mk
|
||||
|
||||
# ignore-windows
|
||||
# ignore-macos
|
||||
# ignore-apple
|
||||
#
|
||||
# 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
|
||||
all:
|
||||
|
@ -2,7 +2,7 @@
|
||||
include ../tools.mk
|
||||
|
||||
# ignore-windows
|
||||
# ignore-macos
|
||||
# ignore-apple
|
||||
|
||||
# Test for #39529.
|
||||
# `-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.
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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-macos
|
||||
# ignore-apple
|
||||
|
||||
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