mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Auto merge of #82953 - JohnTitor:rollup-8rtk5g2, r=JohnTitor
Rollup of 10 pull requests Successful merges: - #77511 (Add StatementKind::CopyNonOverlapping) - #79208 (Stabilize `unsafe_op_in_unsafe_fn` lint) - #82411 (Fixes to ExitStatus and its docs) - #82733 (Add powerpc-unknown-openbsd target) - #82802 (Build rustdoc for run-make tests, not just run-make-fulldeps) - #82849 (Add Option::get_or_default) - #82908 (⬆️ rust-analyzer) - #82937 (Update README.md to use the correct cmake version number) - #82938 (Bump tracing-tree dependency) - #82942 (Don't hardcode the `v1` prelude in diagnostics, to allow for new preludes.) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
861872bc45
@ -5460,9 +5460,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-tree"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a60657cfbf397c603257a8230b3f427e6a2a4e5911a59331b9bb4dffff5b608"
|
||||
checksum = "1712b40907f8d9bc2bc66763ab61dec914b7123d7149e59feb0d4e2a95fc4967"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"atty",
|
||||
|
@ -31,7 +31,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild].
|
||||
* `g++` 5.1 or later or `clang++` 3.5 or later
|
||||
* `python` 3 or 2.7
|
||||
* GNU `make` 3.81 or later
|
||||
* `cmake` 3.4.3 or later
|
||||
* `cmake` 3.13.4 or later
|
||||
* `ninja`
|
||||
* `curl`
|
||||
* `git`
|
||||
|
@ -832,6 +832,27 @@ fn codegen_stmt<'tcx>(
|
||||
}
|
||||
}
|
||||
StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
src,
|
||||
dst,
|
||||
count,
|
||||
}) => {
|
||||
let dst = codegen_operand(fx, dst);
|
||||
let pointee = dst
|
||||
.layout()
|
||||
.pointee_info_at(fx, rustc_target::abi::Size::ZERO)
|
||||
.expect("Expected pointer");
|
||||
let dst = dst.load_scalar(fx);
|
||||
let src = codegen_operand(fx, src).load_scalar(fx);
|
||||
let count = codegen_operand(fx, count).load_scalar(fx);
|
||||
let elem_size: u64 = pointee.size.bytes();
|
||||
let bytes = if elem_size != 1 {
|
||||
fx.bcx.ins().imul_imm(count, elem_size as i64)
|
||||
} else {
|
||||
count
|
||||
};
|
||||
fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#![feature(or_patterns)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![recursion_limit = "256"]
|
||||
#![feature(box_syntax)]
|
||||
|
||||
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
|
||||
//! The backend-agnostic functions of this crate use functions defined in various traits that
|
||||
|
@ -641,67 +641,73 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
return;
|
||||
}
|
||||
|
||||
if intrinsic.is_some() && intrinsic != Some(sym::drop_in_place) {
|
||||
let intrinsic = intrinsic.unwrap();
|
||||
let dest = match ret_dest {
|
||||
_ if fn_abi.ret.is_indirect() => llargs[0],
|
||||
ReturnDest::Nothing => {
|
||||
bx.const_undef(bx.type_ptr_to(bx.arg_memory_ty(&fn_abi.ret)))
|
||||
}
|
||||
ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.llval,
|
||||
ReturnDest::DirectOperand(_) => {
|
||||
bug!("Cannot use direct operand with an intrinsic call")
|
||||
}
|
||||
};
|
||||
|
||||
let args: Vec<_> = args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, arg)| {
|
||||
// The indices passed to simd_shuffle* in the
|
||||
// third argument must be constant. This is
|
||||
// checked by const-qualification, which also
|
||||
// promotes any complex rvalues to constants.
|
||||
if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") {
|
||||
if let mir::Operand::Constant(constant) = arg {
|
||||
let c = self.eval_mir_constant(constant);
|
||||
let (llval, ty) = self.simd_shuffle_indices(
|
||||
&bx,
|
||||
constant.span,
|
||||
constant.literal.ty,
|
||||
c,
|
||||
);
|
||||
return OperandRef { val: Immediate(llval), layout: bx.layout_of(ty) };
|
||||
} else {
|
||||
span_bug!(span, "shuffle indices must be constant");
|
||||
}
|
||||
match intrinsic {
|
||||
None | Some(sym::drop_in_place) => {}
|
||||
Some(sym::copy_nonoverlapping) => unreachable!(),
|
||||
Some(intrinsic) => {
|
||||
let dest = match ret_dest {
|
||||
_ if fn_abi.ret.is_indirect() => llargs[0],
|
||||
ReturnDest::Nothing => {
|
||||
bx.const_undef(bx.type_ptr_to(bx.arg_memory_ty(&fn_abi.ret)))
|
||||
}
|
||||
ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.llval,
|
||||
ReturnDest::DirectOperand(_) => {
|
||||
bug!("Cannot use direct operand with an intrinsic call")
|
||||
}
|
||||
};
|
||||
|
||||
self.codegen_operand(&mut bx, arg)
|
||||
})
|
||||
.collect();
|
||||
let args: Vec<_> = args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, arg)| {
|
||||
// The indices passed to simd_shuffle* in the
|
||||
// third argument must be constant. This is
|
||||
// checked by const-qualification, which also
|
||||
// promotes any complex rvalues to constants.
|
||||
if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") {
|
||||
if let mir::Operand::Constant(constant) = arg {
|
||||
let c = self.eval_mir_constant(constant);
|
||||
let (llval, ty) = self.simd_shuffle_indices(
|
||||
&bx,
|
||||
constant.span,
|
||||
constant.literal.ty,
|
||||
c,
|
||||
);
|
||||
return OperandRef {
|
||||
val: Immediate(llval),
|
||||
layout: bx.layout_of(ty),
|
||||
};
|
||||
} else {
|
||||
span_bug!(span, "shuffle indices must be constant");
|
||||
}
|
||||
}
|
||||
|
||||
Self::codegen_intrinsic_call(
|
||||
&mut bx,
|
||||
*instance.as_ref().unwrap(),
|
||||
&fn_abi,
|
||||
&args,
|
||||
dest,
|
||||
span,
|
||||
);
|
||||
self.codegen_operand(&mut bx, arg)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
|
||||
self.store_return(&mut bx, ret_dest, &fn_abi.ret, dst.llval);
|
||||
Self::codegen_intrinsic_call(
|
||||
&mut bx,
|
||||
*instance.as_ref().unwrap(),
|
||||
&fn_abi,
|
||||
&args,
|
||||
dest,
|
||||
span,
|
||||
);
|
||||
|
||||
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
|
||||
self.store_return(&mut bx, ret_dest, &fn_abi.ret, dst.llval);
|
||||
}
|
||||
|
||||
if let Some((_, target)) = *destination {
|
||||
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
|
||||
helper.funclet_br(self, &mut bx, target);
|
||||
} else {
|
||||
bx.unreachable();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some((_, target)) = *destination {
|
||||
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
|
||||
helper.funclet_br(self, &mut bx, target);
|
||||
} else {
|
||||
bx.unreachable();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the rust-call tupled arguments off.
|
||||
|
@ -125,19 +125,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
let offset = args[1].immediate();
|
||||
bx.gep(ptr, &[offset])
|
||||
}
|
||||
|
||||
sym::copy_nonoverlapping => {
|
||||
copy_intrinsic(
|
||||
bx,
|
||||
false,
|
||||
false,
|
||||
substs.type_at(0),
|
||||
args[1].immediate(),
|
||||
args[0].immediate(),
|
||||
args[2].immediate(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
sym::copy => {
|
||||
copy_intrinsic(
|
||||
bx,
|
||||
|
@ -115,6 +115,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
self.codegen_coverage(&mut bx, coverage.clone());
|
||||
bx
|
||||
}
|
||||
mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {
|
||||
ref src,
|
||||
ref dst,
|
||||
ref count,
|
||||
}) => {
|
||||
let dst_val = self.codegen_operand(&mut bx, dst);
|
||||
let src_val = self.codegen_operand(&mut bx, src);
|
||||
let count = self.codegen_operand(&mut bx, count).immediate();
|
||||
let pointee_layout = dst_val
|
||||
.layout
|
||||
.pointee_info_at(&mut bx, rustc_target::abi::Size::ZERO)
|
||||
.expect("Expected pointer");
|
||||
let bytes = bx.mul(count, bx.const_usize(pointee_layout.size.bytes()));
|
||||
|
||||
let align = pointee_layout.align;
|
||||
let dst = dst_val.immediate();
|
||||
let src = src_val.immediate();
|
||||
bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty());
|
||||
bx
|
||||
}
|
||||
mir::StatementKind::FakeRead(..)
|
||||
| mir::StatementKind::Retag { .. }
|
||||
| mir::StatementKind::AscribeUserType(..)
|
||||
|
@ -12,7 +12,7 @@ libc = "0.2"
|
||||
atty = "0.2"
|
||||
tracing = { version = "0.1.25" }
|
||||
tracing-subscriber = { version = "0.2.16", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
|
||||
tracing-tree = "0.1.8"
|
||||
tracing-tree = "0.1.9"
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
|
@ -275,6 +275,8 @@ declare_features! (
|
||||
(accepted, move_ref_pattern, "1.49.0", Some(68354), None),
|
||||
/// The smallest useful subset of `const_generics`.
|
||||
(accepted, min_const_generics, "1.51.0", Some(74878), None),
|
||||
/// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block.
|
||||
(accepted, unsafe_block_in_unsafe_fn, "1.51.0", Some(71668), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: accepted features
|
||||
|
@ -557,9 +557,6 @@ declare_features! (
|
||||
/// Allows the use of `#[ffi_const]` on foreign functions.
|
||||
(active, ffi_const, "1.45.0", Some(58328), None),
|
||||
|
||||
/// No longer treat an unsafe function as an unsafe block.
|
||||
(active, unsafe_block_in_unsafe_fn, "1.45.0", Some(71668), None),
|
||||
|
||||
/// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`.
|
||||
(active, abi_avr_interrupt, "1.45.0", Some(69664), None),
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
use crate::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_lint! {
|
||||
/// The `forbidden_lint_groups` lint detects violations of
|
||||
@ -2489,16 +2488,11 @@ declare_lint! {
|
||||
|
||||
declare_lint! {
|
||||
/// The `unsafe_op_in_unsafe_fn` lint detects unsafe operations in unsafe
|
||||
/// functions without an explicit unsafe block. This lint only works on
|
||||
/// the [**nightly channel**] with the
|
||||
/// `#![feature(unsafe_block_in_unsafe_fn)]` feature.
|
||||
///
|
||||
/// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
|
||||
/// functions without an explicit unsafe block.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![feature(unsafe_block_in_unsafe_fn)]
|
||||
/// #![deny(unsafe_op_in_unsafe_fn)]
|
||||
///
|
||||
/// unsafe fn foo() {}
|
||||
@ -2536,7 +2530,6 @@ declare_lint! {
|
||||
pub UNSAFE_OP_IN_UNSAFE_FN,
|
||||
Allow,
|
||||
"unsafe operations in unsafe functions without an explicit unsafe block are deprecated",
|
||||
@feature_gate = sym::unsafe_block_in_unsafe_fn;
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
|
@ -1541,6 +1541,11 @@ pub enum StatementKind<'tcx> {
|
||||
/// counter varible at runtime, each time the code region is executed.
|
||||
Coverage(Box<Coverage>),
|
||||
|
||||
/// Denotes a call to the intrinsic function copy_overlapping, where `src_dst` denotes the
|
||||
/// memory being read from and written to(one field to save memory), and size
|
||||
/// indicates how many bytes are being copied over.
|
||||
CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>),
|
||||
|
||||
/// No-op. Useful for deleting instructions without affecting statement indices.
|
||||
Nop,
|
||||
}
|
||||
@ -1659,6 +1664,13 @@ impl Debug for Statement<'_> {
|
||||
write!(fmt, "Coverage::{:?}", coverage.kind)
|
||||
}
|
||||
}
|
||||
CopyNonOverlapping(box crate::mir::CopyNonOverlapping {
|
||||
ref src,
|
||||
ref dst,
|
||||
ref count,
|
||||
}) => {
|
||||
write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count)
|
||||
}
|
||||
Nop => write!(fmt, "nop"),
|
||||
}
|
||||
}
|
||||
@ -1670,6 +1682,14 @@ pub struct Coverage {
|
||||
pub code_region: Option<CodeRegion>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
|
||||
pub struct CopyNonOverlapping<'tcx> {
|
||||
pub src: Operand<'tcx>,
|
||||
pub dst: Operand<'tcx>,
|
||||
/// Number of elements to copy from src to dest, not bytes.
|
||||
pub count: Operand<'tcx>,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Places
|
||||
|
||||
|
@ -28,11 +28,9 @@ pub enum UnsafetyViolationKind {
|
||||
BorrowPacked,
|
||||
/// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
|
||||
/// Has to be handled as a lint for backwards compatibility.
|
||||
/// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`.
|
||||
UnsafeFn,
|
||||
/// Borrow of packed field in an `unsafe fn` but outside an `unsafe` block.
|
||||
/// Has to be handled as a lint for backwards compatibility.
|
||||
/// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`.
|
||||
UnsafeFnBorrowPacked,
|
||||
}
|
||||
|
||||
|
@ -436,6 +436,15 @@ macro_rules! make_mir_visitor {
|
||||
location
|
||||
)
|
||||
}
|
||||
StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{
|
||||
ref $($mutability)? src,
|
||||
ref $($mutability)? dst,
|
||||
ref $($mutability)? count,
|
||||
}) => {
|
||||
self.visit_operand(src, location);
|
||||
self.visit_operand(dst, location);
|
||||
self.visit_operand(count, location)
|
||||
}
|
||||
StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
@ -92,6 +92,15 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
self.consume_operand(location, input);
|
||||
}
|
||||
}
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
ref src,
|
||||
ref dst,
|
||||
ref count,
|
||||
}) => {
|
||||
self.consume_operand(location, src);
|
||||
self.consume_operand(location, dst);
|
||||
self.consume_operand(location, count);
|
||||
}
|
||||
StatementKind::Nop
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
|
@ -626,6 +626,15 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc
|
||||
self.consume_operand(location, (input, span), flow_state);
|
||||
}
|
||||
}
|
||||
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
..
|
||||
}) => {
|
||||
span_bug!(
|
||||
span,
|
||||
"Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
|
||||
)
|
||||
}
|
||||
StatementKind::Nop
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
|
@ -1520,6 +1520,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
..
|
||||
}) => span_bug!(
|
||||
stmt.source_info.span,
|
||||
"Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics",
|
||||
),
|
||||
StatementKind::FakeRead(..)
|
||||
| StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
|
@ -305,6 +305,7 @@ impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
||||
| mir::StatementKind::Retag { .. }
|
||||
| mir::StatementKind::AscribeUserType(..)
|
||||
| mir::StatementKind::Coverage(..)
|
||||
| mir::StatementKind::CopyNonOverlapping(..)
|
||||
| mir::StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +149,7 @@ impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir,
|
||||
| StatementKind::FakeRead(..)
|
||||
| StatementKind::Nop
|
||||
| StatementKind::Retag(..)
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::StorageLive(..) => {}
|
||||
}
|
||||
}
|
||||
|
@ -318,6 +318,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||
StatementKind::Retag { .. }
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
@ -323,28 +323,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let result = Scalar::from_uint(truncated_bits, layout.size);
|
||||
self.write_scalar(result, dest)?;
|
||||
}
|
||||
sym::copy | sym::copy_nonoverlapping => {
|
||||
let elem_ty = instance.substs.type_at(0);
|
||||
let elem_layout = self.layout_of(elem_ty)?;
|
||||
let count = self.read_scalar(&args[2])?.to_machine_usize(self)?;
|
||||
let elem_align = elem_layout.align.abi;
|
||||
|
||||
let size = elem_layout.size.checked_mul(count, self).ok_or_else(|| {
|
||||
err_ub_format!("overflow computing total size of `{}`", intrinsic_name)
|
||||
})?;
|
||||
let src = self.read_scalar(&args[0])?.check_init()?;
|
||||
let src = self.memory.check_ptr_access(src, size, elem_align)?;
|
||||
let dest = self.read_scalar(&args[1])?.check_init()?;
|
||||
let dest = self.memory.check_ptr_access(dest, size, elem_align)?;
|
||||
|
||||
if let (Some(src), Some(dest)) = (src, dest) {
|
||||
self.memory.copy(
|
||||
src,
|
||||
dest,
|
||||
size,
|
||||
intrinsic_name == sym::copy_nonoverlapping,
|
||||
)?;
|
||||
}
|
||||
sym::copy => {
|
||||
self.copy(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?;
|
||||
}
|
||||
sym::offset => {
|
||||
let ptr = self.read_scalar(&args[0])?.check_init()?;
|
||||
|
@ -2,6 +2,7 @@
|
||||
//!
|
||||
//! The main entry point is the `step` method.
|
||||
|
||||
use crate::interpret::OpTy;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{InterpResult, Scalar};
|
||||
use rustc_target::abi::LayoutOf;
|
||||
@ -113,6 +114,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
M::retag(self, *kind, &dest)?;
|
||||
}
|
||||
|
||||
// Call CopyNonOverlapping
|
||||
CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
|
||||
let count = self.eval_operand(count, None)?;
|
||||
|
||||
let src = self.eval_operand(src, None)?;
|
||||
let dst = self.eval_operand(dst, None)?;
|
||||
self.copy(&src, &dst, &count, /* nonoverlapping */ true)?;
|
||||
}
|
||||
|
||||
// Statements we do not track.
|
||||
AscribeUserType(..) => {}
|
||||
|
||||
@ -140,6 +150,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn copy(
|
||||
&mut self,
|
||||
src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
||||
dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
||||
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
||||
nonoverlapping: bool,
|
||||
) -> InterpResult<'tcx> {
|
||||
let count = self.read_scalar(&count)?.to_machine_usize(self)?;
|
||||
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
|
||||
let (size, align) = (layout.size, layout.align.abi);
|
||||
let src =
|
||||
self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;
|
||||
|
||||
let dst =
|
||||
self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;
|
||||
|
||||
let size = size.checked_mul(count, self).ok_or_else(|| {
|
||||
err_ub_format!("overflow computing total size of `copy_nonoverlapping`")
|
||||
})?;
|
||||
|
||||
if let (Some(src), Some(dst)) = (src, dst) {
|
||||
self.memory.copy(src, dst, size, nonoverlapping)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Evaluate an assignment statement.
|
||||
///
|
||||
/// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
|
||||
|
@ -25,6 +25,7 @@ Rust MIR: a lowered representation of Rust.
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(option_expect_none)]
|
||||
#![feature(option_get_or_default)]
|
||||
#![feature(or_patterns)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(control_flow_enum)]
|
||||
|
@ -808,6 +808,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
||||
UnsafetyViolationKind::General,
|
||||
UnsafetyViolationDetails::UseOfInlineAssembly,
|
||||
),
|
||||
StatementKind::CopyNonOverlapping(..) => unreachable!(),
|
||||
}
|
||||
self.super_statement(statement, location);
|
||||
}
|
||||
@ -340,7 +341,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
||||
false
|
||||
}
|
||||
// With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s
|
||||
Safety::FnUnsafe if self.tcx.features().unsafe_block_in_unsafe_fn => {
|
||||
Safety::FnUnsafe => {
|
||||
for violation in violations {
|
||||
let mut violation = *violation;
|
||||
|
||||
@ -355,8 +356,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
||||
}
|
||||
false
|
||||
}
|
||||
// `unsafe` function bodies allow unsafe without additional unsafe blocks (before RFC 2585)
|
||||
Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
|
||||
Safety::BuiltinUnsafe => true,
|
||||
Safety::ExplicitUnsafe(hir_id) => {
|
||||
// mark unsafe block as used if there are any unsafe operations inside
|
||||
if !violations.is_empty() {
|
||||
|
@ -392,10 +392,7 @@ impl BasicCoverageBlockData {
|
||||
}
|
||||
}
|
||||
let operand = counter_kind.as_operand_id();
|
||||
if let Some(replaced) = self
|
||||
.edge_from_bcbs
|
||||
.get_or_insert_with(FxHashMap::default)
|
||||
.insert(from_bcb, counter_kind)
|
||||
if let Some(replaced) = self.edge_from_bcbs.get_or_default().insert(from_bcb, counter_kind)
|
||||
{
|
||||
Error::from_string(format!(
|
||||
"attempt to set an edge counter more than once; from_bcb: \
|
||||
|
@ -687,6 +687,7 @@ pub(super) fn filtered_statement_span(
|
||||
|
||||
// Retain spans from all other statements
|
||||
StatementKind::FakeRead(_, _) // Not including `ForGuardBinding`
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Assign(_)
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::LlvmInlineAsm(_)
|
||||
|
@ -587,6 +587,7 @@ impl Conflicts<'a> {
|
||||
| StatementKind::FakeRead(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
@ -1454,6 +1454,7 @@ impl Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
||||
| StatementKind::Retag(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,27 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
||||
terminator.kind = TerminatorKind::Goto { target };
|
||||
}
|
||||
}
|
||||
sym::copy_nonoverlapping => {
|
||||
let target = destination.unwrap().1;
|
||||
let mut args = args.drain(..);
|
||||
block.statements.push(Statement {
|
||||
source_info: terminator.source_info,
|
||||
kind: StatementKind::CopyNonOverlapping(
|
||||
box rustc_middle::mir::CopyNonOverlapping {
|
||||
src: args.next().unwrap(),
|
||||
dst: args.next().unwrap(),
|
||||
count: args.next().unwrap(),
|
||||
},
|
||||
),
|
||||
});
|
||||
assert_eq!(
|
||||
args.next(),
|
||||
None,
|
||||
"Extra argument for copy_non_overlapping intrinsic"
|
||||
);
|
||||
drop(args);
|
||||
terminator.kind = TerminatorKind::Goto { target };
|
||||
}
|
||||
sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
|
||||
if let Some((destination, target)) = *destination {
|
||||
let lhs;
|
||||
|
@ -55,6 +55,7 @@ impl RemoveNoopLandingPads {
|
||||
StatementKind::Assign { .. }
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::LlvmInlineAsm { .. }
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Retag { .. } => {
|
||||
return false;
|
||||
}
|
||||
|
@ -428,6 +428,7 @@ impl Visitor<'_> for UsedLocals {
|
||||
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
match statement.kind {
|
||||
StatementKind::LlvmInlineAsm(..)
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Retag(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::FakeRead(..)
|
||||
|
@ -294,7 +294,49 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
ref src,
|
||||
ref dst,
|
||||
ref count,
|
||||
}) => {
|
||||
let src_ty = src.ty(&self.body.local_decls, self.tcx);
|
||||
let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) {
|
||||
src_deref.ty
|
||||
} else {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Expected src to be ptr in copy_nonoverlapping, got: {}", src_ty),
|
||||
);
|
||||
return;
|
||||
};
|
||||
let dst_ty = dst.ty(&self.body.local_decls, self.tcx);
|
||||
let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) {
|
||||
dst_deref.ty
|
||||
} else {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Expected dst to be ptr in copy_nonoverlapping, got: {}", dst_ty),
|
||||
);
|
||||
return;
|
||||
};
|
||||
// since CopyNonOverlapping is parametrized by 1 type,
|
||||
// we only need to check that they are equal and not keep an extra parameter.
|
||||
if op_src_ty != op_dst_ty {
|
||||
self.fail(location, format!("bad arg ({:?} != {:?})", op_src_ty, op_dst_ty));
|
||||
}
|
||||
|
||||
let op_cnt_ty = count.ty(&self.body.local_decls, self.tcx);
|
||||
if op_cnt_ty != self.tcx.types.usize {
|
||||
self.fail(location, format!("bad arg ({:?} != usize)", op_cnt_ty))
|
||||
}
|
||||
}
|
||||
StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
| StatementKind::LlvmInlineAsm(..)
|
||||
| StatementKind::Retag(_, _)
|
||||
| StatementKind::Coverage(_)
|
||||
| StatementKind::Nop => {}
|
||||
}
|
||||
|
||||
self.super_statement(statement, location);
|
||||
|
@ -245,6 +245,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
|
||||
Retag(..) => "Retag",
|
||||
AscribeUserType(..) => "AscribeUserType",
|
||||
Coverage(..) => "Coverage",
|
||||
CopyNonOverlapping(..) => "CopyNonOverlapping",
|
||||
Nop => "Nop",
|
||||
}
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||
.lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant)
|
||||
.into_iter()
|
||||
.map(|suggestion| import_candidate_to_enum_paths(&suggestion))
|
||||
.filter(|(_, enum_ty_path)| enum_ty_path != "std::prelude::v1")
|
||||
.filter(|(_, enum_ty_path)| !enum_ty_path.starts_with("std::prelude::"))
|
||||
.collect();
|
||||
if !enum_candidates.is_empty() {
|
||||
if let (PathSource::Type, Some(span)) =
|
||||
|
@ -694,6 +694,7 @@ supported_targets! {
|
||||
("i686-unknown-openbsd", i686_unknown_openbsd),
|
||||
("sparc64-unknown-openbsd", sparc64_unknown_openbsd),
|
||||
("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
|
||||
("powerpc-unknown-openbsd", powerpc_unknown_openbsd),
|
||||
|
||||
("aarch64-unknown-netbsd", aarch64_unknown_netbsd),
|
||||
("armv6-unknown-netbsd-eabihf", armv6_unknown_netbsd_eabihf),
|
||||
|
16
compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
Normal file
16
compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use crate::abi::Endian;
|
||||
use crate::spec::Target;
|
||||
|
||||
pub fn target() -> Target {
|
||||
let mut base = super::openbsd_base::opts();
|
||||
base.endian = Endian::Big;
|
||||
base.max_atomic_width = Some(32);
|
||||
|
||||
Target {
|
||||
llvm_target: "powerpc-unknown-openbsd".to_string(),
|
||||
pointer_width: 32,
|
||||
data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
|
||||
arch: "powerpc".to_string(),
|
||||
options: base,
|
||||
}
|
||||
}
|
@ -200,7 +200,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if self.can_coerce(expr_ty, sole_field_ty) {
|
||||
let variant_path = self.tcx.def_path_str(variant.def_id);
|
||||
// FIXME #56861: DRYer prelude filtering
|
||||
Some(variant_path.trim_start_matches("std::prelude::v1::").to_string())
|
||||
if let Some(path) = variant_path.strip_prefix("std::prelude::") {
|
||||
if let Some((_, path)) = path.split_once("::") {
|
||||
return Some(path.to_string());
|
||||
}
|
||||
}
|
||||
Some(variant_path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -133,7 +133,7 @@
|
||||
#![feature(trusted_len)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unicode_internals)]
|
||||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
#![cfg_attr(bootstrap, feature(unsafe_block_in_unsafe_fn))]
|
||||
#![feature(unsize)]
|
||||
#![feature(unsized_fn_params)]
|
||||
#![feature(allocator_internals)]
|
||||
|
@ -164,8 +164,8 @@
|
||||
#![feature(const_caller_location)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(no_niche)] // rust-lang/rust#68303
|
||||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
#![feature(int_error_matching)]
|
||||
#![cfg_attr(bootstrap, feature(unsafe_block_in_unsafe_fn))]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
#[prelude_import]
|
||||
|
@ -854,6 +854,34 @@ impl<T> Option<T> {
|
||||
// Entry-like operations to insert if None and return a reference
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Inserts the default value into the option if it is [`None`], then
|
||||
/// returns a mutable reference to the contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(option_get_or_default)]
|
||||
///
|
||||
/// let mut x = None;
|
||||
///
|
||||
/// {
|
||||
/// let y: &mut u32 = x.get_or_default();
|
||||
/// assert_eq!(y, &0);
|
||||
///
|
||||
/// *y = 7;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(x, Some(7));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "option_get_or_default", issue = "82901")]
|
||||
pub fn get_or_default(&mut self) -> &mut T
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
self.get_or_insert_with(Default::default)
|
||||
}
|
||||
|
||||
/// Inserts `value` into the option if it is [`None`], then
|
||||
/// returns a mutable reference to the contained value.
|
||||
///
|
||||
|
@ -72,7 +72,6 @@
|
||||
#![feature(peekable_peek_mut)]
|
||||
#![cfg_attr(not(bootstrap), feature(ptr_metadata))]
|
||||
#![feature(once_cell)]
|
||||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
#![feature(unsized_tuple_coercion)]
|
||||
#![feature(int_bits_const)]
|
||||
#![feature(nonzero_leading_trailing_zeros)]
|
||||
@ -80,8 +79,9 @@
|
||||
#![feature(integer_atomics)]
|
||||
#![feature(slice_group_by)]
|
||||
#![feature(trusted_random_access)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![cfg_attr(bootstrap, feature(unsafe_block_in_unsafe_fn))]
|
||||
#![cfg_attr(not(bootstrap), feature(unsize))]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
|
@ -327,7 +327,7 @@
|
||||
#![feature(try_blocks)]
|
||||
#![feature(try_reserve)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
#![cfg_attr(bootstrap, feature(unsafe_block_in_unsafe_fn))]
|
||||
#![feature(unsafe_cell_raw_get)]
|
||||
#![feature(unwind_attributes)]
|
||||
#![feature(vec_into_raw_parts)]
|
||||
|
@ -885,7 +885,7 @@ impl Command {
|
||||
}
|
||||
|
||||
/// Executes a command as a child process, waiting for it to finish and
|
||||
/// collecting its exit status.
|
||||
/// collecting its status.
|
||||
///
|
||||
/// By default, stdin, stdout and stderr are inherited from the parent.
|
||||
///
|
||||
@ -899,7 +899,7 @@ impl Command {
|
||||
/// .status()
|
||||
/// .expect("failed to execute process");
|
||||
///
|
||||
/// println!("process exited with: {}", status);
|
||||
/// println!("process finished with: {}", status);
|
||||
///
|
||||
/// assert!(status.success());
|
||||
/// ```
|
||||
@ -1368,11 +1368,17 @@ impl From<fs::File> for Stdio {
|
||||
|
||||
/// Describes the result of a process after it has terminated.
|
||||
///
|
||||
/// This `struct` is used to represent the exit status of a child process.
|
||||
/// This `struct` is used to represent the exit status or other termination of a child process.
|
||||
/// Child processes are created via the [`Command`] struct and their exit
|
||||
/// status is exposed through the [`status`] method, or the [`wait`] method
|
||||
/// of a [`Child`] process.
|
||||
///
|
||||
/// An `ExitStatus` represents every possible disposition of a process. On Unix this
|
||||
/// is the **wait status**. It is *not* simply an *exit status* (a value passed to `exit`).
|
||||
///
|
||||
/// For proper error reporting of failed processes, print the value of `ExitStatus` using its
|
||||
/// implementation of [`Display`](crate::fmt::Display).
|
||||
///
|
||||
/// [`status`]: Command::status
|
||||
/// [`wait`]: Child::wait
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -1400,7 +1406,7 @@ impl ExitStatus {
|
||||
/// if status.success() {
|
||||
/// println!("'projects/' directory created");
|
||||
/// } else {
|
||||
/// println!("failed to create 'projects/' directory");
|
||||
/// println!("failed to create 'projects/' directory: {}", status);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
@ -1410,9 +1416,14 @@ impl ExitStatus {
|
||||
|
||||
/// Returns the exit code of the process, if any.
|
||||
///
|
||||
/// On Unix, this will return `None` if the process was terminated
|
||||
/// by a signal; `std::os::unix` provides an extension trait for
|
||||
/// extracting the signal and other details from the `ExitStatus`.
|
||||
/// In Unix terms the return value is the **exit status**: the value passed to `exit`, if the
|
||||
/// process finished by calling `exit`. Note that on Unix the exit status is truncated to 8
|
||||
/// bits, and that values that didn't come from a program's call to `exit` may be invented the
|
||||
/// runtime system (often, for example, 255, 254, 127 or 126).
|
||||
///
|
||||
/// On Unix, this will return `None` if the process was terminated by a signal.
|
||||
/// [`ExitStatusExt`](crate::os::unix::process::ExitStatusExt) is an
|
||||
/// extension trait for extracting any such signal, and other details, from the `ExitStatus`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -188,12 +188,20 @@ impl CommandExt for process::Command {
|
||||
|
||||
/// Unix-specific extensions to [`process::ExitStatus`].
|
||||
///
|
||||
/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as passed to the
|
||||
/// `exit` system call or returned by [`ExitStatus::code()`](crate::process::ExitStatus::code).
|
||||
/// It represents **any wait status**, as returned by one of the `wait` family of system calls.
|
||||
///
|
||||
/// This is because a Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but
|
||||
/// can also represent other kinds of process event.
|
||||
///
|
||||
/// This trait is sealed: it cannot be implemented outside the standard library.
|
||||
/// This is so that future additional methods are not breaking changes.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait ExitStatusExt: Sealed {
|
||||
/// Creates a new `ExitStatus` from the raw underlying `i32` return value of
|
||||
/// a process.
|
||||
/// Creates a new `ExitStatus` from the raw underlying integer status value from `wait`
|
||||
///
|
||||
/// The value should be a **wait status, not an exit status**.
|
||||
#[stable(feature = "exit_status_from", since = "1.12.0")]
|
||||
fn from_raw(raw: i32) -> Self;
|
||||
|
||||
@ -222,6 +230,8 @@ pub trait ExitStatusExt: Sealed {
|
||||
fn continued(&self) -> bool;
|
||||
|
||||
/// Returns the underlying raw `wait` status.
|
||||
///
|
||||
/// The returned integer is a **wait status, not an exit status**.
|
||||
#[unstable(feature = "unix_process_wait_more", issue = "80695")]
|
||||
fn into_raw(self) -> i32;
|
||||
}
|
||||
|
@ -527,9 +527,22 @@ impl fmt::Display for ExitStatus {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(code) = self.code() {
|
||||
write!(f, "exit code: {}", code)
|
||||
} else if let Some(signal) = self.signal() {
|
||||
if self.core_dumped() {
|
||||
write!(f, "signal: {} (core dumped)", signal)
|
||||
} else {
|
||||
write!(f, "signal: {}", signal)
|
||||
}
|
||||
} else if let Some(signal) = self.stopped_signal() {
|
||||
write!(f, "stopped (not terminated) by signal: {}", signal)
|
||||
} else if self.continued() {
|
||||
write!(f, "continued (WIFCONTINUED)")
|
||||
} else {
|
||||
let signal = self.signal().unwrap();
|
||||
write!(f, "signal: {}", signal)
|
||||
write!(f, "unrecognised wait status: {} {:#x}", self.0, self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "process_unix/tests.rs"]
|
||||
mod tests;
|
||||
|
30
library/std/src/sys/unix/process/process_unix/tests.rs
Normal file
30
library/std/src/sys/unix/process/process_unix/tests.rs
Normal file
@ -0,0 +1,30 @@
|
||||
#[test]
|
||||
fn exitstatus_display_tests() {
|
||||
// In practice this is the same on every Unix.
|
||||
// If some weird platform turns out to be different, and this test fails, use #[cfg].
|
||||
use crate::os::unix::process::ExitStatusExt;
|
||||
use crate::process::ExitStatus;
|
||||
|
||||
let t = |v, s| assert_eq!(s, format!("{}", <ExitStatus as ExitStatusExt>::from_raw(v)));
|
||||
|
||||
t(0x0000f, "signal: 15");
|
||||
t(0x0008b, "signal: 11 (core dumped)");
|
||||
t(0x00000, "exit code: 0");
|
||||
t(0x0ff00, "exit code: 255");
|
||||
|
||||
// On MacOS, 0x0137f is WIFCONTINUED, not WIFSTOPPED. Probably *BSD is similar.
|
||||
// https://github.com/rust-lang/rust/pull/82749#issuecomment-790525956
|
||||
// The purpose of this test is to test our string formatting, not our understanding of the wait
|
||||
// status magic numbers. So restrict these to Linux.
|
||||
if cfg!(target_os = "linux") {
|
||||
t(0x0137f, "stopped (not terminated) by signal: 19");
|
||||
t(0x0ffff, "continued (WIFCONTINUED)");
|
||||
}
|
||||
|
||||
// Testing "unrecognised wait status" is hard because the wait.h macros typically
|
||||
// assume that the value came from wait and isn't mad. With the glibc I have here
|
||||
// this works:
|
||||
if cfg!(all(target_os = "linux", target_env = "gnu")) {
|
||||
t(0x000ff, "unrecognised wait status: 255 0xff");
|
||||
}
|
||||
}
|
@ -1076,7 +1076,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
|
||||
|
||||
// Avoid depending on rustdoc when we don't need it.
|
||||
if mode == "rustdoc"
|
||||
|| (mode == "run-make" && suite.ends_with("fulldeps"))
|
||||
|| mode == "run-make"
|
||||
|| (mode == "ui" && is_rustdoc)
|
||||
|| mode == "js-doc-test"
|
||||
|| mode == "rustdoc-json"
|
||||
|
@ -198,6 +198,7 @@ target | std | host | notes
|
||||
`powerpc-unknown-linux-gnuspe` | ✓ | | PowerPC SPE Linux
|
||||
`powerpc-unknown-linux-musl` | ? | |
|
||||
`powerpc-unknown-netbsd` | ✓ | ✓ |
|
||||
`powerpc-unknown-openbsd` | ? | |
|
||||
`powerpc-wrs-vxworks` | ? | |
|
||||
`powerpc-wrs-vxworks-spe` | ? | |
|
||||
`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
|
||||
|
@ -20,7 +20,7 @@ itertools = "0.9"
|
||||
regex = "1"
|
||||
rustdoc-json-types = { path = "../rustdoc-json-types" }
|
||||
tracing = "0.1"
|
||||
tracing-tree = "0.1.6"
|
||||
tracing-tree = "0.1.9"
|
||||
|
||||
[dependencies.tracing-subscriber]
|
||||
version = "0.2.13"
|
||||
|
@ -1,6 +0,0 @@
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
//~^ ERROR the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
//~| ERROR the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
//~| ERROR the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
|
||||
fn main() {}
|
@ -1,30 +0,0 @@
|
||||
error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
--> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1
|
||||
|
|
||||
LL | #![deny(unsafe_op_in_unsafe_fn)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #71668 <https://github.com/rust-lang/rust/issues/71668> for more information
|
||||
= help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
--> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1
|
||||
|
|
||||
LL | #![deny(unsafe_op_in_unsafe_fn)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #71668 <https://github.com/rust-lang/rust/issues/71668> for more information
|
||||
= help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
--> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1
|
||||
|
|
||||
LL | #![deny(unsafe_op_in_unsafe_fn)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #71668 <https://github.com/rust-lang/rust/issues/71668> for more information
|
||||
= help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -1,4 +1,3 @@
|
||||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![deny(unused_unsafe)]
|
||||
|
||||
|
@ -1,18 +1,18 @@
|
||||
error: call to unsafe function is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:10:5
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:9:5
|
||||
|
|
||||
LL | unsf();
|
||||
| ^^^^^^ call to unsafe function
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:1:9
|
||||
|
|
||||
LL | #![deny(unsafe_op_in_unsafe_fn)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:11:5
|
||||
|
|
||||
LL | *PTR;
|
||||
| ^^^^ dereference of raw pointer
|
||||
@ -20,7 +20,7 @@ LL | *PTR;
|
||||
= note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error: use of mutable static is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:13:5
|
||||
|
|
||||
LL | VOID = ();
|
||||
| ^^^^^^^^^ use of mutable static
|
||||
@ -28,25 +28,25 @@ LL | VOID = ();
|
||||
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
|
||||
error: unnecessary `unsafe` block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:17:5
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
|
||||
|
|
||||
LL | unsafe {}
|
||||
| ^^^^^^ unnecessary `unsafe` block
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:3:9
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9
|
||||
|
|
||||
LL | #![deny(unused_unsafe)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: call to unsafe function is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:5
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5
|
||||
|
|
||||
LL | unsf();
|
||||
| ^^^^^^ call to unsafe function
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:23:8
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:8
|
||||
|
|
||||
LL | #[deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
@ -54,7 +54,7 @@ LL | #[deny(warnings)]
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5
|
||||
|
|
||||
LL | *PTR;
|
||||
| ^^^^ dereference of raw pointer
|
||||
@ -62,7 +62,7 @@ LL | *PTR;
|
||||
= note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error: use of mutable static is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
|
||||
|
|
||||
LL | VOID = ();
|
||||
| ^^^^^^^^^ use of mutable static
|
||||
@ -70,13 +70,13 @@ LL | VOID = ();
|
||||
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
|
||||
error: unnecessary `unsafe` block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5
|
||||
|
|
||||
LL | unsafe {}
|
||||
| ^^^^^^ unnecessary `unsafe` block
|
||||
|
||||
error: unnecessary `unsafe` block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:45:14
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:44:14
|
||||
|
|
||||
LL | unsafe { unsafe { unsf() } }
|
||||
| ------ ^^^^^^ unnecessary `unsafe` block
|
||||
@ -84,7 +84,7 @@ LL | unsafe { unsafe { unsf() } }
|
||||
| because it's nested under this `unsafe` block
|
||||
|
||||
error: unnecessary `unsafe` block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:56:5
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:5
|
||||
|
|
||||
LL | unsafe fn allow_level() {
|
||||
| ----------------------- because it's nested under this `unsafe` fn
|
||||
@ -93,7 +93,7 @@ LL | unsafe { unsf() }
|
||||
| ^^^^^^ unnecessary `unsafe` block
|
||||
|
||||
error: unnecessary `unsafe` block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:68:9
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:67:9
|
||||
|
|
||||
LL | unsafe fn nested_allow_level() {
|
||||
| ------------------------------ because it's nested under this `unsafe` fn
|
||||
@ -102,7 +102,7 @@ LL | unsafe { unsf() }
|
||||
| ^^^^^^ unnecessary `unsafe` block
|
||||
|
||||
error[E0133]: call to unsafe function is unsafe and requires unsafe block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:74:5
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:5
|
||||
|
|
||||
LL | unsf();
|
||||
| ^^^^^^ call to unsafe function
|
||||
@ -110,7 +110,7 @@ LL | unsf();
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:78:9
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:77:9
|
||||
|
|
||||
LL | unsf();
|
||||
| ^^^^^^ call to unsafe function
|
||||
|
@ -210,7 +210,7 @@ fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statemen
|
||||
StatementKind::Assign(box (place, rval)) => {
|
||||
check_place(tcx, *place, span, body)?;
|
||||
check_rvalue(tcx, body, def_id, rval, span)
|
||||
},
|
||||
}
|
||||
|
||||
StatementKind::FakeRead(_, place) |
|
||||
// just an assignment
|
||||
@ -218,6 +218,13 @@ fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statemen
|
||||
|
||||
StatementKind::LlvmInlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
|
||||
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping{
|
||||
dst, src, count,
|
||||
}) => {
|
||||
check_operand(tcx, dst, span, body)?;
|
||||
check_operand(tcx, src, span, body)?;
|
||||
check_operand(tcx, count, span, body)
|
||||
}
|
||||
// These are all NOPs
|
||||
StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 5df3ee8274fdb7cdeb2b0871b4efea8cbf4724a1
|
||||
Subproject commit d54e1157b66017e4aae38328cd213286e39ca130
|
Loading…
Reference in New Issue
Block a user