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:
bors 2021-03-10 01:25:43 +00:00
commit 861872bc45
56 changed files with 441 additions and 191 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -149,6 +149,7 @@ impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir,
| StatementKind::FakeRead(..)
| StatementKind::Nop
| StatementKind::Retag(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::StorageLive(..) => {}
}
}

View File

@ -318,6 +318,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Nop => {}
}
}

View File

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

View File

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

View File

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

View File

@ -808,6 +808,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
| StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Nop => {}
}
}

View File

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

View File

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

View File

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

View File

@ -587,6 +587,7 @@ impl Conflicts<'a> {
| StatementKind::FakeRead(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Nop => {}
}
}

View File

@ -1454,6 +1454,7 @@ impl Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
| StatementKind::Retag(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Nop => {}
}
}

View File

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

View File

@ -55,6 +55,7 @@ impl RemoveNoopLandingPads {
StatementKind::Assign { .. }
| StatementKind::SetDiscriminant { .. }
| StatementKind::LlvmInlineAsm { .. }
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Retag { .. } => {
return false;
}

View File

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

View File

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

View File

@ -245,6 +245,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
Retag(..) => "Retag",
AscribeUserType(..) => "AscribeUserType",
Coverage(..) => "Coverage",
CopyNonOverlapping(..) => "CopyNonOverlapping",
Nop => "Nop",
}
}

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,3 @@
#![feature(unsafe_block_in_unsafe_fn)]
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(unused_unsafe)]

View File

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

View File

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