Skip to content

Commit 0a986a1

Browse files
committed
gcc/rust: Implement basic infrastructure for Drop trait
Basic Infra to handle drop trait implementation. ChangeLog: * .gitignore: Hide Zed editor files. gcc/rust/ChangeLog: * Make-lang.in: Add datum.h and drop.h. * backend/rust-compile-context.h (RUST_COMPILE_CONTEXT): Add methods to hold cleanup and drop place. * backend/rust-compile-expr.cc (CompileExpr::CompileExpr): Wrap raw tree node inside datum with type and kind. (CompileExpr::CompileDatum): New API method to get datum. (CompileExpr::visit): Set datum after setting translated. * backend/rust-compile-expr.h (RUST_COMPILE_EXPR): Add CompileDatum API. * backend/rust-compile-stmt.cc (CompileStmt::visit): Add cleanup for ExprStmt, setup drop_flag state in let statement. * backend/rust-compile-var-decl.h (RUST_COMPILE_VAR_DECL): Create and store drop path/place for new declared variables. * rust-backend.h (block_add_statements_with_cleanups): New header function. * rust-gcc.cc (block_add_statements_with_cleanups): Wrap block body and cleanup into try_finally. * typecheck/rust-hir-type-check.h: Add method to get associated_traits_to_impls. * util/rust-lang-item.cc: Register drop lang item. * util/rust-lang-item.h: Register drop lang item. * backend/rust-compile-datum.cc: Implementation for datum.h. * backend/rust-compile-datum.h: Introduce the Datum system for tracking values through expression compilation. * backend/rust-compile-drop.cc: Implementation for drop.h. * backend/rust-compile-drop.h: Introduce Drop Place to track variable state and runtime cleanup information. gcc/testsuite/ChangeLog: * rust/execute/torture/drop-struct.rs: Add basic drop test. Signed-off-by: Islam-Imad <islamimad404@gmail.com>
1 parent 0c1834c commit 0a986a1

17 files changed

+1290
-51
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ cscope.out
3939
.local.vimrc
4040
.lvimrc
4141
.vscode
42+
.zed
4243

4344
.clang-format
4445
.clang-tidy

gcc/rust/Make-lang.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ GRS_OBJS = \
224224
rust/rust-compile-base.o \
225225
rust/rust-tree.o \
226226
rust/rust-compile-context.o \
227+
rust/rust-compile-datum.o \
228+
rust/rust-compile-drop.o \
227229
rust/rust-export-metadata.o \
228230
rust/rust-imports.o \
229231
rust/rust-import-archive.o \

gcc/rust/backend/rust-compile-context.h

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#ifndef RUST_COMPILE_CONTEXT
2020
#define RUST_COMPILE_CONTEXT
2121

22+
#include "rust-compile-drop.h"
23+
#include "rust-compile-datum.h"
24+
#include "rust-location.h"
2225
#include "rust-system.h"
2326
#include "rust-hir-map.h"
2427
#include "rust-name-resolver.h"
@@ -28,6 +31,9 @@
2831
#include "rust-mangle.h"
2932
#include "rust-tree.h"
3033
#include "rust-immutable-name-resolution-context.h"
34+
#include "rust-tyty.h"
35+
#include <algorithm>
36+
#include <tuple>
3137

3238
namespace Rust {
3339
namespace Compile {
@@ -101,6 +107,7 @@ class Context
101107
{
102108
scope_stack.push_back (scope);
103109
statements.push_back ({});
110+
cleanups.push_back ({});
104111
}
105112

106113
tree pop_block ()
@@ -110,9 +117,17 @@ class Context
110117

111118
auto stmts = statements.back ();
112119
statements.pop_back ();
113-
114-
Backend::block_add_statements (block, stmts);
115-
120+
auto cls = cleanups.back ();
121+
cleanups.pop_back ();
122+
std::reverse (cls.begin (), cls.end ());
123+
if (cls.empty ())
124+
{
125+
Backend::block_add_statements (block, stmts);
126+
}
127+
else
128+
{
129+
Backend::block_add_statements_with_cleanups (block, stmts, cls);
130+
}
116131
return block;
117132
}
118133

@@ -130,6 +145,7 @@ class Context
130145
}
131146

132147
void add_statement (tree stmt) { statements.back ().push_back (stmt); }
148+
void add_cleanup (tree stmt) { cleanups.back ().push_back (stmt); }
133149

134150
void insert_var_decl (HirId id, ::Bvariable *decl)
135151
{
@@ -146,6 +162,20 @@ class Context
146162
return true;
147163
}
148164

165+
void insert_var_drop_place (HirId id, DropPlace *dp)
166+
{
167+
var_drop_places[id] = dp;
168+
}
169+
170+
bool lookup_var_drop_place (HirId id, DropPlace **dp)
171+
{
172+
auto it = var_drop_places.find (id);
173+
if (it == var_drop_places.end ())
174+
return false;
175+
*dp = it->second;
176+
return true;
177+
}
178+
149179
void insert_function_decl (const TyTy::FnType *ref, tree fn)
150180
{
151181
auto id = ref->get_ty_ref ();
@@ -417,7 +447,9 @@ class Context
417447
std::map<HirId, tree> compiled_fn_map;
418448
std::map<HirId, tree> compiled_consts;
419449
std::map<HirId, tree> compiled_labels;
450+
std::map<HirId, DropPlace *> var_drop_places;
420451
std::vector<::std::vector<tree>> statements;
452+
std::vector<::std::vector<tree>> cleanups;
421453
std::vector<tree> scope_stack;
422454
std::vector<::Bvariable *> loop_value_stack;
423455
std::vector<tree> loop_begin_labels;
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// Copyright (C) 2020-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-datum.h"
20+
#include "rust-backend.h"
21+
#include "rust-compile-context.h"
22+
#include "rust-compile-drop.h"
23+
#include "rust-compile-type.h"
24+
#include "rust-tyty.h"
25+
namespace Rust {
26+
namespace Compile {
27+
28+
Datum
29+
Datum::to_lvalue (Context *ctx, HirId expr_id)
30+
{
31+
if (kind == DatumKind::Lvalue)
32+
return *this;
33+
assert (is_valid () && "invalid datum");
34+
DropContext *drop_ctx = DropContext::get (ctx);
35+
tree compiled_type = TyTyResolveCompile::compile (ctx, ty);
36+
assert_node (compiled_type, "something wrong with compiled_type");
37+
tree pstatement = NULL_TREE;
38+
tree fndecl = ctx->peek_fn ().fndecl;
39+
tree bind_tree = ctx->peek_enclosing_scope ();
40+
LocalVariable tmp
41+
= Backend::temporary_variable (fndecl, bind_tree, compiled_type, val, false,
42+
locus, &pstatement);
43+
assert (pstatement != NULL_TREE);
44+
ctx->add_statement (pstatement);
45+
val = Backend::var_expression (tmp, locus);
46+
if (drop_ctx->needs_drop (ty))
47+
{
48+
DropPath tmp_path;
49+
tmp_path.root = expr_id;
50+
tmp_path.var_name = "tmp_expr_" + std::to_string (expr_id);
51+
DropPlace *place = drop_ctx->make_drop_place (val, tmp_path, ty);
52+
assert (place != nullptr);
53+
tree drop_expr = drop_ctx->drop (place);
54+
assert_node (drop_expr, "drop expr is not valid");
55+
ctx->add_cleanup (drop_expr);
56+
ctx->add_statement (drop_ctx->init (place));
57+
drop_place = place;
58+
}
59+
kind = DatumKind::Lvalue;
60+
return *this;
61+
}
62+
63+
Datum
64+
Datum::to_rvalue (Context *ctx)
65+
{
66+
if (kind == DatumKind::Rvalue)
67+
return *this;
68+
assert (is_valid () && "invalid datum");
69+
DropContext *drop_ctx = DropContext::get (ctx);
70+
tree compiled_type = TyTyResolveCompile::compile (ctx, ty);
71+
assert_node (compiled_type, "something wrong with compiled type");
72+
tree pstatement = NULL_TREE;
73+
tree fndecl = ctx->peek_fn ().fndecl;
74+
tree bind_tree = ctx->peek_enclosing_scope ();
75+
LocalVariable scratch
76+
= Backend::temporary_variable (fndecl, bind_tree, compiled_type, NULL_TREE,
77+
false, locus, &pstatement);
78+
assert (pstatement != NULL_TREE);
79+
ctx->add_statement (pstatement);
80+
tree scratch_expr = Backend::var_expression (scratch, locus);
81+
tree copy = Backend::assignment_statement (scratch_expr, val, locus);
82+
ctx->add_statement (copy);
83+
if (needs_drop (drop_ctx) && drop_place)
84+
ctx->add_statement (drop_ctx->uninit (drop_place));
85+
return Datum::new_rvalue (scratch_expr, ty, locus);
86+
}
87+
88+
void
89+
Datum::store_to (Context *ctx, tree dest_ptr)
90+
{
91+
tree assignment = Backend::assignment_statement (dest_ptr, val, locus);
92+
ctx->add_statement (assignment);
93+
post_store (ctx);
94+
}
95+
96+
void
97+
Datum::post_store (Context *ctx)
98+
{
99+
if (kind == DatumKind::Lvalue && ty != nullptr && drop_place != nullptr)
100+
{
101+
DropContext *drop_ctx = DropContext::get (ctx);
102+
if (drop_ctx->needs_drop (ty))
103+
ctx->add_statement (drop_ctx->uninit (drop_place));
104+
}
105+
}
106+
107+
Datum
108+
Datum::get_field (Context *ctx, size_t field_index, location_t field_locus)
109+
{
110+
tree field_expr
111+
= Backend::struct_field_expression (val, field_index, field_locus);
112+
TyTy::BaseType *field_ty = nullptr;
113+
assert (is_valid () && "invalid datum in get_field");
114+
TyTy::BaseType *resolved = ty->destructure ();
115+
switch (resolved->get_kind ())
116+
{
117+
case TyTy::TypeKind::ADT:
118+
{
119+
TyTy::ADTType *adt = resolved->as<TyTy::ADTType> ();
120+
TyTy::VariantDef *variant = adt->get_variants ().at (0);
121+
field_ty = variant->get_field_at_index (field_index)->get_field_type ();
122+
break;
123+
}
124+
case TyTy::TypeKind::TUPLE:
125+
{
126+
TyTy::TupleType *tuple = resolved->as<TyTy::TupleType> ();
127+
field_ty = tuple->get_field (field_index);
128+
break;
129+
}
130+
default:
131+
todo_die ("handle all remaining cases explicitly");
132+
break;
133+
}
134+
DropPlace *field_dp = nullptr;
135+
if (drop_place != nullptr && !drop_place->is_leaf ())
136+
{
137+
DropPath child_path = drop_place->path.child (field_index);
138+
for (auto *child : drop_place->children)
139+
if (child->path == child_path)
140+
field_dp = child;
141+
}
142+
return Datum::new_lvalue (field_expr, field_ty, field_dp, field_locus);
143+
}
144+
145+
void
146+
Datum::add_clean_if_rvalue (Context *ctx, HirId expr_id)
147+
{
148+
if (kind == DatumKind::Lvalue)
149+
return;
150+
DropContext *drop_ctx = DropContext::get (ctx);
151+
if (!needs_drop (drop_ctx))
152+
return;
153+
to_lvalue (ctx, expr_id);
154+
}
155+
} // namespace Compile
156+
} // namespace Rust
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (C) 2020-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+
#ifndef RUST_COMPILE_DATUM_H
20+
#define RUST_COMPILE_DATUM_H
21+
22+
#include "rust-compile-drop.h"
23+
#include "rust-location.h"
24+
#include "rust-tyty.h"
25+
26+
namespace Rust {
27+
namespace Compile {
28+
29+
class Context;
30+
enum class DatumKind
31+
{
32+
Lvalue,
33+
Rvalue,
34+
Invalid,
35+
};
36+
37+
struct Datum
38+
{
39+
tree val = NULL_TREE;
40+
TyTy::BaseType *ty = nullptr;
41+
DatumKind kind = DatumKind::Invalid;
42+
DropPlace *drop_place = nullptr;
43+
location_t locus = UNDEF_LOCATION;
44+
45+
static Datum new_datum (tree val, TyTy::BaseType *ty, DatumKind kind,
46+
DropPlace *drop_place, location_t locus)
47+
{
48+
Datum d;
49+
d.val = val;
50+
d.ty = ty;
51+
d.kind = kind;
52+
d.drop_place = drop_place;
53+
d.locus = locus;
54+
return d;
55+
}
56+
static Datum new_lvalue (tree val, TyTy::BaseType *ty, DropPlace *drop_place,
57+
location_t locus)
58+
{
59+
return new_datum (val, ty, DatumKind::Lvalue, drop_place, locus);
60+
}
61+
static Datum new_rvalue (tree val, TyTy::BaseType *ty, location_t locus)
62+
{
63+
return new_datum (val, ty, DatumKind::Rvalue, nullptr, locus);
64+
}
65+
66+
bool is_lvalue () const { return kind == DatumKind::Lvalue; }
67+
bool is_rvalue () const { return kind == DatumKind::Rvalue; }
68+
bool is_valid () const
69+
{
70+
return check_node (val) && ty != nullptr && kind != DatumKind::Invalid;
71+
}
72+
void set_not_valid ()
73+
{
74+
val = error_mark_node;
75+
ty = nullptr;
76+
kind = DatumKind::Invalid;
77+
}
78+
79+
bool needs_drop (DropContext *drop_ctx) const
80+
{
81+
if (!is_valid ())
82+
return false;
83+
return drop_ctx->needs_drop (ty);
84+
}
85+
86+
Datum get_field (Context *ctx, size_t field_index, location_t locus);
87+
tree raw_tree () const { return val; }
88+
89+
void add_clean_if_rvalue (Context *ctx, HirId expr_id);
90+
Datum to_lvalue (Context *ctx, HirId expr_id);
91+
Datum to_rvalue (Context *ctx);
92+
void store_to (Context *ctx, tree dest_ptr);
93+
void post_store (Context *ctx);
94+
};
95+
} // namespace Compile
96+
} // namespace Rust
97+
#endif // RUST_COMPILE_DATUM_H

0 commit comments

Comments
 (0)