Line data Source code
1 : // Copyright (C) 2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-compile-drop.h"
20 : #include "rust-compile-drop-builder.h"
21 : #include "rust-compile-base.h"
22 : #include "rust-compile-context.h"
23 : #include "rust-compile-implitem.h"
24 : #include "rust-bir-drop-analysis.h"
25 : #include "rust-hir-path-probe-impl-trait.h"
26 : #include "rust-hir-trait-reference.h"
27 : #include "rust-hir-type-bounds.h"
28 : #include "rust-lang-item.h"
29 : #include "rust-tyty.h"
30 :
31 : namespace Rust {
32 : namespace Compile {
33 :
34 70589 : CompileDrop::CompileDrop (Context *ctx) : ctx (ctx) {}
35 :
36 : bool
37 31345 : CompileDrop::type_has_drop_impl (TyTy::BaseType *ty)
38 : {
39 31345 : auto drop_lang_item
40 31345 : = ctx->get_mappings ().lookup_lang_item (LangItem::Kind::DROP);
41 :
42 31345 : if (!drop_lang_item.has_value ())
43 : return false;
44 :
45 240 : DefId drop_id = drop_lang_item.value ();
46 :
47 240 : auto candidates = Resolver::TypeBoundsProbe::Probe (ty);
48 361 : for (auto &candidate : candidates)
49 : {
50 240 : Resolver::TraitReference *trait_ref = candidate.first;
51 361 : if (trait_ref != nullptr && trait_ref->get_defid () == drop_id)
52 119 : return true;
53 : }
54 :
55 : return false;
56 240 : }
57 :
58 : // Find the Drop trait, look for the drop method, and build the function call.
59 : tree
60 58 : CompileDrop::compile_drop_call (Bvariable *var, TyTy::BaseType *ty,
61 : location_t locus)
62 : {
63 58 : auto drop_lang = ctx->get_mappings ().lookup_lang_item (LangItem::Kind::DROP);
64 58 : if (!drop_lang.has_value ())
65 : return NULL_TREE;
66 :
67 58 : Resolver::TraitReference *drop_ref = nullptr;
68 58 : bool ok
69 58 : = ctx->get_tyctx ()->lookup_trait_reference (drop_lang.value (), &drop_ref);
70 58 : if (!ok)
71 : return NULL_TREE;
72 :
73 58 : HIR::PathIdentSegment segment ("drop");
74 58 : auto candidates
75 58 : = Resolver::PathProbeImplTrait::Probe (ty->get_root (), segment, drop_ref);
76 :
77 58 : rust_assert (candidates.size () == 1);
78 :
79 58 : auto &candidate = *candidates.begin ();
80 58 : rust_assert (candidate.is_impl_candidate ());
81 58 : rust_assert (candidate.ty->get_kind () == TyTy::TypeKind::FNDEF);
82 :
83 58 : auto *fn_type = static_cast<TyTy::FnType *> (candidate.ty);
84 58 : tree fn_addr
85 58 : = CompileInherentImplItem::Compile (candidate.item.impl.impl_item, ctx,
86 : fn_type, locus);
87 :
88 58 : tree var_expr = Backend::var_expression (var, locus);
89 58 : tree var_addr = HIRCompileBase::address_expression (var_expr, locus);
90 :
91 58 : return Backend::call_expression (fn_addr, {var_addr}, nullptr, locus);
92 58 : }
93 :
94 : tree
95 39244 : CompileDrop::build_current_scope_drop_cleanup ()
96 : {
97 39244 : std::vector<tree> drop_stmts;
98 :
99 39244 : DropBuilder drop_builder (*ctx);
100 39244 : auto &drop_candidates = drop_builder.peek_block_drop_candidates ();
101 :
102 39307 : for (auto it = drop_candidates.rbegin (); it != drop_candidates.rend (); ++it)
103 : {
104 63 : if (BIR::DropAnalysis::get ().is_definitely_dead (it->hirid))
105 5 : continue;
106 :
107 58 : TyTy::BaseType *ty = nullptr;
108 58 : Bvariable *var = nullptr;
109 :
110 58 : bool ok = ctx->get_tyctx ()->lookup_type (it->hirid, &ty);
111 58 : rust_assert (ok);
112 :
113 58 : ok = ctx->lookup_var_decl (it->hirid, &var);
114 58 : rust_assert (ok);
115 :
116 58 : tree drop_call = compile_drop_call (var, ty, it->locus);
117 58 : if (drop_call != NULL_TREE)
118 : {
119 58 : tree drop_stmt = convert_to_void (drop_call, ICV_STATEMENT);
120 58 : Bvariable *flag = nullptr;
121 58 : if (ctx->lookup_drop_flag (it->hirid, &flag))
122 : {
123 1 : tree condition = Backend::var_expression (flag, it->locus);
124 1 : tree clear = drop_builder.drop_flag_assignment (it->hirid, false,
125 1 : it->locus);
126 1 : tree guarded_drop = Backend::statement_list ({clear, drop_stmt});
127 1 : drop_stmt
128 1 : = Backend::if_statement (ctx->peek_fn ().fndecl, condition,
129 1 : guarded_drop, NULL_TREE, it->locus);
130 : }
131 58 : drop_stmts.push_back (drop_stmt);
132 : }
133 : }
134 :
135 39244 : if (drop_stmts.empty ())
136 : return NULL_TREE;
137 :
138 50 : return Backend::statement_list (drop_stmts);
139 39244 : }
140 :
141 : } // namespace Compile
142 : } // namespace Rust
|