Ask questionsunused_unsafe: stop interpreting `unsafe fn`s as unsafe contexts

In other words, the following will result in a lint being emitted today:

unsafe fn _bar() {}

unsafe fn _foo() {
    unsafe {


warning: unnecessary `unsafe` block
 --> src/
3 | unsafe fn _foo() {
  | ---------------- because it's nested under this `unsafe` fn
4 |     unsafe {
  |     ^^^^^^ unnecessary `unsafe` block
  = note: `#[warn(unused_unsafe)]` on by default

Based on the discussion in a recent language team meeting (see summary as outlined by @nikomatsakis in, we would like to stop emitting the lint in this case where we have unsafe operations inside an unsafe { ... } inside an unsafe fn (it's probably easiest to not emit the lint at all as opposed to emitting a different lint name, but this can be determined as part of the implementation).

cc @RalfJung @rust-lang/lang


<!-- TRIAGEBOT_ASSIGN_START --> This issue has been assigned to @LeSeulArtichaut via this comment. <!-- TRIAGEBOT_ASSIGN_DATA_START$${"user":"LeSeulArtichaut"}$$TRIAGEBOT_ASSIGN_DATA_END -->



Answer questions eddyb

So looking at the code, it seems that the outermost active unsafe block (or unsafe fn) is used:

(NB: very confusing terminology around unpushed_unsafe, AFAICT it means "unsafe unrelated to {Push,Pop}Unsafe", and the latter is a hacky way to do allow_internal_unsafe, so we should rip it out sooner or later - but it shouldn't impact this issue, it's just confusing)

This are the possible values for Safety:

So when the "current safety" is Safety::FnUnsafe, it early-returns, instead of replacing it with the inner Safety::ExplicitUnsafe.

By making this change, I think we can get the desired lint effect (while unsafe fn still allowing unsafe operations outside of unsafe blocks):

- Safety::Safe => {}
+ Safety::Safe | Safety::FnUnsafe => {}

Related questions

Spurious NaNs produced by trig functions with valid inputs on Windows GNU toolchains hot 2
using 'cargo install xsv' on windows 10 triggers rustc internal error hot 1
chain() make collect very slow hot 1
if/while Some(n) = &mut foo sugar will leak a temporary mutable borrow to current scope in particular situation hot 1
build an empty project failed (undefined reference to `__onexitbegin') hot 1
Invalid collision with TryFrom implementation? hot 1
Crater runs for Rust 1.38.0 hot 1
Spurious NaNs produced by trig functions with valid inputs on Windows GNU toolchains hot 1
under latest MinGW, cannot link with C code using stdout hot 1
Archive all nightlies hot 1
Building LLVM with Clang fails hot 1
Internal compiler error: can't buffer lints after HIR lowering hot 1
E0373 help suggests `move async` but the correct syntax is `async move` hot 1
Tracking issue for `Option::contains` and `Result::contains` hot 1
async fn + rustfmt don't "just work" inside of RLS hot 1
Github User Rank List