Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ cscope.out
.local.vimrc
.lvimrc
.vscode
.zed

.clang-format
.clang-tidy
Expand Down
2 changes: 2 additions & 0 deletions gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ GRS_OBJS = \
rust/rust-compile-base.o \
rust/rust-tree.o \
rust/rust-compile-context.o \
rust/rust-compile-datum.o \
rust/rust-compile-drop.o \
rust/rust-export-metadata.o \
rust/rust-imports.o \
rust/rust-import-archive.o \
Expand Down
38 changes: 35 additions & 3 deletions gcc/rust/backend/rust-compile-context.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#ifndef RUST_COMPILE_CONTEXT
#define RUST_COMPILE_CONTEXT

#include "rust-compile-drop.h"
#include "rust-compile-datum.h"
#include "rust-location.h"
#include "rust-system.h"
#include "rust-hir-map.h"
#include "rust-name-resolver.h"
Expand All @@ -28,6 +31,9 @@
#include "rust-mangle.h"
#include "rust-tree.h"
#include "rust-immutable-name-resolution-context.h"
#include "rust-tyty.h"
#include <algorithm>
#include <tuple>

namespace Rust {
namespace Compile {
Expand Down Expand Up @@ -101,6 +107,7 @@ class Context
{
scope_stack.push_back (scope);
statements.push_back ({});
cleanups.push_back ({});
}

tree pop_block ()
Expand All @@ -110,9 +117,17 @@ class Context

auto stmts = statements.back ();
statements.pop_back ();

Backend::block_add_statements (block, stmts);

auto cls = cleanups.back ();
cleanups.pop_back ();
std::reverse (cls.begin (), cls.end ());
if (cls.empty ())
{
Backend::block_add_statements (block, stmts);
}
else
{
Backend::block_add_statements_with_cleanups (block, stmts, cls);
}
return block;
}

Expand All @@ -130,6 +145,7 @@ class Context
}

void add_statement (tree stmt) { statements.back ().push_back (stmt); }
void add_cleanup (tree stmt) { cleanups.back ().push_back (stmt); }

void insert_var_decl (HirId id, ::Bvariable *decl)
{
Expand All @@ -146,6 +162,20 @@ class Context
return true;
}

void insert_var_drop_place (HirId id, DropPlace *dp)
{
var_drop_places[id] = dp;
}

bool lookup_var_drop_place (HirId id, DropPlace **dp)
{
auto it = var_drop_places.find (id);
if (it == var_drop_places.end ())
return false;
*dp = it->second;
return true;
}

void insert_function_decl (const TyTy::FnType *ref, tree fn)
{
auto id = ref->get_ty_ref ();
Expand Down Expand Up @@ -417,7 +447,9 @@ class Context
std::map<HirId, tree> compiled_fn_map;
std::map<HirId, tree> compiled_consts;
std::map<HirId, tree> compiled_labels;
std::map<HirId, DropPlace *> var_drop_places;
std::vector<::std::vector<tree>> statements;
std::vector<::std::vector<tree>> cleanups;
std::vector<tree> scope_stack;
std::vector<::Bvariable *> loop_value_stack;
std::vector<tree> loop_begin_labels;
Expand Down
156 changes: 156 additions & 0 deletions gcc/rust/backend/rust-compile-datum.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// Copyright (C) 2020-2026 Free Software Foundation, Inc.

// This file is part of GCC.

// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.

// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.

// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.

#include "rust-compile-datum.h"
#include "rust-backend.h"
#include "rust-compile-context.h"
#include "rust-compile-drop.h"
#include "rust-compile-type.h"
#include "rust-tyty.h"
namespace Rust {
namespace Compile {

Datum
Datum::to_lvalue (Context *ctx, HirId expr_id)
{
if (kind == DatumKind::Lvalue)
return *this;
assert (is_valid () && "invalid datum");
DropContext *drop_ctx = DropContext::get (ctx);
tree compiled_type = TyTyResolveCompile::compile (ctx, ty);
assert_node (compiled_type, "something wrong with compiled_type");
tree pstatement = NULL_TREE;
tree fndecl = ctx->peek_fn ().fndecl;
tree bind_tree = ctx->peek_enclosing_scope ();
LocalVariable tmp
= Backend::temporary_variable (fndecl, bind_tree, compiled_type, val, false,
locus, &pstatement);
assert (pstatement != NULL_TREE);
ctx->add_statement (pstatement);
val = Backend::var_expression (tmp, locus);
if (drop_ctx->needs_drop (ty))
{
DropPath tmp_path;
tmp_path.root = expr_id;
tmp_path.var_name = "tmp_expr_" + std::to_string (expr_id);
DropPlace *place = drop_ctx->make_drop_place (val, tmp_path, ty);
assert (place != nullptr);
tree drop_expr = drop_ctx->drop (place);
assert_node (drop_expr, "drop expr is not valid");
ctx->add_cleanup (drop_expr);
ctx->add_statement (drop_ctx->init (place));
drop_place = place;
}
kind = DatumKind::Lvalue;
return *this;
}

Datum
Datum::to_rvalue (Context *ctx)
{
if (kind == DatumKind::Rvalue)
return *this;
assert (is_valid () && "invalid datum");
DropContext *drop_ctx = DropContext::get (ctx);
tree compiled_type = TyTyResolveCompile::compile (ctx, ty);
assert_node (compiled_type, "something wrong with compiled type");
tree pstatement = NULL_TREE;
tree fndecl = ctx->peek_fn ().fndecl;
tree bind_tree = ctx->peek_enclosing_scope ();
LocalVariable scratch
= Backend::temporary_variable (fndecl, bind_tree, compiled_type, NULL_TREE,
false, locus, &pstatement);
assert (pstatement != NULL_TREE);
ctx->add_statement (pstatement);
tree scratch_expr = Backend::var_expression (scratch, locus);
tree copy = Backend::assignment_statement (scratch_expr, val, locus);
ctx->add_statement (copy);
if (needs_drop (drop_ctx) && drop_place)
ctx->add_statement (drop_ctx->uninit (drop_place));
return Datum::new_rvalue (scratch_expr, ty, locus);
}

void
Datum::store_to (Context *ctx, tree dest_ptr)
{
tree assignment = Backend::assignment_statement (dest_ptr, val, locus);
ctx->add_statement (assignment);
post_store (ctx);
}

void
Datum::post_store (Context *ctx)
{
if (kind == DatumKind::Lvalue && ty != nullptr && drop_place != nullptr)
{
DropContext *drop_ctx = DropContext::get (ctx);
if (drop_ctx->needs_drop (ty))
ctx->add_statement (drop_ctx->uninit (drop_place));
}
}

Datum
Datum::get_field (Context *ctx, size_t field_index, location_t field_locus)
{
tree field_expr
= Backend::struct_field_expression (val, field_index, field_locus);
TyTy::BaseType *field_ty = nullptr;
assert (is_valid () && "invalid datum in get_field");
TyTy::BaseType *resolved = ty->destructure ();
switch (resolved->get_kind ())
{
case TyTy::TypeKind::ADT:
{
TyTy::ADTType *adt = resolved->as<TyTy::ADTType> ();
TyTy::VariantDef *variant = adt->get_variants ().at (0);
field_ty = variant->get_field_at_index (field_index)->get_field_type ();
break;
}
case TyTy::TypeKind::TUPLE:
{
TyTy::TupleType *tuple = resolved->as<TyTy::TupleType> ();
field_ty = tuple->get_field (field_index);
break;
}
default:
todo_die ("handle all remaining cases explicitly");
break;
}
DropPlace *field_dp = nullptr;
if (drop_place != nullptr && !drop_place->is_leaf ())
{
DropPath child_path = drop_place->path.child (field_index);
for (auto *child : drop_place->children)
if (child->path == child_path)
field_dp = child;
}
return Datum::new_lvalue (field_expr, field_ty, field_dp, field_locus);
}

void
Datum::add_clean_if_rvalue (Context *ctx, HirId expr_id)
{
if (kind == DatumKind::Lvalue)
return;
DropContext *drop_ctx = DropContext::get (ctx);
if (!needs_drop (drop_ctx))
return;
to_lvalue (ctx, expr_id);
}
} // namespace Compile
} // namespace Rust
97 changes: 97 additions & 0 deletions gcc/rust/backend/rust-compile-datum.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (C) 2020-2026 Free Software Foundation, Inc.

// This file is part of GCC.

// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.

// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.

// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.

#ifndef RUST_COMPILE_DATUM_H
#define RUST_COMPILE_DATUM_H

#include "rust-compile-drop.h"
#include "rust-location.h"
#include "rust-tyty.h"

namespace Rust {
namespace Compile {

class Context;
enum class DatumKind
{
Lvalue,
Rvalue,
Invalid,
};

struct Datum
{
tree val = NULL_TREE;
TyTy::BaseType *ty = nullptr;
DatumKind kind = DatumKind::Invalid;
DropPlace *drop_place = nullptr;
location_t locus = UNDEF_LOCATION;

static Datum new_datum (tree val, TyTy::BaseType *ty, DatumKind kind,
DropPlace *drop_place, location_t locus)
{
Datum d;
d.val = val;
d.ty = ty;
d.kind = kind;
d.drop_place = drop_place;
d.locus = locus;
return d;
}
static Datum new_lvalue (tree val, TyTy::BaseType *ty, DropPlace *drop_place,
location_t locus)
{
return new_datum (val, ty, DatumKind::Lvalue, drop_place, locus);
}
static Datum new_rvalue (tree val, TyTy::BaseType *ty, location_t locus)
{
return new_datum (val, ty, DatumKind::Rvalue, nullptr, locus);
}

bool is_lvalue () const { return kind == DatumKind::Lvalue; }
bool is_rvalue () const { return kind == DatumKind::Rvalue; }
bool is_valid () const
{
return check_node (val) && ty != nullptr && kind != DatumKind::Invalid;
}
void set_not_valid ()
{
val = error_mark_node;
ty = nullptr;
kind = DatumKind::Invalid;
}

bool needs_drop (DropContext *drop_ctx) const
{
if (!is_valid ())
return false;
return drop_ctx->needs_drop (ty);
}

Datum get_field (Context *ctx, size_t field_index, location_t locus);
tree raw_tree () const { return val; }

void add_clean_if_rvalue (Context *ctx, HirId expr_id);
Datum to_lvalue (Context *ctx, HirId expr_id);
Datum to_rvalue (Context *ctx);
void store_to (Context *ctx, tree dest_ptr);
void post_store (Context *ctx);
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_DATUM_H
Loading
Loading