gccrs: Add HIR to GCC GENERIC lowering for all nodes

This patch implements the lowering mentioned in the previous patch for all HIR nodes.

	gcc/rust/
	* backend/rust-compile-block.cc: New.
	* backend/rust-compile-block.h: New.
	* backend/rust-compile-expr.cc: New.
	* backend/rust-compile-expr.h: New.
	* backend/rust-compile-extern.h: New.
	* backend/rust-compile-fnparam.cc: New.
	* backend/rust-compile-fnparam.h: New.
	* backend/rust-compile-implitem.cc: New.
	* backend/rust-compile-implitem.h: New.
	* backend/rust-compile-intrinsic.cc: New.
	* backend/rust-compile-intrinsic.h: New.
	* backend/rust-compile-item.cc: New.
	* backend/rust-compile-item.h: New.
	* backend/rust-compile-pattern.cc: New.
	* backend/rust-compile-pattern.h: New.
	* backend/rust-compile-resolve-path.cc: New.
	* backend/rust-compile-resolve-path.h: New.
	* backend/rust-compile-stmt.cc: New.
	* backend/rust-compile-stmt.h: New.
	* backend/rust-compile-struct-field-expr.cc: New.
	* backend/rust-compile-struct-field-expr.h: New.
	* backend/rust-compile-type.cc: New.
	* backend/rust-compile-type.h: New.
	* backend/rust-compile-var-decl.h: New.

Co-authored-by: David Faust <david.faust@oracle.com>
This commit is contained in:
Philip Herron
2022-10-21 14:27:56 +02:00
committed by Arthur Cohen
parent 15f04af347
commit 019b2f1558
24 changed files with 6690 additions and 0 deletions

View File

@@ -0,0 +1,158 @@
// Copyright (C) 2020-2022 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-block.h"
#include "rust-compile-stmt.h"
#include "rust-compile-expr.h"
namespace Rust {
namespace Compile {
CompileBlock::CompileBlock (Context *ctx, Bvariable *result)
: HIRCompileBase (ctx), translated (nullptr), result (result)
{}
tree
CompileBlock::compile (HIR::BlockExpr *expr, Context *ctx, Bvariable *result)
{
CompileBlock compiler (ctx, result);
compiler.visit (*expr);
return compiler.translated;
}
void
CompileBlock::visit (HIR::BlockExpr &expr)
{
fncontext fnctx = ctx->peek_fn ();
tree fndecl = fnctx.fndecl;
Location start_location = expr.get_locus ();
Location end_location = expr.get_end_locus ();
auto body_mappings = expr.get_mappings ();
Resolver::Rib *rib = nullptr;
if (!ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), &rib))
{
rust_fatal_error (expr.get_locus (), "failed to setup locals per block");
return;
}
std::vector<Bvariable *> locals
= compile_locals_for_block (ctx, *rib, fndecl);
tree enclosing_scope = ctx->peek_enclosing_scope ();
tree new_block = ctx->get_backend ()->block (fndecl, enclosing_scope, locals,
start_location, end_location);
ctx->push_block (new_block);
for (auto &s : expr.get_statements ())
{
auto compiled_expr = CompileStmt::Compile (s.get (), ctx);
if (compiled_expr != nullptr)
{
tree s = convert_to_void (compiled_expr, ICV_STATEMENT);
ctx->add_statement (s);
}
}
if (expr.has_expr ())
{
// the previous passes will ensure this is a valid return or
// a valid trailing expression
tree compiled_expr = CompileExpr::Compile (expr.expr.get (), ctx);
if (compiled_expr != nullptr)
{
if (result == nullptr)
{
ctx->add_statement (compiled_expr);
}
else
{
tree result_reference = ctx->get_backend ()->var_expression (
result, expr.get_final_expr ()->get_locus ());
tree assignment
= ctx->get_backend ()->assignment_statement (result_reference,
compiled_expr,
expr.get_locus ());
ctx->add_statement (assignment);
}
}
}
ctx->pop_block ();
translated = new_block;
}
void
CompileConditionalBlocks::visit (HIR::IfExpr &expr)
{
fncontext fnctx = ctx->peek_fn ();
tree fndecl = fnctx.fndecl;
tree condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx);
tree then_block = CompileBlock::compile (expr.get_if_block (), ctx, result);
translated
= ctx->get_backend ()->if_statement (fndecl, condition_expr, then_block,
NULL, expr.get_locus ());
}
void
CompileConditionalBlocks::visit (HIR::IfExprConseqElse &expr)
{
fncontext fnctx = ctx->peek_fn ();
tree fndecl = fnctx.fndecl;
tree condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx);
tree then_block = CompileBlock::compile (expr.get_if_block (), ctx, result);
tree else_block = CompileBlock::compile (expr.get_else_block (), ctx, result);
translated
= ctx->get_backend ()->if_statement (fndecl, condition_expr, then_block,
else_block, expr.get_locus ());
}
void
CompileConditionalBlocks::visit (HIR::IfExprConseqIf &expr)
{
fncontext fnctx = ctx->peek_fn ();
tree fndecl = fnctx.fndecl;
tree condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx);
tree then_block = CompileBlock::compile (expr.get_if_block (), ctx, result);
// else block
std::vector<Bvariable *> locals;
Location start_location = expr.get_conseq_if_expr ()->get_locus ();
Location end_location = expr.get_conseq_if_expr ()->get_locus (); // FIXME
tree enclosing_scope = ctx->peek_enclosing_scope ();
tree else_block = ctx->get_backend ()->block (fndecl, enclosing_scope, locals,
start_location, end_location);
ctx->push_block (else_block);
tree else_stmt_decl
= CompileConditionalBlocks::compile (expr.get_conseq_if_expr (), ctx,
result);
ctx->add_statement (else_stmt_decl);
ctx->pop_block ();
translated
= ctx->get_backend ()->if_statement (fndecl, condition_expr, then_block,
else_block, expr.get_locus ());
}
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,211 @@
// Copyright (C) 2020-2022 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_BLOCK
#define RUST_COMPILE_BLOCK
#include "rust-compile-base.h"
namespace Rust {
namespace Compile {
class CompileBlock : private HIRCompileBase
{
public:
static tree compile (HIR::BlockExpr *expr, Context *ctx, Bvariable *result);
protected:
void visit (HIR::BlockExpr &expr);
private:
CompileBlock (Context *ctx, Bvariable *result);
tree translated;
Bvariable *result;
};
class CompileConditionalBlocks : public HIRCompileBase,
public HIR::HIRExpressionVisitor
{
public:
static tree compile (HIR::IfExpr *expr, Context *ctx, Bvariable *result)
{
CompileConditionalBlocks resolver (ctx, result);
expr->accept_vis (resolver);
return resolver.translated;
}
void visit (HIR::IfExpr &expr) override;
void visit (HIR::IfExprConseqElse &expr) override;
void visit (HIR::IfExprConseqIf &expr) override;
// Empty visit for unused Expression HIR nodes.
void visit (HIR::PathInExpression &) override {}
void visit (HIR::QualifiedPathInExpression &) override {}
void visit (HIR::ClosureExprInner &) override {}
void visit (HIR::ClosureExprInnerTyped &) override {}
void visit (HIR::StructExprFieldIdentifier &) override {}
void visit (HIR::StructExprFieldIdentifierValue &) override {}
void visit (HIR::StructExprFieldIndexValue &) override {}
void visit (HIR::StructExprStruct &) override {}
void visit (HIR::StructExprStructFields &) override {}
void visit (HIR::LiteralExpr &) override {}
void visit (HIR::BorrowExpr &) override {}
void visit (HIR::DereferenceExpr &) override {}
void visit (HIR::ErrorPropagationExpr &) override {}
void visit (HIR::NegationExpr &) override {}
void visit (HIR::ArithmeticOrLogicalExpr &) override {}
void visit (HIR::ComparisonExpr &) override {}
void visit (HIR::LazyBooleanExpr &) override {}
void visit (HIR::TypeCastExpr &) override {}
void visit (HIR::AssignmentExpr &) override {}
void visit (HIR::CompoundAssignmentExpr &) override {}
void visit (HIR::GroupedExpr &) override {}
void visit (HIR::ArrayExpr &) override {}
void visit (HIR::ArrayIndexExpr &) override {}
void visit (HIR::TupleExpr &) override {}
void visit (HIR::TupleIndexExpr &) override {}
void visit (HIR::CallExpr &) override {}
void visit (HIR::MethodCallExpr &) override {}
void visit (HIR::FieldAccessExpr &) override {}
void visit (HIR::BlockExpr &) override {}
void visit (HIR::ContinueExpr &) override {}
void visit (HIR::BreakExpr &) override {}
void visit (HIR::RangeFromToExpr &) override {}
void visit (HIR::RangeFromExpr &) override {}
void visit (HIR::RangeToExpr &) override {}
void visit (HIR::RangeFullExpr &) override {}
void visit (HIR::RangeFromToInclExpr &) override {}
void visit (HIR::RangeToInclExpr &) override {}
void visit (HIR::ReturnExpr &) override {}
void visit (HIR::UnsafeBlockExpr &) override {}
void visit (HIR::LoopExpr &) override {}
void visit (HIR::WhileLoopExpr &) override {}
void visit (HIR::WhileLetLoopExpr &) override {}
void visit (HIR::ForLoopExpr &) override {}
void visit (HIR::IfExprConseqIfLet &) override {}
void visit (HIR::IfLetExpr &) override {}
void visit (HIR::IfLetExprConseqElse &) override {}
void visit (HIR::IfLetExprConseqIf &) override {}
void visit (HIR::IfLetExprConseqIfLet &) override {}
void visit (HIR::MatchExpr &) override {}
void visit (HIR::AwaitExpr &) override {}
void visit (HIR::AsyncBlockExpr &) override {}
private:
CompileConditionalBlocks (Context *ctx, Bvariable *result)
: HIRCompileBase (ctx), translated (nullptr), result (result)
{}
tree translated;
Bvariable *result;
};
class CompileExprWithBlock : public HIRCompileBase,
public HIR::HIRExpressionVisitor
{
public:
static tree compile (HIR::ExprWithBlock *expr, Context *ctx,
Bvariable *result)
{
CompileExprWithBlock resolver (ctx, result);
expr->accept_vis (resolver);
return resolver.translated;
}
void visit (HIR::IfExpr &expr) override
{
translated = CompileConditionalBlocks::compile (&expr, ctx, result);
}
void visit (HIR::IfExprConseqElse &expr) override
{
translated = CompileConditionalBlocks::compile (&expr, ctx, result);
}
void visit (HIR::IfExprConseqIf &expr) override
{
translated = CompileConditionalBlocks::compile (&expr, ctx, result);
}
// Empty visit for unused Expression HIR nodes.
void visit (HIR::PathInExpression &) override {}
void visit (HIR::QualifiedPathInExpression &) override {}
void visit (HIR::ClosureExprInner &) override {}
void visit (HIR::ClosureExprInnerTyped &) override {}
void visit (HIR::StructExprFieldIdentifier &) override {}
void visit (HIR::StructExprFieldIdentifierValue &) override {}
void visit (HIR::StructExprFieldIndexValue &) override {}
void visit (HIR::StructExprStruct &) override {}
void visit (HIR::StructExprStructFields &) override {}
void visit (HIR::LiteralExpr &) override {}
void visit (HIR::BorrowExpr &) override {}
void visit (HIR::DereferenceExpr &) override {}
void visit (HIR::ErrorPropagationExpr &) override {}
void visit (HIR::NegationExpr &) override {}
void visit (HIR::ArithmeticOrLogicalExpr &) override {}
void visit (HIR::ComparisonExpr &) override {}
void visit (HIR::LazyBooleanExpr &) override {}
void visit (HIR::TypeCastExpr &) override {}
void visit (HIR::AssignmentExpr &) override {}
void visit (HIR::CompoundAssignmentExpr &) override {}
void visit (HIR::GroupedExpr &) override {}
void visit (HIR::ArrayExpr &) override {}
void visit (HIR::ArrayIndexExpr &) override {}
void visit (HIR::TupleExpr &) override {}
void visit (HIR::TupleIndexExpr &) override {}
void visit (HIR::CallExpr &) override {}
void visit (HIR::MethodCallExpr &) override {}
void visit (HIR::FieldAccessExpr &) override {}
void visit (HIR::BlockExpr &) override {}
void visit (HIR::ContinueExpr &) override {}
void visit (HIR::BreakExpr &) override {}
void visit (HIR::RangeFromToExpr &) override {}
void visit (HIR::RangeFromExpr &) override {}
void visit (HIR::RangeToExpr &) override {}
void visit (HIR::RangeFullExpr &) override {}
void visit (HIR::RangeFromToInclExpr &) override {}
void visit (HIR::RangeToInclExpr &) override {}
void visit (HIR::ReturnExpr &) override {}
void visit (HIR::UnsafeBlockExpr &) override {}
void visit (HIR::LoopExpr &) override {}
void visit (HIR::WhileLoopExpr &) override {}
void visit (HIR::WhileLetLoopExpr &) override {}
void visit (HIR::ForLoopExpr &) override {}
void visit (HIR::IfExprConseqIfLet &) override {}
void visit (HIR::IfLetExpr &) override {}
void visit (HIR::IfLetExprConseqElse &) override {}
void visit (HIR::IfLetExprConseqIf &) override {}
void visit (HIR::IfLetExprConseqIfLet &) override {}
void visit (HIR::MatchExpr &) override {}
void visit (HIR::AwaitExpr &) override {}
void visit (HIR::AsyncBlockExpr &) override {}
private:
CompileExprWithBlock (Context *ctx, Bvariable *result)
: HIRCompileBase (ctx), translated (nullptr), result (result)
{}
tree translated;
Bvariable *result;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_BLOCK

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,148 @@
// Copyright (C) 2020-2022 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_EXPR
#define RUST_COMPILE_EXPR
#include "rust-compile-base.h"
namespace Rust {
namespace Compile {
class CompileExpr : private HIRCompileBase, protected HIR::HIRExpressionVisitor
{
public:
static tree Compile (HIR::Expr *expr, Context *ctx);
void visit (HIR::TupleIndexExpr &expr) override;
void visit (HIR::TupleExpr &expr) override;
void visit (HIR::ReturnExpr &expr) override;
void visit (HIR::CallExpr &expr) override;
void visit (HIR::MethodCallExpr &expr) override;
void visit (HIR::LiteralExpr &expr) override;
void visit (HIR::AssignmentExpr &expr) override;
void visit (HIR::CompoundAssignmentExpr &expr) override;
void visit (HIR::ArrayIndexExpr &expr) override;
void visit (HIR::ArrayExpr &expr) override;
void visit (HIR::ArithmeticOrLogicalExpr &expr) override;
void visit (HIR::ComparisonExpr &expr) override;
void visit (HIR::LazyBooleanExpr &expr) override;
void visit (HIR::NegationExpr &expr) override;
void visit (HIR::TypeCastExpr &expr) override;
void visit (HIR::IfExpr &expr) override;
void visit (HIR::IfExprConseqIf &expr) override;
void visit (HIR::IfExprConseqElse &expr) override;
void visit (HIR::BlockExpr &expr) override;
void visit (HIR::UnsafeBlockExpr &expr) override;
void visit (HIR::StructExprStruct &struct_expr) override;
void visit (HIR::StructExprStructFields &struct_expr) override;
void visit (HIR::GroupedExpr &expr) override;
void visit (HIR::FieldAccessExpr &expr) override;
void visit (HIR::QualifiedPathInExpression &expr) override;
void visit (HIR::PathInExpression &expr) override;
void visit (HIR::LoopExpr &expr) override;
void visit (HIR::WhileLoopExpr &expr) override;
void visit (HIR::BreakExpr &expr) override;
void visit (HIR::ContinueExpr &expr) override;
void visit (HIR::BorrowExpr &expr) override;
void visit (HIR::DereferenceExpr &expr) override;
void visit (HIR::MatchExpr &expr) override;
void visit (HIR::RangeFromToExpr &expr) override;
void visit (HIR::RangeFromExpr &expr) override;
void visit (HIR::RangeToExpr &expr) override;
void visit (HIR::RangeFullExpr &expr) override;
void visit (HIR::RangeFromToInclExpr &expr) override;
// Empty visit for unused Expression HIR nodes.
void visit (HIR::ClosureExprInner &) override {}
void visit (HIR::ClosureExprInnerTyped &) override {}
void visit (HIR::StructExprFieldIdentifier &) override {}
void visit (HIR::StructExprFieldIdentifierValue &) override {}
void visit (HIR::StructExprFieldIndexValue &) override {}
void visit (HIR::ErrorPropagationExpr &) override {}
void visit (HIR::RangeToInclExpr &) override {}
void visit (HIR::WhileLetLoopExpr &) override {}
void visit (HIR::ForLoopExpr &) override {}
void visit (HIR::IfExprConseqIfLet &) override {}
void visit (HIR::IfLetExpr &) override {}
void visit (HIR::IfLetExprConseqElse &) override {}
void visit (HIR::IfLetExprConseqIf &) override {}
void visit (HIR::IfLetExprConseqIfLet &) override {}
void visit (HIR::AwaitExpr &) override {}
void visit (HIR::AsyncBlockExpr &) override {}
protected:
tree get_fn_addr_from_dyn (const TyTy::DynamicObjectType *dyn,
TyTy::BaseType *receiver, TyTy::FnType *fntype,
tree receiver_ref, Location expr_locus);
tree get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn,
TyTy::BaseType *receiver, TyTy::FnType *fntype,
tree receiver_ref, Location expr_locus);
tree resolve_method_address (TyTy::FnType *fntype, HirId ref,
TyTy::BaseType *receiver,
HIR::PathIdentSegment &segment,
Analysis::NodeMapping expr_mappings,
Location expr_locus);
tree
resolve_operator_overload (Analysis::RustLangItem::ItemType lang_item_type,
HIR::OperatorExprMeta expr, tree lhs, tree rhs,
HIR::Expr *lhs_expr, HIR::Expr *rhs_expr);
tree compile_bool_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty);
tree compile_integer_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty);
tree compile_float_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty);
tree compile_char_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty);
tree compile_byte_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty);
tree compile_string_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty);
tree compile_byte_string_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty);
tree type_cast_expression (tree type_to_cast_to, tree expr, Location locus);
tree array_value_expr (Location expr_locus, const TyTy::ArrayType &array_tyty,
tree array_type, HIR::ArrayElemsValues &elems);
tree array_copied_expr (Location expr_locus,
const TyTy::ArrayType &array_tyty, tree array_type,
HIR::ArrayElemsCopied &elems);
private:
CompileExpr (Context *ctx);
tree translated;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_EXPR

View File

@@ -0,0 +1,172 @@
// Copyright (C) 2020-2022 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_EXTERN_ITEM
#define RUST_COMPILE_EXTERN_ITEM
#include "rust-compile-base.h"
#include "rust-compile-intrinsic.h"
namespace Rust {
namespace Compile {
class CompileExternItem : public HIRCompileBase,
public HIR::HIRExternalItemVisitor
{
public:
static tree compile (HIR::ExternalItem *item, Context *ctx,
TyTy::BaseType *concrete = nullptr,
bool is_query_mode = false,
Location ref_locus = Location ())
{
CompileExternItem compiler (ctx, concrete, ref_locus);
item->accept_vis (compiler);
if (is_query_mode && compiler.reference == error_mark_node)
rust_internal_error_at (ref_locus, "failed to compile extern item: %s",
item->as_string ().c_str ());
return compiler.reference;
}
void visit (HIR::ExternalStaticItem &item) override
{
// check if its already been compiled
Bvariable *lookup = ctx->get_backend ()->error_variable ();
if (ctx->lookup_var_decl (item.get_mappings ().get_hirid (), &lookup))
{
reference = ctx->get_backend ()->var_expression (lookup, ref_locus);
return;
}
TyTy::BaseType *resolved_type = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (item.get_mappings ().get_hirid (),
&resolved_type);
rust_assert (ok);
std::string name = item.get_item_name ();
// FIXME this is assuming C ABI
std::string asm_name = name;
tree type = TyTyResolveCompile::compile (ctx, resolved_type);
bool is_external = true;
bool is_hidden = false;
bool in_unique_section = false;
Bvariable *static_global
= ctx->get_backend ()->global_variable (name, asm_name, type, is_external,
is_hidden, in_unique_section,
item.get_locus ());
ctx->insert_var_decl (item.get_mappings ().get_hirid (), static_global);
ctx->push_var (static_global);
reference = ctx->get_backend ()->var_expression (static_global, ref_locus);
}
void visit (HIR::ExternalFunctionItem &function) override
{
TyTy::BaseType *fntype_tyty;
if (!ctx->get_tyctx ()->lookup_type (function.get_mappings ().get_hirid (),
&fntype_tyty))
{
rust_fatal_error (function.get_locus (),
"failed to lookup function type");
return;
}
rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (fntype_tyty);
if (fntype->has_subsititions_defined ())
{
// we cant do anything for this only when it is used and a concrete type
// is given
if (concrete == nullptr)
return;
else
{
rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
fntype = static_cast<TyTy::FnType *> (concrete);
}
}
// items can be forward compiled which means we may not need to invoke this
// code. We might also have already compiled this generic function as well.
tree lookup = NULL_TREE;
if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup,
fntype->get_id (), fntype))
{
reference = address_expression (lookup, ref_locus);
return;
}
if (fntype->has_subsititions_defined ())
{
// override the Hir Lookups for the substituions in this context
fntype->override_context ();
}
if (fntype->get_abi () == ABI::INTRINSIC)
{
Intrinsics compile (ctx);
tree fndecl = compile.compile (fntype);
ctx->insert_function_decl (fntype, fndecl);
return;
}
tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
std::string ir_symbol_name = function.get_item_name ();
std::string asm_name = function.get_item_name ();
if (fntype->get_abi () == ABI::RUST)
{
// then we need to get the canonical path of it and mangle it
const Resolver::CanonicalPath *canonical_path = nullptr;
bool ok = ctx->get_mappings ()->lookup_canonical_path (
function.get_mappings ().get_nodeid (), &canonical_path);
rust_assert (ok);
ir_symbol_name = canonical_path->get () + fntype->subst_as_string ();
asm_name = ctx->mangle_item (fntype, *canonical_path);
}
const unsigned int flags = Backend::function_is_declaration;
tree fndecl
= ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name,
asm_name, flags, function.get_locus ());
TREE_PUBLIC (fndecl) = 1;
setup_abi_options (fndecl, fntype->get_abi ());
ctx->insert_function_decl (fntype, fndecl);
reference = address_expression (fndecl, ref_locus);
}
private:
CompileExternItem (Context *ctx, TyTy::BaseType *concrete, Location ref_locus)
: HIRCompileBase (ctx), concrete (concrete), reference (error_mark_node),
ref_locus (ref_locus)
{}
TyTy::BaseType *concrete;
tree reference;
Location ref_locus;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_EXTERN_ITEM

View File

@@ -0,0 +1,121 @@
// Copyright (C) 2020-2022 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-fnparam.h"
#include "rust-compile-pattern.h"
#include "gimple-expr.h"
namespace Rust {
namespace Compile {
CompileFnParam::CompileFnParam (Context *ctx, tree fndecl, tree decl_type,
Location locus)
: HIRCompileBase (ctx), fndecl (fndecl), decl_type (decl_type), locus (locus),
compiled_param (ctx->get_backend ()->error_variable ())
{}
Bvariable *
CompileFnParam::compile (Context *ctx, tree fndecl, HIR::FunctionParam *param,
tree decl_type, Location locus)
{
CompileFnParam compiler (ctx, fndecl, decl_type, locus);
param->get_param_name ()->accept_vis (compiler);
return compiler.compiled_param;
}
Bvariable *
CompileFnParam::compile (Context *ctx, tree fndecl, HIR::Pattern *param,
tree decl_type, Location locus)
{
CompileFnParam compiler (ctx, fndecl, decl_type, locus);
param->accept_vis (compiler);
return compiler.compiled_param;
}
void
CompileFnParam::visit (HIR::IdentifierPattern &pattern)
{
if (!pattern.is_mut ())
decl_type = ctx->get_backend ()->immutable_type (decl_type);
compiled_param
= ctx->get_backend ()->parameter_variable (fndecl,
pattern.get_identifier (),
decl_type, locus);
}
void
CompileFnParam::visit (HIR::WildcardPattern &pattern)
{
decl_type = ctx->get_backend ()->immutable_type (decl_type);
compiled_param
= ctx->get_backend ()->parameter_variable (fndecl, "_", decl_type, locus);
}
void
CompileFnParam::visit (HIR::StructPattern &pattern)
{
// generate the anon param
tree tmp_ident = create_tmp_var_name ("RSTPRM");
std::string cpp_str_identifier = std::string (IDENTIFIER_POINTER (tmp_ident));
decl_type = ctx->get_backend ()->immutable_type (decl_type);
compiled_param
= ctx->get_backend ()->parameter_variable (fndecl, cpp_str_identifier,
decl_type, locus);
// setup the pattern bindings
tree anon_param = ctx->get_backend ()->var_expression (compiled_param, locus);
CompilePatternBindings::Compile (&pattern, anon_param, ctx);
}
void
CompileFnParam::visit (HIR::TupleStructPattern &pattern)
{
// generate the anon param
tree tmp_ident = create_tmp_var_name ("RSTPRM");
std::string cpp_str_identifier = std::string (IDENTIFIER_POINTER (tmp_ident));
decl_type = ctx->get_backend ()->immutable_type (decl_type);
compiled_param
= ctx->get_backend ()->parameter_variable (fndecl, cpp_str_identifier,
decl_type, locus);
// setup the pattern bindings
tree anon_param = ctx->get_backend ()->var_expression (compiled_param, locus);
CompilePatternBindings::Compile (&pattern, anon_param, ctx);
}
Bvariable *
CompileSelfParam::compile (Context *ctx, tree fndecl, HIR::SelfParam &self,
tree decl_type, Location locus)
{
bool is_immutable
= self.get_self_kind () == HIR::SelfParam::ImplicitSelfKind::IMM
|| self.get_self_kind () == HIR::SelfParam::ImplicitSelfKind::IMM_REF;
if (is_immutable)
decl_type = ctx->get_backend ()->immutable_type (decl_type);
return ctx->get_backend ()->parameter_variable (fndecl, "self", decl_type,
locus);
}
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,70 @@
// Copyright (C) 2020-2022 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_FNPARAM
#define RUST_COMPILE_FNPARAM
#include "rust-compile-base.h"
namespace Rust {
namespace Compile {
class CompileFnParam : private HIRCompileBase, protected HIR::HIRPatternVisitor
{
public:
static Bvariable *compile (Context *ctx, tree fndecl,
HIR::FunctionParam *param, tree decl_type,
Location locus);
static Bvariable *compile (Context *ctx, tree fndecl, HIR::Pattern *param,
tree decl_type, Location locus);
void visit (HIR::IdentifierPattern &pattern) override;
void visit (HIR::WildcardPattern &pattern) override;
void visit (HIR::StructPattern &) override;
void visit (HIR::TupleStructPattern &) override;
// Empty visit for unused Pattern HIR nodes.
void visit (HIR::GroupedPattern &) override {}
void visit (HIR::LiteralPattern &) override {}
void visit (HIR::PathInExpression &) override {}
void visit (HIR::QualifiedPathInExpression &) override {}
void visit (HIR::RangePattern &) override {}
void visit (HIR::ReferencePattern &) override {}
void visit (HIR::SlicePattern &) override {}
void visit (HIR::TuplePattern &) override {}
private:
CompileFnParam (Context *ctx, tree fndecl, tree decl_type, Location locus);
tree fndecl;
tree decl_type;
Location locus;
Bvariable *compiled_param;
};
class CompileSelfParam : private HIRCompileBase
{
public:
static Bvariable *compile (Context *ctx, tree fndecl, HIR::SelfParam &self,
tree decl_type, Location locus);
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_FNPARAM

View File

@@ -0,0 +1,101 @@
// Copyright (C) 2020-2022 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-implitem.h"
#include "rust-compile-expr.h"
#include "rust-compile-fnparam.h"
namespace Rust {
namespace Compile {
void
CompileTraitItem::visit (HIR::TraitItemConst &constant)
{
rust_assert (concrete != nullptr);
TyTy::BaseType *resolved_type = concrete;
const Resolver::CanonicalPath *canonical_path = nullptr;
bool ok = ctx->get_mappings ()->lookup_canonical_path (
constant.get_mappings ().get_nodeid (), &canonical_path);
rust_assert (ok);
HIR::Expr *const_value_expr = constant.get_expr ().get ();
tree const_expr
= compile_constant_item (ctx, resolved_type, canonical_path,
const_value_expr, constant.get_locus ());
ctx->push_const (const_expr);
ctx->insert_const_decl (constant.get_mappings ().get_hirid (), const_expr);
reference = const_expr;
}
void
CompileTraitItem::visit (HIR::TraitItemFunc &func)
{
rust_assert (func.has_block_defined ());
rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (concrete);
fntype->monomorphize ();
// items can be forward compiled which means we may not need to invoke this
// code. We might also have already compiled this generic function as well.
tree lookup = NULL_TREE;
if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup,
fntype->get_id (), fntype))
{
// has this been added to the list then it must be finished
if (ctx->function_completed (lookup))
{
tree dummy = NULL_TREE;
if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
{
ctx->insert_function_decl (fntype, lookup);
}
reference = address_expression (lookup, ref_locus);
return;
}
}
if (fntype->has_subsititions_defined ())
{
// override the Hir Lookups for the substituions in this context
fntype->override_context ();
}
const Resolver::CanonicalPath *canonical_path = nullptr;
bool ok = ctx->get_mappings ()->lookup_canonical_path (
func.get_mappings ().get_nodeid (), &canonical_path);
rust_assert (ok);
// FIXME: How do we get the proper visibility here?
auto vis = HIR::Visibility (HIR::Visibility::VisType::PUBLIC);
HIR::TraitFunctionDecl &function = func.get_decl ();
tree fndecl
= compile_function (ctx, function.get_function_name (),
function.get_self (), function.get_function_params (),
function.get_qualifiers (), vis,
func.get_outer_attrs (), func.get_locus (),
func.get_block_expr ().get (), canonical_path, fntype,
function.has_return_type ());
reference = address_expression (fndecl, ref_locus);
}
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,91 @@
// Copyright (C) 2020-2022 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_IMPLITEM_H
#define RUST_COMPILE_IMPLITEM_H
#include "rust-compile-item.h"
#include "rust-compile-expr.h"
#include "rust-compile-fnparam.h"
namespace Rust {
namespace Compile {
// this is a proxy for HIR::ImplItem's back to use the normel HIR::Item path
class CompileInherentImplItem : public CompileItem
{
public:
static tree Compile (HIR::ImplItem *item, Context *ctx,
TyTy::BaseType *concrete = nullptr,
bool is_query_mode = false,
Location ref_locus = Location ())
{
CompileInherentImplItem compiler (ctx, concrete, ref_locus);
item->accept_vis (compiler);
if (is_query_mode && compiler.reference == error_mark_node)
rust_internal_error_at (ref_locus, "failed to compile impl item: %s",
item->as_string ().c_str ());
return compiler.reference;
}
private:
CompileInherentImplItem (Context *ctx, TyTy::BaseType *concrete,
Location ref_locus)
: CompileItem (ctx, concrete, ref_locus)
{}
};
class CompileTraitItem : public HIRCompileBase, public HIR::HIRTraitItemVisitor
{
public:
static tree Compile (HIR::TraitItem *item, Context *ctx,
TyTy::BaseType *concrete, bool is_query_mode = false,
Location ref_locus = Location ())
{
CompileTraitItem compiler (ctx, concrete, ref_locus);
item->accept_vis (compiler);
if (is_query_mode && compiler.reference == error_mark_node)
rust_internal_error_at (ref_locus, "failed to compile trait item: %s",
item->as_string ().c_str ());
return compiler.reference;
}
void visit (HIR::TraitItemConst &constant) override;
void visit (HIR::TraitItemFunc &func) override;
void visit (HIR::TraitItemType &typ) override {}
private:
CompileTraitItem (Context *ctx, TyTy::BaseType *concrete, Location ref_locus)
: HIRCompileBase (ctx), concrete (concrete), reference (error_mark_node),
ref_locus (ref_locus)
{}
TyTy::BaseType *concrete;
tree reference;
Location ref_locus;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_IMPLITEM_H

View File

@@ -0,0 +1,515 @@
// 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-intrinsic.h"
#include "fold-const.h"
#include "langhooks.h"
#include "rust-compile-context.h"
#include "rust-compile-type.h"
#include "rust-compile-fnparam.h"
#include "rust-builtins.h"
#include "rust-diagnostics.h"
#include "rust-location.h"
#include "rust-tree.h"
#include "tree-core.h"
#include "print-tree.h"
namespace Rust {
namespace Compile {
static tree
offset_handler (Context *ctx, TyTy::FnType *fntype);
static tree
sizeof_handler (Context *ctx, TyTy::FnType *fntype);
static tree
transmute_handler (Context *ctx, TyTy::FnType *fntype);
static tree
rotate_handler (Context *ctx, TyTy::FnType *fntype, tree_code op);
static tree
wrapping_op_handler (Context *ctx, TyTy::FnType *fntype, tree_code op);
static tree
copy_nonoverlapping_handler (Context *ctx, TyTy::FnType *fntype);
static inline tree
rotate_left_handler (Context *ctx, TyTy::FnType *fntype)
{
return rotate_handler (ctx, fntype, LROTATE_EXPR);
}
static inline tree
rotate_right_handler (Context *ctx, TyTy::FnType *fntype)
{
return rotate_handler (ctx, fntype, RROTATE_EXPR);
}
static inline tree
wrapping_add_handler (Context *ctx, TyTy::FnType *fntype)
{
return wrapping_op_handler (ctx, fntype, PLUS_EXPR);
}
static inline tree
wrapping_sub_handler (Context *ctx, TyTy::FnType *fntype)
{
return wrapping_op_handler (ctx, fntype, MINUS_EXPR);
}
static inline tree
wrapping_mul_handler (Context *ctx, TyTy::FnType *fntype)
{
return wrapping_op_handler (ctx, fntype, MULT_EXPR);
}
static const std::map<std::string,
std::function<tree (Context *, TyTy::FnType *)>>
generic_intrinsics = {{"offset", &offset_handler},
{"size_of", &sizeof_handler},
{"transmute", &transmute_handler},
{"rotate_left", &rotate_left_handler},
{"rotate_right", &rotate_right_handler},
{"wrapping_add", &wrapping_add_handler},
{"wrapping_sub", &wrapping_sub_handler},
{"wrapping_mul", &wrapping_mul_handler},
{"copy_nonoverlapping", &copy_nonoverlapping_handler}};
Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
tree
Intrinsics::compile (TyTy::FnType *fntype)
{
rust_assert (fntype->get_abi () == ABI::INTRINSIC);
tree builtin = error_mark_node;
BuiltinsContext &builtin_ctx = BuiltinsContext::get ();
if (builtin_ctx.lookup_simple_builtin (fntype->get_identifier (), &builtin))
return builtin;
// is it an generic builtin?
auto it = generic_intrinsics.find (fntype->get_identifier ());
if (it != generic_intrinsics.end ())
return it->second (ctx, fntype);
Location locus = ctx->get_mappings ()->lookup_location (fntype->get_ref ());
rust_error_at (locus, "unknown builtin intrinsic: %s",
fntype->get_identifier ().c_str ());
return error_mark_node;
}
/**
* Items can be forward compiled which means we may not need to invoke this
* code. We might also have already compiled this generic function as well.
*/
static bool
check_for_cached_intrinsic (Context *ctx, TyTy::FnType *fntype, tree *lookup)
{
if (ctx->lookup_function_decl (fntype->get_ty_ref (), lookup,
fntype->get_id (), fntype))
{
// Has this been added to the list? Then it must be finished
if (ctx->function_completed (*lookup))
{
tree dummy = NULL_TREE;
if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
ctx->insert_function_decl (fntype, *lookup);
return true;
}
}
return false;
}
/**
* Maybe override the Hir Lookups for the substituions in this context
*/
static void
maybe_override_ctx (TyTy::FnType *fntype)
{
if (fntype->has_subsititions_defined ())
fntype->override_context ();
}
/**
* Compile and setup a function's parameters
*/
static void
compile_fn_params (Context *ctx, TyTy::FnType *fntype, tree fndecl,
std::vector<Bvariable *> *compiled_param_variables,
std::vector<tree_node *> *compiled_param_types = nullptr)
{
for (auto &parm : fntype->get_params ())
{
auto &referenced_param = parm.first;
auto &param_tyty = parm.second;
auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty);
Location param_locus = referenced_param->get_locus ();
Bvariable *compiled_param_var
= CompileFnParam::compile (ctx, fndecl, referenced_param,
compiled_param_type, param_locus);
compiled_param_variables->push_back (compiled_param_var);
if (compiled_param_types)
compiled_param_types->push_back (compiled_param_type);
}
}
static tree
compile_intrinsic_function (Context *ctx, TyTy::FnType *fntype)
{
maybe_override_ctx (fntype);
const Resolver::CanonicalPath &canonical_path = fntype->get_ident ().path;
tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
std::string ir_symbol_name
= canonical_path.get () + fntype->subst_as_string ();
std::string asm_name = ctx->mangle_item (fntype, canonical_path);
unsigned int flags = 0;
tree fndecl
= ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, asm_name,
flags, fntype->get_ident ().locus);
TREE_PUBLIC (fndecl) = 0;
TREE_READONLY (fndecl) = 1;
DECL_ARTIFICIAL (fndecl) = 1;
DECL_EXTERNAL (fndecl) = 0;
DECL_DECLARED_INLINE_P (fndecl) = 1;
return fndecl;
}
static void
enter_intrinsic_block (Context *ctx, tree fndecl)
{
tree enclosing_scope = NULL_TREE;
Location start_location = Location ();
Location end_location = Location ();
auto block = ctx->get_backend ()->block (fndecl, enclosing_scope, {},
start_location, end_location);
ctx->push_block (block);
}
static void
finalize_intrinsic_block (Context *ctx, tree fndecl)
{
tree bind_tree = ctx->pop_block ();
gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
DECL_SAVED_TREE (fndecl) = bind_tree;
ctx->push_function (fndecl);
}
static tree
offset_handler (Context *ctx, TyTy::FnType *fntype)
{
// offset intrinsic has two params dst pointer and offset isize
rust_assert (fntype->get_params ().size () == 2);
auto fndecl = compile_intrinsic_function (ctx, fntype);
std::vector<Bvariable *> param_vars;
compile_fn_params (ctx, fntype, fndecl, &param_vars);
auto &dst_param = param_vars.at (0);
auto &size_param = param_vars.at (1);
rust_assert (param_vars.size () == 2);
if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
return error_mark_node;
enter_intrinsic_block (ctx, fndecl);
// BUILTIN offset FN BODY BEGIN
tree dst = ctx->get_backend ()->var_expression (dst_param, Location ());
tree size = ctx->get_backend ()->var_expression (size_param, Location ());
tree pointer_offset_expr
= pointer_offset_expression (dst, size, BUILTINS_LOCATION);
auto return_statement
= ctx->get_backend ()->return_statement (fndecl, {pointer_offset_expr},
Location ());
ctx->add_statement (return_statement);
// BUILTIN offset FN BODY END
finalize_intrinsic_block (ctx, fndecl);
return fndecl;
}
static tree
sizeof_handler (Context *ctx, TyTy::FnType *fntype)
{
// size_of has _zero_ parameters its parameter is the generic one
rust_assert (fntype->get_params ().size () == 0);
tree lookup = NULL_TREE;
if (check_for_cached_intrinsic (ctx, fntype, &lookup))
return lookup;
auto fndecl = compile_intrinsic_function (ctx, fntype);
// get the template parameter type tree fn size_of<T>();
rust_assert (fntype->get_num_substitutions () == 1);
auto &param_mapping = fntype->get_substs ().at (0);
const TyTy::ParamType *param_tyty = param_mapping.get_param_ty ();
TyTy::BaseType *resolved_tyty = param_tyty->resolve ();
tree template_parameter_type
= TyTyResolveCompile::compile (ctx, resolved_tyty);
enter_intrinsic_block (ctx, fndecl);
// BUILTIN size_of FN BODY BEGIN
tree size_expr = TYPE_SIZE_UNIT (template_parameter_type);
auto return_statement
= ctx->get_backend ()->return_statement (fndecl, {size_expr}, Location ());
ctx->add_statement (return_statement);
// BUILTIN size_of FN BODY END
finalize_intrinsic_block (ctx, fndecl);
return fndecl;
}
static tree
transmute_handler (Context *ctx, TyTy::FnType *fntype)
{
// transmute intrinsic has one parameter
rust_assert (fntype->get_params ().size () == 1);
tree lookup = NULL_TREE;
if (check_for_cached_intrinsic (ctx, fntype, &lookup))
return lookup;
auto fndecl = compile_intrinsic_function (ctx, fntype);
std::vector<Bvariable *> param_vars;
std::vector<tree_node *> compiled_types;
compile_fn_params (ctx, fntype, fndecl, &param_vars, &compiled_types);
if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
return error_mark_node;
// param to convert
Bvariable *convert_me_param = param_vars.at (0);
tree convert_me_expr
= ctx->get_backend ()->var_expression (convert_me_param, Location ());
// check for transmute pre-conditions
tree target_type_expr = TREE_TYPE (DECL_RESULT (fndecl));
tree source_type_expr = compiled_types.at (0);
tree target_size_expr = TYPE_SIZE (target_type_expr);
tree source_size_expr = TYPE_SIZE (source_type_expr);
// for some reason, unit types and other zero-sized types return NULL for the
// size expressions
unsigned HOST_WIDE_INT target_size
= target_size_expr ? TREE_INT_CST_LOW (target_size_expr) : 0;
unsigned HOST_WIDE_INT source_size
= source_size_expr ? TREE_INT_CST_LOW (source_size_expr) : 0;
// size check for concrete types
// TODO(liushuyu): check alignment for pointers; check for dependently-sized
// types
if (target_size != source_size)
{
rust_error_at (fntype->get_locus (),
"cannot transmute between types of different sizes, or "
"dependently-sized types");
rust_inform (fntype->get_ident ().locus, "source type: %qs (%lu bits)",
fntype->get_params ().at (0).second->as_string ().c_str (),
(unsigned long) source_size);
rust_inform (fntype->get_ident ().locus, "target type: %qs (%lu bits)",
fntype->get_return_type ()->as_string ().c_str (),
(unsigned long) target_size);
}
enter_intrinsic_block (ctx, fndecl);
// BUILTIN transmute FN BODY BEGIN
// Return *((orig_type*)&decl) */
tree t
= build_fold_addr_expr_loc (Location ().gcc_location (), convert_me_expr);
t = fold_build1_loc (Location ().gcc_location (), NOP_EXPR,
build_pointer_type (target_type_expr), t);
tree result_expr
= build_fold_indirect_ref_loc (Location ().gcc_location (), t);
auto return_statement
= ctx->get_backend ()->return_statement (fndecl, {result_expr},
Location ());
ctx->add_statement (return_statement);
// BUILTIN transmute FN BODY END
finalize_intrinsic_block (ctx, fndecl);
return fndecl;
}
static tree
rotate_handler (Context *ctx, TyTy::FnType *fntype, tree_code op)
{
// rotate intrinsic has two parameter
rust_assert (fntype->get_params ().size () == 2);
tree lookup = NULL_TREE;
if (check_for_cached_intrinsic (ctx, fntype, &lookup))
return lookup;
auto fndecl = compile_intrinsic_function (ctx, fntype);
// setup the params
std::vector<Bvariable *> param_vars;
compile_fn_params (ctx, fntype, fndecl, &param_vars);
auto &x_param = param_vars.at (0);
auto &y_param = param_vars.at (1);
rust_assert (param_vars.size () == 2);
if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
return error_mark_node;
enter_intrinsic_block (ctx, fndecl);
// BUILTIN rotate FN BODY BEGIN
tree x = ctx->get_backend ()->var_expression (x_param, Location ());
tree y = ctx->get_backend ()->var_expression (y_param, Location ());
tree rotate_expr
= fold_build2_loc (BUILTINS_LOCATION, op, TREE_TYPE (x), x, y);
auto return_statement
= ctx->get_backend ()->return_statement (fndecl, {rotate_expr},
Location ());
ctx->add_statement (return_statement);
// BUILTIN rotate FN BODY END
finalize_intrinsic_block (ctx, fndecl);
return fndecl;
}
/**
* pub fn wrapping_{add, sub, mul}<T>(lhs: T, rhs: T) -> T;
*/
static tree
wrapping_op_handler (Context *ctx, TyTy::FnType *fntype, tree_code op)
{
// wrapping_<op> intrinsics have two parameter
rust_assert (fntype->get_params ().size () == 2);
tree lookup = NULL_TREE;
if (check_for_cached_intrinsic (ctx, fntype, &lookup))
return lookup;
auto fndecl = compile_intrinsic_function (ctx, fntype);
// setup the params
std::vector<Bvariable *> param_vars;
compile_fn_params (ctx, fntype, fndecl, &param_vars);
auto &lhs_param = param_vars.at (0);
auto &rhs_param = param_vars.at (1);
if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
return error_mark_node;
enter_intrinsic_block (ctx, fndecl);
// BUILTIN wrapping_<op> FN BODY BEGIN
auto lhs = ctx->get_backend ()->var_expression (lhs_param, Location ());
auto rhs = ctx->get_backend ()->var_expression (rhs_param, Location ());
// Operations are always wrapping in Rust, as we have -fwrapv enabled by
// default. The difference between a wrapping_{add, sub, mul} and a regular
// arithmetic operation is that these intrinsics do not panic - they always
// carry over.
auto wrap_expr = build2 (op, TREE_TYPE (lhs), lhs, rhs);
auto return_statement
= ctx->get_backend ()->return_statement (fndecl, {wrap_expr}, Location ());
ctx->add_statement (return_statement);
// BUILTIN wrapping_<op> FN BODY END
finalize_intrinsic_block (ctx, fndecl);
return fndecl;
}
/**
* fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
*/
static tree
copy_nonoverlapping_handler (Context *ctx, TyTy::FnType *fntype)
{
rust_assert (fntype->get_params ().size () == 3);
rust_assert (fntype->get_num_substitutions () == 1);
tree lookup = NULL_TREE;
if (check_for_cached_intrinsic (ctx, fntype, &lookup))
return lookup;
auto fndecl = compile_intrinsic_function (ctx, fntype);
// Most intrinsic functions are pure - not `copy_nonoverlapping`
TREE_READONLY (fndecl) = 0;
TREE_SIDE_EFFECTS (fndecl) = 1;
// setup the params
std::vector<Bvariable *> param_vars;
compile_fn_params (ctx, fntype, fndecl, &param_vars);
if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
return error_mark_node;
enter_intrinsic_block (ctx, fndecl);
// BUILTIN copy_nonoverlapping BODY BEGIN
auto src = ctx->get_backend ()->var_expression (param_vars[0], Location ());
auto dst = ctx->get_backend ()->var_expression (param_vars[1], Location ());
auto count = ctx->get_backend ()->var_expression (param_vars[2], Location ());
// We want to create the following statement
// memcpy(dst, src, size_of::<T>());
// so
// memcpy(dst, src, size_expr);
auto *resolved_ty = fntype->get_substs ().at (0).get_param_ty ()->resolve ();
auto param_type = TyTyResolveCompile::compile (ctx, resolved_ty);
tree size_expr
= build2 (MULT_EXPR, size_type_node, TYPE_SIZE_UNIT (param_type), count);
tree memcpy_raw = nullptr;
BuiltinsContext::get ().lookup_simple_builtin ("memcpy", &memcpy_raw);
rust_assert (memcpy_raw);
auto memcpy
= build_fold_addr_expr_loc (Location ().gcc_location (), memcpy_raw);
auto copy_call
= ctx->get_backend ()->call_expression (memcpy, {dst, src, size_expr},
nullptr, Location ());
ctx->add_statement (copy_call);
// BUILTIN copy_nonoverlapping BODY END
finalize_intrinsic_block (ctx, fndecl);
return fndecl;
}
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,40 @@
// 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_INTRINSIC
#define RUST_COMPILE_INTRINSIC
#include "rust-compile-context.h"
#include "langhooks.h"
namespace Rust {
namespace Compile {
class Intrinsics
{
public:
Intrinsics (Context *ctx);
tree compile (TyTy::FnType *fntype);
private:
Context *ctx;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_INTRINSIC

View File

@@ -0,0 +1,206 @@
// Copyright (C) 2020-2022 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-item.h"
#include "rust-compile-implitem.h"
#include "rust-compile-expr.h"
#include "rust-compile-extern.h"
#include "rust-constexpr.h"
namespace Rust {
namespace Compile {
void
CompileItem::visit (HIR::StaticItem &var)
{
// have we already compiled this?
Bvariable *static_decl_ref = nullptr;
if (ctx->lookup_var_decl (var.get_mappings ().get_hirid (), &static_decl_ref))
{
reference
= ctx->get_backend ()->var_expression (static_decl_ref, ref_locus);
return;
}
TyTy::BaseType *resolved_type = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (var.get_mappings ().get_hirid (),
&resolved_type);
rust_assert (ok);
tree type = TyTyResolveCompile::compile (ctx, resolved_type);
tree value = CompileExpr::Compile (var.get_expr (), ctx);
const Resolver::CanonicalPath *canonical_path = nullptr;
ok = ctx->get_mappings ()->lookup_canonical_path (
var.get_mappings ().get_nodeid (), &canonical_path);
rust_assert (ok);
std::string name = canonical_path->get ();
std::string asm_name = ctx->mangle_item (resolved_type, *canonical_path);
bool is_external = false;
bool is_hidden = false;
bool in_unique_section = true;
Bvariable *static_global
= ctx->get_backend ()->global_variable (name, asm_name, type, is_external,
is_hidden, in_unique_section,
var.get_locus ());
ctx->get_backend ()->global_variable_set_init (static_global, value);
ctx->insert_var_decl (var.get_mappings ().get_hirid (), static_global);
ctx->push_var (static_global);
reference = ctx->get_backend ()->var_expression (static_global, ref_locus);
}
void
CompileItem::visit (HIR::ConstantItem &constant)
{
if (ctx->lookup_const_decl (constant.get_mappings ().get_hirid (),
&reference))
return;
// resolve the type
TyTy::BaseType *resolved_type = nullptr;
bool ok
= ctx->get_tyctx ()->lookup_type (constant.get_mappings ().get_hirid (),
&resolved_type);
rust_assert (ok);
// canonical path
const Resolver::CanonicalPath *canonical_path = nullptr;
ok = ctx->get_mappings ()->lookup_canonical_path (
constant.get_mappings ().get_nodeid (), &canonical_path);
rust_assert (ok);
HIR::Expr *const_value_expr = constant.get_expr ();
ctx->push_const_context ();
tree const_expr
= compile_constant_item (ctx, resolved_type, canonical_path,
const_value_expr, constant.get_locus ());
ctx->pop_const_context ();
ctx->push_const (const_expr);
ctx->insert_const_decl (constant.get_mappings ().get_hirid (), const_expr);
reference = const_expr;
}
void
CompileItem::visit (HIR::Function &function)
{
TyTy::BaseType *fntype_tyty;
if (!ctx->get_tyctx ()->lookup_type (function.get_mappings ().get_hirid (),
&fntype_tyty))
{
rust_fatal_error (function.get_locus (),
"failed to lookup function type");
return;
}
rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (fntype_tyty);
if (fntype->has_subsititions_defined ())
{
// we cant do anything for this only when it is used and a concrete type
// is given
if (concrete == nullptr)
return;
else
{
rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
fntype = static_cast<TyTy::FnType *> (concrete);
fntype->monomorphize ();
}
}
// items can be forward compiled which means we may not need to invoke this
// code. We might also have already compiled this generic function as well.
tree lookup = NULL_TREE;
if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup,
fntype->get_id (), fntype))
{
// has this been added to the list then it must be finished
if (ctx->function_completed (lookup))
{
tree dummy = NULL_TREE;
if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
{
ctx->insert_function_decl (fntype, lookup);
}
reference = address_expression (lookup, ref_locus);
return;
}
}
if (fntype->has_subsititions_defined ())
{
// override the Hir Lookups for the substituions in this context
fntype->override_context ();
}
const Resolver::CanonicalPath *canonical_path = nullptr;
bool ok = ctx->get_mappings ()->lookup_canonical_path (
function.get_mappings ().get_nodeid (), &canonical_path);
rust_assert (ok);
tree fndecl
= compile_function (ctx, function.get_function_name (),
function.get_self_param (),
function.get_function_params (),
function.get_qualifiers (), function.get_visibility (),
function.get_outer_attrs (), function.get_locus (),
function.get_definition ().get (), canonical_path,
fntype, function.has_function_return_type ());
reference = address_expression (fndecl, ref_locus);
}
void
CompileItem::visit (HIR::ImplBlock &impl_block)
{
TyTy::BaseType *self_lookup = nullptr;
if (!ctx->get_tyctx ()->lookup_type (
impl_block.get_type ()->get_mappings ().get_hirid (), &self_lookup))
{
rust_error_at (impl_block.get_locus (), "failed to resolve type of impl");
return;
}
for (auto &impl_item : impl_block.get_impl_items ())
CompileInherentImplItem::Compile (impl_item.get (), ctx);
}
void
CompileItem::visit (HIR::ExternBlock &extern_block)
{
for (auto &item : extern_block.get_extern_items ())
{
CompileExternItem::compile (item.get (), ctx, concrete);
}
}
void
CompileItem::visit (HIR::Module &module)
{
for (auto &item : module.get_items ())
CompileItem::compile (item.get (), ctx);
}
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,88 @@
// Copyright (C) 2020-2022 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_ITEM
#define RUST_COMPILE_ITEM
#include "rust-compile-base.h"
namespace Rust {
namespace Compile {
class CompileItem : private HIRCompileBase, protected HIR::HIRStmtVisitor
{
protected:
public:
static tree compile (HIR::Item *item, Context *ctx,
TyTy::BaseType *concrete = nullptr,
bool is_query_mode = false,
Location ref_locus = Location ())
{
CompileItem compiler (ctx, concrete, ref_locus);
item->accept_vis (compiler);
if (is_query_mode && compiler.reference == error_mark_node)
rust_internal_error_at (ref_locus, "failed to compile item: %s",
item->as_string ().c_str ());
return compiler.reference;
}
void visit (HIR::StaticItem &var) override;
void visit (HIR::ConstantItem &constant) override;
void visit (HIR::Function &function) override;
void visit (HIR::ImplBlock &impl_block) override;
void visit (HIR::ExternBlock &extern_block) override;
void visit (HIR::Module &module) override;
// Empty visit for unused Stmt HIR nodes.
void visit (HIR::TupleStruct &) override {}
void visit (HIR::EnumItem &) override {}
void visit (HIR::EnumItemTuple &) override {}
void visit (HIR::EnumItemStruct &) override {}
void visit (HIR::EnumItemDiscriminant &) override {}
void visit (HIR::TypePathSegmentFunction &) override {}
void visit (HIR::TypePath &) override {}
void visit (HIR::QualifiedPathInType &) override {}
void visit (HIR::ExternCrate &) override {}
void visit (HIR::UseDeclaration &) override {}
void visit (HIR::TypeAlias &) override {}
void visit (HIR::StructStruct &) override {}
void visit (HIR::Enum &) override {}
void visit (HIR::Union &) override {}
void visit (HIR::Trait &) override {}
void visit (HIR::EmptyStmt &) override {}
void visit (HIR::LetStmt &) override {}
void visit (HIR::ExprStmtWithoutBlock &) override {}
void visit (HIR::ExprStmtWithBlock &) override {}
protected:
CompileItem (Context *ctx, TyTy::BaseType *concrete, Location ref_locus)
: HIRCompileBase (ctx), concrete (concrete), reference (error_mark_node),
ref_locus (ref_locus)
{}
TyTy::BaseType *concrete;
tree reference;
Location ref_locus;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_ITEM

View File

@@ -0,0 +1,333 @@
// Copyright (C) 2020-2022 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-pattern.h"
#include "rust-compile-expr.h"
#include "rust-compile-resolve-path.h"
#include "rust-constexpr.h"
namespace Rust {
namespace Compile {
void
CompilePatternCaseLabelExpr::visit (HIR::PathInExpression &pattern)
{
// lookup the type
TyTy::BaseType *lookup = nullptr;
bool ok
= ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
&lookup);
rust_assert (ok);
// this must be an enum
rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
rust_assert (adt->is_enum ());
// lookup the variant
HirId variant_id;
ok = ctx->get_tyctx ()->lookup_variant_definition (
pattern.get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
TyTy::VariantDef *variant = nullptr;
ok = adt->lookup_variant_by_id (variant_id, &variant);
rust_assert (ok);
HIR::Expr *discrim_expr = variant->get_discriminant ();
tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
tree folded_discrim_expr = fold_expr (discrim_expr_node);
tree case_low = folded_discrim_expr;
case_label_expr
= build_case_label (case_low, NULL_TREE, associated_case_label);
}
void
CompilePatternCaseLabelExpr::visit (HIR::StructPattern &pattern)
{
CompilePatternCaseLabelExpr::visit (pattern.get_path ());
}
void
CompilePatternCaseLabelExpr::visit (HIR::TupleStructPattern &pattern)
{
CompilePatternCaseLabelExpr::visit (pattern.get_path ());
}
void
CompilePatternCaseLabelExpr::visit (HIR::WildcardPattern &pattern)
{
// operand 0 being NULL_TREE signifies this is the default case label see:
// tree.def for documentation for CASE_LABEL_EXPR
case_label_expr
= build_case_label (NULL_TREE, NULL_TREE, associated_case_label);
}
void
CompilePatternCaseLabelExpr::visit (HIR::LiteralPattern &pattern)
{
// Compile the literal
HIR::LiteralExpr *litexpr
= new HIR::LiteralExpr (pattern.get_pattern_mappings (),
pattern.get_literal (), pattern.get_locus (),
std::vector<AST::Attribute> ());
// Note: Floating point literals are currently accepted but will likely be
// forbidden in LiteralPatterns in a future version of Rust.
// See: https://github.com/rust-lang/rust/issues/41620
// For now, we cannot compile them anyway as CASE_LABEL_EXPR does not support
// floating point types.
if (pattern.get_literal ().get_lit_type () == HIR::Literal::LitType::FLOAT)
{
rust_sorry_at (pattern.get_locus (), "floating-point literal in pattern");
}
tree lit = CompileExpr::Compile (litexpr, ctx);
case_label_expr = build_case_label (lit, NULL_TREE, associated_case_label);
}
static tree
compile_range_pattern_bound (HIR::RangePatternBound *bound,
Analysis::NodeMapping mappings, Location locus,
Context *ctx)
{
tree result = NULL_TREE;
switch (bound->get_bound_type ())
{
case HIR::RangePatternBound::RangePatternBoundType::LITERAL: {
HIR::RangePatternBoundLiteral &ref
= *static_cast<HIR::RangePatternBoundLiteral *> (bound);
HIR::LiteralExpr *litexpr
= new HIR::LiteralExpr (mappings, ref.get_literal (), locus,
std::vector<AST::Attribute> ());
result = CompileExpr::Compile (litexpr, ctx);
}
break;
case HIR::RangePatternBound::RangePatternBoundType::PATH: {
HIR::RangePatternBoundPath &ref
= *static_cast<HIR::RangePatternBoundPath *> (bound);
result = ResolvePathRef::Compile (ref.get_path (), ctx);
// If the path resolves to a const expression, fold it.
result = fold_expr (result);
}
break;
case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: {
HIR::RangePatternBoundQualPath &ref
= *static_cast<HIR::RangePatternBoundQualPath *> (bound);
result = ResolvePathRef::Compile (ref.get_qualified_path (), ctx);
// If the path resolves to a const expression, fold it.
result = fold_expr (result);
}
}
return result;
}
void
CompilePatternCaseLabelExpr::visit (HIR::RangePattern &pattern)
{
tree upper = compile_range_pattern_bound (pattern.get_upper_bound ().get (),
pattern.get_pattern_mappings (),
pattern.get_locus (), ctx);
tree lower = compile_range_pattern_bound (pattern.get_lower_bound ().get (),
pattern.get_pattern_mappings (),
pattern.get_locus (), ctx);
case_label_expr = build_case_label (lower, upper, associated_case_label);
}
// setup the bindings
void
CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
{
// lookup the type
TyTy::BaseType *lookup = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (
pattern.get_path ().get_mappings ().get_hirid (), &lookup);
rust_assert (ok);
// this must be an enum
rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
rust_assert (adt->number_of_variants () > 0);
int variant_index = 0;
TyTy::VariantDef *variant = adt->get_variants ().at (0);
if (adt->is_enum ())
{
HirId variant_id = UNKNOWN_HIRID;
bool ok = ctx->get_tyctx ()->lookup_variant_definition (
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
rust_assert (ok);
}
rust_assert (variant->get_variant_type ()
== TyTy::VariantDef::VariantType::TUPLE);
std::unique_ptr<HIR::TupleStructItems> &items = pattern.get_items ();
switch (items->get_item_type ())
{
case HIR::TupleStructItems::RANGE: {
// TODO
gcc_unreachable ();
}
break;
case HIR::TupleStructItems::NO_RANGE: {
HIR::TupleStructItemsNoRange &items_no_range
= static_cast<HIR::TupleStructItemsNoRange &> (*items.get ());
rust_assert (items_no_range.get_patterns ().size ()
== variant->num_fields ());
if (adt->is_enum ())
{
// we are offsetting by + 1 here since the first field in the record
// is always the discriminator
size_t tuple_field_index = 1;
for (auto &pattern : items_no_range.get_patterns ())
{
tree variant_accessor
= ctx->get_backend ()->struct_field_expression (
match_scrutinee_expr, variant_index, pattern->get_locus ());
tree binding = ctx->get_backend ()->struct_field_expression (
variant_accessor, tuple_field_index++, pattern->get_locus ());
ctx->insert_pattern_binding (
pattern->get_pattern_mappings ().get_hirid (), binding);
}
}
else
{
size_t tuple_field_index = 0;
for (auto &pattern : items_no_range.get_patterns ())
{
tree variant_accessor = match_scrutinee_expr;
tree binding = ctx->get_backend ()->struct_field_expression (
variant_accessor, tuple_field_index++, pattern->get_locus ());
ctx->insert_pattern_binding (
pattern->get_pattern_mappings ().get_hirid (), binding);
}
}
}
break;
}
}
void
CompilePatternBindings::visit (HIR::StructPattern &pattern)
{
// lookup the type
TyTy::BaseType *lookup = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (
pattern.get_path ().get_mappings ().get_hirid (), &lookup);
rust_assert (ok);
// this must be an enum
rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
rust_assert (adt->number_of_variants () > 0);
int variant_index = 0;
TyTy::VariantDef *variant = adt->get_variants ().at (0);
if (adt->is_enum ())
{
HirId variant_id = UNKNOWN_HIRID;
bool ok = ctx->get_tyctx ()->lookup_variant_definition (
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
rust_assert (ok);
}
rust_assert (variant->get_variant_type ()
== TyTy::VariantDef::VariantType::STRUCT);
auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
{
switch (field->get_item_type ())
{
case HIR::StructPatternField::ItemType::TUPLE_PAT: {
// TODO
gcc_unreachable ();
}
break;
case HIR::StructPatternField::ItemType::IDENT_PAT: {
// TODO
gcc_unreachable ();
}
break;
case HIR::StructPatternField::ItemType::IDENT: {
HIR::StructPatternFieldIdent &ident
= static_cast<HIR::StructPatternFieldIdent &> (*field.get ());
size_t offs = 0;
ok
= variant->lookup_field (ident.get_identifier (), nullptr, &offs);
rust_assert (ok);
tree binding = error_mark_node;
if (adt->is_enum ())
{
tree variant_accessor
= ctx->get_backend ()->struct_field_expression (
match_scrutinee_expr, variant_index, ident.get_locus ());
// we are offsetting by + 1 here since the first field in the
// record is always the discriminator
binding = ctx->get_backend ()->struct_field_expression (
variant_accessor, offs + 1, ident.get_locus ());
}
else
{
tree variant_accessor = match_scrutinee_expr;
binding = ctx->get_backend ()->struct_field_expression (
variant_accessor, offs, ident.get_locus ());
}
ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (),
binding);
}
break;
}
}
}
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,95 @@
// Copyright (C) 2020-2022 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-base.h"
namespace Rust {
namespace Compile {
class CompilePatternCaseLabelExpr : public HIRCompileBase,
public HIR::HIRPatternVisitor
{
public:
static tree Compile (HIR::Pattern *pattern, tree associated_case_label,
Context *ctx)
{
CompilePatternCaseLabelExpr compiler (ctx, associated_case_label);
pattern->accept_vis (compiler);
return compiler.case_label_expr;
}
void visit (HIR::PathInExpression &pattern) override;
void visit (HIR::StructPattern &pattern) override;
void visit (HIR::TupleStructPattern &pattern) override;
void visit (HIR::WildcardPattern &pattern) override;
void visit (HIR::RangePattern &pattern) override;
// Empty visit for unused Pattern HIR nodes.
void visit (HIR::GroupedPattern &) override {}
void visit (HIR::IdentifierPattern &) override {}
void visit (HIR::LiteralPattern &) override;
void visit (HIR::QualifiedPathInExpression &) override {}
void visit (HIR::ReferencePattern &) override {}
void visit (HIR::SlicePattern &) override {}
void visit (HIR::TuplePattern &) override {}
CompilePatternCaseLabelExpr (Context *ctx, tree associated_case_label)
: HIRCompileBase (ctx), case_label_expr (error_mark_node),
associated_case_label (associated_case_label)
{}
tree case_label_expr;
tree associated_case_label;
};
class CompilePatternBindings : public HIRCompileBase,
public HIR::HIRPatternVisitor
{
public:
static void Compile (HIR::Pattern *pattern, tree match_scrutinee_expr,
Context *ctx)
{
CompilePatternBindings compiler (ctx, match_scrutinee_expr);
pattern->accept_vis (compiler);
}
void visit (HIR::StructPattern &pattern) override;
void visit (HIR::TupleStructPattern &pattern) override;
// Empty visit for unused Pattern HIR nodes.
void visit (HIR::GroupedPattern &) override {}
void visit (HIR::IdentifierPattern &) override {}
void visit (HIR::LiteralPattern &) override {}
void visit (HIR::PathInExpression &) override {}
void visit (HIR::QualifiedPathInExpression &) override {}
void visit (HIR::RangePattern &) override {}
void visit (HIR::ReferencePattern &) override {}
void visit (HIR::SlicePattern &) override {}
void visit (HIR::TuplePattern &) override {}
void visit (HIR::WildcardPattern &) override {}
protected:
CompilePatternBindings (Context *ctx, tree match_scrutinee_expr)
: HIRCompileBase (ctx), match_scrutinee_expr (match_scrutinee_expr)
{}
tree match_scrutinee_expr;
};
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,301 @@
// Copyright (C) 2020-2022 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-resolve-path.h"
#include "rust-compile-intrinsic.h"
#include "rust-compile-item.h"
#include "rust-compile-implitem.h"
#include "rust-compile-expr.h"
#include "rust-hir-trait-resolve.h"
#include "rust-hir-path-probe.h"
#include "rust-compile-extern.h"
#include "rust-constexpr.h"
namespace Rust {
namespace Compile {
void
ResolvePathRef::visit (HIR::QualifiedPathInExpression &expr)
{
resolved = resolve (expr.get_final_segment ().get_segment (),
expr.get_mappings (), expr.get_locus (), true);
}
void
ResolvePathRef::visit (HIR::PathInExpression &expr)
{
resolved = resolve (expr.get_final_segment ().get_segment (),
expr.get_mappings (), expr.get_locus (), false);
}
tree
ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
const Analysis::NodeMapping &mappings,
Location expr_locus, bool is_qualified_path)
{
TyTy::BaseType *lookup = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
rust_assert (ok);
// need to look up the reference for this identifier
NodeId ref_node_id = UNKNOWN_NODEID;
if (!ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (),
&ref_node_id))
{
// this can fail because it might be a Constructor for something
// in that case the caller should attempt ResolvePathType::Compile
// it might be an enum data-less enum variant
if (lookup->get_kind () != TyTy::TypeKind::ADT)
return error_mark_node;
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
// it might be a unit-struct
if (adt->is_unit ())
{
return ctx->get_backend ()->unit_expression ();
}
if (!adt->is_enum ())
return error_mark_node;
HirId variant_id;
if (!ctx->get_tyctx ()->lookup_variant_definition (mappings.get_hirid (),
&variant_id))
return error_mark_node;
int union_disriminator = -1;
TyTy::VariantDef *variant = nullptr;
if (!adt->lookup_variant_by_id (variant_id, &variant,
&union_disriminator))
return error_mark_node;
// this can only be for discriminant variants the others are built up
// using call-expr or struct-init
rust_assert (variant->get_variant_type ()
== TyTy::VariantDef::VariantType::NUM);
// we need the actual gcc type
tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt);
// make the ctor for the union
HIR::Expr *discrim_expr = variant->get_discriminant ();
tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
tree folded_discrim_expr = fold_expr (discrim_expr_node);
tree qualifier = folded_discrim_expr;
return ctx->get_backend ()->constructor_expression (compiled_adt_type,
true, {qualifier},
union_disriminator,
expr_locus);
}
HirId ref;
if (!ctx->get_mappings ()->lookup_node_to_hir (ref_node_id, &ref))
{
rust_error_at (expr_locus, "reverse call path lookup failure");
return error_mark_node;
}
// might be a constant
tree constant_expr;
if (ctx->lookup_const_decl (ref, &constant_expr))
{
TREE_USED (constant_expr) = 1;
return constant_expr;
}
// this might be a variable reference or a function reference
Bvariable *var = nullptr;
if (ctx->lookup_var_decl (ref, &var))
{
// TREE_USED is setup in the gcc abstraction here
return ctx->get_backend ()->var_expression (var, expr_locus);
}
// might be a match pattern binding
tree binding = error_mark_node;
if (ctx->lookup_pattern_binding (ref, &binding))
{
TREE_USED (binding) = 1;
return binding;
}
// it might be a function call
if (lookup->get_kind () == TyTy::TypeKind::FNDEF)
{
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
tree fn = NULL_TREE;
if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
{
TREE_USED (fn) = 1;
return address_expression (fn, expr_locus);
}
else if (fntype->get_abi () == ABI::INTRINSIC)
{
Intrinsics compile (ctx);
fn = compile.compile (fntype);
TREE_USED (fn) = 1;
return address_expression (fn, expr_locus);
}
}
// let the query system figure it out
tree resolved_item = query_compile (ref, lookup, final_segment, mappings,
expr_locus, is_qualified_path);
if (resolved_item != error_mark_node)
{
TREE_USED (resolved_item) = 1;
}
return resolved_item;
}
tree
HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup,
const HIR::PathIdentSegment &final_segment,
const Analysis::NodeMapping &mappings,
Location expr_locus, bool is_qualified_path)
{
HIR::Item *resolved_item = ctx->get_mappings ()->lookup_hir_item (ref);
HirId parent_block;
HIR::ExternalItem *resolved_extern_item
= ctx->get_mappings ()->lookup_hir_extern_item (ref, &parent_block);
bool is_hir_item = resolved_item != nullptr;
bool is_hir_extern_item = resolved_extern_item != nullptr;
if (is_hir_item)
{
if (!lookup->has_subsititions_defined ())
return CompileItem::compile (resolved_item, ctx, nullptr, true,
expr_locus);
else
return CompileItem::compile (resolved_item, ctx, lookup, true,
expr_locus);
}
else if (is_hir_extern_item)
{
if (!lookup->has_subsititions_defined ())
return CompileExternItem::compile (resolved_extern_item, ctx, nullptr,
true, expr_locus);
else
return CompileExternItem::compile (resolved_extern_item, ctx, lookup,
true, expr_locus);
}
else
{
HirId parent_impl_id = UNKNOWN_HIRID;
HIR::ImplItem *resolved_item
= ctx->get_mappings ()->lookup_hir_implitem (ref, &parent_impl_id);
bool is_impl_item = resolved_item != nullptr;
if (is_impl_item)
{
rust_assert (parent_impl_id != UNKNOWN_HIRID);
HIR::Item *impl_ref
= ctx->get_mappings ()->lookup_hir_item (parent_impl_id);
rust_assert (impl_ref != nullptr);
HIR::ImplBlock *impl = static_cast<HIR::ImplBlock *> (impl_ref);
TyTy::BaseType *self = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (
impl->get_type ()->get_mappings ().get_hirid (), &self);
rust_assert (ok);
if (!lookup->has_subsititions_defined ())
return CompileInherentImplItem::Compile (resolved_item, ctx,
nullptr, true, expr_locus);
else
return CompileInherentImplItem::Compile (resolved_item, ctx, lookup,
true, expr_locus);
}
else
{
// it might be resolved to a trait item
HIR::TraitItem *trait_item
= ctx->get_mappings ()->lookup_hir_trait_item (ref);
HIR::Trait *trait = ctx->get_mappings ()->lookup_trait_item_mapping (
trait_item->get_mappings ().get_hirid ());
Resolver::TraitReference *trait_ref
= &Resolver::TraitReference::error_node ();
bool ok = ctx->get_tyctx ()->lookup_trait_reference (
trait->get_mappings ().get_defid (), &trait_ref);
rust_assert (ok);
TyTy::BaseType *receiver = nullptr;
ok = ctx->get_tyctx ()->lookup_receiver (mappings.get_hirid (),
&receiver);
rust_assert (ok);
if (receiver->get_kind () == TyTy::TypeKind::PARAM)
{
TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
receiver = p->resolve ();
}
// the type resolver can only resolve type bounds to their trait
// item so its up to us to figure out if this path should resolve
// to an trait-impl-block-item or if it can be defaulted to the
// trait-impl-item's definition
std::vector<Resolver::PathProbeCandidate> candidates
= Resolver::PathProbeImplTrait::Probe (receiver, final_segment,
trait_ref);
if (candidates.size () == 0)
{
// this means we are defaulting back to the trait_item if
// possible
Resolver::TraitItemReference *trait_item_ref = nullptr;
bool ok = trait_ref->lookup_hir_trait_item (*trait_item,
&trait_item_ref);
rust_assert (ok); // found
rust_assert (trait_item_ref->is_optional ()); // has definition
return CompileTraitItem::Compile (
trait_item_ref->get_hir_trait_item (), ctx, lookup, true,
expr_locus);
}
else
{
Resolver::PathProbeCandidate &candidate = candidates.at (0);
rust_assert (candidate.is_impl_candidate ());
HIR::ImplBlock *impl = candidate.item.impl.parent;
HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
TyTy::BaseType *self = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (
impl->get_type ()->get_mappings ().get_hirid (), &self);
rust_assert (ok);
if (!lookup->has_subsititions_defined ())
return CompileInherentImplItem::Compile (impl_item, ctx,
nullptr, true,
expr_locus);
else
return CompileInherentImplItem::Compile (impl_item, ctx, lookup,
true, expr_locus);
lookup->set_ty_ref (impl_item->get_impl_mappings ().get_hirid ());
}
}
}
return error_mark_node;
}
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,73 @@
// Copyright (C) 2020-2022 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_RESOLVE_PATH
#define RUST_COMPILE_RESOLVE_PATH
#include "rust-compile-base.h"
namespace Rust {
namespace Compile {
class ResolvePathRef : public HIRCompileBase, public HIR::HIRPatternVisitor
{
public:
static tree Compile (HIR::QualifiedPathInExpression &expr, Context *ctx)
{
ResolvePathRef resolver (ctx);
expr.accept_vis (resolver);
return resolver.resolved;
}
static tree Compile (HIR::PathInExpression &expr, Context *ctx)
{
ResolvePathRef resolver (ctx);
expr.accept_vis (resolver);
return resolver.resolved;
}
void visit (HIR::PathInExpression &expr) override;
void visit (HIR::QualifiedPathInExpression &expr) override;
// Empty visit for unused Pattern HIR nodes.
void visit (HIR::GroupedPattern &) override {}
void visit (HIR::IdentifierPattern &) override {}
void visit (HIR::LiteralPattern &) override {}
void visit (HIR::RangePattern &) override {}
void visit (HIR::ReferencePattern &) override {}
void visit (HIR::SlicePattern &) override {}
void visit (HIR::StructPattern &) override {}
void visit (HIR::TuplePattern &) override {}
void visit (HIR::TupleStructPattern &) override {}
void visit (HIR::WildcardPattern &) override {}
ResolvePathRef (Context *ctx)
: HIRCompileBase (ctx), resolved (error_mark_node)
{}
tree resolve (const HIR::PathIdentSegment &final_segment,
const Analysis::NodeMapping &mappings, Location locus,
bool is_qualified_path);
tree resolved;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_RESOLVE_PATH

View File

@@ -0,0 +1,115 @@
// Copyright (C) 2020-2022 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-stmt.h"
#include "rust-compile-expr.h"
namespace Rust {
namespace Compile {
CompileStmt::CompileStmt (Context *ctx)
: HIRCompileBase (ctx), translated (nullptr)
{}
tree
CompileStmt::Compile (HIR::Stmt *stmt, Context *ctx)
{
CompileStmt compiler (ctx);
stmt->accept_vis (compiler);
return compiler.translated;
}
void
CompileStmt::visit (HIR::ExprStmtWithBlock &stmt)
{
translated = CompileExpr::Compile (stmt.get_expr (), ctx);
}
void
CompileStmt::visit (HIR::ExprStmtWithoutBlock &stmt)
{
translated = CompileExpr::Compile (stmt.get_expr (), ctx);
}
void
CompileStmt::visit (HIR::LetStmt &stmt)
{
// nothing to do
if (!stmt.has_init_expr ())
return;
const HIR::Pattern &stmt_pattern = *stmt.get_pattern ();
HirId stmt_id = stmt_pattern.get_pattern_mappings ().get_hirid ();
TyTy::BaseType *ty = nullptr;
if (!ctx->get_tyctx ()->lookup_type (stmt_id, &ty))
{
// FIXME this should be an assertion instead
rust_fatal_error (stmt.get_locus (),
"failed to lookup variable declaration type");
return;
}
Bvariable *var = nullptr;
if (!ctx->lookup_var_decl (stmt_id, &var))
{
// FIXME this should be an assertion instead and use error mark node
rust_fatal_error (stmt.get_locus (),
"failed to lookup compiled variable declaration");
return;
}
tree init = CompileExpr::Compile (stmt.get_init_expr (), ctx);
// FIXME use error_mark_node, check that CompileExpr returns error_mark_node
// on failure and make this an assertion
if (init == nullptr)
return;
TyTy::BaseType *actual = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (
stmt.get_init_expr ()->get_mappings ().get_hirid (), &actual);
rust_assert (ok);
tree stmt_type = TyTyResolveCompile::compile (ctx, ty);
Location lvalue_locus = stmt.get_pattern ()->get_locus ();
Location rvalue_locus = stmt.get_init_expr ()->get_locus ();
TyTy::BaseType *expected = ty;
init = coercion_site (stmt.get_mappings ().get_hirid (), init, actual,
expected, lvalue_locus, rvalue_locus);
auto fnctx = ctx->peek_fn ();
if (ty->is_unit ())
{
ctx->add_statement (init);
auto unit_type_init_expr
= ctx->get_backend ()->constructor_expression (stmt_type, false, {}, -1,
rvalue_locus);
auto s = ctx->get_backend ()->init_statement (fnctx.fndecl, var,
unit_type_init_expr);
ctx->add_statement (s);
}
else
{
auto s = ctx->get_backend ()->init_statement (fnctx.fndecl, var, init);
ctx->add_statement (s);
}
}
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,69 @@
// Copyright (C) 2020-2022 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_STMT
#define RUST_COMPILE_STMT
#include "rust-compile-base.h"
namespace Rust {
namespace Compile {
class CompileStmt : private HIRCompileBase, protected HIR::HIRStmtVisitor
{
public:
static tree Compile (HIR::Stmt *stmt, Context *ctx);
void visit (HIR::ExprStmtWithBlock &stmt) override;
void visit (HIR::ExprStmtWithoutBlock &stmt) override;
void visit (HIR::LetStmt &stmt) override;
// Empty visit for unused Stmt HIR nodes.
void visit (HIR::TupleStruct &) override {}
void visit (HIR::EnumItem &) override {}
void visit (HIR::EnumItemTuple &) override {}
void visit (HIR::EnumItemStruct &) override {}
void visit (HIR::EnumItemDiscriminant &) override {}
void visit (HIR::TypePathSegmentFunction &) override {}
void visit (HIR::TypePath &) override {}
void visit (HIR::QualifiedPathInType &) override {}
void visit (HIR::Module &) override {}
void visit (HIR::ExternCrate &) override {}
void visit (HIR::UseDeclaration &) override {}
void visit (HIR::Function &) override {}
void visit (HIR::TypeAlias &) override {}
void visit (HIR::StructStruct &) override {}
void visit (HIR::Enum &) override {}
void visit (HIR::Union &) override {}
void visit (HIR::ConstantItem &) override {}
void visit (HIR::StaticItem &) override {}
void visit (HIR::Trait &) override {}
void visit (HIR::ImplBlock &) override {}
void visit (HIR::ExternBlock &) override {}
void visit (HIR::EmptyStmt &) override {}
private:
CompileStmt (Context *ctx);
tree translated;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_STMT

View File

@@ -0,0 +1,81 @@
// Copyright (C) 2020-2022 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-struct-field-expr.h"
#include "rust-compile-expr.h"
namespace Rust {
namespace Compile {
CompileStructExprField::CompileStructExprField (Context *ctx)
: HIRCompileBase (ctx), translated (error_mark_node)
{}
tree
CompileStructExprField::Compile (HIR::StructExprField *field, Context *ctx)
{
CompileStructExprField compiler (ctx);
switch (field->get_kind ())
{
case HIR::StructExprField::StructExprFieldKind::IDENTIFIER:
compiler.visit (static_cast<HIR::StructExprFieldIdentifier &> (*field));
break;
case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE:
compiler.visit (
static_cast<HIR::StructExprFieldIdentifierValue &> (*field));
break;
case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE:
compiler.visit (static_cast<HIR::StructExprFieldIndexValue &> (*field));
break;
}
return compiler.translated;
}
void
CompileStructExprField::visit (HIR::StructExprFieldIdentifierValue &field)
{
translated = CompileExpr::Compile (field.get_value (), ctx);
}
void
CompileStructExprField::visit (HIR::StructExprFieldIndexValue &field)
{
translated = CompileExpr::Compile (field.get_value (), ctx);
}
void
CompileStructExprField::visit (HIR::StructExprFieldIdentifier &field)
{
// we can make the field look like a path expr to take advantage of existing
// code
Analysis::NodeMapping mappings_copy1 = field.get_mappings ();
Analysis::NodeMapping mappings_copy2 = field.get_mappings ();
HIR::PathIdentSegment ident_seg (field.get_field_name ());
HIR::PathExprSegment seg (mappings_copy1, ident_seg, field.get_locus (),
HIR::GenericArgs::create_empty ());
HIR::PathInExpression expr (mappings_copy2, {seg}, field.get_locus (), false,
{});
translated = CompileExpr::Compile (&expr, ctx);
}
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,46 @@
// Copyright (C) 2020-2022 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_STRUCT_FIELD_EXPR
#define RUST_COMPILE_STRUCT_FIELD_EXPR
#include "rust-compile-base.h"
namespace Rust {
namespace Compile {
class CompileStructExprField : private HIRCompileBase
{
public:
static tree Compile (HIR::StructExprField *field, Context *ctx);
protected:
void visit (HIR::StructExprFieldIdentifierValue &field);
void visit (HIR::StructExprFieldIndexValue &field);
void visit (HIR::StructExprFieldIdentifier &field);
private:
CompileStructExprField (Context *ctx);
tree translated;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_STRUCT_FIELD_EXPR

View File

@@ -0,0 +1,713 @@
// Copyright (C) 2020-2022 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-type.h"
#include "rust-compile-expr.h"
#include "rust-constexpr.h"
#include "tree.h"
namespace Rust {
namespace Compile {
static const std::string RUST_ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR";
TyTyResolveCompile::TyTyResolveCompile (Context *ctx, bool trait_object_mode)
: ctx (ctx), trait_object_mode (trait_object_mode),
translated (error_mark_node), recurisve_ops (0)
{}
tree
TyTyResolveCompile::compile (Context *ctx, const TyTy::BaseType *ty,
bool trait_object_mode)
{
TyTyResolveCompile compiler (ctx, trait_object_mode);
ty->accept_vis (compiler);
if (compiler.translated != error_mark_node
&& TYPE_NAME (compiler.translated) != NULL)
{
// canonicalize the type
compiler.translated = ctx->insert_compiled_type (compiler.translated);
}
return compiler.translated;
}
// see: gcc/c/c-decl.cc:8230-8241
// https://github.com/Rust-GCC/gccrs/blob/0024bc2f028369b871a65ceb11b2fddfb0f9c3aa/gcc/c/c-decl.c#L8229-L8241
tree
TyTyResolveCompile::get_implicit_enumeral_node_type (Context *ctx)
{
// static tree enum_node = NULL_TREE;
// if (enum_node == NULL_TREE)
// {
// enum_node = make_node (ENUMERAL_TYPE);
// SET_TYPE_MODE (enum_node, TYPE_MODE (unsigned_type_node));
// SET_TYPE_ALIGN (enum_node, TYPE_ALIGN (unsigned_type_node));
// TYPE_USER_ALIGN (enum_node) = 0;
// TYPE_UNSIGNED (enum_node) = 1;
// TYPE_PRECISION (enum_node) = TYPE_PRECISION (unsigned_type_node);
// TYPE_MIN_VALUE (enum_node) = TYPE_MIN_VALUE (unsigned_type_node);
// TYPE_MAX_VALUE (enum_node) = TYPE_MAX_VALUE (unsigned_type_node);
// // tree identifier = ctx->get_backend ()->get_identifier_node
// // ("enumeral"); tree enum_decl
// // = build_decl (BUILTINS_LOCATION, TYPE_DECL, identifier,
// enum_node);
// // TYPE_NAME (enum_node) = enum_decl;
// }
// return enum_node;
static tree enum_node = NULL_TREE;
if (enum_node == NULL_TREE)
{
enum_node = ctx->get_backend ()->named_type (
"enumeral", ctx->get_backend ()->integer_type (false, 64),
Linemap::predeclared_location ());
}
return enum_node;
}
void
TyTyResolveCompile::visit (const TyTy::ErrorType &)
{
translated = error_mark_node;
}
void
TyTyResolveCompile::visit (const TyTy::InferType &)
{
translated = error_mark_node;
}
void
TyTyResolveCompile::visit (const TyTy::ClosureType &)
{
gcc_unreachable ();
}
void
TyTyResolveCompile::visit (const TyTy::ProjectionType &type)
{
type.get ()->accept_vis (*this);
}
void
TyTyResolveCompile::visit (const TyTy::PlaceholderType &type)
{
type.resolve ()->accept_vis (*this);
}
void
TyTyResolveCompile::visit (const TyTy::ParamType &param)
{
if (recurisve_ops++ >= rust_max_recursion_depth)
{
rust_error_at (Location (),
"%<recursion depth%> count exceeds limit of %i (use "
"%<frust-max-recursion-depth=%> to increase the limit)",
rust_max_recursion_depth);
translated = error_mark_node;
return;
}
param.resolve ()->accept_vis (*this);
}
void
TyTyResolveCompile::visit (const TyTy::FnType &type)
{
Backend::typed_identifier receiver;
std::vector<Backend::typed_identifier> parameters;
std::vector<Backend::typed_identifier> results;
if (!type.get_return_type ()->is_unit ())
{
auto hir_type = type.get_return_type ();
auto ret = TyTyResolveCompile::compile (ctx, hir_type, trait_object_mode);
results.push_back (Backend::typed_identifier (
"_", ret,
ctx->get_mappings ()->lookup_location (hir_type->get_ref ())));
}
for (auto &param_pair : type.get_params ())
{
auto param_tyty = param_pair.second;
auto compiled_param_type
= TyTyResolveCompile::compile (ctx, param_tyty, trait_object_mode);
auto compiled_param = Backend::typed_identifier (
param_pair.first->as_string (), compiled_param_type,
ctx->get_mappings ()->lookup_location (param_tyty->get_ref ()));
parameters.push_back (compiled_param);
}
if (!type.is_varadic ())
translated
= ctx->get_backend ()->function_type (receiver, parameters, results, NULL,
type.get_ident ().locus);
else
translated
= ctx->get_backend ()->function_type_varadic (receiver, parameters,
results, NULL,
type.get_ident ().locus);
}
void
TyTyResolveCompile::visit (const TyTy::FnPtr &type)
{
tree result_type = TyTyResolveCompile::compile (ctx, type.get_return_type ());
std::vector<tree> parameters;
auto &params = type.get_params ();
for (auto &p : params)
{
tree pty = TyTyResolveCompile::compile (ctx, p.get_tyty ());
parameters.push_back (pty);
}
translated = ctx->get_backend ()->function_ptr_type (result_type, parameters,
type.get_ident ().locus);
}
void
TyTyResolveCompile::visit (const TyTy::ADTType &type)
{
tree type_record = error_mark_node;
if (!type.is_enum ())
{
rust_assert (type.number_of_variants () == 1);
TyTy::VariantDef &variant = *type.get_variants ().at (0);
std::vector<Backend::typed_identifier> fields;
for (size_t i = 0; i < variant.num_fields (); i++)
{
const TyTy::StructFieldType *field = variant.get_field_at_index (i);
tree compiled_field_ty
= TyTyResolveCompile::compile (ctx, field->get_field_type ());
Backend::typed_identifier f (field->get_name (), compiled_field_ty,
ctx->get_mappings ()->lookup_location (
type.get_ty_ref ()));
fields.push_back (std::move (f));
}
type_record = type.is_union ()
? ctx->get_backend ()->union_type (fields)
: ctx->get_backend ()->struct_type (fields);
}
else
{
// see:
// https://github.com/bminor/binutils-gdb/blob/527b8861cd472385fa9160a91dd6d65a25c41987/gdb/dwarf2/read.c#L9010-L9241
//
// enums are actually a big union so for example the rust enum:
//
// enum AnEnum {
// A,
// B,
// C (char),
// D { x: i64, y: i64 },
// }
//
// we actually turn this into
//
// union {
// struct A { int RUST$ENUM$DISR; }; <- this is a data-less variant
// struct B { int RUST$ENUM$DISR; }; <- this is a data-less variant
// struct C { int RUST$ENUM$DISR; char __0; };
// struct D { int RUST$ENUM$DISR; i64 x; i64 y; };
// }
//
// Ada, qual_union_types might still work for this but I am not 100% sure.
// I ran into some issues lets reuse our normal union and ask Ada people
// about it.
std::vector<tree> variant_records;
for (auto &variant : type.get_variants ())
{
std::vector<Backend::typed_identifier> fields;
// add in the qualifier field for the variant
tree enumeral_type
= TyTyResolveCompile::get_implicit_enumeral_node_type (ctx);
Backend::typed_identifier f (RUST_ENUM_DISR_FIELD_NAME, enumeral_type,
ctx->get_mappings ()->lookup_location (
variant->get_id ()));
fields.push_back (std::move (f));
// compile the rest of the fields
for (size_t i = 0; i < variant->num_fields (); i++)
{
const TyTy::StructFieldType *field
= variant->get_field_at_index (i);
tree compiled_field_ty
= TyTyResolveCompile::compile (ctx, field->get_field_type ());
std::string field_name = field->get_name ();
if (variant->get_variant_type ()
== TyTy::VariantDef::VariantType::TUPLE)
field_name = "__" + field->get_name ();
Backend::typed_identifier f (
field_name, compiled_field_ty,
ctx->get_mappings ()->lookup_location (type.get_ty_ref ()));
fields.push_back (std::move (f));
}
tree variant_record = ctx->get_backend ()->struct_type (fields);
tree named_variant_record = ctx->get_backend ()->named_type (
variant->get_ident ().path.get (), variant_record,
variant->get_ident ().locus);
// set the qualifier to be a builtin
DECL_ARTIFICIAL (TYPE_FIELDS (variant_record)) = 1;
// add them to the list
variant_records.push_back (named_variant_record);
}
// now we need to make the actual union, but first we need to make
// named_type TYPE_DECL's out of the variants
size_t i = 0;
std::vector<Backend::typed_identifier> enum_fields;
for (auto &variant_record : variant_records)
{
TyTy::VariantDef *variant = type.get_variants ().at (i++);
std::string implicit_variant_name = variant->get_identifier ();
Backend::typed_identifier f (implicit_variant_name, variant_record,
ctx->get_mappings ()->lookup_location (
type.get_ty_ref ()));
enum_fields.push_back (std::move (f));
}
// finally make the union or the enum
type_record = ctx->get_backend ()->union_type (enum_fields);
}
// Handle repr options
// TODO: "packed" should only narrow type alignment and "align" should only
// widen it. Do we need to check and enforce this here, or is it taken care of
// later on in the gcc middle-end?
TyTy::ADTType::ReprOptions repr = type.get_repr_options ();
if (repr.pack)
{
TYPE_PACKED (type_record) = 1;
if (repr.pack > 1)
{
SET_TYPE_ALIGN (type_record, repr.pack * 8);
TYPE_USER_ALIGN (type_record) = 1;
}
}
else if (repr.align)
{
SET_TYPE_ALIGN (type_record, repr.align * 8);
TYPE_USER_ALIGN (type_record) = 1;
}
std::string named_struct_str
= type.get_ident ().path.get () + type.subst_as_string ();
translated = ctx->get_backend ()->named_type (named_struct_str, type_record,
type.get_ident ().locus);
}
void
TyTyResolveCompile::visit (const TyTy::TupleType &type)
{
if (type.num_fields () == 0)
{
translated = ctx->get_backend ()->unit_type ();
return;
}
// create implicit struct
std::vector<Backend::typed_identifier> fields;
for (size_t i = 0; i < type.num_fields (); i++)
{
TyTy::BaseType *field = type.get_field (i);
tree compiled_field_ty = TyTyResolveCompile::compile (ctx, field);
// rustc uses the convention __N, where N is an integer, to
// name the fields of a tuple. We follow this as well,
// because this is used by GDB. One further reason to prefer
// this, rather than simply emitting the integer, is that this
// approach makes it simpler to use a C-only debugger, or
// GDB's C mode, when debugging Rust.
Backend::typed_identifier f ("__" + std::to_string (i), compiled_field_ty,
ctx->get_mappings ()->lookup_location (
type.get_ty_ref ()));
fields.push_back (std::move (f));
}
tree struct_type_record = ctx->get_backend ()->struct_type (fields);
translated
= ctx->get_backend ()->named_type (type.as_string (), struct_type_record,
type.get_ident ().locus);
}
void
TyTyResolveCompile::visit (const TyTy::ArrayType &type)
{
tree element_type
= TyTyResolveCompile::compile (ctx, type.get_element_type ());
tree capacity_expr = CompileExpr::Compile (&type.get_capacity_expr (), ctx);
tree folded_capacity_expr = fold_expr (capacity_expr);
translated
= ctx->get_backend ()->array_type (element_type, folded_capacity_expr);
}
void
TyTyResolveCompile::visit (const TyTy::SliceType &type)
{
tree type_record = create_slice_type_record (type);
std::string named_struct_str
= std::string ("[") + type.get_element_type ()->get_name () + "]";
translated = ctx->get_backend ()->named_type (named_struct_str, type_record,
type.get_ident ().locus);
}
void
TyTyResolveCompile::visit (const TyTy::BoolType &type)
{
translated
= ctx->get_backend ()->named_type ("bool",
ctx->get_backend ()->bool_type (),
Linemap::predeclared_location ());
}
void
TyTyResolveCompile::visit (const TyTy::IntType &type)
{
switch (type.get_int_kind ())
{
case TyTy::IntType::I8:
translated = ctx->get_backend ()->named_type (
"i8", ctx->get_backend ()->integer_type (false, 8),
Linemap::predeclared_location ());
return;
case TyTy::IntType::I16:
translated = ctx->get_backend ()->named_type (
"i16", ctx->get_backend ()->integer_type (false, 16),
Linemap::predeclared_location ());
return;
case TyTy::IntType::I32:
translated = ctx->get_backend ()->named_type (
"i32", ctx->get_backend ()->integer_type (false, 32),
Linemap::predeclared_location ());
return;
case TyTy::IntType::I64:
translated = ctx->get_backend ()->named_type (
"i64", ctx->get_backend ()->integer_type (false, 64),
Linemap::predeclared_location ());
return;
case TyTy::IntType::I128:
translated = ctx->get_backend ()->named_type (
"i128", ctx->get_backend ()->integer_type (false, 128),
Linemap::predeclared_location ());
return;
}
}
void
TyTyResolveCompile::visit (const TyTy::UintType &type)
{
switch (type.get_uint_kind ())
{
case TyTy::UintType::U8:
translated = ctx->get_backend ()->named_type (
"u8", ctx->get_backend ()->integer_type (true, 8),
Linemap::predeclared_location ());
return;
case TyTy::UintType::U16:
translated = ctx->get_backend ()->named_type (
"u16", ctx->get_backend ()->integer_type (true, 16),
Linemap::predeclared_location ());
return;
case TyTy::UintType::U32:
translated = ctx->get_backend ()->named_type (
"u32", ctx->get_backend ()->integer_type (true, 32),
Linemap::predeclared_location ());
return;
case TyTy::UintType::U64:
translated = ctx->get_backend ()->named_type (
"u64", ctx->get_backend ()->integer_type (true, 64),
Linemap::predeclared_location ());
return;
case TyTy::UintType::U128:
translated = ctx->get_backend ()->named_type (
"u128", ctx->get_backend ()->integer_type (true, 128),
Linemap::predeclared_location ());
return;
}
}
void
TyTyResolveCompile::visit (const TyTy::FloatType &type)
{
switch (type.get_float_kind ())
{
case TyTy::FloatType::F32:
translated
= ctx->get_backend ()->named_type ("f32",
ctx->get_backend ()->float_type (32),
Linemap::predeclared_location ());
return;
case TyTy::FloatType::F64:
translated
= ctx->get_backend ()->named_type ("f64",
ctx->get_backend ()->float_type (64),
Linemap::predeclared_location ());
return;
}
}
void
TyTyResolveCompile::visit (const TyTy::USizeType &type)
{
translated = ctx->get_backend ()->named_type (
"usize",
ctx->get_backend ()->integer_type (
true, ctx->get_backend ()->get_pointer_size ()),
Linemap::predeclared_location ());
}
void
TyTyResolveCompile::visit (const TyTy::ISizeType &type)
{
translated = ctx->get_backend ()->named_type (
"isize",
ctx->get_backend ()->integer_type (
false, ctx->get_backend ()->get_pointer_size ()),
Linemap::predeclared_location ());
}
void
TyTyResolveCompile::visit (const TyTy::CharType &type)
{
translated
= ctx->get_backend ()->named_type ("char",
ctx->get_backend ()->wchar_type (),
Linemap::predeclared_location ());
}
void
TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
{
const TyTy::SliceType *slice = nullptr;
const TyTy::StrType *str = nullptr;
if (type.is_dyn_slice_type (&slice))
{
tree type_record = create_slice_type_record (*slice);
std::string dyn_slice_type_str
= std::string (type.is_mutable () ? "&mut " : "&") + "["
+ slice->get_element_type ()->get_name () + "]";
translated
= ctx->get_backend ()->named_type (dyn_slice_type_str, type_record,
slice->get_locus ());
return;
}
else if (type.is_dyn_str_type (&str))
{
tree type_record = create_str_type_record (*str);
std::string dyn_str_type_str
= std::string (type.is_mutable () ? "&mut " : "&") + "str";
translated
= ctx->get_backend ()->named_type (dyn_str_type_str, type_record,
str->get_locus ());
return;
}
tree base_compiled_type
= TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
if (type.is_mutable ())
{
translated = ctx->get_backend ()->reference_type (base_compiled_type);
}
else
{
auto base = ctx->get_backend ()->immutable_type (base_compiled_type);
translated = ctx->get_backend ()->reference_type (base);
}
}
void
TyTyResolveCompile::visit (const TyTy::PointerType &type)
{
const TyTy::SliceType *slice = nullptr;
const TyTy::StrType *str = nullptr;
if (type.is_dyn_slice_type (&slice))
{
tree type_record = create_slice_type_record (*slice);
std::string dyn_slice_type_str
= std::string (type.is_mutable () ? "*mut " : "*const ") + "["
+ slice->get_element_type ()->get_name () + "]";
translated
= ctx->get_backend ()->named_type (dyn_slice_type_str, type_record,
slice->get_locus ());
return;
}
else if (type.is_dyn_str_type (&str))
{
tree type_record = create_str_type_record (*str);
std::string dyn_str_type_str
= std::string (type.is_mutable () ? "*mut " : "*const ") + "str";
translated
= ctx->get_backend ()->named_type (dyn_str_type_str, type_record,
str->get_locus ());
return;
}
tree base_compiled_type
= TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
if (type.is_mutable ())
{
translated = ctx->get_backend ()->pointer_type (base_compiled_type);
}
else
{
auto base = ctx->get_backend ()->immutable_type (base_compiled_type);
translated = ctx->get_backend ()->pointer_type (base);
}
}
void
TyTyResolveCompile::visit (const TyTy::StrType &type)
{
tree raw_str = create_str_type_record (type);
translated
= ctx->get_backend ()->named_type ("str", raw_str,
Linemap::predeclared_location ());
}
void
TyTyResolveCompile::visit (const TyTy::NeverType &)
{
translated = ctx->get_backend ()->unit_type ();
}
void
TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type)
{
if (trait_object_mode)
{
translated = ctx->get_backend ()->integer_type (
true, ctx->get_backend ()->get_pointer_size ());
return;
}
// create implicit struct
auto items = type.get_object_items ();
std::vector<Backend::typed_identifier> fields;
tree uint = ctx->get_backend ()->integer_type (
true, ctx->get_backend ()->get_pointer_size ());
tree uintptr_ty = build_pointer_type (uint);
Backend::typed_identifier f ("pointer", uintptr_ty,
ctx->get_mappings ()->lookup_location (
type.get_ty_ref ()));
fields.push_back (std::move (f));
tree vtable_size = build_int_cst (size_type_node, items.size ());
tree vtable_type = ctx->get_backend ()->array_type (uintptr_ty, vtable_size);
Backend::typed_identifier vtf ("vtable", vtable_type,
ctx->get_mappings ()->lookup_location (
type.get_ty_ref ()));
fields.push_back (std::move (vtf));
tree type_record = ctx->get_backend ()->struct_type (fields);
translated = ctx->get_backend ()->named_type (type.get_name (), type_record,
type.get_ident ().locus);
}
tree
TyTyResolveCompile::create_slice_type_record (const TyTy::SliceType &type)
{
// lookup usize
TyTy::BaseType *usize = nullptr;
bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
rust_assert (ok);
tree element_type
= TyTyResolveCompile::compile (ctx, type.get_element_type ());
tree data_field_ty = build_pointer_type (element_type);
Backend::typed_identifier data_field ("data", data_field_ty,
type.get_locus ());
tree len_field_ty = TyTyResolveCompile::compile (ctx, usize);
Backend::typed_identifier len_field ("len", len_field_ty, type.get_locus ());
tree record = ctx->get_backend ()->struct_type ({data_field, len_field});
SLICE_FLAG (record) = 1;
TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record);
return record;
}
tree
TyTyResolveCompile::create_str_type_record (const TyTy::StrType &type)
{
// lookup usize
TyTy::BaseType *usize = nullptr;
bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
rust_assert (ok);
tree char_ptr = build_pointer_type (char_type_node);
tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
tree element_type = const_char_type;
tree data_field_ty = build_pointer_type (element_type);
Backend::typed_identifier data_field ("data", data_field_ty,
type.get_locus ());
tree len_field_ty = TyTyResolveCompile::compile (ctx, usize);
Backend::typed_identifier len_field ("len", len_field_ty, type.get_locus ());
tree record = ctx->get_backend ()->struct_type ({data_field, len_field});
SLICE_FLAG (record) = 1;
TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record);
return record;
}
} // namespace Compile
} // namespace Rust

View File

@@ -0,0 +1,79 @@
// Copyright (C) 2020-2022 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_TYPE
#define RUST_COMPILE_TYPE
#include "rust-compile-context.h"
namespace Rust {
namespace Compile {
class TyTyResolveCompile : protected TyTy::TyConstVisitor
{
public:
static tree compile (Context *ctx, const TyTy::BaseType *ty,
bool trait_object_mode = false);
static tree get_implicit_enumeral_node_type (Context *ctx);
void visit (const TyTy::InferType &) override;
void visit (const TyTy::ADTType &) override;
void visit (const TyTy::TupleType &) override;
void visit (const TyTy::FnType &) override;
void visit (const TyTy::FnPtr &) override;
void visit (const TyTy::ArrayType &) override;
void visit (const TyTy::SliceType &) override;
void visit (const TyTy::BoolType &) override;
void visit (const TyTy::IntType &) override;
void visit (const TyTy::UintType &) override;
void visit (const TyTy::FloatType &) override;
void visit (const TyTy::USizeType &) override;
void visit (const TyTy::ISizeType &) override;
void visit (const TyTy::ErrorType &) override;
void visit (const TyTy::CharType &) override;
void visit (const TyTy::ReferenceType &) override;
void visit (const TyTy::PointerType &) override;
void visit (const TyTy::ParamType &) override;
void visit (const TyTy::StrType &) override;
void visit (const TyTy::NeverType &) override;
void visit (const TyTy::PlaceholderType &) override;
void visit (const TyTy::ProjectionType &) override;
void visit (const TyTy::DynamicObjectType &) override;
void visit (const TyTy::ClosureType &) override;
public:
static hashval_t type_hasher (tree type);
protected:
tree create_slice_type_record (const TyTy::SliceType &type);
tree create_str_type_record (const TyTy::StrType &type);
private:
TyTyResolveCompile (Context *ctx, bool trait_object_mode);
Context *ctx;
bool trait_object_mode;
tree translated;
int recurisve_ops;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_TYPE

View File

@@ -0,0 +1,95 @@
// Copyright (C) 2020-2022 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_VAR_DECL
#define RUST_COMPILE_VAR_DECL
#include "rust-compile-base.h"
#include "rust-hir-visitor.h"
namespace Rust {
namespace Compile {
class CompileVarDecl : public HIRCompileBase, public HIR::HIRPatternVisitor
{
using HIR::HIRPatternVisitor::visit;
public:
static ::Bvariable *compile (tree fndecl, tree translated_type,
HIR::Pattern *pattern, Context *ctx)
{
CompileVarDecl compiler (ctx, fndecl, translated_type);
pattern->accept_vis (compiler);
return compiler.compiled_variable;
}
void visit (HIR::IdentifierPattern &pattern) override
{
if (!pattern.is_mut ())
translated_type = ctx->get_backend ()->immutable_type (translated_type);
compiled_variable
= ctx->get_backend ()->local_variable (fndecl, pattern.get_identifier (),
translated_type, NULL /*decl_var*/,
pattern.get_locus ());
HirId stmt_id = pattern.get_pattern_mappings ().get_hirid ();
ctx->insert_var_decl (stmt_id, compiled_variable);
}
void visit (HIR::WildcardPattern &pattern) override
{
translated_type = ctx->get_backend ()->immutable_type (translated_type);
compiled_variable
= ctx->get_backend ()->local_variable (fndecl, "_", translated_type,
NULL /*decl_var*/,
pattern.get_locus ());
HirId stmt_id = pattern.get_pattern_mappings ().get_hirid ();
ctx->insert_var_decl (stmt_id, compiled_variable);
}
// Empty visit for unused Pattern HIR nodes.
void visit (HIR::GroupedPattern &) override {}
void visit (HIR::LiteralPattern &) override {}
void visit (HIR::PathInExpression &) override {}
void visit (HIR::QualifiedPathInExpression &) override {}
void visit (HIR::RangePattern &) override {}
void visit (HIR::ReferencePattern &) override {}
void visit (HIR::SlicePattern &) override {}
void visit (HIR::StructPattern &) override {}
void visit (HIR::TuplePattern &) override {}
void visit (HIR::TupleStructPattern &) override {}
private:
CompileVarDecl (Context *ctx, tree fndecl, tree translated_type)
: HIRCompileBase (ctx), fndecl (fndecl), translated_type (translated_type),
compiled_variable (ctx->get_backend ()->error_variable ())
{}
tree fndecl;
tree translated_type;
Bvariable *compiled_variable;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_VAR_DECL