diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 6569bdabf115..d7bad33e62b2 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -892,6 +892,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`mem_replace_option_with_some`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_some) * [`mem_replace_with_default`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default) * [`missing_const_for_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn) +* [`multiple_unsafe_ops_per_block`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_unsafe_ops_per_block) * [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) * [`non_std_lazy_statics`](https://rust-lang.github.io/rust-clippy/master/index.html#non_std_lazy_statics) * [`option_as_ref_deref`](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 2a042e6c3d85..e04d0a3e4f23 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -781,6 +781,7 @@ define_Conf! { mem_replace_option_with_some, mem_replace_with_default, missing_const_for_fn, + multiple_unsafe_ops_per_block, needless_borrow, non_std_lazy_statics, option_as_ref_deref, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4542105d3277..bd6c50cbc454 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -765,7 +765,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(move |_| Box::new(semicolon_block::SemicolonBlock::new(conf))), Box::new(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)), Box::new(|_| Box::new(size_of_ref::SizeOfRef)), - Box::new(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock)), + Box::new(move |_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock::new(conf))), Box::new(move |_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters::new(conf))), Box::new(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi)), Box::new(|_| Box::new(collection_is_never_read::CollectionIsNeverRead)), diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index bc5e72270f4e..34b32142d571 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -1,14 +1,16 @@ -use clippy_utils::desugar_await; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::visitors::{Descend, Visitable, for_each_expr}; -use core::ops::ControlFlow::Continue; +use clippy_utils::msrvs::Msrv; +use clippy_utils::{desugar_await, msrvs}; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, UnOp}; -use rustc_ast::Mutability; +use rustc_ast::{BorrowKind, Mutability}; use rustc_hir as hir; +use rustc_hir::intravisit::{Visitor, walk_body, walk_expr}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::declare_lint_pass; +use rustc_middle::hir::nested_filter; +use rustc_middle::ty::{self, TypeckResults}; +use rustc_session::impl_lint_pass; use rustc_span::{DesugaringKind, Span}; declare_clippy_lint! { @@ -60,7 +62,18 @@ declare_clippy_lint! { restriction, "more than one unsafe operation per `unsafe` block" } -declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]); + +pub struct MultipleUnsafeOpsPerBlock { + msrv: Msrv, +} + +impl_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]); + +impl MultipleUnsafeOpsPerBlock { + pub fn new(conf: &Conf) -> Self { + Self { msrv: conf.msrv } + } +} impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { @@ -70,8 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { { return; } - let mut unsafe_ops = vec![]; - collect_unsafe_exprs(cx, block, &mut unsafe_ops); + let unsafe_ops = UnsafeExprCollector::collect_unsafe_exprs(cx, block, self.msrv); if unsafe_ops.len() > 1 { span_lint_and_then( cx, @@ -91,25 +103,77 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { } } -fn collect_unsafe_exprs<'tcx>( - cx: &LateContext<'tcx>, - node: impl Visitable<'tcx>, - unsafe_ops: &mut Vec<(&'static str, Span)>, -) { - for_each_expr(cx, node, |expr| { +#[derive(Clone, Copy)] +enum UnderRawPtr { + /// The expression is not located under a raw pointer + No, + /// The expression is located under a raw pointer, MSRV yet unknown + Yes, + /// The expression is located under a raw pointer and MSRV has been determined. + /// `true` means that taking a raw pointer to a union field is a safe operation. + WithSafeMsrv(bool), +} + +struct UnsafeExprCollector<'cx, 'tcx> { + cx: &'cx LateContext<'tcx>, + typeck_results: &'tcx TypeckResults<'tcx>, + msrv: Msrv, + unsafe_ops: Vec<(&'static str, Span)>, + under_raw_ptr: UnderRawPtr, +} + +impl<'cx, 'tcx> UnsafeExprCollector<'cx, 'tcx> { + fn collect_unsafe_exprs( + cx: &'cx LateContext<'tcx>, + block: &'tcx hir::Block<'tcx>, + msrv: Msrv, + ) -> Vec<(&'static str, Span)> { + let mut collector = Self { + cx, + typeck_results: cx.typeck_results(), + msrv, + unsafe_ops: vec![], + under_raw_ptr: UnderRawPtr::No, + }; + collector.visit_block(block); + collector.unsafe_ops + } +} + +impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'_, 'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + // `self.under_raw_ptr` is preventively reset, while the current value is + // preserved in `under_raw_ptr`. + let under_raw_ptr = self.under_raw_ptr; + self.under_raw_ptr = UnderRawPtr::No; + match expr.kind { // The `await` itself will desugar to two unsafe calls, but we should ignore those. // Instead, check the expression that is `await`ed _ if let Some(e) = desugar_await(expr) => { - collect_unsafe_exprs(cx, e, unsafe_ops); - return Continue(Descend::No); + return self.visit_expr(e); }, - ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)), + ExprKind::InlineAsm(_) => self.unsafe_ops.push(("inline assembly used here", expr.span)), + + ExprKind::AddrOf(BorrowKind::Raw, _, _) => { + self.under_raw_ptr = UnderRawPtr::Yes; + }, ExprKind::Field(e, _) => { - if cx.typeck_results().expr_ty(e).is_union() { - unsafe_ops.push(("union field access occurs here", expr.span)); + if self.typeck_results.expr_ty(e).is_union() { + // Restore `self.under_raw_pointer` and determine safety of taking a raw pointer to + // a union field if this is not known already. + self.under_raw_ptr = if matches!(under_raw_ptr, UnderRawPtr::Yes) { + UnderRawPtr::WithSafeMsrv(self.msrv.meets(self.cx, msrvs::SAFE_RAW_PTR_TO_UNION_FIELD)) + } else { + under_raw_ptr + }; + if matches!(self.under_raw_ptr, UnderRawPtr::No | UnderRawPtr::WithSafeMsrv(false)) { + self.unsafe_ops.push(("union field access occurs here", expr.span)); + } } }, @@ -127,32 +191,32 @@ fn collect_unsafe_exprs<'tcx>( .. }, )) => { - unsafe_ops.push(("access of a mutable static occurs here", expr.span)); + self.unsafe_ops + .push(("access of a mutable static occurs here", expr.span)); }, - ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty_adjusted(e).is_raw_ptr() => { - unsafe_ops.push(("raw pointer dereference occurs here", expr.span)); + ExprKind::Unary(UnOp::Deref, e) if self.typeck_results.expr_ty_adjusted(e).is_raw_ptr() => { + self.unsafe_ops.push(("raw pointer dereference occurs here", expr.span)); }, ExprKind::Call(path_expr, _) => { - let sig = match *cx.typeck_results().expr_ty(path_expr).kind() { - ty::FnDef(id, _) => cx.tcx.fn_sig(id).skip_binder(), - ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr), - _ => return Continue(Descend::Yes), + let opt_sig = match *self.typeck_results.expr_ty(path_expr).kind() { + ty::FnDef(id, _) => Some(self.cx.tcx.fn_sig(id).skip_binder()), + ty::FnPtr(sig_tys, hdr) => Some(sig_tys.with(hdr)), + _ => None, }; - if sig.safety().is_unsafe() { - unsafe_ops.push(("unsafe function call occurs here", expr.span)); + if opt_sig.is_some_and(|sig| sig.safety().is_unsafe()) { + self.unsafe_ops.push(("unsafe function call occurs here", expr.span)); } }, ExprKind::MethodCall(..) => { - if let Some(sig) = cx - .typeck_results() + let opt_sig = self + .typeck_results .type_dependent_def_id(expr.hir_id) - .map(|def_id| cx.tcx.fn_sig(def_id)) - && sig.skip_binder().safety().is_unsafe() - { - unsafe_ops.push(("unsafe method call occurs here", expr.span)); + .map(|def_id| self.cx.tcx.fn_sig(def_id)); + if opt_sig.is_some_and(|sig| sig.skip_binder().safety().is_unsafe()) { + self.unsafe_ops.push(("unsafe method call occurs here", expr.span)); } }, @@ -173,15 +237,26 @@ fn collect_unsafe_exprs<'tcx>( } )) ) { - unsafe_ops.push(("modification of a mutable static occurs here", expr.span)); - collect_unsafe_exprs(cx, rhs, unsafe_ops); - return Continue(Descend::No); + self.unsafe_ops + .push(("modification of a mutable static occurs here", expr.span)); + return self.visit_expr(rhs); } }, _ => {}, } - Continue::<(), _>(Descend::Yes) - }); + walk_expr(self, expr); + } + + fn visit_body(&mut self, body: &hir::Body<'tcx>) { + let saved_typeck_results = self.typeck_results; + self.typeck_results = self.cx.tcx.typeck_body(body.id()); + walk_body(self, body); + self.typeck_results = saved_typeck_results; + } + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.cx.tcx + } } diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 86d17a8231d5..d1e39375c1e7 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -23,6 +23,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,92,0 { SAFE_RAW_PTR_TO_UNION_FIELD } 1,88,0 { LET_CHAINS } 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST } 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL } diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 132673d5164a..ca3c6cb486d9 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,5 +1,6 @@ //@needs-asm-support //@aux-build:proc_macros.rs +#![feature(stmt_expr_attributes)] #![expect( dropping_copy_types, clippy::unnecessary_operation, @@ -209,4 +210,69 @@ async fn issue13879() { } } +fn issue16076() { + #[derive(Clone, Copy)] + union U { + i: u32, + f: f32, + } + + let u = U { i: 0 }; + + // Taking a raw pointer to a place is safe since Rust 1.92 + #[clippy::msrv = "1.92"] + unsafe { + _ = &raw const u.i; + _ = &raw const u.i; + } + + // However it was not the case before Rust 1.92 + #[clippy::msrv = "1.91"] + unsafe { + //~^ multiple_unsafe_ops_per_block + _ = &raw const u.i; + _ = &raw const u.i; + } + + // Taking a reference to a union field is not safe + unsafe { + //~^ multiple_unsafe_ops_per_block + _ = &u.i; + _ = &u.i; + } + + // Check that we still check and lint the prefix of the raw pointer to a field access + #[expect(clippy::deref_addrof)] + unsafe { + //~^ multiple_unsafe_ops_per_block + _ = &raw const (*&raw const u).i; + _ = &raw const (*&raw const u).i; + } + + union V { + u: U, + } + + // Taking a raw pointer to a union field of an union field (etc.) is safe + let v = V { u }; + unsafe { + _ = &raw const v.u.i; + _ = &raw const v.u.i; + } +} + +fn check_closures() { + unsafe fn apply(f: impl Fn()) { + todo!() + } + unsafe fn f(_x: i32) { + todo!() + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + apply(|| f(0)); + } +} + fn main() {} diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr index 922a464c6b6e..9daad8e93969 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -1,5 +1,5 @@ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:38:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:39:5 | LL | / unsafe { LL | | @@ -9,12 +9,12 @@ LL | | } | |_____^ | note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:40:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:41:9 | LL | STATIC += 1; | ^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:41:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:42:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | not_very_safe(); = help: to override `-D warnings` add `#[allow(clippy::multiple_unsafe_ops_per_block)]` error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:48:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:49:5 | LL | / unsafe { LL | | @@ -32,18 +32,18 @@ LL | | } | |_____^ | note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:50:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:51:14 | LL | drop(u.u); | ^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:51:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:52:9 | LL | *raw_ptr(); | ^^^^^^^^^^ error: this `unsafe` block contains 3 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:56:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:57:5 | LL | / unsafe { LL | | @@ -54,23 +54,23 @@ LL | | } | |_____^ | note: inline assembly used here - --> tests/ui/multiple_unsafe_ops_per_block.rs:58:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:59:9 | LL | asm!("nop"); | ^^^^^^^^^^^ note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:59:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:60:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:60:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:61:9 | LL | STATIC = 0; | ^^^^^^^^^^ error: this `unsafe` block contains 6 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:66:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:67:5 | LL | / unsafe { LL | | @@ -82,55 +82,55 @@ LL | | } | |_____^ | note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:68:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:69:14 | LL | drop(u.u); | ^^^ note: access of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:69:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:70:14 | LL | drop(STATIC); | ^^^^^^ note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:70:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:71:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:71:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:72:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:72:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:73:9 | LL | *raw_ptr(); | ^^^^^^^^^^ note: inline assembly used here - --> tests/ui/multiple_unsafe_ops_per_block.rs:73:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:74:9 | LL | asm!("nop"); | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:110:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:111:9 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:110:18 + --> tests/ui/multiple_unsafe_ops_per_block.rs:111:18 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:110:43 + --> tests/ui/multiple_unsafe_ops_per_block.rs:111:43 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:131:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:132:9 | LL | / unsafe { LL | | @@ -140,18 +140,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:133:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:134:13 | LL | x(); | ^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:134:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:135:13 | LL | x(); | ^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:143:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:144:13 | LL | / unsafe { LL | | @@ -161,18 +161,18 @@ LL | | } | |_____________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:145:17 + --> tests/ui/multiple_unsafe_ops_per_block.rs:146:17 | LL | T::X(); | ^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:146:17 + --> tests/ui/multiple_unsafe_ops_per_block.rs:147:17 | LL | T::X(); | ^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:154:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:155:9 | LL | / unsafe { LL | | @@ -182,18 +182,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:156:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:157:13 | LL | x.0(); | ^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:157:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:158:13 | LL | x.0(); | ^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:184:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:185:5 | LL | / unsafe { LL | | @@ -204,18 +204,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:186:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:187:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:187:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:188:9 | LL | STATIC += 1; | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:199:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:200:5 | LL | / unsafe { LL | | @@ -225,18 +225,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:201:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:202:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:202:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:203:9 | LL | foo_unchecked().await; | ^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:206:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:207:5 | LL | / unsafe { LL | | @@ -245,15 +245,98 @@ LL | | } | |_____^ | note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:208:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:209:9 | LL | Some(foo_unchecked()).unwrap_unchecked().await; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:208:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:209:14 | LL | Some(foo_unchecked()).unwrap_unchecked().await; | ^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:231:5 + | +LL | / unsafe { +LL | | +LL | | _ = &raw const u.i; +LL | | _ = &raw const u.i; +LL | | } + | |_____^ + | +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:233:24 + | +LL | _ = &raw const u.i; + | ^^^ +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:234:24 + | +LL | _ = &raw const u.i; + | ^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:238:5 + | +LL | / unsafe { +LL | | +LL | | _ = &u.i; +LL | | _ = &u.i; +LL | | } + | |_____^ + | +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:240:14 + | +LL | _ = &u.i; + | ^^^ +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:241:14 + | +LL | _ = &u.i; + | ^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:246:5 + | +LL | / unsafe { +LL | | +LL | | _ = &raw const (*&raw const u).i; +LL | | _ = &raw const (*&raw const u).i; +LL | | } + | |_____^ + | +note: raw pointer dereference occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:248:24 + | +LL | _ = &raw const (*&raw const u).i; + | ^^^^^^^^^^^^^^^ +note: raw pointer dereference occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:249:24 + | +LL | _ = &raw const (*&raw const u).i; + | ^^^^^^^^^^^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:272:5 + | +LL | / unsafe { +LL | | +LL | | apply(|| f(0)); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:274:9 + | +LL | apply(|| f(0)); + | ^^^^^^^^^^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:274:18 + | +LL | apply(|| f(0)); + | ^^^^ + +error: aborting due to 15 previous errors