Skip to content

gccrs: Add Drop support for block-local variable#4564

Merged
CohenArthur merged 6 commits into
Rust-GCC:masterfrom
Lishin1215:drop-let-tracking-and-logic
Jun 15, 2026
Merged

gccrs: Add Drop support for block-local variable#4564
CohenArthur merged 6 commits into
Rust-GCC:masterfrom
Lishin1215:drop-let-tracking-and-logic

Conversation

@Lishin1215

@Lishin1215 Lishin1215 commented May 29, 2026

Copy link
Copy Markdown
Contributor

This PR consists of 4 commits:

For now, it handles cases like:

fn main() -> i32 {
    {
        let _x = Droppable;
    }

    0
}

It also emits a temporary rust_sorry_at for unsupported Drop ref/subpatterns.


commit 1
gccrs: add block drop candidate tracking infrastructure

gcc/rust/ChangeLog:

      * backend/rust-compile-context.h (struct DropCandidate): New struct
        for tracking block-local drop candidates.

commit 2
gccrs: add block-exit Drop calls

gcc/rust/ChangeLog:

        * backend/rust-compile-block.cc (compile_drop_call): New helper to
        build a drop call.
        (CompileBlock::visit): Add drop calls for candidates.
        * backend/rust-compile-pattern.cc (type_has_drop_impl): New helper to
        check whether a type implements Drop.
        (CompilePatternLet::visit): Save initialized simple drop candidates.

gcc/testsuite/ChangeLog:

        * rust/execute/drop-block-scope.rs: New test.

commit 3
gccrs: report unsupported Drop ref patterns

gcc/rust/ChangeLog:

        * backend/rust-compile-pattern.cc (CompilePatternLet::visit): Check ref
        pattern base types and emit a sorry for unsupported Drop ref/subpatterns.

gcc/testsuite/ChangeLog:

        * rust/execute/drop-block-scope.rs: Extend test coverage for simple
        immutable and mutable bindings.
        * rust/compile/drop-ref-pattern.rs: New test.

commit 4
gccrs: move Drop helpers to separate files

gcc/rust/ChangeLog:

        * Make-lang.in: Add rust-compile-drop.o.
        * backend/rust-compile-block.cc (compile_drop_call): Move to CompileDrop.
        (CompileBlock::visit): Use CompileDrop to emit scope drop calls.
        * backend/rust-compile-context.h (struct DropCandidate): Move to rust-compile-drop.h.
        * backend/rust-compile-pattern.cc (type_has_drop_impl): Move to CompileDrop.
        (CompilePatternLet::visit): Use CompileDrop to check Drop impls.
        * backend/rust-compile-drop.cc: New file.
        * backend/rust-compile-drop.h: New file.

Tested with:

        make all-gcc
        make check-rust RUNTESTFLAGS="--all compile.exp=drop-ref-pattern.rs"
        make check-rust RUNTESTFLAGS="--all compile.exp=drop-lang-item.rs"
        make check-rust RUNTESTFLAGS="--all execute.exp=drop-block-scope.rs"

@Lishin1215 Lishin1215 force-pushed the drop-let-tracking-and-logic branch from e21459d to dab0a99 Compare May 29, 2026 21:19
auto s = Backend::init_statement (fnctx.fndecl, var, init_expr);
ctx->add_statement (s);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I only handle the simple case like:

  • let x = Droppable;
  • let mut x = Droppable;
  • let _x = Droppable;

I skipped more complex patterns for this first version, like ref and subpatterns.
I wanted to start with the smallest case first and then extend it later.
Does this scope look okay for a first draft?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then you might want to add a placeholder error message for now:

else if (type_has_drop_impl (ctx, ty))
    rust_sorry_at (pattern.get_locus (), "drop trait not supported for subpatterns & ref patterns");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing this out. I’ll add a rust_sorry_at for Drop types with ref bindings and subpatterns.

return block_drop_candidates.back ();
}

void note_simple_drop_candidate (HirId hirid, location_t locus)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am storing the drop candidates in Context for now.
The idea is that when we encounter an eligible variable in let, I store it in the array.
Please let me know if this is an ideal place.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine for now, but we should think about what future APIs will look like and start building towards that in a later PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll keep the current approach for now and think about what future APIs should look like in a follow-up PR.
Thank you!

Comment thread gcc/rust/backend/rust-compile-block.cc Outdated
namespace Compile {

static tree
compile_drop_call (Context *ctx, Bvariable *var, TyTy::BaseType *ty,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper finds the Drop trait, looks for the drop method, and builds the function call.
I put it in rust-compile-block.cc for now because it is only used when leaving a block.
I think this may need to move to a separate file later, since other scenarios may also need to use it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper finds the Drop trait, looks for the drop method, and builds the function call.

If you felt you had to write this in a github comment writing it as a regular code comment may make sense

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that makes sense. I'll move that explanation into a comment above compile_drop_call.

namespace Compile {

static bool
type_has_drop_impl (Context *ctx, TyTy::BaseType *ty)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this helper to avoid getting variables whose type does not implement Drop.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise I think this function would be great in a file dedicated to Drop functions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, I moved it to CompileDrop in rust-compile-drop.h and rust-compile-drop.cc.
Thank you!

@Polygonalr Polygonalr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arthur or Pierre-Emmanuel will do the proper review, but minor stuff from me.

auto s = Backend::init_statement (fnctx.fndecl, var, init_expr);
ctx->add_statement (s);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then you might want to add a placeholder error message for now:

else if (type_has_drop_impl (ctx, ty))
    rust_sorry_at (pattern.get_locus (), "drop trait not supported for subpatterns & ref patterns");

pub trait Sized {}

#[lang = "drop"]
pub trait Drop {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, I think this should be implemented as part of the compiler. You may want to take a look at how other traits (e.g. Copy, Eq) are implemented under gcc/rust/expand/rust-derive.cc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I’ll take a look at rust-derive.cc. For this draft, I kept the no_core test self-contained, but I agree the Drop support should be handled more directly in the compiler in the future.

Comment thread gcc/rust/backend/rust-compile-block.cc Outdated
namespace Compile {

static tree
compile_drop_call (Context *ctx, Bvariable *var, TyTy::BaseType *ty,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper finds the Drop trait, looks for the drop method, and builds the function call.

If you felt you had to write this in a github comment writing it as a regular code comment may make sense

Comment thread gcc/rust/backend/rust-compile-context.h Outdated
void note_simple_drop_candidate (HirId hirid, location_t locus)
{
rust_assert (!block_drop_candidates.empty ());
block_drop_candidates.back ().push_back ({hirid, locus});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't you emplace_back here since you're building your DropCandidate?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good point. I'll add a small DropCandidate constructor and use emplace_back here.

@CohenArthur CohenArthur left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks really good as a first approach and the code is clear. Well done

Comment thread gcc/rust/backend/rust-compile-context.h Outdated
Comment on lines +53 to +58
struct DropCandidate
{
HirId hirid;
location_t locus;
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to see separate files for these since they are exclusively drop-related. I think it's a great idea to create a separate struct, but it will eventually become more complicated and more methods/functions will be added, so it makes sense to create its own file now

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, I moved DropCandidate to rust-compile-drop.h together with the other Drop-related helpers.
Thank you!

Comment thread gcc/rust/backend/rust-compile-block.cc Outdated
namespace Compile {

static tree
compile_drop_call (Context *ctx, Bvariable *var, TyTy::BaseType *ty,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise this is a great function but I would put it in a class in a separate file. It would also help with caching down the line if that's something we eventually want to do

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, I also moved it into the CompileDrop in rust-compile-drop.h and rust-compile-drop.cc, which should make it easier to extend later.
Thanks!

return block_drop_candidates.back ();
}

void note_simple_drop_candidate (HirId hirid, location_t locus)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine for now, but we should think about what future APIs will look like and start building towards that in a later PR

namespace Compile {

static bool
type_has_drop_impl (Context *ctx, TyTy::BaseType *ty)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise I think this function would be great in a file dedicated to Drop functions

@Lishin1215 Lishin1215 force-pushed the drop-let-tracking-and-logic branch from fe7fb82 to 6ac7327 Compare June 9, 2026 16:23
Comment thread gcc/rust/backend/rust-compile-drop.h Outdated
Comment thread gcc/rust/backend/rust-compile-drop.cc
Comment thread gcc/rust/backend/rust-compile-drop.h Outdated
{
DropCandidate (HirId hirid, location_t locus) : hirid (hirid), locus (locus)
{}
#include "rust-compile-context.h"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reworked this to avoid the forward declarations. rust-compile-drop.h now includes the required context header directly.

DropCandidate now lives in rust-compile-drop-candidate.h, so it remains in a drop-related file, while rust-compile-context.h only includes that small state type instead of the full rust-compile-drop.h header.

Does this look good to you?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it does!

@Lishin1215 Lishin1215 marked this pull request as ready for review June 11, 2026 10:27

@P-E-P P-E-P left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@CohenArthur CohenArthur left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small comment but the implementation looks really good to me, well done Janet

Comment thread gcc/rust/backend/rust-compile-drop.cc Outdated
Comment on lines +73 to +89
for (auto &candidate : candidates)
{
if (!candidate.is_impl_candidate ()
|| candidate.ty->get_kind () != TyTy::TypeKind::FNDEF)
continue;

auto *fn_type = static_cast<TyTy::FnType *> (candidate.ty);
tree fn_addr
= CompileInherentImplItem::Compile (candidate.item.impl.impl_item, ctx,
fn_type, locus);

tree var_expr = Backend::var_expression (var, locus);
tree var_addr = HIRCompileBase::address_expression (var_expr, locus);

return Backend::call_expression (fn_addr, {var_addr}, nullptr, locus);
}
return NULL_TREE;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we should only ever have one candidate which corresponds to the actual Drop lang item trait and its drop function, otherwise we are doing something really evil and the compiler should crash.

Suggested change
for (auto &candidate : candidates)
{
if (!candidate.is_impl_candidate ()
|| candidate.ty->get_kind () != TyTy::TypeKind::FNDEF)
continue;
auto *fn_type = static_cast<TyTy::FnType *> (candidate.ty);
tree fn_addr
= CompileInherentImplItem::Compile (candidate.item.impl.impl_item, ctx,
fn_type, locus);
tree var_expr = Backend::var_expression (var, locus);
tree var_addr = HIRCompileBase::address_expression (var_expr, locus);
return Backend::call_expression (fn_addr, {var_addr}, nullptr, locus);
}
return NULL_TREE;
rust_assert (candidates.size () == 1);
auto &candidate = *candidates.begin ();
rust_assert (candidate.is_impl_candidate ());
rust_assert (candidate.ty->get_kind () == TyTy::TypeKind::FNDEF);
auto *fn_type = static_cast<TyTy::FnType *> (candidate.ty);
tree fn_addr
= CompileInherentImplItem::Compile (candidate.item.impl.impl_item, ctx,
fn_type, locus);
tree var_expr = Backend::var_expression (var, locus);
tree var_addr = HIRCompileBase::address_expression (var_expr, locus);
return Backend::call_expression (fn_addr, {var_addr}, nullptr, locus);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I understand now. Since this should resolve to exactly one Drop candidate, I changed it to use assertions so invalid compiler state is caught instead of being ignored.

Comment on lines +30 to +35
static bool type_has_drop_impl (Context *ctx, TyTy::BaseType *ty);

static tree compile_drop_call (Context *ctx, Bvariable *var,
TyTy::BaseType *ty, location_t locus);

static void emit_current_scope_drop_calls (Context *ctx);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are always passing the Context *ctx argument in each of these functions, I think it would be worth in a later PR to keep it as a class member and reuse it. But don't do it now as this is fine for now 👍

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that makes sense. I’ll keep the current approach for now and consider this in a follow-up cleanup PR.

@CohenArthur CohenArthur added the drop Issue with automatic `Drop::drop` calls insertion, drop ordering, drop rules label Jun 11, 2026
Add the basic structure for saving local variables that may need Drop.

gcc/rust/ChangeLog:

	* backend/rust-compile-context.h (struct DropCandidate): New struct
	for tracking block-local drop candidates.

Signed-off-by: lishin <lishin1008@gmail.com>
Add a helper for building Drop calls, and use it when leaving a block.
Add a block-exit test case.

gcc/rust/ChangeLog:

	* backend/rust-compile-block.cc (compile_drop_call): New helper to
	build a drop call.
	(CompileBlock::visit): Add drop calls for candidates.
	* backend/rust-compile-pattern.cc (type_has_drop_impl): New helper to
	check whether a type implements Drop.
	(CompilePatternLet::visit): Save initialized simple drop candidates.

gcc/testsuite/ChangeLog:

	* rust/execute/drop-block-scope.rs: New test.

Signed-off-by: lishin <lishin1008@gmail.com>
Add an unsupported error for ref patterns and subpatterns.
Add an unsupported ref-pattern test case,
and extend the existing block-exit test case.

gcc/rust/ChangeLog:

	* backend/rust-compile-pattern.cc (CompilePatternLet::visit): Check ref
	pattern base types and emit a sorry for unsupported Drop ref/subpatterns.

gcc/testsuite/ChangeLog:

	* rust/execute/drop-block-scope.rs: Extend test coverage for simple
	immutable and mutable bindings.
	* rust/compile/drop-ref-pattern.rs: New test.

Signed-off-by: lishin <lishin1008@gmail.com>
Refactor helper code into separate rust-compile-drop files.
This keeps the Drop-related logic in one place.

gcc/rust/ChangeLog:

	* Make-lang.in: Add rust-compile-drop.o.
	* backend/rust-compile-block.cc (compile_drop_call): Move to CompileDrop.
	(CompileBlock::visit): Use CompileDrop to emit scope drop calls.
	* backend/rust-compile-context.h (struct DropCandidate): Move to rust-compile-drop.h.
	* backend/rust-compile-pattern.cc (type_has_drop_impl): Move to CompileDrop.
	(CompilePatternLet::visit): Use CompileDrop to check Drop impls.
	* backend/rust-compile-drop.cc: New file.
	* backend/rust-compile-drop.h: New file.

Signed-off-by: Lishin <lishin1008@gmail.com>
Add function-scope Drop support for the implicit return case.
Add two test cases. This does not yet support explicit return.

gcc/rust/ChangeLog:

	* backend/rust-compile-base.cc (HIRCompileBase::compile_function_body):
	Add drop calls at the end of function bodies.

gcc/testsuite/ChangeLog:

	* rust/execute/drop-function-scope-unit.rs: New test.
	* rust/execute/drop-function-scope.rs: New test.

Signed-off-by: lishin <lishin1008@gmail.com>
Move DropCandidate into a small drop-specific header and fix the
include sturcture.

Also add missing copyright headers, fix the include guard name, and
assert that Drop lookup returns a single function candidate.

gcc/rust/ChangeLog:

	* backend/rust-compile-context.h: Include
	rust-compile-drop-candidate.h instead of rust-compile-drop.h.
	* backend/rust-compile-drop.cc: Add copyright header.
	(CompileDrop::compile_drop_call): Assert that Drop lookup returns a
	single function candidate.
	* backend/rust-compile-drop.h: Add copyright header. Include
	rust-compile-context.h.
	(RUST_COMPILE_DROP): Rename to...
	(RUST_COMPILE_DROP_H): ...this.
	(DropCandidate): Move to...
	* backend/rust-compile-drop-candidate.h: ...this new file.

Signed-off-by: Lishin <lishin1008@gmail.com>
@Lishin1215 Lishin1215 force-pushed the drop-let-tracking-and-logic branch from fe46d6c to d35c6aa Compare June 12, 2026 09:04

@CohenArthur CohenArthur left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me! well done!!

@CohenArthur CohenArthur added this pull request to the merge queue Jun 15, 2026
Merged via the queue into Rust-GCC:master with commit 9af2a5f Jun 15, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

drop Issue with automatic `Drop::drop` calls insertion, drop ordering, drop rules

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants