gccrs-final-report

Project Overview

A short summary of Rust Drop, the work completed in gccrs, and future work.

← Back to Final Report

During Google Summer of Code 2026, I worked on adding the basic infrastructure for Rust’s Drop trait to gccrs. The work involved C++, Rust, GCC tree expressions, BIR, control-flow graphs, and DejaGNU tests.

1. What is Drop?

Rust uses the Drop trait for value cleanup. The cleanup runs after a value is no longer needed.

fn example() {
    let a = Droppable("a");

    {
        let b = Droppable("b");
    }
}

In this example, the inner block ends first, so b is dropped first. Later, a is dropped at the end of the function. Values in the same scope are dropped in reverse declaration order. This is called LIFO order.

Early exits also need cleanup. Examples include return, break, and continue. A move transfers a value to a new location. The compiler must not drop the old location. The programmer writes the cleanup code in Drop::drop. The compiler inserts the call at the correct scope exit. It also skips the call for a moved value.

2. Support before and after the project

Before this project, gccrs did not automatically insert Drop calls at scope exit.

The original project plan started with a small and testable subset: simple, non-generic local variables. The project later added multiple locals, correct LIFO order, nested scopes, and whole-local moves. Temporaries, partial initialization, and generic cases were not completed and remain future work.

FeatureBefore this projectWhat works nowRelated pull requests
Recognizing the Drop traitgccrs did not know that Drop was a special Rust trait.Merged: gccrs recognizes Drop as a language item.#4559
Dropping locals and parametersLocal variables and function parameters were not dropped automatically when their scope ended.Merged: gccrs can Drop supported simple local bindings and function parameters in block and function scopes.#4564, #4591
Drop ordergccrs did not handle multiple values or nested scopes.Merged: the newest value is dropped first. Inner scopes are cleaned before outer scopes, and body locals are dropped before function parameters.#4632, #4718
Returning or leaving a blockNormal function exits, return, break, and continue did not run cleanup.Merged: normal exits, tail expressions, explicit return, and the tested unlabeled break and continue cases run cleanup.#4602, #4621, #4685, #4711, #4710
Straight-line movesgccrs could still Drop the old location after its value was moved.Merged in the BIR/borrow-check path: gccrs can detect a whole-local move in straight-line code and skip Drop at the old location.#4730, #4748
Conditional movesgccrs could not tell that a value might be moved in one branch but not another.Under review: CFG analysis tracks the value across branches, and backend Drop flags handle the runtime decision. Neither PR is merged yet.#4777, #4798

This is a useful subset of Drop behavior, but it is not full Rust Drop support. The Pull Request Notes show the exact implementation and tests behind each item.

3. Future work

3.1 Complete labeled break and continue cleanup

The current cleanup handles the tested unlabeled break and continue cases. One loop-body case can still run Drop twice when a break appears before a later local declaration. This is tracked in issue #4717.

Labeled break and continue are not supported yet. A labeled jump may leave several nested scopes. gccrs must clean every scope between the jump and its target.

3.2 Support partial moves

A move can take one field but leave the other field in place:

struct Pair {
    left: Droppable,
    right: Droppable,
}

let pair = Pair {
    left: Droppable("left"),
    right: Droppable("right"),
};

let a = pair.left;

pair.left was moved, but pair.right still needs cleanup. gccrs must track the fields separately. The same tracking is needed when only some fields have been initialized.

3.3 Support temporary values

A value can need cleanup even when it is not stored in a named local variable:

fn f() {
    make_droppable();
}

The result of make_droppable() is a temporary value. gccrs must Drop it at the end of its temporary scope.

3.4 Support generic Drop

The same generic function can receive types with different cleanup needs:

fn finish<T>(value: T) {
    // value is dropped when the function ends, if needed
}

fn main() {
    finish(42);               // i32 does not need Drop
    finish(Droppable("x"));   // Droppable must run Drop
}

gccrs must generate the correct cleanup for each concrete T. This still needs design and implementation work.

4. Reflection and Thanks

This project taught me about GCC tree expressions, structured cleanup, the boundary between the gccrs frontend and backend, BIR, CFG data-flow analysis, and compiler testing.

I wanted to work on generic Drop support. I did not reach this part during GSoC. BIR and CFG analysis took more time than I expected. I also spent time making the gccrs scope design closer to the rustc design. Both tasks were necessary for correct move handling. I chose to finish them first.

I would like to thank my mentors, Arthur Cohen and Pierre-Emmanuel Patry, for their reviews, explanations, and design feedback throughout the project.

Read the Design Note → · Browse the Pull Request Notes → · View the Weekly Updates →