From: lishin <[email protected]>

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]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/f04080f419b936719b22b2d6816661e12a4ea1f5

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4564

 gcc/rust/backend/rust-compile-block.cc        | 58 +++++++++++++++++++
 gcc/rust/backend/rust-compile-pattern.cc      | 30 ++++++++++
 .../rust/execute/drop-block-scope.rs          | 34 +++++++++++
 3 files changed, 122 insertions(+)
 create mode 100644 gcc/testsuite/rust/execute/drop-block-scope.rs

diff --git a/gcc/rust/backend/rust-compile-block.cc 
b/gcc/rust/backend/rust-compile-block.cc
index 9a95d4e15..21ee37c48 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 d57616e6d..eb1541c8a 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 000000000..678ad63d7
--- /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
+}
-- 
2.54.0

Reply via email to