https://gcc.gnu.org/g:289436de097e2e8fead96c7d30afc9d8e7e773c6
commit r17-1892-g289436de097e2e8fead96c7d30afc9d8e7e773c6 Author: lishin <[email protected]> Date: Fri May 29 17:59:00 2026 +0000 gccrs: add block-exit Drop calls 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 <[email protected]> Diff: --- gcc/rust/backend/rust-compile-block.cc | 58 ++++++++++++++++++++++++++ gcc/rust/backend/rust-compile-pattern.cc | 30 +++++++++++++ gcc/testsuite/rust/execute/drop-block-scope.rs | 34 +++++++++++++++ 3 files changed, 122 insertions(+) diff --git a/gcc/rust/backend/rust-compile-block.cc b/gcc/rust/backend/rust-compile-block.cc index 9a95d4e15787..21ee37c48b73 100644 --- a/gcc/rust/backend/rust-compile-block.cc +++ b/gcc/rust/backend/rust-compile-block.cc @@ -19,11 +19,51 @@ #include "rust-compile-block.h" #include "rust-compile-stmt.h" #include "rust-compile-expr.h" +#include "rust-compile-implitem.h" #include "rust-hir-expr.h" +#include "rust-hir-path-probe.h" +#include "rust-lang-item.h" namespace Rust { namespace Compile { +static tree +compile_drop_call (Context *ctx, Bvariable *var, TyTy::BaseType *ty, + location_t locus) +{ + auto drop_lang = ctx->get_mappings ().lookup_lang_item (LangItem::Kind::DROP); + if (!drop_lang.has_value ()) + return NULL_TREE; + + Resolver::TraitReference *drop_ref = nullptr; + bool ok + = ctx->get_tyctx ()->lookup_trait_reference (drop_lang.value (), &drop_ref); + if (!ok) + return NULL_TREE; + + HIR::PathIdentSegment segment ("drop"); + auto candidates + = Resolver::PathProbeImplTrait::Probe (ty->get_root (), segment, drop_ref); + + 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; +} + CompileBlock::CompileBlock (Context *ctx, Bvariable *result) : HIRCompileBase (ctx), translated (nullptr), result (result) {} @@ -85,6 +125,24 @@ CompileBlock::visit (HIR::BlockExpr &expr) ctx->add_statement (assignment); } + auto &drop_candidates = ctx->peek_block_drop_candidates (); + + for (auto it = drop_candidates.rbegin (); it != drop_candidates.rend (); ++it) + { + TyTy::BaseType *ty = nullptr; + Bvariable *var = nullptr; + + bool ok = ctx->get_tyctx ()->lookup_type (it->hirid, &ty); + rust_assert (ok); + + ok = ctx->lookup_var_decl (it->hirid, &var); + rust_assert (ok); + + tree drop_call = compile_drop_call (ctx, var, ty, it->locus); + if (drop_call != NULL_TREE) + ctx->add_statement (convert_to_void (drop_call, ICV_STATEMENT)); + } + ctx->pop_block (); translated = new_block; } diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index d57616e6d095..eb1541c8ab2d 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -27,11 +27,36 @@ #include "rust-hir-pattern.h" #include "rust-system.h" #include "rust-tyty.h" +#include "rust-hir-type-bounds.h" +#include "rust-hir-trait-reference.h" +#include "rust-lang-item.h" #include "tree.h" namespace Rust { namespace Compile { +static bool +type_has_drop_impl (Context *ctx, TyTy::BaseType *ty) +{ + auto drop_lang_item + = ctx->get_mappings ().lookup_lang_item (LangItem::Kind::DROP); + + if (!drop_lang_item.has_value ()) + return false; + + DefId drop_id = drop_lang_item.value (); + + auto candidates = Resolver::TypeBoundsProbe::Probe (ty); + for (auto &candidate : candidates) + { + Resolver::TraitReference *trait_ref = candidate.first; + if (trait_ref != nullptr && trait_ref->get_defid () == drop_id) + return true; + } + + return false; +} + void CompilePatternCheckExpr::visit (HIR::PathInExpression &pattern) { @@ -1343,6 +1368,11 @@ CompilePatternLet::visit (HIR::IdentifierPattern &pattern) auto s = Backend::init_statement (fnctx.fndecl, var, init_expr); ctx->add_statement (s); } + + if (!pattern.has_subpattern () && !pattern.get_is_ref () + && type_has_drop_impl (ctx, ty)) + ctx->note_simple_drop_candidate (pattern.get_mappings ().get_hirid (), + pattern.get_locus ()); } void diff --git a/gcc/testsuite/rust/execute/drop-block-scope.rs b/gcc/testsuite/rust/execute/drop-block-scope.rs new file mode 100644 index 000000000000..678ad63d7529 --- /dev/null +++ b/gcc/testsuite/rust/execute/drop-block-scope.rs @@ -0,0 +1,34 @@ +// { dg-output "d\r*\n" } +#![feature(no_core)] +#![feature(lang_items)] +#![no_core] + +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "sized"] +pub trait Sized {} + +#[lang = "drop"] +pub trait Drop { + fn drop(&mut self); +} + +struct Droppable; + +impl Drop for Droppable { + fn drop(&mut self) { + let msg = "d\n\0" as *const str as *const i8; + unsafe { + printf(msg); + } + } +} + +fn main() -> i32 { + { + let _x = Droppable; + } + 0 +}
