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:
bors 2024-05-29 03:55:21 +00:00
commit 751691271d
140 changed files with 1278 additions and 465 deletions

View File

@ -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);

View File

@ -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 {

View File

@ -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
} }

View File

@ -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(_)

View File

@ -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) => {

View File

@ -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);
} }

View File

@ -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>>

View File

@ -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>> {

View File

@ -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.

View File

@ -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).

View File

@ -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(

View File

@ -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),
) )
} }

View File

@ -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:?}")
}
} }
} }
} }

View File

@ -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();

View File

@ -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),

View File

@ -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))?;

View File

@ -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 })
} }
} }

View File

@ -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>,

View File

@ -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,

View File

@ -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,
}) })
} }
} }

View File

@ -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)]

View File

@ -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 {

View File

@ -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,

View File

@ -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)?)

View File

@ -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 };
}
_ => {} _ => {}
} }
} }

View File

@ -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)?;

View File

@ -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, _) => {

View File

@ -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:

View File

@ -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.

View File

@ -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(),

View File

@ -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 =

View File

@ -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,

View File

@ -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>>);

View File

@ -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,
} }
} }
} }

View File

@ -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,

View File

@ -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());

View File

@ -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(())
} }

View File

@ -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(),

View File

@ -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,

View File

@ -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,
} }
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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());
} }

View File

@ -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",

View File

@ -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 {

View File

@ -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,

View File

@ -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"

View 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
```

View File

@ -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",

View File

@ -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.

View File

@ -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)

View File

@ -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"

View File

@ -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)
} }
} }

View File

@ -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>>> {

View File

@ -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());
}
}

View File

@ -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

View File

@ -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());
}
}

View File

@ -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

View File

@ -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());
}
}

View File

@ -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

View File

@ -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);
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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() {

View File

@ -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.

View File

@ -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"]

View File

@ -1,6 +1,6 @@
// //
//@ ignore-windows //@ ignore-windows
//@ ignore-macos //@ ignore-apple
//@ ignore-wasm //@ ignore-wasm
//@ ignore-emscripten //@ ignore-emscripten

View File

@ -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)

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

View File

@ -1,5 +1,5 @@
// //
//@ only-macos //@ only-apple
//@ compile-flags: -O //@ compile-flags: -O
#![crate_type = "rlib"] #![crate_type = "rlib"]

View File

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

View File

@ -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

View File

@ -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

View 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;
}
}

View File

@ -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()
})
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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.

View File

@ -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)

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

View File

@ -1,4 +1,4 @@
# only-macos # only-apple
include ../tools.mk include ../tools.mk

View File

@ -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)

View 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");
}

View File

@ -1,5 +1,5 @@
# ignore-cross-compile # ignore-cross-compile
# ignore-macos # ignore-apple
include ../tools.mk include ../tools.mk

View File

@ -0,0 +1 @@
// empty crate

Some files were not shown because too many files have changed in this diff Show More