mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 22:41:50 +00:00
Auto merge of #103513 - Dylan-DPC:rollup-nn3ite2, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #98204 (Stabilize `Option::unzip()`) - #102587 (rustc: Use `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler`) - #103122 (Remove misc_cast and validate types when casting) - #103379 (Truncate thread names on Linux and Apple targets) - #103482 (Clairify Vec::capacity docs) - #103511 (Codegen tweaks) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c6bd7e21c6
@ -1,3 +1,5 @@
|
||||
#![feature(unix_sigpipe)]
|
||||
|
||||
// A note about jemalloc: rustc uses jemalloc when built for CI and
|
||||
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
||||
// mechanism. However, for complicated reasons (see
|
||||
@ -23,6 +25,7 @@
|
||||
// libraries. So we must reference jemalloc symbols one way or another, because
|
||||
// this file is the only object code in the rustc executable.
|
||||
|
||||
#[unix_sigpipe = "sig_dfl"]
|
||||
fn main() {
|
||||
// See the comment at the top of this file for an explanation of this.
|
||||
#[cfg(feature = "jemalloc-sys")]
|
||||
@ -58,6 +61,5 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
rustc_driver::set_sigpipe_handler();
|
||||
rustc_driver::main()
|
||||
}
|
||||
|
@ -337,40 +337,26 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
|
||||
pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
op: hir::BinOpKind,
|
||||
lhs: Bx::Value,
|
||||
rhs: Bx::Value,
|
||||
) -> Bx::Value {
|
||||
cast_shift_rhs(bx, op, lhs, rhs)
|
||||
}
|
||||
|
||||
fn cast_shift_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
op: hir::BinOpKind,
|
||||
lhs: Bx::Value,
|
||||
rhs: Bx::Value,
|
||||
) -> Bx::Value {
|
||||
// Shifts may have any size int on the rhs
|
||||
if op.is_shift() {
|
||||
let mut rhs_llty = bx.cx().val_ty(rhs);
|
||||
let mut lhs_llty = bx.cx().val_ty(lhs);
|
||||
if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
|
||||
rhs_llty = bx.cx().element_type(rhs_llty)
|
||||
}
|
||||
if bx.cx().type_kind(lhs_llty) == TypeKind::Vector {
|
||||
lhs_llty = bx.cx().element_type(lhs_llty)
|
||||
}
|
||||
let rhs_sz = bx.cx().int_width(rhs_llty);
|
||||
let lhs_sz = bx.cx().int_width(lhs_llty);
|
||||
if lhs_sz < rhs_sz {
|
||||
bx.trunc(rhs, lhs_llty)
|
||||
} else if lhs_sz > rhs_sz {
|
||||
// FIXME (#1877: If in the future shifting by negative
|
||||
// values is no longer undefined then this is wrong.
|
||||
bx.zext(rhs, lhs_llty)
|
||||
} else {
|
||||
rhs
|
||||
}
|
||||
let mut rhs_llty = bx.cx().val_ty(rhs);
|
||||
let mut lhs_llty = bx.cx().val_ty(lhs);
|
||||
if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
|
||||
rhs_llty = bx.cx().element_type(rhs_llty)
|
||||
}
|
||||
if bx.cx().type_kind(lhs_llty) == TypeKind::Vector {
|
||||
lhs_llty = bx.cx().element_type(lhs_llty)
|
||||
}
|
||||
let rhs_sz = bx.cx().int_width(rhs_llty);
|
||||
let lhs_sz = bx.cx().int_width(lhs_llty);
|
||||
if lhs_sz < rhs_sz {
|
||||
bx.trunc(rhs, lhs_llty)
|
||||
} else if lhs_sz > rhs_sz {
|
||||
// FIXME (#1877: If in the future shifting by negative
|
||||
// values is no longer undefined then this is wrong.
|
||||
bx.zext(rhs, lhs_llty)
|
||||
} else {
|
||||
rhs
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_middle::mir::interpret::ConstValue;
|
||||
use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
|
||||
@ -140,7 +139,7 @@ pub fn build_unchecked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
lhs: Bx::Value,
|
||||
rhs: Bx::Value,
|
||||
) -> Bx::Value {
|
||||
let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shl, lhs, rhs);
|
||||
let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
|
||||
// #1877, #10183: Ensure that input is always valid
|
||||
let rhs = shift_mask_rhs(bx, rhs);
|
||||
bx.shl(lhs, rhs)
|
||||
@ -152,7 +151,7 @@ pub fn build_unchecked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
lhs: Bx::Value,
|
||||
rhs: Bx::Value,
|
||||
) -> Bx::Value {
|
||||
let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shr, lhs, rhs);
|
||||
let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
|
||||
// #1877, #10183: Ensure that input is always valid
|
||||
let rhs = shift_mask_rhs(bx, rhs);
|
||||
let is_signed = lhs_t.is_signed();
|
||||
|
@ -63,7 +63,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lltarget<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
/// Get a basic block (creating it if necessary), possibly with a landing
|
||||
/// pad next to it.
|
||||
fn llbb_with_landing_pad<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
&self,
|
||||
fx: &mut FunctionCx<'a, 'tcx, Bx>,
|
||||
target: mir::BasicBlock,
|
||||
@ -73,32 +75,36 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
let target_funclet = fx.cleanup_kinds[target].funclet_bb(target);
|
||||
match (self.funclet_bb, target_funclet) {
|
||||
(None, None) => (lltarget, false),
|
||||
(Some(f), Some(t_f)) if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) => {
|
||||
(lltarget, false)
|
||||
}
|
||||
// jump *into* cleanup - need a landing pad if GNU, cleanup pad if MSVC
|
||||
(None, Some(_)) => (fx.landing_pad_for(target), false),
|
||||
(Some(_), None) => span_bug!(span, "{:?} - jump out of cleanup?", self.terminator),
|
||||
(Some(_), Some(_)) => (fx.landing_pad_for(target), true),
|
||||
(Some(f), Some(t_f)) => {
|
||||
if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) {
|
||||
(lltarget, false)
|
||||
} else {
|
||||
(fx.landing_pad_for(target), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a basic block.
|
||||
fn llblock<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
/// Get a basic block (creating it if necessary), possibly with cleanup
|
||||
/// stuff in it or next to it.
|
||||
fn llbb_with_cleanup<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
&self,
|
||||
fx: &mut FunctionCx<'a, 'tcx, Bx>,
|
||||
target: mir::BasicBlock,
|
||||
) -> Bx::BasicBlock {
|
||||
let (lltarget, is_cleanupret) = self.lltarget(fx, target);
|
||||
let (lltarget, is_cleanupret) = self.llbb_with_landing_pad(fx, target);
|
||||
if is_cleanupret {
|
||||
// MSVC cross-funclet jump - need a trampoline
|
||||
|
||||
debug!("llblock: creating cleanup trampoline for {:?}", target);
|
||||
debug_assert!(base::wants_msvc_seh(fx.cx.tcx().sess));
|
||||
debug!("llbb_with_cleanup: creating cleanup trampoline for {:?}", target);
|
||||
let name = &format!("{:?}_cleanup_trampoline_{:?}", self.bb, target);
|
||||
let trampoline = Bx::append_block(fx.cx, fx.llfn, name);
|
||||
let mut trampoline_bx = Bx::build(fx.cx, trampoline);
|
||||
let trampoline_llbb = Bx::append_block(fx.cx, fx.llfn, name);
|
||||
let mut trampoline_bx = Bx::build(fx.cx, trampoline_llbb);
|
||||
trampoline_bx.cleanup_ret(self.funclet(fx).unwrap(), Some(lltarget));
|
||||
trampoline
|
||||
trampoline_llbb
|
||||
} else {
|
||||
lltarget
|
||||
}
|
||||
@ -110,10 +116,11 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
bx: &mut Bx,
|
||||
target: mir::BasicBlock,
|
||||
) {
|
||||
let (lltarget, is_cleanupret) = self.lltarget(fx, target);
|
||||
let (lltarget, is_cleanupret) = self.llbb_with_landing_pad(fx, target);
|
||||
if is_cleanupret {
|
||||
// micro-optimization: generate a `ret` rather than a jump
|
||||
// MSVC micro-optimization: generate a `ret` rather than a jump
|
||||
// to a trampoline.
|
||||
debug_assert!(base::wants_msvc_seh(fx.cx.tcx().sess));
|
||||
bx.cleanup_ret(self.funclet(fx).unwrap(), Some(lltarget));
|
||||
} else {
|
||||
bx.br(lltarget);
|
||||
@ -138,7 +145,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||
|
||||
let unwind_block = if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) {
|
||||
Some(self.llblock(fx, cleanup))
|
||||
Some(self.llbb_with_cleanup(fx, cleanup))
|
||||
} else if fx.mir[self.bb].is_cleanup
|
||||
&& fn_abi.can_unwind
|
||||
&& !base::wants_msvc_seh(fx.cx.tcx().sess)
|
||||
@ -231,7 +238,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
options,
|
||||
line_spans,
|
||||
instance,
|
||||
Some((ret_llbb, self.llblock(fx, cleanup), self.funclet(fx))),
|
||||
Some((ret_llbb, self.llbb_with_cleanup(fx, cleanup), self.funclet(fx))),
|
||||
);
|
||||
} else {
|
||||
bx.codegen_inline_asm(template, &operands, options, line_spans, instance, None);
|
||||
@ -281,8 +288,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
if target_iter.len() == 1 {
|
||||
// If there are two targets (one conditional, one fallback), emit br instead of switch
|
||||
let (test_value, target) = target_iter.next().unwrap();
|
||||
let lltrue = helper.llblock(self, target);
|
||||
let llfalse = helper.llblock(self, targets.otherwise());
|
||||
let lltrue = helper.llbb_with_cleanup(self, target);
|
||||
let llfalse = helper.llbb_with_cleanup(self, targets.otherwise());
|
||||
if switch_ty == bx.tcx().types.bool {
|
||||
// Don't generate trivial icmps when switching on bool
|
||||
match test_value {
|
||||
@ -299,8 +306,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
} else {
|
||||
bx.switch(
|
||||
discr.immediate(),
|
||||
helper.llblock(self, targets.otherwise()),
|
||||
target_iter.map(|(value, target)| (value, helper.llblock(self, target))),
|
||||
helper.llbb_with_cleanup(self, targets.otherwise()),
|
||||
target_iter.map(|(value, target)| (value, helper.llbb_with_cleanup(self, target))),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -530,7 +537,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
let cond = bx.expect(cond, expected);
|
||||
|
||||
// Create the failure block and the conditional branch to it.
|
||||
let lltarget = helper.llblock(self, target);
|
||||
let lltarget = helper.llbb_with_cleanup(self, target);
|
||||
let panic_block = bx.append_sibling_block("panic");
|
||||
if expected {
|
||||
bx.cond_br(cond, lltarget, panic_block);
|
||||
@ -1459,20 +1466,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
// bar();
|
||||
// }
|
||||
Some(&mir::TerminatorKind::Abort) => {
|
||||
let cs_bb =
|
||||
let cs_llbb =
|
||||
Bx::append_block(self.cx, self.llfn, &format!("cs_funclet{:?}", bb));
|
||||
let cp_bb =
|
||||
let cp_llbb =
|
||||
Bx::append_block(self.cx, self.llfn, &format!("cp_funclet{:?}", bb));
|
||||
ret_llbb = cs_bb;
|
||||
ret_llbb = cs_llbb;
|
||||
|
||||
let mut cs_bx = Bx::build(self.cx, cs_bb);
|
||||
let cs = cs_bx.catch_switch(None, None, &[cp_bb]);
|
||||
let mut cs_bx = Bx::build(self.cx, cs_llbb);
|
||||
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
|
||||
|
||||
// The "null" here is actually a RTTI type descriptor for the
|
||||
// C++ personality function, but `catch (...)` has no type so
|
||||
// it's null. The 64 here is actually a bitfield which
|
||||
// represents that this is a catch-all block.
|
||||
let mut cp_bx = Bx::build(self.cx, cp_bb);
|
||||
let mut cp_bx = Bx::build(self.cx, cp_llbb);
|
||||
let null = cp_bx.const_null(
|
||||
cp_bx.type_i8p_ext(cp_bx.cx().data_layout().instruction_address_space),
|
||||
);
|
||||
@ -1481,10 +1488,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
cp_bx.br(llbb);
|
||||
}
|
||||
_ => {
|
||||
let cleanup_bb =
|
||||
let cleanup_llbb =
|
||||
Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb));
|
||||
ret_llbb = cleanup_bb;
|
||||
let mut cleanup_bx = Bx::build(self.cx, cleanup_bb);
|
||||
ret_llbb = cleanup_llbb;
|
||||
let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
|
||||
funclet = cleanup_bx.cleanup_pad(None, &[]);
|
||||
cleanup_bx.br(llbb);
|
||||
}
|
||||
@ -1492,19 +1499,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
self.funclets[bb] = Some(funclet);
|
||||
ret_llbb
|
||||
} else {
|
||||
let bb = Bx::append_block(self.cx, self.llfn, "cleanup");
|
||||
let mut bx = Bx::build(self.cx, bb);
|
||||
let cleanup_llbb = Bx::append_block(self.cx, self.llfn, "cleanup");
|
||||
let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
|
||||
|
||||
let llpersonality = self.cx.eh_personality();
|
||||
let llretty = self.landing_pad_type();
|
||||
let lp = bx.cleanup_landing_pad(llretty, llpersonality);
|
||||
let lp = cleanup_bx.cleanup_landing_pad(llretty, llpersonality);
|
||||
|
||||
let slot = self.get_personality_slot(&mut bx);
|
||||
slot.storage_live(&mut bx);
|
||||
Pair(bx.extract_value(lp, 0), bx.extract_value(lp, 1)).store(&mut bx, slot);
|
||||
let slot = self.get_personality_slot(&mut cleanup_bx);
|
||||
slot.storage_live(&mut cleanup_bx);
|
||||
Pair(cleanup_bx.extract_value(lp, 0), cleanup_bx.extract_value(lp, 1))
|
||||
.store(&mut cleanup_bx, slot);
|
||||
|
||||
bx.br(llbb);
|
||||
bx.llbb()
|
||||
cleanup_bx.br(llbb);
|
||||
cleanup_llbb
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,10 +148,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, &mir);
|
||||
|
||||
let start_llbb = Bx::append_block(cx, llfn, "start");
|
||||
let mut bx = Bx::build(cx, start_llbb);
|
||||
let mut start_bx = Bx::build(cx, start_llbb);
|
||||
|
||||
if mir.basic_blocks.iter().any(|bb| bb.is_cleanup) {
|
||||
bx.set_personality_fn(cx.eh_personality());
|
||||
start_bx.set_personality_fn(cx.eh_personality());
|
||||
}
|
||||
|
||||
let cleanup_kinds = analyze::cleanup_kinds(&mir);
|
||||
@ -180,7 +180,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
caller_location: None,
|
||||
};
|
||||
|
||||
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx);
|
||||
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
|
||||
|
||||
// Evaluate all required consts; codegen later assumes that CTFE will never fail.
|
||||
let mut all_consts_ok = true;
|
||||
@ -206,29 +206,29 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
|
||||
// Allocate variable and temp allocas
|
||||
fx.locals = {
|
||||
let args = arg_local_refs(&mut bx, &mut fx, &memory_locals);
|
||||
let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals);
|
||||
|
||||
let mut allocate_local = |local| {
|
||||
let decl = &mir.local_decls[local];
|
||||
let layout = bx.layout_of(fx.monomorphize(decl.ty));
|
||||
let layout = start_bx.layout_of(fx.monomorphize(decl.ty));
|
||||
assert!(!layout.ty.has_erasable_regions());
|
||||
|
||||
if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
|
||||
debug!("alloc: {:?} (return place) -> place", local);
|
||||
let llretptr = bx.get_param(0);
|
||||
let llretptr = start_bx.get_param(0);
|
||||
return LocalRef::Place(PlaceRef::new_sized(llretptr, layout));
|
||||
}
|
||||
|
||||
if memory_locals.contains(local) {
|
||||
debug!("alloc: {:?} -> place", local);
|
||||
if layout.is_unsized() {
|
||||
LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut bx, layout))
|
||||
LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut start_bx, layout))
|
||||
} else {
|
||||
LocalRef::Place(PlaceRef::alloca(&mut bx, layout))
|
||||
LocalRef::Place(PlaceRef::alloca(&mut start_bx, layout))
|
||||
}
|
||||
} else {
|
||||
debug!("alloc: {:?} -> operand", local);
|
||||
LocalRef::new_operand(&mut bx, layout)
|
||||
LocalRef::new_operand(&mut start_bx, layout)
|
||||
}
|
||||
};
|
||||
|
||||
@ -240,7 +240,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
};
|
||||
|
||||
// Apply debuginfo to the newly allocated locals.
|
||||
fx.debug_introduce_locals(&mut bx);
|
||||
fx.debug_introduce_locals(&mut start_bx);
|
||||
|
||||
// Codegen the body of each block using reverse postorder
|
||||
for (bb, _) in traversal::reverse_postorder(&mir) {
|
||||
|
@ -42,10 +42,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
}
|
||||
// FIXME: We shouldn't use `misc_cast` for these but handle them separately.
|
||||
IntToInt | FloatToInt | FloatToFloat | IntToFloat | FnPtrToPtr | PtrToPtr => {
|
||||
|
||||
IntToInt | IntToFloat => {
|
||||
let src = self.read_immediate(src)?;
|
||||
let res = self.misc_cast(&src, cast_ty)?;
|
||||
let res = self.int_to_int_or_float(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
}
|
||||
|
||||
FloatToFloat | FloatToInt => {
|
||||
let src = self.read_immediate(src)?;
|
||||
let res = self.float_to_float_or_int(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
}
|
||||
|
||||
FnPtrToPtr | PtrToPtr => {
|
||||
let src = self.read_immediate(&src)?;
|
||||
let res = self.ptr_to_ptr(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
}
|
||||
|
||||
@ -126,13 +138,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn misc_cast(
|
||||
pub fn int_to_int_or_float(
|
||||
&mut self,
|
||||
src: &ImmTy<'tcx, M::Provenance>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
|
||||
if (src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool())
|
||||
&& (cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char())
|
||||
{
|
||||
let scalar = src.to_scalar();
|
||||
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
|
||||
} else {
|
||||
bug!("Unexpected cast from type {:?}", src.layout.ty)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn float_to_float_or_int(
|
||||
&mut self,
|
||||
src: &ImmTy<'tcx, M::Provenance>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
|
||||
use rustc_type_ir::sty::TyKind::*;
|
||||
trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty);
|
||||
|
||||
match src.layout.ty.kind() {
|
||||
// Floating point
|
||||
@ -142,19 +168,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Float(FloatTy::F64) => {
|
||||
return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into());
|
||||
}
|
||||
// The rest is integer/pointer-"like", including fn ptr casts
|
||||
_ => assert!(
|
||||
src.layout.ty.is_bool()
|
||||
|| src.layout.ty.is_char()
|
||||
|| src.layout.ty.is_integral()
|
||||
|| src.layout.ty.is_any_ptr(),
|
||||
"Unexpected cast from type {:?}",
|
||||
src.layout.ty
|
||||
),
|
||||
_ => {
|
||||
bug!("Can't cast 'Float' type into {:?}", cast_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// # First handle non-scalar source values.
|
||||
|
||||
/// Handles 'FnPtrToPtr' and 'PtrToPtr' casts.
|
||||
pub fn ptr_to_ptr(
|
||||
&mut self,
|
||||
src: &ImmTy<'tcx, M::Provenance>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
|
||||
// Handle casting any ptr to raw ptr (might be a fat ptr).
|
||||
if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() {
|
||||
let dest_layout = self.layout_of(cast_ty)?;
|
||||
@ -178,11 +203,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
bug!("Can't cast 'Ptr' or 'FnPtr' into {:?}", cast_ty);
|
||||
}
|
||||
|
||||
// # The remaining source values are scalar and "int-like".
|
||||
let scalar = src.to_scalar();
|
||||
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
|
||||
}
|
||||
|
||||
pub fn pointer_expose_address_cast(
|
||||
|
@ -556,21 +556,36 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..));
|
||||
}
|
||||
Rvalue::Cast(kind, operand, target_type) => {
|
||||
let op_ty = operand.ty(self.body, self.tcx);
|
||||
match kind {
|
||||
CastKind::DynStar => {
|
||||
// FIXME(dyn-star): make sure nothing needs to be done here.
|
||||
}
|
||||
// Nothing to check here
|
||||
// FIXME: Add Checks for these
|
||||
CastKind::PointerFromExposedAddress
|
||||
| CastKind::PointerExposeAddress
|
||||
| CastKind::Pointer(_) => {}
|
||||
_ => {
|
||||
let op_ty = operand.ty(self.body, self.tcx);
|
||||
if op_ty.is_enum() {
|
||||
CastKind::IntToInt | CastKind::IntToFloat => {
|
||||
let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool();
|
||||
let target_valid = target_type.is_numeric() || target_type.is_char();
|
||||
if !input_valid || !target_valid {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Wrong cast kind {kind:?} for the type {op_ty}",),
|
||||
);
|
||||
}
|
||||
}
|
||||
CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
|
||||
if !(op_ty.is_any_ptr() && target_type.is_unsafe_ptr()) {
|
||||
self.fail(location, "Can't cast {op_ty} into 'Ptr'");
|
||||
}
|
||||
}
|
||||
CastKind::FloatToFloat | CastKind::FloatToInt => {
|
||||
if !op_ty.is_floating_point() || !target_type.is_numeric() {
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"enum -> int casts should go through `Rvalue::Discriminant`: {operand:?}:{op_ty} as {target_type}",
|
||||
"Trying to cast non 'Float' as {kind:?} into {target_type:?}"
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -868,13 +868,14 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
(ptr, len, capacity, alloc)
|
||||
}
|
||||
|
||||
/// Returns the number of elements the vector can hold without
|
||||
/// Returns the total number of elements the vector can hold without
|
||||
/// reallocating.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let vec: Vec<i32> = Vec::with_capacity(10);
|
||||
/// let mut vec: Vec<i32> = Vec::with_capacity(10);
|
||||
/// vec.push(42);
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
|
@ -1713,8 +1713,6 @@ impl<T, U> Option<(T, U)> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(unzip_option)]
|
||||
///
|
||||
/// let x = Some((1, "hi"));
|
||||
/// let y = None::<(u8, u32)>;
|
||||
///
|
||||
@ -1722,8 +1720,13 @@ impl<T, U> Option<(T, U)> {
|
||||
/// assert_eq!(y.unzip(), (None, None));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "unzip_option", issue = "87800", reason = "recently added")]
|
||||
pub const fn unzip(self) -> (Option<T>, Option<U>) {
|
||||
#[stable(feature = "unzip_option", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_unstable(feature = "const_option", issue = "67441")]
|
||||
pub const fn unzip(self) -> (Option<T>, Option<U>)
|
||||
where
|
||||
T: ~const Destruct,
|
||||
U: ~const Destruct,
|
||||
{
|
||||
match self {
|
||||
Some((a, b)) => (Some(a), Some(b)),
|
||||
None => (None, None),
|
||||
|
@ -95,7 +95,6 @@
|
||||
#![feature(strict_provenance_atomic_ptr)]
|
||||
#![feature(trusted_random_access)]
|
||||
#![feature(unsize)]
|
||||
#![feature(unzip_option)]
|
||||
#![feature(const_array_from_ref)]
|
||||
#![feature(const_slice_from_ref)]
|
||||
#![feature(waker_getters)]
|
||||
|
@ -132,8 +132,11 @@ impl Thread {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
const TASK_COMM_LEN: usize = 16;
|
||||
|
||||
unsafe {
|
||||
// Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20.
|
||||
let name = truncate_cstr(name, TASK_COMM_LEN);
|
||||
libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
|
||||
}
|
||||
}
|
||||
@ -148,6 +151,7 @@ impl Thread {
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
let name = truncate_cstr(name, libc::MAXTHREADNAMESIZE);
|
||||
libc::pthread_setname_np(name.as_ptr());
|
||||
}
|
||||
}
|
||||
@ -276,6 +280,20 @@ impl Drop for Thread {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))]
|
||||
fn truncate_cstr(cstr: &CStr, max_with_nul: usize) -> crate::borrow::Cow<'_, CStr> {
|
||||
use crate::{borrow::Cow, ffi::CString};
|
||||
|
||||
if cstr.to_bytes_with_nul().len() > max_with_nul {
|
||||
let bytes = cstr.to_bytes()[..max_with_nul - 1].to_vec();
|
||||
// SAFETY: the non-nul bytes came straight from a CStr.
|
||||
// (CString will add the terminating nul.)
|
||||
Cow::Owned(unsafe { CString::from_vec_unchecked(bytes) })
|
||||
} else {
|
||||
Cow::Borrowed(cstr)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(
|
||||
|
@ -37,6 +37,37 @@ fn test_named_thread() {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
// Note: musl didn't add pthread_getname_np until 1.2.3
|
||||
all(target_os = "linux", target_env = "gnu"),
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "watchos"
|
||||
))]
|
||||
#[test]
|
||||
fn test_named_thread_truncation() {
|
||||
use crate::ffi::CStr;
|
||||
|
||||
let long_name = crate::iter::once("test_named_thread_truncation")
|
||||
.chain(crate::iter::repeat(" yada").take(100))
|
||||
.collect::<String>();
|
||||
|
||||
let result = Builder::new().name(long_name.clone()).spawn(move || {
|
||||
// Rust remembers the full thread name itself.
|
||||
assert_eq!(thread::current().name(), Some(long_name.as_str()));
|
||||
|
||||
// But the system is limited -- make sure we successfully set a truncation.
|
||||
let mut buf = vec![0u8; long_name.len() + 1];
|
||||
unsafe {
|
||||
libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len());
|
||||
}
|
||||
let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
|
||||
assert!(cstr.to_bytes().len() > 0);
|
||||
assert!(long_name.as_bytes().starts_with(cstr.to_bytes()));
|
||||
});
|
||||
result.unwrap().join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_invalid_named_thread() {
|
||||
|
@ -437,13 +437,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) {
|
||||
// Int-to-(int|float): always safe
|
||||
(ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) =>
|
||||
this.misc_cast(&op, dest.layout.ty)?,
|
||||
this.int_to_int_or_float(&op, dest.layout.ty)?,
|
||||
// Float-to-float: always safe
|
||||
(ty::Float(_), ty::Float(_)) =>
|
||||
this.misc_cast(&op, dest.layout.ty)?,
|
||||
this.float_to_float_or_int(&op, dest.layout.ty)?,
|
||||
// Float-to-int in safe mode
|
||||
(ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast =>
|
||||
this.misc_cast(&op, dest.layout.ty)?,
|
||||
this.float_to_float_or_int(&op, dest.layout.ty)?,
|
||||
// Float-to-int in unchecked mode
|
||||
(ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast =>
|
||||
this.float_to_int_unchecked(op.to_scalar().to_f32()?, dest.layout.ty)?.into(),
|
||||
|
Loading…
Reference in New Issue
Block a user