# Unnecessary \`unsafe\` block…

**URL:** <https://internals.rust-lang.org/t/unnecessary-unsafe-block/16144>\
**Category:** language design\
**Created:** [February 15, 2022, 12:52pm UTC](https://internals.rust-lang.org/t/unnecessary-unsafe-block/16144 "2022-02-15T12:52:57Z")\
**Posts on this page:** 1\
**Showing post:** 19

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [February 16, 2022, 7:16pm UTC](https://internals.rust-lang.org/t/unnecessary-unsafe-block/16144/19 "2022-02-16T19:16:28Z")

</div>

This is an interesting idea IMO. There’s certainly value in marking blocks as “the code in here in particular is involved in ensuring some safety-pre/post-conditions for unsafe code, pay attention when modifying it”. This kind of annotation can then apply to potentially quite large blocks of code, without obfuscating the detail of _where exactly_ the unsafe operation actually happened.

This kind of block might as well just be an ordinary block with a `SAFETY` comment though, IDK. Following your proposal of two levels of `unsafe`, I thought back to this idea of mine:

> [@Unsafe categories](https://internals.rust-lang.org/t/unsafe-categories/15334/2):
>
> I personally feel like it would be nicer to just add the ability to use the unsafe keyword in a smaller scope than a whole block, namely, on each individual unsafe operation. In terms of syntax, a possibility for each unsafe feature, i.e. each of The following language level features cannot be used in the safe subset of Rust: Dereferencing a [raw pointer](https://doc.rust-lang.org/stable/reference/types/pointer.html). Reading or writing a [mutable](https://doc.rust-lang.org/stable/reference/items/static-items.html#mutable-statics) or [external](https://doc.rust-lang.org/stable/reference/items/external-blocks.html) static variable. Accessing a field of a [union](https://doc.rust-lang.org/stable/reference/items/unions.html), other than to assign to it. Calling an unsafe fu…

and I think it might combine quite well. If we have

- a feature for `unsafe` keyword directly on unsafe operations themself e.g. as presented in the linked post above
- a lint that disallows unsafe operations directly within an `unsafe` block _without_ using another instance of the `unsafe` keyword on the operation itself
- perhaps also a lint that makes it so that `unsafe` blocks are still required

this would enforce a coding style similar to the example code you gave above, but the syntax would look like this instead:

```rust
fn safe() {
    safe_operation1();
    safe_operation2();

    // SAFETY: This is safe because we're going to uphold all the invariants.
    let foo = unsafe { // ← still doesn’t directly allow unsafe operations
        let x = safe_preparation_operation(MAGIC_SAFEWORD);
        x.prepare_even_more_safely();
        // SAFETY: This is safe because x has been prepared so safely.
        let result1 = x.unsafe this_is_where_the_unsafe_magic_happens();
        // ↖ still required despite the outer `unsafe` block
        gimme_that_result(result1);

        // SAFETY: Our ffi is all good.
        let final_result = x.unsafe this_is_where_the_unsafe_ffi_happens();
        // (admitted, you only know that this is about FFI, when looking at the docs
        // of `this_is_where_the_unsafe_ffi_happens`, but at least it’s very
        // clear where exactly you have to look)

        final_result
    };

    /* and now, let's completely ignore and */ drop(foo) /*, yay!! */;

    safe_operation3();
}

```

If instead of using `unsafe { … }`, marking the block here is done with comments alone, it wouldn’t be too bad either IMO. You’d just need a new convention, e.g.

```rust
fn safe() {
    safe_operation1();
    safe_operation2();

    // SAFETY-CRITICAL: this block ensures the pre-conditions
    // of two unsafe operations, be careful when modifying it
    let foo = {
        let x = safe_preparation_operation(MAGIC_SAFEWORD);
        x.prepare_even_more_safely();
        // SAFETY: This is safe because x has been prepared so safely.
        let result1 = x.unsafe this_is_where_the_unsafe_magic_happens();
        gimme_that_result(result1);

        // SAFETY: Our ffi is all good.
        let final_result = x.unsafe this_is_where_the_unsafe_ffi_happens();
        // (admitted, you only know that this is about FFI, when looking at the docs
        // of `this_is_where_the_unsafe_ffi_happens`, but at least it’s very
        // clear where exactly you have to look)

        final_result
    };

    /* and now, let's completely ignore and */ drop(foo) /*, yay!! */;

    safe_operation3();
}

```

Using some kind of conventional marker in comments like “`SAFETY-CRITICAL`”, you can mark blocks, or perhaps entire function bodies (probably commonly relevant for `unsafe fn` implementations) or even entire modules (in particular when we don’t have unsafe fields yet) with this marker and add a note what one must look out for when modifying any code within the relevant block, function, or module.

In particular such a `SAFETY-CRITICAL` comment would also imply that in the example above, anything that happens _outside_ of the block is not relevant for ensuring the soundness of the `unsafe` method calls. If e.g. only ensuring the safety conditions of one of multiple unsafe calls within such a block was completely handled within that block, then a `SAFETY-CRITICAL` would explain which of the operations that is, e.g.

```rust
/// # Safety
/// You must ensure XYZ when calling this function
unsafe fn foo() {
    // SAFETY-CRITICAL: in this function body qux is safe to call because
    // of the safety conditions of `foo` above.

    bar();
    // SAFETY-CRITICAL: baz() and f() below together are relevant for g() to be safe to call
    {
        baz();
        // SAFETY: [explain why exactly qux() is safe to call because of XYZ]
        unsafe qux();
        f();
        // SAFETY: [explain why exactly g() is safe to call because the previous calls to baz() and f()]
        unsafe g();
    }
}

```

so the comments above would indicate that

- care must be taken when changing anything in the definition of `foo()` to make sure that `qux()` stays safe to call
- additionally, care must be taken when changing anything inside of the block to make sure that `g()` stays safe to call

---

_[View the full topic](https://internals.rust-lang.org/t/unnecessary-unsafe-block/16144)._
