rust-lang / rust-lang/rfcs

Finally blocks for safer, faster, and clearer unsafe code

Open
#1,010 11 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

T-lang
Dominant language
Markdown
Stars
6.6k
Forks
1.7k
Avg merge
16h 14m
Merged PRs (30d)
1

Description

BinaryHeap currently has the following impl of sift_up that relies on the drop flag and LLVM being smart to avoid some swaps while being panic-safe:

    fn sift_up(&mut self, start: usize, mut pos: usize) {
        unsafe {
            let new = replace(&mut self.data[pos], zeroed());

            while pos > start {
                let parent = (pos - 1) >> 1;

                if new <= self.data[parent] { break; }

                let x = replace(&mut self.data[parent], zeroed());
                ptr::write(&mut self.data[pos], x);
                pos = parent;
            }
            ptr::write(&mut self.data[pos], new);
        }
    }

This code is quite unclear, and relies on a lot of things going right. However if we had a finally block, we could do the following:

    fn sift_up(&mut self, start: usize, mut pos: usize) {
        unsafe {
            let new = ptr::read(&self.data[pos]);

            while pos > start {
                let parent = (pos - 1) >> 1;

                if new <= self.data[parent] { break; }

                ptr::copy_nonoverlapping(&mut self.data[pos], &self.data[parent], 1);
                pos = parent;
            }

            finally {
                ptr::write(&mut self.data[pos], new);
            }
        }
    }

Which clearly captures the actual semantics we want. This functionality can be emulated by creating a struct with a drop impl, but it requires "weakly capturing" all the values through *const's. However that is noisy, cumbersome, confusing, and needlessly unsafe. A first class finally block can be verified to correctly run no matter where unwinding occurs (possibly through verifying that nothing it "closes" over is ever conditionally moved out).

I've constructed similar code while working on some trusted_len iterator problems (using the *const weak closing drop impl).

It would be fine with me if finally was considered unsafe, since its value to me is for cleanly failing in transient unsafe states.

I am logging this as only an issue because I don't have the knowledgebase to flesh out the precise rules, and because there's no way this can land for 1.0.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue provides no repository files, tests, or implementation entry points. Start with the BinaryHeap::sift_up examples and the discussion of panic safety, unwinding, and weakly captured drop implementations. Done would require defining precise finally-block rules and a viable Rust language design, which the issue explicitly leaves unresolved.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.