# Suggestion: Target-focused \`unsafe\` call

**URL:** <https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144>\
**Category:** language design\
**Created:** [September 29, 2020, 12:51am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144 "2020-09-29T00:51:38Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [September 29, 2020, 12:51am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/1 "2020-09-29T00:51:39Z")

</div>

I hate `unsafe` blocks because they're too broad. Today I've met a chain of calls, where the last method was unsafe. Here's how it looks:

```rust
unsafe {
    x
        .method1(a, b, c)
        .method2(1, 2, 3)
        .method3(1 + 4, concat!("I", " ", "am cool"))
        .unsafe_method()
}

```

Now I can easily do an unsafe operation mistakenly inside, and the compiler will tell me nothing.

I think that a target-focused `unsafe` call syntax will be better. My suggestion is:

```rust
unsafe unsafe_fn(1, 2);
x.unsafe unsafe_method("Hi");
self.unsafe unsafe_method(unsafe_fn()); // Error!
// Correct:
self.unsafe unsafe_method(unsafe unsafe_fn());

```

Now the compiler can know that only the call is meant to be unsafe, and catch mistaken unfortunate other unsafe sections.

---

<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:** [September 29, 2020, 1:04am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/2 "2020-09-29T01:04:42Z")

</div>

Iʼve had the same idea myself. Unfortunately it is not _particularly_ pretty, but I wouldn't know any better way and it seems immensely useful. More than the unintentional use of unsafe things, this also prohibits the situation where someone _reading_ code has literally no idea where in that huge `unsafe` block the actual unsafety is happening and whether one has actually spotted every single unsafe thing there is or maybe missed one.

Another thing would be that there should also be syntax for unsafe language features that are not function or method calls, like e.g. dereferencing raw pointers. And of course unsafe functions should not have their bodies be unsafe blocks by default. Then one could eventually even have a tool convert unsafe blocks into explicit `unsafe`-on-every-use syntax to aid autiting overly `unsafe`-block reliant or old code.

A downside to this approach is that sometimes an `unsafe` block communicates which “safe” code is relevant to the unsafe operations and what things belong together. On the other hand there is literally _always_ also safe code that's relevant to the soundness of unsafe code but _not_ inside of the `unsafe` block, so relying too much on such implicit extra information is dangerous anyways.

Lastly, of course it's more verbose. For a sequence of statements with lots of unsafety the extra verbosity could make readability harder. For a potential alternative, I was thinking of perhaps there should be syntax highlighting from the IDE that (very clearly) points out exactly where in an `unsafe` block the unsafe methods, functions, pointer derefs, etc happen. But it feels like a bit of a weak language design if the only way to really understand Rust code is by looking at it thorough an IDE.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [September 29, 2020, 1:10am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/3 "2020-09-29T01:10:19Z")

</div>

> [@steffahn](#):
>
> Another thing would be that there should also be syntax for unsafe language features that are not function or method calls, like e.g. dereferencing raw pointers.

I don't think we have any another syntax that needs that. The idiom of Rust "everything is an expression" allows you to write code like `unsafe { *p }.method()` which I'm really conformable with. I don't know any other syntax of Rust expect calls that suffers from this problem.

The problem with calls is double: all calls cannot be marked `unsafe` without their parameters being `unsafe` too (i.e. `unsafe { f(g()) }` executes `g()` in an unsafe context, too), and methods are even more problematic since they cannot be marked `unsafe` without their receiver (i.e. `unsafe { g().f() }` executes `g()` in an unsafe context in addition to `f()`). The methods' problem can be solved using a syntax like `g().unsafe { f() }`, but that still has a new syntax while not solving all problems (so my suggestion is preferred over), and for me at least, this syntax doesn't intuitively ascribes `f()` to `g()`'s return value.

> [@steffahn](#):
>
> And of course unsafe functions should not have their bodies be unsafe blocks by default. Then one could eventually even have a tool convert unsafe blocks into explicit `unsafe` -on-every-use syntax.

This is already on the roadmap: [RFC 2585](https://github.com/rust-lang/rfcs/pull/2585). The RFC says that the plan is to eventually make it warn-by-default then err-by-default (because this is a breaking change).

> [@steffahn](#):
>
> Lastly, of course it's more verbose. For a sequence of statements with lots of unsafety the extra verbosity could make readability harder

I strongly prefer this verbosity over the cons. And if you're doing something _really_ unsafe, you can still wrap the whole code with an `unsafe` block. Your choice.

> [@steffahn](#):
>
> For a potential alternative, I was thinking of perhaps there should be syntax highlighting from the IDE that (very clearly) points out exactly where in an `unsafe` block the unsafe methods, functions, pointer derefs, etc happen.

I think Rust should not rely on IDEs, and that still doesn't solve all problems, only the readability, which I think it's less important than the potential unsafety.

---

<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:** [September 29, 2020, 1:42am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/4 "2020-09-29T01:42:03Z")

</div>

> [@chrefr](#):
>
> The idiom of Rust "everything is an expression" allows you to write code like `unsafe { *p }.method()` which I'm really conformable with. I don't know any other syntax of Rust expect calls that suffers from this problem.
> 
> The problem with calls is double: all calls cannot be marked `unsafe` without their parameters being `unsafe` too (i.e. `unsafe { f(g()) }` executes `g()` in an unsafe context, too),

If `p` is a more complicated expression, the same problems apply that `unsafe { *p }` will allow unsafe things to be called inside of `p`.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [September 29, 2020, 2:21am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/5 "2020-09-29T02:21:26Z")

</div>

> [@steffahn](#):
>
> If `p` is a more complicated expression, the same problems apply that `unsafe { *p }` will allow unsafe things to be called inside of `p` .

This may be an issue, you're right, but I don't worry so much about that. Mainly because pointer dereferencing is rare and extracting to a variable is easy in this case, but also because I haven't met this (yet) 😉

**Edit** : Also, I don't have an idea for an appropriate syntax in this case.

**Edit 2** : Maybe `unsafe(*)p` or `unsafe{*}p`?

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [September 29, 2020, 2:33am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/6 "2020-09-29T02:33:08Z")

</div>

Without necessarily trying to argue against this, note that the current best available alternative would be something like the following:

```rust
    let y = x
        .method1(a, b, c)
        .method2(1, 2, 3)
        .method3(1 + 4, concat!("I", " ", "am cool"));
    unsafe { y.unsafe_method(); }

```

Or, if the methods just chain by returning `&mut self`:

```rust
    x
        .method1(a, b, c)
        .method2(1, 2, 3)
        .method3(1 + 4, concat!("I", " ", "am cool"));
    unsafe { x.unsafe_method(); }

```

Either of those seems relatively reasonable as an alternative. That's the baseline we need to weigh a potential syntax change against.

I _do_ tend to try to make `unsafe` as narrow as possible, and I've felt the resulting awkwardness as well when doing so requires introducing new temporaries. I feel like the syntax proposals thus far, though, are less self-explanatory and harder to mentally parse.

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [September 29, 2020, 4:07am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/7 "2020-09-29T04:07:24Z")

</div>

> [@steffahn](#):
>
> I was thinking of perhaps there should be syntax highlighting from the IDE that (very clearly) points out exactly where in an `unsafe` block the unsafe methods, functions, pointer derefs, etc happen

Note that rust-analyzer can already do that, using semantic highlighting.

That said, I don't think introducing a temporary variable is too much to ask. The current syntax is straightforward and easy to understand. This is important when dealing with unsafe (and therefore security-critical) code.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [September 29, 2020, 4:28am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/8 "2020-09-29T04:28:54Z")

</div>

@Aloso and @josh,

First of all, extracting into variable solves the methods problem, but it's not so good for arguments evaluation. Although we _can_ pull them out, this gets unreasonable quickly.

And about methods: you're right when we're talking about `self` or something like the builder pattern, but for instance in my case, I'm dealing with a chain of tightly coupled operators. Something like get a stack stored in a field - then get the last item inside it - then unwrap. Naming operands will result in meaningless names such as `this_scope_before_unwrap`. I _can_ just call it `this_scope` then `let this_scope = this_scope.unwrap()`, I know, but outside of noisy and boilerplate code, I also think this does not fully express the value stored inside the variable.

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [September 29, 2020, 7:17am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/9 "2020-09-29T07:17:59Z")

</div>

> [@chrefr](#):
>
> but it's not so good for arguments evaluation

What do you mean? You _can_ put and omit `unsafe` blocks separately for each argument, because they are distinct expressions. `foo(bar, unsafe { baz() })` works just fine.

* * *

By the way, did you consider _why_ the syntax is the way it is? `unsafe` applies to an expression. It need not be a function call. However, `.some_unsafe_method()` is **not** a fully-fledged expression by itself. It is the right-hand-side of a method call expression, and it's useless without the `self` on the LHS.

This syntax change would suggest to alter the semantics of `unsafe` so as to apply to parts of expressions or incomplete expressions. Working with partial constructs in a highly regular language is always a headache to readers of the code and compiler writers, and is consequently not a good idea in general.

Especially when the solution is literally trivial – why would you even consider creating a single variable such a burden as to warrant completely new syntax? That seems unreasonable to me. The bar for features should be much, _much_ higher than "it annoys me sometimes", because new features are _expensive_. You should not be taking this stuff lightly.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [September 29, 2020, 11:41am UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/10 "2020-09-29T11:41:37Z")

</div>

> [@H2CO3](#):
>
> What do you mean? You _can_ put and omit `unsafe` blocks separately for each argument, because they are distinct expressions. `foo(bar, unsafe { baz() })` works just fine.

No, I mean `unsafe { foo(bar, baz()) }`. You _can_ do `let b = baz(); unsafe { foo(bar, b); }` but function arguments are not just one (like the receiver) and usually it's not so easy to name them.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [September 29, 2020, 5:00pm UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/11 "2020-09-29T17:00:08Z")

</div>

Hopefully one day we'll have some form of tuple splatting so one can always do something like

```rust
let args = (bar, baz());
unsafe { foo(...args) };

```

if naming all the arguments individually is unappealing.

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [September 29, 2020, 6:53pm UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/12 "2020-09-29T18:53:59Z")

</div>

As one potential idea: what about a `safe` block?

`unsafe { foo(bar, safe { baz() }) }`

We could even have an (optional, off-by-default) lint that warns you if you have a non-trivial expression inside an `unsafe` block that doesn't need `unsafe`, and a suggestion to use `safe` for that.

Similarly:

`unsafe { safe { x.chain1().chain2() }.chain_unsafe() }`

I don't think _all_ code should be written this way, but it'd be an option for people who want to use it.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [September 30, 2020, 1:21pm UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/13 "2020-09-30T13:21:54Z")

</div>

It might be possible to mark just a particular function invocation:

```rust
let a = f{unsafe}(a.safe1(), b.safe2(), c.g{unsafe}());

```

Here `{unsafe}` "binds" to the following parenthesis. This means that we're okay with this being an invocation of an `unsafe` function in a regular safe context

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [September 30, 2020, 1:47pm UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/14 "2020-09-30T13:47:43Z")

</div>

That looks ugly: it's not obvious which part it binds to, and it's backwards compared to the current place of `unsafe` (which is prefix w.r.t. the curlies but infix here), as well as inconsistent because it is no longer the scope of the curlies that is being marked as unsafe.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [September 30, 2020, 3:33pm UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/15 "2020-09-30T15:33:57Z")

</div>

I'm not sure if this is a problem at all. Over-reaching `unsafe` doesn't disable any safety features in safe code, so it doesn't cause any direct harm to the code. It increases the scope of code that needs to be carefully reviewed, so it's a bit of a waste of time/attention.

Once you start bending the syntax to micromanage every bit of every expression, that syntax itself will add more noise and complicate code review more than the slightly too big `unsafe` block.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [September 30, 2020, 3:33pm UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/16 "2020-09-30T15:33:58Z")

</div>

It's not obvious to me that the `unsafe` token is the whole problem here. I feel like any code that's trying to be this focused about the location of the blocks probably also wants to be writing `// SAFETY:` comments on all of them, which is so much more syntactic overhead than an extra `let` or two.

I wonder if instead there'd be a good way for the compiler to help you record which of the unsafe obligations you've met, both to help you make sure you've checked all of them and so that adding a new call needing new things in an unsafe block would be able to warn you.

Of course, at some point that's called "make a newtype that promises it"...

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [September 30, 2020, 4:47pm UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/17 "2020-09-30T16:47:45Z")

</div>

> [@scottmcm](#):
>
> Of course, at some point that's called "make a newtype that promises it"...

☝

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [October 1, 2020, 8:17pm UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/18 "2020-10-01T20:17:24Z")

</div>

The bit about SAFETY reminds me of this silly macro from a few weeks ago: [https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7e11bfcdd85e83c16cbcef7ace2b8848](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7e11bfcdd85e83c16cbcef7ace2b8848)

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [October 1, 2020, 8:25pm UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/19 "2020-10-01T20:25:12Z")

</div>

> [@mcy](#):
>
> The bit about SAFETY reminds me of this silly macro from a few weeks ago: [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7e11bfcdd85e83c16cbcef7ace2b8848)

Why? This is really nice!

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [October 1, 2020, 8:32pm UTC](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144/20 "2020-10-01T20:32:55Z")

</div>

Specifically about compiler-checks to make sure that each and every unsafe operation has an associated safety comment. I'm not a fan of the version I posted, since it fails to do it on a per-operation basis.

[Next page](https://internals.rust-lang.org/t/suggestion-target-focused-unsafe-call/13144.md?page=2)
