summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2022-10-21 14:01:04 +0200
committerArthur Cohen <arthur.cohen@embecosm.com>2022-12-13 14:00:07 +0100
commit15f04af347e3b65f436808077cbac4fa566019f9 (patch)
tree32ec5a4c2ca65044848cb37137c1074ed63f5401
parent509e4c32c6a80ede6c6dda0f4cfc96f94d24c4d6 (diff)
gccrs: Add base for HIR to GCC GENERIC lowering
This pass walks the HIR crate and turns them into GCC `tree`s. We do not have any Rust specific tree's. We are slowly removing the backend abstraction which was ported over from gccgo in favour of using `tree`s directly. gcc/rust/ * backend/rust-builtins.h: New. * backend/rust-compile-base.cc: New. * backend/rust-compile-base.h: New. * backend/rust-mangle.cc: New. * backend/rust-mangle.h: New. * backend/rust-tree.cc: New. * backend/rust-tree.h: New. * rust-backend.h: New. * rust-gcc.cc: New. Co-authored-by: David Faust <david.faust@oracle.com>
-rw-r--r--gcc/rust/backend/rust-builtins.h189
-rw-r--r--gcc/rust/backend/rust-compile-base.cc730
-rw-r--r--gcc/rust/backend/rust-compile-base.h146
-rw-r--r--gcc/rust/backend/rust-mangle.cc307
-rw-r--r--gcc/rust/backend/rust-mangle.h52
-rw-r--r--gcc/rust/backend/rust-tree.cc958
-rw-r--r--gcc/rust/backend/rust-tree.h508
-rw-r--r--gcc/rust/rust-backend.h506
-rw-r--r--gcc/rust/rust-gcc.cc2718
9 files changed, 6114 insertions, 0 deletions
diff --git a/gcc/rust/backend/rust-builtins.h b/gcc/rust/backend/rust-builtins.h
new file mode 100644
index 00000000000..2bfa6c6cdf7
--- /dev/null
+++ b/gcc/rust/backend/rust-builtins.h
@@ -0,0 +1,189 @@
+// 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_BUILTINS_H
+#define RUST_BUILTINS_H
+
+#include "rust-system.h"
+#include "tree.h"
+#include "langhooks.h"
+
+namespace Rust {
+namespace Compile {
+
+// https://github.com/rust-lang/rust/blob/master/library/core/src/intrinsics.rs
+// https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/intrinsic.rs
+// https://github.com/Rust-GCC/gccrs/issues/658
+//
+// let llvm_name = match name {
+// sym::sqrtf32 => "llvm.sqrt.f32",
+// sym::sqrtf64 => "llvm.sqrt.f64",
+// sym::powif32 => "llvm.powi.f32",
+// sym::powif64 => "llvm.powi.f64",
+// sym::sinf32 => "llvm.sin.f32",
+// sym::sinf64 => "llvm.sin.f64",
+// sym::cosf32 => "llvm.cos.f32",
+// sym::cosf64 => "llvm.cos.f64",
+// sym::powf32 => "llvm.pow.f32",
+// sym::powf64 => "llvm.pow.f64",
+// sym::expf32 => "llvm.exp.f32",
+// sym::expf64 => "llvm.exp.f64",
+// sym::exp2f32 => "llvm.exp2.f32",
+// sym::exp2f64 => "llvm.exp2.f64",
+// sym::logf32 => "llvm.log.f32",
+// sym::logf64 => "llvm.log.f64",
+// sym::log10f32 => "llvm.log10.f32",
+// sym::log10f64 => "llvm.log10.f64",
+// sym::log2f32 => "llvm.log2.f32",
+// sym::log2f64 => "llvm.log2.f64",
+// sym::fmaf32 => "llvm.fma.f32",
+// sym::fmaf64 => "llvm.fma.f64",
+// sym::fabsf32 => "llvm.fabs.f32",
+// sym::fabsf64 => "llvm.fabs.f64",
+// sym::minnumf32 => "llvm.minnum.f32",
+// sym::minnumf64 => "llvm.minnum.f64",
+// sym::maxnumf32 => "llvm.maxnum.f32",
+// sym::maxnumf64 => "llvm.maxnum.f64",
+// sym::copysignf32 => "llvm.copysign.f32",
+// sym::copysignf64 => "llvm.copysign.f64",
+// sym::floorf32 => "llvm.floor.f32",
+// sym::floorf64 => "llvm.floor.f64",
+// sym::ceilf32 => "llvm.ceil.f32",
+// sym::ceilf64 => "llvm.ceil.f64",
+// sym::truncf32 => "llvm.trunc.f32",
+// sym::truncf64 => "llvm.trunc.f64",
+// sym::rintf32 => "llvm.rint.f32",
+// sym::rintf64 => "llvm.rint.f64",
+// sym::nearbyintf32 => "llvm.nearbyint.f32",
+// sym::nearbyintf64 => "llvm.nearbyint.f64",
+// sym::roundf32 => "llvm.round.f32",
+// sym::roundf64 => "llvm.round.f64",
+// _ => return None,
+// };
+// Some(cx.get_intrinsic(&llvm_name))
+class BuiltinsContext
+{
+public:
+ static BuiltinsContext &get ()
+ {
+ static BuiltinsContext instance;
+ return instance;
+ }
+
+ bool lookup_simple_builtin (const std::string &name, tree *builtin)
+ {
+ auto it = rust_intrinsic_to_gcc_builtin.find (name);
+ if (it == rust_intrinsic_to_gcc_builtin.end ())
+ return false;
+
+ return lookup_gcc_builtin (it->second, builtin);
+ }
+
+private:
+ static const int builtin_const = 1 << 0;
+ static const int builtin_noreturn = 1 << 1;
+ static const int builtin_novops = 1 << 2;
+
+ BuiltinsContext () { setup (); }
+
+ void setup ()
+ {
+ tree math_function_type_f32
+ = build_function_type_list (float_type_node, float_type_node, NULL_TREE);
+
+ define_builtin ("sinf32", BUILT_IN_SINF, "__builtin_sinf", "sinf",
+ math_function_type_f32, builtin_const);
+
+ define_builtin ("sqrtf32", BUILT_IN_SQRTF, "__builtin_sqrtf", "sqrtf",
+ math_function_type_f32, builtin_const);
+
+ define_builtin ("unreachable", BUILT_IN_UNREACHABLE,
+ "__builtin_unreachable", NULL,
+ build_function_type (void_type_node, void_list_node),
+ builtin_const | builtin_noreturn);
+
+ define_builtin ("abort", BUILT_IN_ABORT, "__builtin_abort", "abort",
+ build_function_type (void_type_node, void_list_node),
+ builtin_const | builtin_noreturn);
+
+ define_builtin ("breakpoint", BUILT_IN_TRAP, "__builtin_trap", "breakpoint",
+ build_function_type (void_type_node, void_list_node),
+ builtin_const | builtin_noreturn);
+
+ define_builtin (
+ "memcpy", BUILT_IN_MEMCPY, "__builtin_memcpy", "memcpy",
+ build_function_type_list (build_pointer_type (void_type_node),
+ build_pointer_type (void_type_node),
+ build_pointer_type (void_type_node),
+ size_type_node, NULL_TREE),
+ 0);
+ }
+
+ // Define a builtin function. BCODE is the builtin function code
+ // defined by builtins.def. NAME is the name of the builtin function.
+ // LIBNAME is the name of the corresponding library function, and is
+ // NULL if there isn't one. FNTYPE is the type of the function.
+ // CONST_P is true if the function has the const attribute.
+ // NORETURN_P is true if the function has the noreturn attribute.
+ void define_builtin (const std::string rust_name, built_in_function bcode,
+ const char *name, const char *libname, tree fntype,
+ int flags)
+ {
+ tree decl = add_builtin_function (name, fntype, bcode, BUILT_IN_NORMAL,
+ libname, NULL_TREE);
+ if ((flags & builtin_const) != 0)
+ TREE_READONLY (decl) = 1;
+ if ((flags & builtin_noreturn) != 0)
+ TREE_THIS_VOLATILE (decl) = 1;
+ if ((flags & builtin_novops) != 0)
+ DECL_IS_NOVOPS (decl) = 1;
+ set_builtin_decl (bcode, decl, true);
+ this->builtin_functions_[name] = decl;
+ if (libname != NULL)
+ {
+ decl = add_builtin_function (libname, fntype, bcode, BUILT_IN_NORMAL,
+ NULL, NULL_TREE);
+ if ((flags & builtin_const) != 0)
+ TREE_READONLY (decl) = 1;
+ if ((flags & builtin_noreturn) != 0)
+ TREE_THIS_VOLATILE (decl) = 1;
+ if ((flags & builtin_novops) != 0)
+ DECL_IS_NOVOPS (decl) = 1;
+ this->builtin_functions_[libname] = decl;
+ }
+
+ rust_intrinsic_to_gcc_builtin[rust_name] = name;
+ }
+
+ bool lookup_gcc_builtin (const std::string &name, tree *builtin)
+ {
+ auto it = builtin_functions_.find (name);
+ if (it == builtin_functions_.end ())
+ return false;
+
+ *builtin = it->second;
+ return true;
+ }
+
+ // A mapping of the GCC built-ins exposed to GCC Rust.
+ std::map<std::string, tree> builtin_functions_;
+ std::map<std::string, std::string> rust_intrinsic_to_gcc_builtin;
+};
+
+} // namespace Compile
+} // namespace Rust
+
+#endif // RUST_BUILTINS_H
diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc
new file mode 100644
index 00000000000..2b5c850872f
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-base.cc
@@ -0,0 +1,730 @@
+// 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"
+#include "rust-abi.h"
+#include "rust-compile-item.h"
+#include "rust-compile-stmt.h"
+#include "rust-compile-expr.h"
+#include "rust-compile-fnparam.h"
+#include "rust-compile-var-decl.h"
+#include "rust-constexpr.h"
+#include "rust-diagnostics.h"
+#include "rust-expr.h" // for AST::AttrInputLiteral
+#include "rust-macro.h" // for AST::MetaNameValueStr
+
+#include "fold-const.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "tree.h"
+
+namespace Rust {
+namespace Compile {
+
+bool inline should_mangle_item (const tree fndecl)
+{
+ return lookup_attribute ("no_mangle", DECL_ATTRIBUTES (fndecl)) == NULL_TREE;
+}
+
+void
+HIRCompileBase::setup_fndecl (tree fndecl, bool is_main_entry_point,
+ bool is_generic_fn, HIR::Visibility &visibility,
+ const HIR::FunctionQualifiers &qualifiers,
+ const AST::AttrVec &attrs)
+{
+ // if its the main fn or pub visibility mark its as DECL_PUBLIC
+ // please see https://github.com/Rust-GCC/gccrs/pull/137
+ bool is_pub = visibility.get_vis_type () == HIR::Visibility::VisType::PUBLIC;
+ if (is_main_entry_point || (is_pub && !is_generic_fn))
+ {
+ TREE_PUBLIC (fndecl) = 1;
+ }
+
+ // is it a const fn
+ if (qualifiers.is_const ())
+ {
+ TREE_READONLY (fndecl) = 1;
+ }
+
+ // is it inline?
+ for (const auto &attr : attrs)
+ {
+ bool is_inline = attr.get_path ().as_string ().compare ("inline") == 0;
+ bool is_must_use
+ = attr.get_path ().as_string ().compare ("must_use") == 0;
+ bool is_cold = attr.get_path ().as_string ().compare ("cold") == 0;
+ bool is_link_section
+ = attr.get_path ().as_string ().compare ("link_section") == 0;
+ bool no_mangle = attr.get_path ().as_string ().compare ("no_mangle") == 0;
+ bool is_deprecated
+ = attr.get_path ().as_string ().compare ("deprecated") == 0;
+
+ if (is_inline)
+ {
+ handle_inline_attribute_on_fndecl (fndecl, attr);
+ }
+ else if (is_must_use)
+ {
+ handle_must_use_attribute_on_fndecl (fndecl, attr);
+ }
+ else if (is_cold)
+ {
+ handle_cold_attribute_on_fndecl (fndecl, attr);
+ }
+ else if (is_link_section)
+ {
+ handle_link_section_attribute_on_fndecl (fndecl, attr);
+ }
+ else if (is_deprecated)
+ {
+ handle_deprecated_attribute_on_fndecl (fndecl, attr);
+ }
+ else if (no_mangle)
+ {
+ handle_no_mangle_attribute_on_fndecl (fndecl, attr);
+ }
+ }
+}
+
+void
+HIRCompileBase::handle_cold_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr)
+{
+ // simple #[cold]
+ if (!attr.has_attr_input ())
+ {
+ tree cold = get_identifier ("cold");
+ // this will get handled by the GCC backend later
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (cold, NULL_TREE, DECL_ATTRIBUTES (fndecl));
+ return;
+ }
+
+ rust_error_at (attr.get_locus (),
+ "attribute %<cold%> does not accept any arguments");
+}
+
+void
+HIRCompileBase::handle_link_section_attribute_on_fndecl (
+ tree fndecl, const AST::Attribute &attr)
+{
+ if (!attr.has_attr_input ())
+ {
+ rust_error_at (attr.get_locus (),
+ "%<link_section%> expects exactly one argment");
+ return;
+ }
+
+ rust_assert (attr.get_attr_input ().get_attr_input_type ()
+ == AST::AttrInput::AttrInputType::LITERAL);
+
+ auto &literal = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
+ const auto &msg_str = literal.get_literal ().as_string ();
+
+ if (decl_section_name (fndecl))
+ {
+ rust_warning_at (attr.get_locus (), 0, "section name redefined");
+ }
+
+ set_decl_section_name (fndecl, msg_str.c_str ());
+}
+
+void
+HIRCompileBase::handle_no_mangle_attribute_on_fndecl (
+ tree fndecl, const AST::Attribute &attr)
+{
+ if (attr.has_attr_input ())
+ {
+ rust_error_at (attr.get_locus (),
+ "attribute %<no_mangle%> does not accept any arguments");
+ return;
+ }
+
+ DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("no_mangle"), NULL_TREE,
+ DECL_ATTRIBUTES (fndecl));
+}
+
+void
+HIRCompileBase::handle_deprecated_attribute_on_fndecl (
+ tree fndecl, const AST::Attribute &attr)
+{
+ tree value = NULL_TREE;
+ TREE_DEPRECATED (fndecl) = 1;
+
+ // simple #[deprecated]
+ if (!attr.has_attr_input ())
+ return;
+
+ const AST::AttrInput &input = attr.get_attr_input ();
+ auto input_type = input.get_attr_input_type ();
+
+ if (input_type == AST::AttrInput::AttrInputType::LITERAL)
+ {
+ // handle #[deprecated = "message"]
+ auto &literal
+ = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
+ const auto &msg_str = literal.get_literal ().as_string ();
+ value = build_string (msg_str.size (), msg_str.c_str ());
+ }
+ else if (input_type == AST::AttrInput::AttrInputType::TOKEN_TREE)
+ {
+ // handle #[deprecated(since = "...", note = "...")]
+ const auto &option = static_cast<const AST::DelimTokenTree &> (input);
+ AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item ();
+ for (const auto &item : meta_item->get_items ())
+ {
+ auto converted_item = item->to_meta_name_value_str ();
+ if (!converted_item)
+ continue;
+ auto key_value = converted_item->get_name_value_pair ();
+ if (key_value.first.compare ("since") == 0)
+ {
+ // valid, but this is handled by Cargo and some third-party audit
+ // tools
+ continue;
+ }
+ else if (key_value.first.compare ("note") == 0)
+ {
+ const auto &msg_str = key_value.second;
+ if (value)
+ rust_error_at (attr.get_locus (), "multiple %<note%> items");
+ value = build_string (msg_str.size (), msg_str.c_str ());
+ }
+ else
+ {
+ rust_error_at (attr.get_locus (), "unknown meta item %qs",
+ key_value.first.c_str ());
+ }
+ }
+ }
+
+ if (value)
+ {
+ tree attr_list = build_tree_list (NULL_TREE, value);
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (get_identifier ("deprecated"), attr_list,
+ DECL_ATTRIBUTES (fndecl));
+ }
+}
+
+void
+HIRCompileBase::handle_inline_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr)
+{
+ // simple #[inline]
+ if (!attr.has_attr_input ())
+ {
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
+ return;
+ }
+
+ const AST::AttrInput &input = attr.get_attr_input ();
+ bool is_token_tree
+ = input.get_attr_input_type () == AST::AttrInput::AttrInputType::TOKEN_TREE;
+ rust_assert (is_token_tree);
+ const auto &option = static_cast<const AST::DelimTokenTree &> (input);
+ AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item ();
+ if (meta_item->get_items ().size () != 1)
+ {
+ rust_error_at (attr.get_locus (), "invalid number of arguments");
+ return;
+ }
+
+ const std::string inline_option
+ = meta_item->get_items ().at (0)->as_string ();
+
+ // we only care about NEVER and ALWAYS else its an error
+ bool is_always = inline_option.compare ("always") == 0;
+ bool is_never = inline_option.compare ("never") == 0;
+
+ // #[inline(never)]
+ if (is_never)
+ {
+ DECL_UNINLINABLE (fndecl) = 1;
+ }
+ // #[inline(always)]
+ else if (is_always)
+ {
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
+ DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("always_inline"),
+ NULL, DECL_ATTRIBUTES (fndecl));
+ }
+ else
+ {
+ rust_error_at (attr.get_locus (), "unknown inline option");
+ }
+}
+
+void
+HIRCompileBase::handle_must_use_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr)
+{
+ tree nodiscard = get_identifier ("nodiscard");
+ tree value = NULL_TREE;
+
+ if (attr.has_attr_input ())
+ {
+ rust_assert (attr.get_attr_input ().get_attr_input_type ()
+ == AST::AttrInput::AttrInputType::LITERAL);
+
+ auto &literal
+ = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
+ const auto &msg_str = literal.get_literal ().as_string ();
+ tree message = build_string (msg_str.size (), msg_str.c_str ());
+
+ value = tree_cons (nodiscard, message, NULL_TREE);
+ }
+
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (nodiscard, value, DECL_ATTRIBUTES (fndecl));
+}
+
+void
+HIRCompileBase::setup_abi_options (tree fndecl, ABI abi)
+{
+ tree abi_tree = NULL_TREE;
+
+ switch (abi)
+ {
+ case Rust::ABI::RUST:
+ case Rust::ABI::INTRINSIC:
+ case Rust::ABI::C:
+ case Rust::ABI::CDECL:
+ // `decl_attributes` function (not the macro) has the side-effect of
+ // actually switching the codegen backend to use the ABI we annotated.
+ // However, since `cdecl` is the default ABI GCC will be using, explicitly
+ // specifying that ABI will cause GCC to emit a warning saying the
+ // attribute is useless (which is confusing to the user as the attribute
+ // is added by us).
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (get_identifier ("cdecl"), NULL, DECL_ATTRIBUTES (fndecl));
+
+ return;
+
+ case Rust::ABI::STDCALL:
+ abi_tree = get_identifier ("stdcall");
+
+ break;
+
+ case Rust::ABI::FASTCALL:
+ abi_tree = get_identifier ("fastcall");
+
+ break;
+
+ case Rust::ABI::SYSV64:
+ abi_tree = get_identifier ("sysv_abi");
+
+ break;
+
+ case Rust::ABI::WIN64:
+ abi_tree = get_identifier ("ms_abi");
+
+ break;
+
+ default:
+ break;
+ }
+
+ decl_attributes (&fndecl, build_tree_list (abi_tree, NULL_TREE), 0);
+}
+
+// ported from gcc/c/c-typecheck.c
+//
+// Mark EXP saying that we need to be able to take the
+// address of it; it should not be allocated in a register.
+// Returns true if successful. ARRAY_REF_P is true if this
+// is for ARRAY_REF construction - in that case we don't want
+// to look through VIEW_CONVERT_EXPR from VECTOR_TYPE to ARRAY_TYPE,
+// it is fine to use ARRAY_REFs for vector subscripts on vector
+// register variables.
+bool
+HIRCompileBase::mark_addressable (tree exp, Location locus)
+{
+ tree x = exp;
+
+ while (1)
+ switch (TREE_CODE (x))
+ {
+ case VIEW_CONVERT_EXPR:
+ if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
+ && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))))
+ return true;
+ x = TREE_OPERAND (x, 0);
+ break;
+
+ case COMPONENT_REF:
+ // TODO
+ // if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
+ // {
+ // error ("cannot take address of bit-field %qD", TREE_OPERAND (x,
+ // 1)); return false;
+ // }
+
+ /* FALLTHRU */
+ case ADDR_EXPR:
+ case ARRAY_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ x = TREE_OPERAND (x, 0);
+ break;
+
+ case COMPOUND_LITERAL_EXPR:
+ TREE_ADDRESSABLE (x) = 1;
+ TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (x)) = 1;
+ return true;
+
+ case CONSTRUCTOR:
+ TREE_ADDRESSABLE (x) = 1;
+ return true;
+
+ case VAR_DECL:
+ case CONST_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ // (we don't have a concept of a "register" declaration)
+ // fallthrough */
+
+ /* FALLTHRU */
+ case FUNCTION_DECL:
+ TREE_ADDRESSABLE (x) = 1;
+
+ /* FALLTHRU */
+ default:
+ return true;
+ }
+
+ return false;
+}
+
+tree
+HIRCompileBase::address_expression (tree expr, Location location)
+{
+ if (expr == error_mark_node)
+ return error_mark_node;
+
+ if (!mark_addressable (expr, location))
+ return error_mark_node;
+
+ return build_fold_addr_expr_loc (location.gcc_location (), expr);
+}
+
+tree
+HIRCompileBase::indirect_expression (tree expr, Location locus)
+{
+ if (expr == error_mark_node)
+ return error_mark_node;
+
+ return build_fold_indirect_ref_loc (locus.gcc_location (), expr);
+}
+
+std::vector<Bvariable *>
+HIRCompileBase::compile_locals_for_block (Context *ctx, Resolver::Rib &rib,
+ tree fndecl)
+{
+ std::vector<Bvariable *> locals;
+ for (auto it : rib.get_declarations ())
+ {
+ NodeId node_id = it.first;
+ HirId ref = UNKNOWN_HIRID;
+ if (!ctx->get_mappings ()->lookup_node_to_hir (node_id, &ref))
+ continue;
+
+ // we only care about local patterns
+ HIR::Pattern *pattern = ctx->get_mappings ()->lookup_hir_pattern (ref);
+ if (pattern == nullptr)
+ continue;
+
+ // lookup the type
+ TyTy::BaseType *tyty = nullptr;
+ if (!ctx->get_tyctx ()->lookup_type (ref, &tyty))
+ continue;
+
+ // compile the local
+ tree type = TyTyResolveCompile::compile (ctx, tyty);
+ Bvariable *compiled
+ = CompileVarDecl::compile (fndecl, type, pattern, ctx);
+ locals.push_back (compiled);
+ }
+ return locals;
+}
+
+void
+HIRCompileBase::compile_function_body (Context *ctx, tree fndecl,
+ HIR::BlockExpr &function_body,
+ bool has_return_type)
+{
+ for (auto &s : function_body.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 (function_body.has_expr ())
+ {
+ // the previous passes will ensure this is a valid return
+ // or a valid trailing expression
+ tree compiled_expr
+ = CompileExpr::Compile (function_body.expr.get (), ctx);
+
+ if (compiled_expr != nullptr)
+ {
+ if (has_return_type)
+ {
+ std::vector<tree> retstmts;
+ retstmts.push_back (compiled_expr);
+
+ auto ret = ctx->get_backend ()->return_statement (
+ fndecl, retstmts,
+ function_body.get_final_expr ()->get_locus ());
+ ctx->add_statement (ret);
+ }
+ else
+ {
+ // FIXME can this actually happen?
+ ctx->add_statement (compiled_expr);
+ }
+ }
+ }
+}
+
+tree
+HIRCompileBase::compile_function (
+ Context *ctx, const std::string &fn_name, HIR::SelfParam &self_param,
+ std::vector<HIR::FunctionParam> &function_params,
+ const HIR::FunctionQualifiers &qualifiers, HIR::Visibility &visibility,
+ AST::AttrVec &outer_attrs, Location locus, HIR::BlockExpr *function_body,
+ const Resolver::CanonicalPath *canonical_path, TyTy::FnType *fntype,
+ bool function_has_return)
+{
+ tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
+ std::string ir_symbol_name
+ = canonical_path->get () + fntype->subst_as_string ();
+
+ // we don't mangle the main fn since we haven't implemented the main shim
+ bool is_main_fn = fn_name.compare ("main") == 0;
+ std::string asm_name = fn_name;
+
+ unsigned int flags = 0;
+ tree fndecl = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name,
+ "" /* asm_name */, flags, locus);
+
+ setup_fndecl (fndecl, is_main_fn, fntype->has_subsititions_defined (),
+ visibility, qualifiers, outer_attrs);
+ setup_abi_options (fndecl, qualifiers.get_abi ());
+
+ // conditionally mangle the function name
+ bool should_mangle = should_mangle_item (fndecl);
+ if (!is_main_fn && should_mangle)
+ asm_name = ctx->mangle_item (fntype, *canonical_path);
+ SET_DECL_ASSEMBLER_NAME (fndecl,
+ get_identifier_with_length (asm_name.data (),
+ asm_name.length ()));
+
+ // insert into the context
+ ctx->insert_function_decl (fntype, fndecl);
+
+ // setup the params
+ TyTy::BaseType *tyret = fntype->get_return_type ();
+ std::vector<Bvariable *> param_vars;
+ if (!self_param.is_error ())
+ {
+ rust_assert (fntype->is_method ());
+ TyTy::BaseType *self_tyty_lookup = fntype->get_self_type ();
+
+ tree self_type = TyTyResolveCompile::compile (ctx, self_tyty_lookup);
+ Bvariable *compiled_self_param
+ = CompileSelfParam::compile (ctx, fndecl, self_param, self_type,
+ self_param.get_locus ());
+
+ param_vars.push_back (compiled_self_param);
+ ctx->insert_var_decl (self_param.get_mappings ().get_hirid (),
+ compiled_self_param);
+ }
+
+ // offset from + 1 for the TyTy::FnType being used when this is a method to
+ // skip over Self on the FnType
+ bool is_method = !self_param.is_error ();
+ size_t i = is_method ? 1 : 0;
+ for (auto &referenced_param : function_params)
+ {
+ auto tyty_param = fntype->param_at (i++);
+ auto param_tyty = tyty_param.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);
+
+ param_vars.push_back (compiled_param_var);
+
+ const HIR::Pattern &param_pattern = *referenced_param.get_param_name ();
+ ctx->insert_var_decl (param_pattern.get_pattern_mappings ().get_hirid (),
+ compiled_param_var);
+ }
+
+ if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
+ return error_mark_node;
+
+ // lookup locals
+ auto body_mappings = function_body->get_mappings ();
+ Resolver::Rib *rib = nullptr;
+ bool ok
+ = ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), &rib);
+ rust_assert (ok);
+
+ std::vector<Bvariable *> locals
+ = compile_locals_for_block (ctx, *rib, fndecl);
+
+ tree enclosing_scope = NULL_TREE;
+ Location start_location = function_body->get_locus ();
+ Location end_location = function_body->get_end_locus ();
+
+ tree code_block = ctx->get_backend ()->block (fndecl, enclosing_scope, locals,
+ start_location, end_location);
+ ctx->push_block (code_block);
+
+ Bvariable *return_address = nullptr;
+ if (function_has_return)
+ {
+ tree return_type = TyTyResolveCompile::compile (ctx, tyret);
+
+ bool address_is_taken = false;
+ tree ret_var_stmt = NULL_TREE;
+
+ return_address
+ = ctx->get_backend ()->temporary_variable (fndecl, code_block,
+ return_type, NULL,
+ address_is_taken, locus,
+ &ret_var_stmt);
+
+ ctx->add_statement (ret_var_stmt);
+ }
+
+ ctx->push_fn (fndecl, return_address);
+ compile_function_body (ctx, fndecl, *function_body, function_has_return);
+ tree bind_tree = ctx->pop_block ();
+
+ gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
+ DECL_SAVED_TREE (fndecl) = bind_tree;
+
+ ctx->pop_fn ();
+ ctx->push_function (fndecl);
+
+ return fndecl;
+}
+
+tree
+HIRCompileBase::compile_constant_item (
+ Context *ctx, TyTy::BaseType *resolved_type,
+ const Resolver::CanonicalPath *canonical_path, HIR::Expr *const_value_expr,
+ Location locus)
+{
+ const std::string &ident = canonical_path->get ();
+ tree type = TyTyResolveCompile::compile (ctx, resolved_type);
+ tree const_type = build_qualified_type (type, TYPE_QUAL_CONST);
+
+ bool is_block_expr
+ = const_value_expr->get_expression_type () == HIR::Expr::ExprType::Block;
+
+ // compile the expression
+ tree folded_expr = error_mark_node;
+ if (!is_block_expr)
+ {
+ tree value = CompileExpr::Compile (const_value_expr, ctx);
+ folded_expr = fold_expr (value);
+ }
+ else
+ {
+ // in order to compile a block expr we want to reuse as much existing
+ // machineary that we already have. This means the best approach is to
+ // make a _fake_ function with a block so it can hold onto temps then
+ // use our constexpr code to fold it completely or error_mark_node
+ Backend::typed_identifier receiver;
+ tree compiled_fn_type = ctx->get_backend ()->function_type (
+ receiver, {}, {Backend::typed_identifier ("_", const_type, locus)},
+ NULL, locus);
+
+ tree fndecl
+ = ctx->get_backend ()->function (compiled_fn_type, ident, "", 0, locus);
+ TREE_READONLY (fndecl) = 1;
+
+ tree enclosing_scope = NULL_TREE;
+ HIR::BlockExpr *function_body
+ = static_cast<HIR::BlockExpr *> (const_value_expr);
+ Location start_location = function_body->get_locus ();
+ Location end_location = function_body->get_end_locus ();
+
+ tree code_block
+ = ctx->get_backend ()->block (fndecl, enclosing_scope, {},
+ start_location, end_location);
+ ctx->push_block (code_block);
+
+ bool address_is_taken = false;
+ tree ret_var_stmt = NULL_TREE;
+ Bvariable *return_address
+ = ctx->get_backend ()->temporary_variable (fndecl, code_block,
+ const_type, NULL,
+ address_is_taken, locus,
+ &ret_var_stmt);
+
+ ctx->add_statement (ret_var_stmt);
+ ctx->push_fn (fndecl, return_address);
+
+ compile_function_body (ctx, fndecl, *function_body, true);
+ tree bind_tree = ctx->pop_block ();
+
+ gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
+ DECL_SAVED_TREE (fndecl) = bind_tree;
+
+ ctx->pop_fn ();
+
+ // lets fold it into a call expr
+ tree call = build_call_array_loc (locus.gcc_location (), const_type,
+ fndecl, 0, NULL);
+ folded_expr = fold_expr (call);
+ }
+
+ return named_constant_expression (const_type, ident, folded_expr, locus);
+}
+
+tree
+HIRCompileBase::named_constant_expression (tree type_tree,
+ const std::string &name,
+ tree const_val, Location location)
+{
+ if (type_tree == error_mark_node || const_val == error_mark_node)
+ return error_mark_node;
+
+ tree name_tree = get_identifier_with_length (name.data (), name.length ());
+ tree decl
+ = build_decl (location.gcc_location (), CONST_DECL, name_tree, type_tree);
+ DECL_INITIAL (decl) = const_val;
+ TREE_CONSTANT (decl) = 1;
+ TREE_READONLY (decl) = 1;
+
+ rust_preserve_from_gc (decl);
+ return decl;
+}
+
+} // namespace Compile
+} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h
new file mode 100644
index 00000000000..4c20933cafc
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-base.h
@@ -0,0 +1,146 @@
+// 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_BASE
+#define RUST_COMPILE_BASE
+
+#include "rust-compile-context.h"
+#include "rust-compile-type.h"
+#include "rust-hir-visitor.h"
+#include "rust-hir-full.h"
+
+namespace Rust {
+namespace Compile {
+
+class HIRCompileBase
+{
+public:
+ virtual ~HIRCompileBase () {}
+
+protected:
+ HIRCompileBase (Context *ctx) : ctx (ctx) {}
+
+ Context *ctx;
+
+protected:
+ Context *get_context () { return ctx; }
+
+ tree coercion_site (HirId id, tree rvalue, const TyTy::BaseType *actual,
+ const TyTy::BaseType *expected, Location lvalue_locus,
+ Location rvalue_locus);
+ tree coercion_site1 (tree rvalue, const TyTy::BaseType *actual,
+ const TyTy::BaseType *expected, Location lvalue_locus,
+ Location rvalue_locus);
+
+ tree coerce_to_dyn_object (tree compiled_ref, const TyTy::BaseType *actual,
+ const TyTy::DynamicObjectType *ty, Location locus);
+
+ tree compute_address_for_trait_item (
+ const Resolver::TraitItemReference *ref,
+ const TyTy::TypeBoundPredicate *predicate,
+ std::vector<std::pair<Resolver::TraitReference *, HIR::ImplBlock *>>
+ &receiver_bounds,
+ const TyTy::BaseType *receiver, const TyTy::BaseType *root, Location locus);
+
+ bool verify_array_capacities (tree ltype, tree rtype, Location ltype_locus,
+ Location rtype_locus);
+
+ tree query_compile (HirId ref, TyTy::BaseType *lookup,
+ const HIR::PathIdentSegment &final_segment,
+ const Analysis::NodeMapping &mappings,
+ Location expr_locus, bool is_qualified_path);
+
+ tree resolve_adjustements (std::vector<Resolver::Adjustment> &adjustments,
+ tree expression, Location locus);
+
+ tree resolve_deref_adjustment (Resolver::Adjustment &adjustment,
+ tree expression, Location locus);
+
+ tree resolve_indirection_adjustment (Resolver::Adjustment &adjustment,
+ tree expression, Location locus);
+
+ tree resolve_unsized_adjustment (Resolver::Adjustment &adjustment,
+ tree expression, Location locus);
+
+ tree resolve_unsized_slice_adjustment (Resolver::Adjustment &adjustment,
+ tree expression, Location locus);
+
+ tree resolve_unsized_dyn_adjustment (Resolver::Adjustment &adjustment,
+ tree expression, Location locus);
+
+ static void setup_fndecl (tree fndecl, bool is_main_entry_point,
+ bool is_generic_fn, HIR::Visibility &visibility,
+ const HIR::FunctionQualifiers &qualifiers,
+ const AST::AttrVec &attrs);
+
+ static void handle_inline_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr);
+
+ static void handle_cold_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr);
+
+ static void handle_must_use_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr);
+
+ static void
+ handle_link_section_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr);
+ static void
+ handle_deprecated_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr);
+
+ static void handle_no_mangle_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr);
+
+ static void setup_abi_options (tree fndecl, ABI abi);
+
+ static tree address_expression (tree expr, Location locus);
+
+ static tree indirect_expression (tree expr, Location locus);
+
+ static bool mark_addressable (tree, Location);
+
+ static std::vector<Bvariable *>
+ compile_locals_for_block (Context *ctx, Resolver::Rib &rib, tree fndecl);
+
+ static void compile_function_body (Context *ctx, tree fndecl,
+ HIR::BlockExpr &function_body,
+ bool has_return_type);
+
+ static tree compile_function (
+ Context *ctx, const std::string &fn_name, HIR::SelfParam &self_param,
+ std::vector<HIR::FunctionParam> &function_params,
+ const HIR::FunctionQualifiers &qualifiers, HIR::Visibility &visibility,
+ AST::AttrVec &outer_attrs, Location locus, HIR::BlockExpr *function_body,
+ const Resolver::CanonicalPath *canonical_path, TyTy::FnType *fntype,
+ bool function_has_return);
+
+ static tree
+ compile_constant_item (Context *ctx, TyTy::BaseType *resolved_type,
+ const Resolver::CanonicalPath *canonical_path,
+ HIR::Expr *const_value_expr, Location locus);
+
+ static tree named_constant_expression (tree type_tree,
+ const std::string &name,
+ tree const_val, Location location);
+};
+
+} // namespace Compile
+} // namespace Rust
+
+#endif // RUST_COMPILE_BASE
diff --git a/gcc/rust/backend/rust-mangle.cc b/gcc/rust/backend/rust-mangle.cc
new file mode 100644
index 00000000000..4d202078a70
--- /dev/null
+++ b/gcc/rust/backend/rust-mangle.cc
@@ -0,0 +1,307 @@
+#include "rust-mangle.h"
+#include "fnv-hash.h"
+#include "rust-base62.h"
+
+// FIXME: Rename those to legacy_*
+static const std::string kMangledSymbolPrefix = "_ZN";
+static const std::string kMangledSymbolDelim = "E";
+static const std::string kMangledGenericDelim = "$C$";
+static const std::string kMangledSubstBegin = "$LT$";
+static const std::string kMangledSubstEnd = "$GT$";
+static const std::string kMangledSpace = "$u20$";
+static const std::string kMangledRef = "$RF$";
+static const std::string kMangledPtr = "$BP$";
+static const std::string kMangledLeftSqParen = "$u5b$"; // [
+static const std::string kMangledRightSqParen = "$u5d$"; // ]
+static const std::string kQualPathBegin = "_" + kMangledSubstBegin;
+static const std::string kMangledComma = "$C$";
+
+namespace Rust {
+namespace Compile {
+
+Mangler::MangleVersion Mangler::version = MangleVersion::LEGACY;
+
+static std::string
+legacy_mangle_name (const std::string &name)
+{
+ // example
+ // <&T as core::fmt::Debug>::fmt:
+ // _ZN42_$LT$$RF$T$u20$as$u20$core..fmt..Debug$GT$3fmt17h6dac924c0051eef7E
+ // replace all white space with $ and & with RF
+ //
+ // <example::Bar as example::A>::fooA:
+ // _ZN43_$LT$example..Bar$u20$as$u20$example..A$GT$4fooA17hfc615fa76c7db7a0E:
+ //
+ // core::ptr::const_ptr::<impl *const T>::cast:
+ // _ZN4core3ptr9const_ptr33_$LT$impl$u20$$BP$const$u20$T$GT$4cast17hb79f4617226f1d55E:
+ //
+ // core::ptr::const_ptr::<impl *const [T]>::as_ptr:
+ // _ZN4core3ptr9const_ptr43_$LT$impl$u20$$BP$const$u20$$u5b$T$u5d$$GT$6as_ptr17he16e0dcd9473b04fE:
+ //
+ // example::Foo<T>::new:
+ // _ZN7example12Foo$LT$T$GT$3new17h9a2aacb7fd783515E:
+ //
+ // <example::Identity as example::FnLike<&T,&T>>::call
+ // _ZN74_$LT$example..Identity$u20$as$u20$example..FnLike$LT$$RF$T$C$$RF$T$GT$$GT$4call17ha9ee58935895acb3E
+
+ std::string buffer;
+ for (size_t i = 0; i < name.size (); i++)
+ {
+ std::string m;
+ char c = name.at (i);
+
+ if (c == ' ')
+ m = kMangledSpace;
+ else if (c == '&')
+ m = kMangledRef;
+ else if (i == 0 && c == '<')
+ m = kQualPathBegin;
+ else if (c == '<')
+ m = kMangledSubstBegin;
+ else if (c == '>')
+ m = kMangledSubstEnd;
+ else if (c == '*')
+ m = kMangledPtr;
+ else if (c == '[')
+ m = kMangledLeftSqParen;
+ else if (c == ']')
+ m = kMangledRightSqParen;
+ else if (c == ',')
+ m = kMangledComma;
+ else if (c == ':')
+ {
+ rust_assert (i + 1 < name.size ());
+ rust_assert (name.at (i + 1) == ':');
+ i++;
+ m = "..";
+ }
+ else
+ m.push_back (c);
+
+ buffer += m;
+ }
+
+ return std::to_string (buffer.size ()) + buffer;
+}
+
+static std::string
+legacy_mangle_canonical_path (const Resolver::CanonicalPath &path)
+{
+ std::string buffer;
+ for (size_t i = 0; i < path.size (); i++)
+ {
+ auto &seg = path.get_seg_at (i);
+ buffer += legacy_mangle_name (seg.second);
+ }
+ return buffer;
+}
+
+// rustc uses a sip128 hash for legacy mangling, but an fnv 128 was quicker to
+// implement for now
+static std::string
+legacy_hash (const std::string &fingerprint)
+{
+ Hash::FNV128 hasher;
+ hasher.write ((const unsigned char *) fingerprint.c_str (),
+ fingerprint.size ());
+
+ uint64_t hi, lo;
+ hasher.sum (&hi, &lo);
+
+ char hex[16 + 1];
+ memset (hex, 0, sizeof hex);
+ snprintf (hex, sizeof hex, "%08" PRIx64 "%08" PRIx64, lo, hi);
+
+ return "h" + std::string (hex, sizeof (hex) - 1);
+}
+
+static std::string
+v0_tuple_prefix (const TyTy::BaseType *ty)
+{
+ if (ty->is_unit ())
+ return "u";
+
+ // FIXME: ARTHUR: Add rest of algorithm
+ return "";
+}
+
+static std::string
+v0_numeric_prefix (const TyTy::BaseType *ty)
+{
+ static const std::map<std::string, std::string> num_prefixes = {
+ {"[i8]", "a"}, {"[u8]", "h"}, {"[i16]", "s"}, {"[u16]", "t"},
+ {"[i32]", "l"}, {"[u32]", "m"}, {"[i64]", "x"}, {"[u64]", "y"},
+ {"[isize]", "i"}, {"[usize]", "j"}, {"[f32]", "f"}, {"[f64]", "d"},
+ };
+
+ auto ty_kind = ty->get_kind ();
+ auto ty_str = ty->as_string ();
+ auto numeric_iter = num_prefixes.end ();
+
+ // Special numeric types
+ if (ty_kind == TyTy::TypeKind::ISIZE)
+ return "i";
+ else if (ty_kind == TyTy::TypeKind::USIZE)
+ return "j";
+
+ numeric_iter = num_prefixes.find (ty_str);
+ if (numeric_iter != num_prefixes.end ())
+ return numeric_iter->second;
+
+ return "";
+}
+
+static std::string
+v0_simple_type_prefix (const TyTy::BaseType *ty)
+{
+ switch (ty->get_kind ())
+ {
+ case TyTy::TypeKind::BOOL:
+ return "b";
+ case TyTy::TypeKind::CHAR:
+ return "c";
+ case TyTy::TypeKind::STR:
+ return "e";
+ case TyTy::TypeKind::NEVER:
+ return "z";
+
+ // Placeholder types
+ case TyTy::TypeKind::ERROR: // Fallthrough
+ case TyTy::TypeKind::INFER: // Fallthrough
+ case TyTy::TypeKind::PLACEHOLDER: // Fallthrough
+ case TyTy::TypeKind::PARAM:
+ // FIXME: TyTy::TypeKind::BOUND is also a valid variant in rustc
+ return "p";
+
+ case TyTy::TypeKind::TUPLE:
+ return v0_tuple_prefix (ty);
+
+ case TyTy::TypeKind::UINT: // Fallthrough
+ case TyTy::TypeKind::INT: // Fallthrough
+ case TyTy::TypeKind::FLOAT: // Fallthrough
+ case TyTy::TypeKind::ISIZE: // Fallthrough
+ case TyTy::TypeKind::USIZE: // Fallthrough
+ return v0_numeric_prefix (ty);
+
+ default:
+ return "";
+ }
+
+ gcc_unreachable ();
+}
+
+// Add an underscore-terminated base62 integer to the mangling string.
+// This corresponds to the `<base-62-number>` grammar in the v0 mangling RFC:
+// - 0 is encoded as "_"
+// - any other value is encoded as itself minus one in base 62, followed by
+// "_"
+static void
+v0_add_integer_62 (std::string &mangled, uint64_t x)
+{
+ if (x > 0)
+ mangled.append (base62_integer (x - 1));
+
+ mangled.append ("_");
+}
+
+// Add a tag-prefixed base62 integer to the mangling string when the
+// integer is greater than 0:
+// - 0 is encoded as "" (nothing)
+// - any other value is encoded as <tag> + v0_add_integer_62(itself), that is
+// <tag> + base62(itself - 1) + '_'
+static void
+v0_add_opt_integer_62 (std::string &mangled, std::string tag, uint64_t x)
+{
+ if (x > 0)
+ {
+ mangled.append (tag);
+ v0_add_integer_62 (mangled, x);
+ }
+}
+
+static void
+v0_add_disambiguator (std::string &mangled, uint64_t dis)
+{
+ v0_add_opt_integer_62 (mangled, "s", dis);
+}
+
+// Add an identifier to the mangled string. This corresponds to the
+// `<identifier>` grammar in the v0 mangling RFC.
+static void
+v0_add_identifier (std::string &mangled, const std::string &identifier)
+{
+ // FIXME: gccrs cannot handle unicode identifiers yet, so we never have to
+ // create mangling for unicode values for now. However, this is handled
+ // by the v0 mangling scheme. The grammar for unicode identifier is
+ // contained in <undisambiguated-identifier>, right under the <identifier>
+ // one. If the identifier contains unicode values, then an extra "u" needs
+ // to be added to the mangling string and `punycode` must be used to encode
+ // the characters.
+
+ mangled += std::to_string (identifier.size ());
+
+ // If the first character of the identifier is a digit or an underscore, we
+ // add an extra underscore
+ if (identifier[0] == '_')
+ mangled.append ("_");
+
+ mangled.append (identifier);
+}
+
+static std::string
+v0_type_prefix (const TyTy::BaseType *ty)
+{
+ auto ty_prefix = v0_simple_type_prefix (ty);
+ if (!ty_prefix.empty ())
+ return ty_prefix;
+
+ // FIXME: We need to fetch more type prefixes
+ gcc_unreachable ();
+}
+
+static std::string
+legacy_mangle_item (const TyTy::BaseType *ty,
+ const Resolver::CanonicalPath &path)
+{
+ const std::string hash = legacy_hash (ty->as_string ());
+ const std::string hash_sig = legacy_mangle_name (hash);
+
+ return kMangledSymbolPrefix + legacy_mangle_canonical_path (path) + hash_sig
+ + kMangledSymbolDelim;
+}
+
+static std::string
+v0_mangle_item (const TyTy::BaseType *ty, const Resolver::CanonicalPath &path)
+{
+ // we can get this from the canonical_path
+ auto mappings = Analysis::Mappings::get ();
+ std::string crate_name;
+ bool ok = mappings->get_crate_name (path.get_crate_num (), crate_name);
+ rust_assert (ok);
+
+ std::string mangled;
+ // FIXME: Add real algorithm once all pieces are implemented
+ auto ty_prefix = v0_type_prefix (ty);
+ v0_add_identifier (mangled, crate_name);
+ v0_add_disambiguator (mangled, 62);
+
+ gcc_unreachable ();
+}
+
+std::string
+Mangler::mangle_item (const TyTy::BaseType *ty,
+ const Resolver::CanonicalPath &path) const
+{
+ switch (version)
+ {
+ case Mangler::MangleVersion::LEGACY:
+ return legacy_mangle_item (ty, path);
+ case Mangler::MangleVersion::V0:
+ return v0_mangle_item (ty, path);
+ default:
+ gcc_unreachable ();
+ }
+}
+
+} // namespace Compile
+} // namespace Rust
diff --git a/gcc/rust/backend/rust-mangle.h b/gcc/rust/backend/rust-mangle.h
new file mode 100644
index 00000000000..6d5a64f8bce
--- /dev/null
+++ b/gcc/rust/backend/rust-mangle.h
@@ -0,0 +1,52 @@
+// 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_MANGLE_H
+#define RUST_MANGLE_H
+
+#include "rust-system.h"
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Compile {
+
+class Mangler
+{
+public:
+ enum MangleVersion
+ {
+ // Values defined in rust/lang.opt
+ LEGACY = 0,
+ V0 = 1,
+ };
+
+ // this needs to support Legacy and V0 see github #429 or #305
+ std::string mangle_item (const TyTy::BaseType *ty,
+ const Resolver::CanonicalPath &path) const;
+
+ static void set_mangling (int frust_mangling_value)
+ {
+ version = static_cast<MangleVersion> (frust_mangling_value);
+ }
+
+private:
+ static enum MangleVersion version;
+};
+
+} // namespace Compile
+} // namespace Rust
+
+#endif // RUST_MANGLE_H
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
new file mode 100644
index 00000000000..3d71e19fe82
--- /dev/null
+++ b/gcc/rust/backend/rust-tree.cc
@@ -0,0 +1,958 @@
+// 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-tree.h"
+#include "fold-const.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "escaped_string.h"
+
+namespace Rust {
+
+void
+mark_exp_read (tree exp)
+{
+ if (exp == NULL)
+ return;
+
+ switch (TREE_CODE (exp))
+ {
+ case VAR_DECL:
+ gcc_fallthrough ();
+ case PARM_DECL:
+ DECL_READ_P (exp) = 1;
+ break;
+ case ARRAY_REF:
+ case COMPONENT_REF:
+ case MODIFY_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ CASE_CONVERT:
+ case ADDR_EXPR:
+ case INDIRECT_REF:
+ case FLOAT_EXPR:
+ case NON_DEPENDENT_EXPR:
+ case VIEW_CONVERT_EXPR:
+ mark_exp_read (TREE_OPERAND (exp, 0));
+ break;
+ case COMPOUND_EXPR:
+ mark_exp_read (TREE_OPERAND (exp, 1));
+ break;
+ case COND_EXPR:
+ if (TREE_OPERAND (exp, 1))
+ mark_exp_read (TREE_OPERAND (exp, 1));
+ if (TREE_OPERAND (exp, 2))
+ mark_exp_read (TREE_OPERAND (exp, 2));
+ break;
+ default:
+ break;
+ }
+}
+
+tree
+convert_from_reference (tree val)
+{
+ if (TREE_TYPE (val) && TYPE_REF_P (TREE_TYPE (val)))
+ {
+ tree t = TREE_TYPE (TREE_TYPE (val));
+ tree ref = build1 (INDIRECT_REF, t, val);
+
+ mark_exp_read (val);
+
+ TREE_SIDE_EFFECTS (ref)
+ = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (val));
+ val = ref;
+ }
+
+ return val;
+}
+
+tree
+mark_use (tree expr, bool rvalue_p, bool read_p,
+ location_t loc /* = UNKNOWN_LOCATION */,
+ bool reject_builtin /* = true */)
+{
+#define RECUR(t) mark_use ((t), rvalue_p, read_p, loc, reject_builtin)
+
+ if (expr == NULL_TREE || error_operand_p (expr))
+ return expr;
+
+ if (reject_builtin)
+ return error_mark_node;
+
+ if (read_p)
+ mark_exp_read (expr);
+
+ bool recurse_op[3] = {false, false, false};
+ switch (TREE_CODE (expr))
+ {
+ case COMPONENT_REF:
+ case NON_DEPENDENT_EXPR:
+ recurse_op[0] = true;
+ break;
+ case COMPOUND_EXPR:
+ recurse_op[1] = true;
+ break;
+ case COND_EXPR:
+ recurse_op[2] = true;
+ if (TREE_OPERAND (expr, 1))
+ recurse_op[1] = true;
+ break;
+ case INDIRECT_REF:
+ if (REFERENCE_REF_P (expr))
+ {
+ /* Try to look through the reference. */
+ tree ref = TREE_OPERAND (expr, 0);
+ tree r = mark_rvalue_use (ref, loc, reject_builtin);
+ if (r != ref)
+ expr = convert_from_reference (r);
+ }
+ break;
+
+ case VIEW_CONVERT_EXPR:
+ if (location_wrapper_p (expr))
+ {
+ loc = EXPR_LOCATION (expr);
+ tree op = TREE_OPERAND (expr, 0);
+ tree nop = RECUR (op);
+ if (nop == error_mark_node)
+ return error_mark_node;
+ else if (op == nop)
+ /* No change. */;
+ else if (DECL_P (nop) || CONSTANT_CLASS_P (nop))
+ {
+ /* Reuse the location wrapper. */
+ TREE_OPERAND (expr, 0) = nop;
+ /* If we're replacing a DECL with a constant, we also need to
+ change the TREE_CODE of the location wrapper. */
+ if (rvalue_p)
+ TREE_SET_CODE (expr, NON_LVALUE_EXPR);
+ }
+ else
+ {
+ /* Drop the location wrapper. */
+ expr = nop;
+ protected_set_expr_location (expr, loc);
+ }
+ return expr;
+ }
+ gcc_fallthrough ();
+ CASE_CONVERT:
+ recurse_op[0] = true;
+ break;
+
+ default:
+ break;
+ }
+
+ for (int i = 0; i < 3; ++i)
+ if (recurse_op[i])
+ {
+ tree op = TREE_OPERAND (expr, i);
+ op = RECUR (op);
+ if (op == error_mark_node)
+ return error_mark_node;
+ TREE_OPERAND (expr, i) = op;
+ }
+
+ return expr;
+#undef RECUR
+}
+
+tree
+mark_rvalue_use (tree e, location_t loc /* = UNKNOWN_LOCATION */,
+ bool reject_builtin /* = true */)
+{
+ return mark_use (e, true, true, loc, reject_builtin);
+}
+
+tree
+mark_lvalue_use (tree expr)
+{
+ return mark_use (expr, false, true, input_location, false);
+}
+
+tree
+mark_lvalue_use_nonread (tree expr)
+{
+ return mark_use (expr, false, false, input_location, false);
+}
+
+tree
+mark_discarded_use (tree expr)
+{
+ if (expr == NULL_TREE)
+ return expr;
+
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
+ switch (TREE_CODE (expr))
+ {
+ case COND_EXPR:
+ TREE_OPERAND (expr, 2) = mark_discarded_use (TREE_OPERAND (expr, 2));
+ gcc_fallthrough ();
+ case COMPOUND_EXPR:
+ TREE_OPERAND (expr, 1) = mark_discarded_use (TREE_OPERAND (expr, 1));
+ return expr;
+
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ case INDIRECT_REF:
+ case MEMBER_REF:
+ break;
+ default:
+ if (DECL_P (expr))
+ break;
+ else
+ return expr;
+ }
+
+ return mark_use (expr, true, true, input_location, false);
+}
+
+tree
+convert_to_void (tree expr, impl_conv_void implicit)
+{
+ location_t loc = expr_loc_or_input_loc (expr);
+ if (expr == error_mark_node || TREE_TYPE (expr) == error_mark_node)
+ return error_mark_node;
+
+ expr = mark_discarded_use (expr);
+ if (implicit == ICV_CAST)
+ /* An explicit cast to void avoids all -Wunused-but-set* warnings. */
+ mark_exp_read (expr);
+
+ if (!TREE_TYPE (expr))
+ return expr;
+
+ if (VOID_TYPE_P (TREE_TYPE (expr)))
+ return expr;
+ switch (TREE_CODE (expr))
+ {
+ case COND_EXPR: {
+ /* The two parts of a cond expr might be separate lvalues. */
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree op2 = TREE_OPERAND (expr, 2);
+ bool side_effects
+ = ((op1 && TREE_SIDE_EFFECTS (op1)) || TREE_SIDE_EFFECTS (op2));
+ tree new_op1, new_op2;
+ new_op1 = NULL_TREE;
+ if (implicit != ICV_CAST && !side_effects)
+ {
+ if (op1)
+ new_op1 = convert_to_void (op1, ICV_SECOND_OF_COND);
+ new_op2 = convert_to_void (op2, ICV_THIRD_OF_COND);
+ }
+ else
+ {
+ if (op1)
+ new_op1 = convert_to_void (op1, ICV_CAST);
+ new_op2 = convert_to_void (op2, ICV_CAST);
+ }
+
+ expr = build3_loc (loc, COND_EXPR, TREE_TYPE (new_op2),
+ TREE_OPERAND (expr, 0), new_op1, new_op2);
+ break;
+ }
+
+ case COMPOUND_EXPR: {
+ /* The second part of a compound expr contains the value. */
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree new_op1;
+ if (implicit != ICV_CAST
+ && !warning_suppressed_p (expr /* What warning? */))
+ new_op1 = convert_to_void (op1, ICV_RIGHT_OF_COMMA);
+ else
+ new_op1 = convert_to_void (op1, ICV_CAST);
+
+ if (new_op1 != op1)
+ {
+ tree t = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (new_op1),
+ TREE_OPERAND (expr, 0), new_op1);
+ expr = t;
+ }
+
+ break;
+ }
+
+ case NON_LVALUE_EXPR:
+ case NOP_EXPR:
+ /* These have already decayed to rvalue. */
+ break;
+
+ case CALL_EXPR:
+ maybe_warn_nodiscard (expr, implicit);
+ break;
+
+ case INDIRECT_REF: {
+ tree type = TREE_TYPE (expr);
+ int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
+ int is_volatile = TYPE_VOLATILE (type);
+ int is_complete = COMPLETE_TYPE_P (type);
+
+ /* Can't load the value if we don't know the type. */
+ if (is_volatile && !is_complete)
+ {
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0,
+ "conversion to void will not access "
+ "object of incomplete type %qT",
+ type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in second operand "
+ "of conditional expression",
+ type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in third operand "
+ "of conditional expression",
+ type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in right operand of "
+ "comma operator",
+ type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in left operand of "
+ "comma operator",
+ type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in statement",
+ type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in for increment "
+ "expression",
+ type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ /* Don't load the value if this is an implicit dereference, or if
+ the type needs to be handled by ctors/dtors. */
+ else if (is_volatile && is_reference)
+ {
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0,
+ "conversion to void will not access "
+ "object of type %qT",
+ type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in second operand of "
+ "conditional expression",
+ type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in third operand of "
+ "conditional expression",
+ type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in right operand of "
+ "comma operator",
+ type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in left operand of comma "
+ "operator",
+ type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in statement",
+ type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in for increment expression",
+ type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else if (is_volatile && TREE_ADDRESSABLE (type))
+ {
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0,
+ "conversion to void will not access "
+ "object of non-trivially-copyable type %qT",
+ type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in second "
+ "operand of conditional expression",
+ type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in third "
+ "operand of conditional expression",
+ type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in right "
+ "operand of comma operator",
+ type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in left "
+ "operand of comma operator",
+ type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in statement",
+ type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in for "
+ "increment expression",
+ type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ if (is_reference || !is_volatile || !is_complete
+ || TREE_ADDRESSABLE (type))
+ {
+ /* Emit a warning (if enabled) when the "effect-less" INDIRECT_REF
+ operation is stripped off. Note that we don't warn about
+ - an expression with TREE_NO_WARNING set. (For an example of
+ such expressions, see build_over_call in call.cc.)
+ - automatic dereferencing of references, since the user cannot
+ control it. (See also warn_if_unused_value() in c-common.cc.)
+ */
+ if (warn_unused_value && implicit != ICV_CAST
+ && !warning_suppressed_p (expr, OPT_Wunused_value)
+ && !is_reference)
+ warning_at (loc, OPT_Wunused_value, "value computed is not used");
+ expr = TREE_OPERAND (expr, 0);
+ if (TREE_CODE (expr) == CALL_EXPR)
+ maybe_warn_nodiscard (expr, implicit);
+ }
+
+ break;
+ }
+
+ case VAR_DECL: {
+ /* External variables might be incomplete. */
+ tree type = TREE_TYPE (expr);
+ int is_complete = COMPLETE_TYPE_P (type);
+
+ if (TYPE_VOLATILE (type) && !is_complete)
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0,
+ "conversion to void will not access "
+ "object %qE of incomplete type %qT",
+ expr, type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in second operand of "
+ "conditional expression",
+ expr, type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in third operand of "
+ "conditional expression",
+ expr, type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in right operand of comma operator",
+ expr, type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in left operand of comma operator",
+ expr, type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in statement",
+ expr, type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in for increment expression",
+ expr, type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ break;
+ }
+
+ default:;
+ }
+
+ if (!TREE_SIDE_EFFECTS (expr))
+ expr = void_node;
+
+ return expr;
+}
+
+void
+maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
+{
+ tree call = expr;
+ if (TREE_CODE (expr) == TARGET_EXPR)
+ call = TARGET_EXPR_INITIAL (expr);
+
+ location_t loc = expr_loc_or_input_loc (call);
+ tree callee = CALL_EXPR_FN (call);
+ if (!callee)
+ return;
+
+ tree type = TREE_TYPE (callee);
+ if (INDIRECT_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ tree rettype = TREE_TYPE (type);
+ tree fn = get_fndecl_from_callee (callee);
+ tree attr;
+ if (implicit != ICV_CAST && fn
+ && (attr = lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn))))
+ {
+ escaped_string msg;
+ tree args = TREE_VALUE (attr);
+ if (args)
+ msg.escape (TREE_STRING_POINTER (TREE_VALUE (args)));
+ const char *format
+ = (msg ? G_ ("ignoring return value of %qD, that must be used: %<%s%>")
+ : G_ ("ignoring return value of %qD, that must be used"));
+ const char *raw_msg = msg ? (const char *) msg : "";
+ auto_diagnostic_group d;
+ if (warning_at (loc, OPT_Wunused_result, format, fn, raw_msg))
+ inform (DECL_SOURCE_LOCATION (fn), "declared here");
+ }
+ else if (implicit != ICV_CAST
+ && (attr
+ = lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype))))
+ {
+ escaped_string msg;
+ tree args = TREE_VALUE (attr);
+ if (args)
+ msg.escape (TREE_STRING_POINTER (TREE_VALUE (args)));
+ const char *format
+ = (msg ? G_ (
+ "ignoring returned value of type %qT, that must be used: %<%s%>")
+ : G_ ("ignoring returned value of type %qT, that must be used"));
+ const char *raw_msg = msg ? (const char *) msg : "";
+ auto_diagnostic_group d;
+ if (warning_at (loc, OPT_Wunused_result, format, rettype, raw_msg))
+ {
+ if (fn)
+ inform (DECL_SOURCE_LOCATION (fn), "in call to %qD, declared here",
+ fn);
+ inform (DECL_SOURCE_LOCATION (TYPE_NAME (rettype)),
+ "%qT declared here", rettype);
+ }
+ }
+}
+
+location_t
+expr_loc_or_loc (const_tree t, location_t or_loc)
+{
+ location_t loc = EXPR_LOCATION (t);
+ if (loc == UNKNOWN_LOCATION)
+ loc = or_loc;
+ return loc;
+}
+
+location_t
+expr_loc_or_input_loc (const_tree t)
+{
+ return expr_loc_or_loc (t, input_location);
+}
+
+// FN is the callee of a CALL_EXPR or AGGR_INIT_EXPR; return the FUNCTION_DECL
+// if we can.
+tree
+get_fndecl_from_callee (tree fn)
+{
+ if (fn == NULL_TREE)
+ return fn;
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ return fn;
+ tree type = TREE_TYPE (fn);
+ if (type == NULL_TREE || !INDIRECT_TYPE_P (type))
+ return NULL_TREE;
+
+ STRIP_NOPS (fn);
+ if (TREE_CODE (fn) == ADDR_EXPR || TREE_CODE (fn) == FDESC_EXPR)
+ fn = TREE_OPERAND (fn, 0);
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ return fn;
+ return NULL_TREE;
+}
+
+tree
+pointer_offset_expression (tree base_tree, tree index_tree, location_t location)
+{
+ tree element_type_tree = TREE_TYPE (TREE_TYPE (base_tree));
+ if (base_tree == error_mark_node || TREE_TYPE (base_tree) == error_mark_node
+ || index_tree == error_mark_node || element_type_tree == error_mark_node)
+ return error_mark_node;
+
+ tree element_size = TYPE_SIZE_UNIT (element_type_tree);
+ index_tree = fold_convert_loc (location, sizetype, index_tree);
+ tree offset
+ = fold_build2_loc (location, MULT_EXPR, sizetype, index_tree, element_size);
+
+ return fold_build2_loc (location, POINTER_PLUS_EXPR, TREE_TYPE (base_tree),
+ base_tree, offset);
+}
+
+// forked from gcc/cp/tree.cc cp_walk_subtrees
+/* Apply FUNC to all language-specific sub-trees of TP in a pre-order
+ traversal. Called from walk_tree. */
+
+tree
+rs_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, void *data,
+ hash_set<tree> *pset)
+{
+ enum tree_code code = TREE_CODE (*tp);
+ tree result;
+
+#define WALK_SUBTREE(NODE) \
+ do \
+ { \
+ result = rs_walk_tree (&(NODE), func, data, pset); \
+ if (result) \
+ goto out; \
+ } \
+ while (0)
+
+ if (TYPE_P (*tp))
+ {
+ /* If *WALK_SUBTREES_P is 1, we're interested in the syntactic form of
+ the argument, so don't look through typedefs, but do walk into
+ template arguments for alias templates (and non-typedefed classes).
+
+ If *WALK_SUBTREES_P > 1, we're interested in type identity or
+ equivalence, so look through typedefs, ignoring template arguments for
+ alias templates, and walk into template args of classes.
+
+ See find_abi_tags_r for an example of setting *WALK_SUBTREES_P to 2
+ when that's the behavior the walk_tree_fn wants. */
+ if (*walk_subtrees_p == 1 && typedef_variant_p (*tp))
+ {
+ *walk_subtrees_p = 0;
+ return NULL_TREE;
+ }
+ }
+
+ /* Not one of the easy cases. We must explicitly go through the
+ children. */
+ result = NULL_TREE;
+ switch (code)
+ {
+ case TREE_LIST:
+ WALK_SUBTREE (TREE_PURPOSE (*tp));
+ break;
+
+ case RECORD_TYPE:
+ if (TYPE_PTRMEMFUNC_P (*tp))
+ WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE_RAW (*tp));
+ break;
+
+ case CONSTRUCTOR:
+ if (COMPOUND_LITERAL_P (*tp))
+ WALK_SUBTREE (TREE_TYPE (*tp));
+ break;
+
+ case DECL_EXPR:
+ /* User variables should be mentioned in BIND_EXPR_VARS
+ and their initializers and sizes walked when walking
+ the containing BIND_EXPR. Compiler temporaries are
+ handled here. And also normal variables in templates,
+ since do_poplevel doesn't build a BIND_EXPR then. */
+ if (VAR_P (TREE_OPERAND (*tp, 0))
+ && (DECL_ARTIFICIAL (TREE_OPERAND (*tp, 0))
+ && !TREE_STATIC (TREE_OPERAND (*tp, 0))))
+ {
+ tree decl = TREE_OPERAND (*tp, 0);
+ WALK_SUBTREE (DECL_INITIAL (decl));
+ WALK_SUBTREE (DECL_SIZE (decl));
+ WALK_SUBTREE (DECL_SIZE_UNIT (decl));
+ }
+ break;
+
+ default:
+ return NULL_TREE;
+ }
+
+ /* We didn't find what we were looking for. */
+out:
+ return result;
+
+#undef WALK_SUBTREE
+}
+
+// forked from gcc/cp/tree.cc cp_expr_location
+
+/* Like EXPR_LOCATION, but also handle some tcc_exceptional that have
+ locations. */
+
+location_t
+rs_expr_location (const_tree t_)
+{
+ tree t = CONST_CAST_TREE (t_);
+ if (t == NULL_TREE)
+ return UNKNOWN_LOCATION;
+
+ return EXPR_LOCATION (t);
+}
+
+// forked from gcc/cp/class.cc is_really_empty_class
+
+/* Returns true if TYPE contains no actual data, just various
+ possible combinations of empty classes. If IGNORE_VPTR is true,
+ a vptr doesn't prevent the class from being considered empty. Typically
+ we want to ignore the vptr on assignment, and not on initialization. */
+
+bool
+is_really_empty_class (tree type, bool ignore_vptr)
+{
+ if (CLASS_TYPE_P (type))
+ {
+ tree field;
+ tree binfo;
+ tree base_binfo;
+ int i;
+
+ /* CLASSTYPE_EMPTY_P isn't set properly until the class is actually laid
+ out, but we'd like to be able to check this before then. */
+ if (COMPLETE_TYPE_P (type) && is_empty_class (type))
+ return true;
+
+ if (!ignore_vptr && TYPE_CONTAINS_VPTR_P (type))
+ return false;
+
+ for (binfo = TYPE_BINFO (type), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
+ if (!is_really_empty_class (BINFO_TYPE (base_binfo), ignore_vptr))
+ return false;
+ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && !DECL_ARTIFICIAL (field)
+ /* An unnamed bit-field is not a data member. */
+ && !DECL_UNNAMED_BIT_FIELD (field)
+ && !is_really_empty_class (TREE_TYPE (field), ignore_vptr))
+ return false;
+ return true;
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ return (integer_zerop (array_type_nelts_top (type))
+ || is_really_empty_class (TREE_TYPE (type), ignore_vptr));
+ return false;
+}
+
+// forked from gcc/cp/class.cc is_empty_class
+
+/* Returns 1 if TYPE contains only padding bytes. */
+
+int
+is_empty_class (tree type)
+{
+ if (type == error_mark_node)
+ return 0;
+
+ if (!CLASS_TYPE_P (type))
+ return 0;
+
+ return CLASSTYPE_EMPTY_P (type);
+}
+
+// forked from gcc/cp/tree.cc array_type_nelts_top
+
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+ (which is an ARRAY_TYPE). This counts only elements of the top
+ array. */
+
+tree
+array_type_nelts_top (tree type)
+{
+ return fold_build2_loc (input_location, PLUS_EXPR, sizetype,
+ array_type_nelts (type), size_one_node);
+}
+
+// forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p
+
+/* Test whether DECL is a builtin that may appear in a
+ constant-expression. */
+
+bool
+builtin_valid_in_constant_expr_p (const_tree decl)
+{
+ STRIP_ANY_LOCATION_WRAPPER (decl);
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ /* Not a function. */
+ return false;
+ if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL)
+ {
+ if (fndecl_built_in_p (decl, BUILT_IN_FRONTEND))
+ switch (DECL_FE_FUNCTION_CODE (decl))
+ {
+ case RS_BUILT_IN_IS_CONSTANT_EVALUATED:
+ case RS_BUILT_IN_SOURCE_LOCATION:
+ case RS_BUILT_IN_IS_CORRESPONDING_MEMBER:
+ case RS_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS:
+ return true;
+ default:
+ break;
+ }
+ /* Not a built-in. */
+ return false;
+ }
+ switch (DECL_FUNCTION_CODE (decl))
+ {
+ /* These always have constant results like the corresponding
+ macros/symbol. */
+ case BUILT_IN_FILE:
+ case BUILT_IN_FUNCTION:
+ case BUILT_IN_LINE:
+
+ /* The following built-ins are valid in constant expressions
+ when their arguments are. */
+ case BUILT_IN_ADD_OVERFLOW_P:
+ case BUILT_IN_SUB_OVERFLOW_P:
+ case BUILT_IN_MUL_OVERFLOW_P:
+
+ /* These have constant results even if their operands are
+ non-constant. */
+ case BUILT_IN_CONSTANT_P:
+ case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// forked from gcc/cp/decl2.cc decl_maybe_constant_var_p
+
+/* Returns true if DECL could be a symbolic constant variable, depending on
+ its initializer. */
+
+bool
+decl_maybe_constant_var_p (tree decl)
+{
+ tree type = TREE_TYPE (decl);
+ if (!VAR_P (decl))
+ return false;
+ if (DECL_DECLARED_CONSTEXPR_P (decl))
+ return true;
+ if (DECL_HAS_VALUE_EXPR_P (decl))
+ /* A proxy isn't constant. */
+ return false;
+ if (TYPE_REF_P (type))
+ /* References can be constant. */;
+ else if (RS_TYPE_CONST_NON_VOLATILE_P (type)
+ && INTEGRAL_OR_ENUMERATION_TYPE_P (type))
+ /* And const integers. */;
+ else
+ return false;
+
+ if (DECL_INITIAL (decl) && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+ /* We know the initializer, and it isn't constant. */
+ return false;
+ else
+ return true;
+}
+
+// forked from gcc/cp/typeck.cc cp_type_quals
+
+/* Returns the type qualifiers for this type, including the qualifiers on the
+ elements for an array type. */
+
+int
+rs_type_quals (const_tree type)
+{
+ int quals;
+ /* This CONST_CAST is okay because strip_array_types returns its
+ argument unmodified and we assign it to a const_tree. */
+ type = strip_array_types (CONST_CAST_TREE (type));
+ if (type == error_mark_node
+ /* Quals on a FUNCTION_TYPE are memfn quals. */
+ || TREE_CODE (type) == FUNCTION_TYPE)
+ return TYPE_UNQUALIFIED;
+ quals = TYPE_QUALS (type);
+ /* METHOD and REFERENCE_TYPEs should never have quals. */
+ gcc_assert (
+ (TREE_CODE (type) != METHOD_TYPE && !TYPE_REF_P (type))
+ || ((quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) == TYPE_UNQUALIFIED));
+ return quals;
+}
+
+} // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
new file mode 100644
index 00000000000..a667cbfc8ad
--- /dev/null
+++ b/gcc/rust/backend/rust-tree.h
@@ -0,0 +1,508 @@
+// 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_TREE
+#define RUST_TREE
+
+#include "rust-system.h"
+#include "coretypes.h"
+#include "tree.h"
+
+/* Returns true if NODE is a pointer. */
+#define TYPE_PTR_P(NODE) (TREE_CODE (NODE) == POINTER_TYPE)
+
+/* Returns true if NODE is a reference. */
+#define TYPE_REF_P(NODE) (TREE_CODE (NODE) == REFERENCE_TYPE)
+
+/* Returns true if NODE is a pointer or a reference. */
+#define INDIRECT_TYPE_P(NODE) (TYPE_PTR_P (NODE) || TYPE_REF_P (NODE))
+
+/* [basic.fundamental]
+
+ Types bool, char, wchar_t, and the signed and unsigned integer types
+ are collectively called integral types.
+
+ Note that INTEGRAL_TYPE_P, as defined in tree.h, allows enumeration
+ types as well, which is incorrect in C++. Keep these checks in
+ ascending code order. */
+#define RS_INTEGRAL_TYPE_P(TYPE) \
+ (TREE_CODE (TYPE) == BOOLEAN_TYPE || TREE_CODE (TYPE) == INTEGER_TYPE)
+
+/* [basic.fundamental]
+
+ Integral and floating types are collectively called arithmetic
+ types.
+
+ As a GNU extension, we also accept complex types.
+
+ Keep these checks in ascending code order. */
+#define ARITHMETIC_TYPE_P(TYPE) \
+ (RS_INTEGRAL_TYPE_P (TYPE) || TREE_CODE (TYPE) == REAL_TYPE \
+ || TREE_CODE (TYPE) == COMPLEX_TYPE)
+
+/* True iff TYPE is cv decltype(nullptr). */
+#define NULLPTR_TYPE_P(TYPE) (TREE_CODE (TYPE) == NULLPTR_TYPE)
+
+/* [basic.types]
+
+ Arithmetic types, enumeration types, pointer types,
+ pointer-to-member types, and std::nullptr_t are collectively called
+ scalar types.
+
+ Keep these checks in ascending code order. */
+#define SCALAR_TYPE_P(TYPE) \
+ (TREE_CODE (TYPE) == ENUMERAL_TYPE || ARITHMETIC_TYPE_P (TYPE) \
+ || TYPE_PTR_P (TYPE) || NULLPTR_TYPE_P (TYPE))
+
+/* True if NODE is an implicit INDIRECT_REF from convert_from_reference. */
+#define REFERENCE_REF_P(NODE) \
+ (INDIRECT_REF_P (NODE) && TREE_TYPE (TREE_OPERAND (NODE, 0)) \
+ && TYPE_REF_P (TREE_TYPE (TREE_OPERAND ((NODE), 0))))
+
+// this is a helper to differentiate RECORD types between actual records and
+// slices
+#define SLICE_FLAG TREE_LANG_FLAG_0
+#define SLICE_TYPE_P(TYPE) \
+ (TREE_CODE (TYPE) == RECORD_TYPE && TREE_LANG_FLAG_0 (TYPE))
+
+/* Returns true if NODE is a pointer to member function type. */
+#define TYPE_PTRMEMFUNC_P(NODE) \
+ (TREE_CODE (NODE) == RECORD_TYPE && TYPE_PTRMEMFUNC_FLAG (NODE))
+
+#define TYPE_PTRMEMFUNC_FLAG(NODE) (TYPE_LANG_FLAG_2 (RECORD_TYPE_CHECK (NODE)))
+
+#define TYPE_PTRMEMFUNC_FN_TYPE_RAW(NODE) (TREE_TYPE (TYPE_FIELDS (NODE)))
+
+/* True if NODE is a compound-literal, i.e., a brace-enclosed
+ initializer cast to a particular type. This is mostly only set during
+ template parsing; once the initializer has been digested into an actual
+ value of the type, the expression is represented by a TARGET_EXPR. */
+#define COMPOUND_LITERAL_P(NODE) \
+ (TREE_CODE (NODE) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (NODE))
+
+/* When appearing in an INDIRECT_REF, it means that the tree structure
+ underneath is actually a call to a constructor. This is needed
+ when the constructor must initialize local storage (which can
+ be automatically destroyed), rather than allowing it to allocate
+ space from the heap.
+
+ When appearing in a SAVE_EXPR, it means that underneath
+ is a call to a constructor.
+
+ When appearing in a CONSTRUCTOR, the expression is an unconverted
+ compound literal.
+
+ When appearing in a FIELD_DECL, it means that this field
+ has been duly initialized in its constructor. */
+#define TREE_HAS_CONSTRUCTOR(NODE) (TREE_LANG_FLAG_4 (NODE))
+
+/* Nonzero if T is a class type. Zero for template type parameters,
+ typename types, and so forth. */
+#define CLASS_TYPE_P(T) \
+ (RECORD_OR_UNION_CODE_P (TREE_CODE (T)) && TYPE_LANG_FLAG_5 (T))
+
+/* [class.virtual]
+
+ A class that declares or inherits a virtual function is called a
+ polymorphic class. */
+#define TYPE_POLYMORPHIC_P(NODE) (TREE_LANG_FLAG_2 (NODE))
+
+/* Nonzero if this class has a virtual function table pointer. */
+#define TYPE_CONTAINS_VPTR_P(NODE) \
+ (TYPE_POLYMORPHIC_P (NODE) || CLASSTYPE_VBASECLASSES (NODE))
+
+/* A vector of BINFOs for the direct and indirect virtual base classes
+ that this type uses in a post-order depth-first left-to-right
+ order. (In other words, these bases appear in the order that they
+ should be initialized.) */
+#define CLASSTYPE_VBASECLASSES(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->vbases)
+
+/* A vector of BINFOs for the direct and indirect virtual base classes
+ that this type uses in a post-order depth-first left-to-right
+ order. (In other words, these bases appear in the order that they
+ should be initialized.) */
+#define CLASSTYPE_VBASECLASSES(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->vbases)
+
+/* We used to have a variant type for lang_type. Keep the name of the
+ checking accessor for the sole survivor. */
+#define LANG_TYPE_CLASS_CHECK(NODE) (TYPE_LANG_SPECIFIC (NODE))
+
+/* Keep these checks in ascending code order. */
+#define RECORD_OR_UNION_CODE_P(T) ((T) == RECORD_TYPE || (T) == UNION_TYPE)
+#define OVERLOAD_TYPE_P(T) (CLASS_TYPE_P (T) || TREE_CODE (T) == ENUMERAL_TYPE)
+
+/* Nonzero if this class is "empty" in the sense of the C++ ABI. */
+#define CLASSTYPE_EMPTY_P(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->empty_p)
+
+/* True if DECL is declared 'constexpr'. */
+#define DECL_DECLARED_CONSTEXPR_P(DECL) \
+ DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (DECL))
+
+#define VAR_OR_FUNCTION_DECL_CHECK(NODE) \
+ TREE_CHECK2 (NODE, VAR_DECL, FUNCTION_DECL)
+
+// Below macros are copied from gcc/c-family/c-common.h
+
+/* In a FIELD_DECL, nonzero if the decl was originally a bitfield. */
+#define DECL_C_BIT_FIELD(NODE) (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)
+#define SET_DECL_C_BIT_FIELD(NODE) \
+ (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1)
+#define CLEAR_DECL_C_BIT_FIELD(NODE) \
+ (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 0)
+
+/* True if the decl was an unnamed bitfield. */
+#define DECL_UNNAMED_BIT_FIELD(NODE) \
+ (DECL_C_BIT_FIELD (NODE) && !DECL_NAME (NODE))
+
+/* 1 iff NODE is function-local. */
+#define DECL_FUNCTION_SCOPE_P(NODE) \
+ (DECL_CONTEXT (NODE) && TREE_CODE (DECL_CONTEXT (NODE)) == FUNCTION_DECL)
+
+/* Nonzero if this type is const-qualified, but not
+ volatile-qualified. Other qualifiers are ignored. This macro is
+ used to test whether or not it is OK to bind an rvalue to a
+ reference. */
+#define RS_TYPE_CONST_NON_VOLATILE_P(NODE) \
+ ((rs_type_quals (NODE) & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) \
+ == TYPE_QUAL_CONST)
+
+/* [basic.fundamental]
+
+ Types bool, char, wchar_t, and the signed and unsigned integer types
+ are collectively called integral types.
+
+ Note that INTEGRAL_TYPE_P, as defined in tree.h, allows enumeration
+ types as well, which is incorrect in C++. Keep these checks in
+ ascending code order. */
+#define RS_INTEGRAL_TYPE_P(TYPE) \
+ (TREE_CODE (TYPE) == BOOLEAN_TYPE || TREE_CODE (TYPE) == INTEGER_TYPE)
+
+/* Returns true if TYPE is an integral or enumeration name. Keep
+ these checks in ascending code order. */
+#define INTEGRAL_OR_ENUMERATION_TYPE_P(TYPE) \
+ (TREE_CODE (TYPE) == ENUMERAL_TYPE || RS_INTEGRAL_TYPE_P (TYPE))
+
+/* Nonzero for a VAR_DECL that was initialized with a
+ constant-expression. */
+#define DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P(NODE) \
+ (TREE_LANG_FLAG_2 (VAR_DECL_CHECK (NODE)))
+
+// Above macros are copied from gcc/c-family/c-common.h
+
+// forked from gcc/cp/cp-tree.h treee_pair_s
+
+struct GTY (()) tree_pair_s
+{
+ tree purpose;
+ tree value;
+};
+
+// forked from gcc/cp/cp-tree.h tree_pair_p
+
+typedef tree_pair_s *tree_pair_p;
+
+// forked from gcc/cp/cp-tree.h lang_type
+
+/* This structure provides additional information above and beyond
+ what is provide in the ordinary tree_type. In the past, we used it
+ for the types of class types, template parameters types, typename
+ types, and so forth. However, there can be many (tens to hundreds
+ of thousands) of template parameter types in a compilation, and
+ there's no need for this additional information in that case.
+ Therefore, we now use this data structure only for class types.
+
+ In the past, it was thought that there would be relatively few
+ class types. However, in the presence of heavy use of templates,
+ many (i.e., thousands) of classes can easily be generated.
+ Therefore, we should endeavor to keep the size of this structure to
+ a minimum. */
+struct GTY (()) lang_type
+{
+ unsigned char align;
+
+ unsigned has_type_conversion : 1;
+ unsigned has_copy_ctor : 1;
+ unsigned has_default_ctor : 1;
+ unsigned const_needs_init : 1;
+ unsigned ref_needs_init : 1;
+ unsigned has_const_copy_assign : 1;
+ unsigned use_template : 2;
+
+ unsigned has_mutable : 1;
+ unsigned com_interface : 1;
+ unsigned non_pod_class : 1;
+ unsigned nearly_empty_p : 1;
+ unsigned user_align : 1;
+ unsigned has_copy_assign : 1;
+ unsigned has_new : 1;
+ unsigned has_array_new : 1;
+
+ unsigned gets_delete : 2;
+ unsigned interface_only : 1;
+ unsigned interface_unknown : 1;
+ unsigned contains_empty_class_p : 1;
+ unsigned anon_aggr : 1;
+ unsigned non_zero_init : 1;
+ unsigned empty_p : 1;
+ /* 32 bits allocated. */
+
+ unsigned vec_new_uses_cookie : 1;
+ unsigned declared_class : 1;
+ unsigned diamond_shaped : 1;
+ unsigned repeated_base : 1;
+ unsigned being_defined : 1;
+ unsigned debug_requested : 1;
+ unsigned fields_readonly : 1;
+ unsigned ptrmemfunc_flag : 1;
+
+ unsigned lazy_default_ctor : 1;
+ unsigned lazy_copy_ctor : 1;
+ unsigned lazy_copy_assign : 1;
+ unsigned lazy_destructor : 1;
+ unsigned has_const_copy_ctor : 1;
+ unsigned has_complex_copy_ctor : 1;
+ unsigned has_complex_copy_assign : 1;
+ unsigned non_aggregate : 1;
+
+ unsigned has_complex_dflt : 1;
+ unsigned has_list_ctor : 1;
+ unsigned non_std_layout : 1;
+ unsigned is_literal : 1;
+ unsigned lazy_move_ctor : 1;
+ unsigned lazy_move_assign : 1;
+ unsigned has_complex_move_ctor : 1;
+ unsigned has_complex_move_assign : 1;
+
+ unsigned has_constexpr_ctor : 1;
+ unsigned unique_obj_representations : 1;
+ unsigned unique_obj_representations_set : 1;
+ bool erroneous : 1;
+ bool non_pod_aggregate : 1;
+
+ /* When adding a flag here, consider whether or not it ought to
+ apply to a template instance if it applies to the template. If
+ so, make sure to copy it in instantiate_class_template! */
+
+ /* There are some bits left to fill out a 32-bit word. Keep track
+ of this by updating the size of this bitfield whenever you add or
+ remove a flag. */
+ unsigned dummy : 3;
+
+ tree primary_base;
+ vec<tree_pair_s, va_gc> *vcall_indices;
+ tree vtables;
+ tree typeinfo_var;
+ vec<tree, va_gc> *vbases;
+ tree as_base;
+ vec<tree, va_gc> *pure_virtuals;
+ tree friend_classes;
+ vec<tree, va_gc> *GTY ((reorder ("resort_type_member_vec"))) members;
+ tree key_method;
+ tree decl_list;
+ tree befriending_classes;
+ /* In a RECORD_TYPE, information specific to Objective-C++, such
+ as a list of adopted protocols or a pointer to a corresponding
+ @interface. See objc/objc-act.h for details. */
+ tree objc_info;
+ /* FIXME reuse another field? */
+ tree lambda_expr;
+};
+
+namespace Rust {
+
+// forked from gcc/cp/cp-tree.h tsubst_flags_t
+
+/* This type is used for parameters and variables which hold
+ combinations of the flags in enum tsubst_flags. */
+typedef int tsubst_flags_t;
+
+// forked from gcc/cp/cvt.cc convert_to_void
+//
+// When an expression is used in a void context, its value is discarded and
+// no lvalue-rvalue and similar conversions happen [expr.static.cast/4,
+// stmt.expr/1, expr.comma/1]. This permits dereferencing an incomplete type
+// in a void context. The C++ standard does not define what an `access' to an
+// object is, but there is reason to believe that it is the lvalue to rvalue
+// conversion -- if it were not, `*&*p = 1' would violate [expr]/4 in that it
+// accesses `*p' not to calculate the value to be stored. But, dcl.type.cv/8
+// indicates that volatile semantics should be the same between C and C++
+// where ever possible. C leaves it implementation defined as to what
+// constitutes an access to a volatile. So, we interpret `*vp' as a read of
+// the volatile object `vp' points to, unless that is an incomplete type. For
+// volatile references we do not do this interpretation, because that would
+// make it impossible to ignore the reference return value from functions. We
+// issue warnings in the confusing cases.
+//
+// The IMPLICIT is ICV_CAST when the user is explicitly converting an
+// expression to void via a cast. If an expression is being implicitly
+// converted, IMPLICIT indicates the context of the implicit conversion.
+
+/* Possible cases of implicit or explicit bad conversions to void. */
+enum impl_conv_void
+{
+ ICV_CAST, /* (explicit) conversion to void */
+ ICV_SECOND_OF_COND, /* second operand of conditional expression */
+ ICV_THIRD_OF_COND, /* third operand of conditional expression */
+ ICV_RIGHT_OF_COMMA, /* right operand of comma operator */
+ ICV_LEFT_OF_COMMA, /* left operand of comma operator */
+ ICV_STATEMENT, /* statement */
+ ICV_THIRD_IN_FOR /* for increment expression */
+};
+
+/* BUILT_IN_FRONTEND function codes. */
+enum rs_built_in_function
+{
+ RS_BUILT_IN_IS_CONSTANT_EVALUATED,
+ RS_BUILT_IN_INTEGER_PACK,
+ RS_BUILT_IN_IS_CORRESPONDING_MEMBER,
+ RS_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS,
+ RS_BUILT_IN_SOURCE_LOCATION,
+ RS_BUILT_IN_LAST
+};
+
+extern tree
+convert_to_void (tree expr, impl_conv_void implicit);
+
+// The lvalue-to-rvalue conversion (7.1) is applied if and only if the
+// expression is a glvalue of volatile-qualified type and it is one of the
+// following:
+// * ( expression ), where expression is one of these expressions,
+// * id-expression (8.1.4),
+// * subscripting (8.2.1),
+// * class member access (8.2.5),
+// * indirection (8.3.1),
+// * pointer-to-member operation (8.5),
+// * conditional expression (8.16) where both the second and the third
+// operands are one of these expressions, or
+// * comma expression (8.19) where the right operand is one of these
+// expressions.
+extern tree
+mark_discarded_use (tree expr);
+
+// Mark EXP as read, not just set, for set but not used -Wunused warning
+// purposes.
+extern void
+mark_exp_read (tree exp);
+
+// We've seen an actual use of EXPR. Possibly replace an outer variable
+// reference inside with its constant value or a lambda capture.
+extern tree
+mark_use (tree expr, bool rvalue_p, bool read_p, location_t loc,
+ bool reject_builtin);
+
+// Called whenever the expression EXPR is used in an rvalue context.
+// When REJECT_BUILTIN is true the expression is checked to make sure
+// it doesn't make it possible to obtain the address of a GCC built-in
+// function with no library fallback (or any of its bits, such as in
+// a conversion to bool).
+extern tree
+mark_rvalue_use (tree e, location_t loc /* = UNKNOWN_LOCATION */,
+ bool reject_builtin /* = true */);
+
+// Called whenever an expression is used in an lvalue context.
+extern tree
+mark_lvalue_use (tree expr);
+
+// As above, but don't consider this use a read.
+extern tree
+mark_lvalue_use_nonread (tree expr);
+
+// We are using a reference VAL for its value. Bash that reference all the way
+// down to its lowest form.
+extern tree
+convert_from_reference (tree val);
+
+// Subroutine of convert_to_void. Warn if we're discarding something with
+// attribute [[nodiscard]].
+extern void
+maybe_warn_nodiscard (tree expr, impl_conv_void implicit);
+
+extern location_t
+expr_loc_or_loc (const_tree t, location_t or_loc);
+
+extern location_t
+expr_loc_or_input_loc (const_tree t);
+
+// FN is the callee of a CALL_EXPR or AGGR_INIT_EXPR; return the FUNCTION_DECL
+// if we can.
+extern tree
+get_fndecl_from_callee (tree fn);
+
+// FIXME some helpers from HIRCompileBase could probably be moved here over time
+
+// Return an expression for the address of BASE[INDEX], used in offset intrinsic
+extern tree
+pointer_offset_expression (tree base_tree, tree index_tree, location_t locus);
+
+/* A tree node, together with a location, so that we can track locations
+ (and ranges) during parsing.
+
+ The location is redundant for node kinds that have locations,
+ but not all node kinds do (e.g. constants, and references to
+ params, locals, etc), so we stash a copy here. */
+
+extern location_t rs_expr_location (const_tree);
+
+extern int
+is_empty_class (tree type);
+
+extern tree array_type_nelts_top (tree);
+
+extern bool
+is_really_empty_class (tree, bool);
+
+extern bool builtin_valid_in_constant_expr_p (const_tree);
+
+extern bool maybe_constexpr_fn (tree);
+
+extern bool var_in_maybe_constexpr_fn (tree);
+
+extern int
+rs_type_quals (const_tree type);
+
+extern bool decl_maybe_constant_var_p (tree);
+
+extern tree
+rs_walk_subtrees (tree *, int *, walk_tree_fn, void *, hash_set<tree> *);
+#define rs_walk_tree(tp, func, data, pset) \
+ walk_tree_1 (tp, func, data, pset, rs_walk_subtrees)
+#define rs_walk_tree_without_duplicates(tp, func, data) \
+ walk_tree_without_duplicates_1 (tp, func, data, rs_walk_subtrees)
+
+// forked from gcc/cp/cp-tree.h cp_expr_loc_or_loc
+
+inline location_t
+rs_expr_loc_or_loc (const_tree t, location_t or_loc)
+{
+ location_t loc = rs_expr_location (t);
+ if (loc == UNKNOWN_LOCATION)
+ loc = or_loc;
+ return loc;
+}
+
+// forked from gcc/cp/cp-tree.h cp_expr_loc_or_input_loc
+
+inline location_t
+rs_expr_loc_or_input_loc (const_tree t)
+{
+ return rs_expr_loc_or_loc (t, input_location);
+}
+
+} // namespace Rust
+
+#endif // RUST_TREE
diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h
new file mode 100644
index 00000000000..126283c1a54
--- /dev/null
+++ b/gcc/rust/rust-backend.h
@@ -0,0 +1,506 @@
+// 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_BACKEND_H
+#define RUST_BACKEND_H
+
+#include <gmp.h>
+#include <mpfr.h>
+#include <mpc.h>
+
+#include "rust-location.h"
+#include "rust-linemap.h"
+#include "rust-diagnostics.h"
+#include "operator.h"
+#include "tree.h"
+
+// Pointers to these types are created by the backend, passed to the
+// frontend, and passed back to the backend. The types must be
+// defined by the backend using these names.
+
+// The backend representation of a variable.
+class Bvariable;
+
+// The backend interface. This is a pure abstract class that a
+// specific backend will implement.
+
+class Backend
+{
+public:
+ virtual ~Backend () {}
+
+ // Name/type/location. Used for function parameters, struct fields,
+ // interface methods.
+ struct typed_identifier
+ {
+ std::string name;
+ tree type;
+ Location location;
+
+ typed_identifier ()
+ : name (), type (NULL_TREE), location (Linemap::unknown_location ())
+ {}
+
+ typed_identifier (const std::string &a_name, tree a_type,
+ Location a_location)
+ : name (a_name), type (a_type), location (a_location)
+ {}
+ };
+
+ // debug
+ virtual void debug (tree) = 0;
+ virtual void debug (Bvariable *) = 0;
+
+ virtual tree get_identifier_node (const std::string &str) = 0;
+
+ // Types.
+
+ // get unit-type
+ virtual tree unit_type () = 0;
+
+ // Get the unnamed boolean type.
+ virtual tree bool_type () = 0;
+
+ // Get the char type
+ virtual tree char_type () = 0;
+
+ // Get the wchar type
+ virtual tree wchar_type () = 0;
+
+ // Get the Host pointer size in bits
+ virtual int get_pointer_size () = 0;
+
+ // Get the raw str type const char*
+ virtual tree raw_str_type () = 0;
+
+ // Get an unnamed integer type with the given signedness and number
+ // of bits.
+ virtual tree integer_type (bool is_unsigned, int bits) = 0;
+
+ // Get an unnamed floating point type with the given number of bits
+ // (32 or 64).
+ virtual tree float_type (int bits) = 0;
+
+ // Get an unnamed complex type with the given number of bits (64 or 128).
+ virtual tree complex_type (int bits) = 0;
+
+ // Get a pointer type.
+ virtual tree pointer_type (tree to_type) = 0;
+
+ // Get a reference type.
+ virtual tree reference_type (tree to_type) = 0;
+
+ // make type immutable
+ virtual tree immutable_type (tree base) = 0;
+
+ // Get a function type. The receiver, parameter, and results are
+ // generated from the types in the Function_type. The Function_type
+ // is provided so that the names are available. This should return
+ // not the type of a Go function (which is a pointer to a struct)
+ // but the type of a C function pointer (which will be used as the
+ // type of the first field of the struct). If there is more than
+ // one result, RESULT_STRUCT is a struct type to hold the results,
+ // and RESULTS may be ignored; if there are zero or one results,
+ // RESULT_STRUCT is NULL.
+ virtual tree function_type (const typed_identifier &receiver,
+ const std::vector<typed_identifier> &parameters,
+ const std::vector<typed_identifier> &results,
+ tree result_struct, Location location)
+ = 0;
+
+ virtual tree
+ function_type_varadic (const typed_identifier &receiver,
+ const std::vector<typed_identifier> &parameters,
+ const std::vector<typed_identifier> &results,
+ tree result_struct, Location location)
+ = 0;
+
+ virtual tree function_ptr_type (tree result,
+ const std::vector<tree> &praameters,
+ Location location)
+ = 0;
+
+ // Get a struct type.
+ virtual tree struct_type (const std::vector<typed_identifier> &fields) = 0;
+
+ // Get a union type.
+ virtual tree union_type (const std::vector<typed_identifier> &fields) = 0;
+
+ // Get an array type.
+ virtual tree array_type (tree element_type, tree length) = 0;
+
+ // Return a named version of a type. The location is the location
+ // of the type definition. This will not be called for a type
+ // created via placeholder_pointer_type, placeholder_struct_type, or
+ // placeholder_array_type.. (It may be called for a pointer,
+ // struct, or array type in a case like "type P *byte; type Q P".)
+ virtual tree named_type (const std::string &name, tree, Location) = 0;
+
+ // Return the size of a type.
+ virtual int64_t type_size (tree) = 0;
+
+ // Return the alignment of a type.
+ virtual int64_t type_alignment (tree) = 0;
+
+ // Return the alignment of a struct field of this type. This is
+ // normally the same as type_alignment, but not always.
+ virtual int64_t type_field_alignment (tree) = 0;
+
+ // Return the offset of field INDEX in a struct type. INDEX is the
+ // entry in the FIELDS std::vector parameter of struct_type or
+ // set_placeholder_struct_type.
+ virtual int64_t type_field_offset (tree, size_t index) = 0;
+
+ // Expressions.
+
+ // Return an expression for a zero value of the given type. This is
+ // used for cases such as local variable initialization and
+ // converting nil to other types.
+ virtual tree zero_expression (tree) = 0;
+
+ virtual tree unit_expression () = 0;
+
+ // Create a reference to a variable.
+ virtual tree var_expression (Bvariable *var, Location) = 0;
+
+ // Return an expression for the multi-precision integer VAL in BTYPE.
+ virtual tree integer_constant_expression (tree btype, mpz_t val) = 0;
+
+ // Return an expression for the floating point value VAL in BTYPE.
+ virtual tree float_constant_expression (tree btype, mpfr_t val) = 0;
+
+ // Return an expression for the complex value VAL in BTYPE.
+ virtual tree complex_constant_expression (tree btype, mpc_t val) = 0;
+
+ // Return an expression for the string value VAL.
+ virtual tree string_constant_expression (const std::string &val) = 0;
+
+ // Get a char literal
+ virtual tree char_constant_expression (char c) = 0;
+
+ // Get a char literal
+ virtual tree wchar_constant_expression (wchar_t c) = 0;
+
+ // Return an expression for the boolean value VAL.
+ virtual tree boolean_constant_expression (bool val) = 0;
+
+ // Return an expression for the real part of BCOMPLEX.
+ virtual tree real_part_expression (tree bcomplex, Location) = 0;
+
+ // Return an expression for the imaginary part of BCOMPLEX.
+ virtual tree imag_part_expression (tree bcomplex, Location) = 0;
+
+ // Return an expression for the complex number (BREAL, BIMAG).
+ virtual tree complex_expression (tree breal, tree bimag, Location) = 0;
+
+ // Return an expression that converts EXPR to TYPE.
+ virtual tree convert_expression (tree type, tree expr, Location) = 0;
+
+ // Return an expression for the field at INDEX in BSTRUCT.
+ virtual tree struct_field_expression (tree bstruct, size_t index, Location)
+ = 0;
+
+ // Create an expression that executes BSTAT before BEXPR.
+ virtual tree compound_expression (tree bstat, tree bexpr, Location) = 0;
+
+ // Return an expression that executes THEN_EXPR if CONDITION is true, or
+ // ELSE_EXPR otherwise and returns the result as type BTYPE, within the
+ // specified function FUNCTION. ELSE_EXPR may be NULL. BTYPE may be NULL.
+ virtual tree conditional_expression (tree function, tree btype,
+ tree condition, tree then_expr,
+ tree else_expr, Location)
+ = 0;
+
+ // Return an expression for the negation operation OP EXPR.
+ // Supported values of OP are enumerated in NegationOperator.
+ virtual tree negation_expression (NegationOperator op, tree expr, Location)
+ = 0;
+
+ // Return an expression for the operation LEFT OP RIGHT.
+ // Supported values of OP are enumerated in ArithmeticOrLogicalOperator.
+ virtual tree arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op,
+ tree left, tree right,
+ Location)
+ = 0;
+
+ // Return an expression for the operation LEFT OP RIGHT.
+ // Supported values of OP are enumerated in ComparisonOperator.
+ virtual tree comparison_expression (ComparisonOperator op, tree left,
+ tree right, Location)
+ = 0;
+
+ // Return an expression for the operation LEFT OP RIGHT.
+ // Supported values of OP are enumerated in LazyBooleanOperator.
+ virtual tree lazy_boolean_expression (LazyBooleanOperator op, tree left,
+ tree right, Location)
+ = 0;
+
+ // Return an expression that constructs BTYPE with VALS. BTYPE must be the
+ // backend representation a of struct. VALS must be in the same order as the
+ // corresponding fields in BTYPE.
+ virtual tree constructor_expression (tree btype, bool is_variant,
+ const std::vector<tree> &vals, int,
+ Location)
+ = 0;
+
+ // Return an expression that constructs an array of BTYPE with INDEXES and
+ // VALS. INDEXES and VALS must have the same amount of elements. Each index
+ // in INDEXES must be in the same order as the corresponding value in VALS.
+ virtual tree
+ array_constructor_expression (tree btype,
+ const std::vector<unsigned long> &indexes,
+ const std::vector<tree> &vals, Location)
+ = 0;
+
+ virtual tree array_initializer (tree, tree, tree, tree, tree, tree *,
+ Location)
+ = 0;
+
+ // Return an expression for ARRAY[INDEX] as an l-value. ARRAY is a valid
+ // fixed-length array, not a slice.
+ virtual tree array_index_expression (tree array, tree index, Location) = 0;
+
+ // Create an expression for a call to FN with ARGS, taking place within
+ // caller CALLER.
+ virtual tree call_expression (tree fn, const std::vector<tree> &args,
+ tree static_chain, Location)
+ = 0;
+
+ // Statements.
+
+ // Create a variable initialization statement in the specified
+ // function. This initializes a local variable at the point in the
+ // program flow where it is declared.
+ virtual tree init_statement (tree, Bvariable *var, tree init) = 0;
+
+ // Create an assignment statement within the specified function.
+ virtual tree assignment_statement (tree lhs, tree rhs, Location) = 0;
+
+ // Create a return statement, passing the representation of the
+ // function and the list of values to return.
+ virtual tree return_statement (tree, const std::vector<tree> &, Location) = 0;
+
+ // Create an if statement within a function. ELSE_BLOCK may be NULL.
+ virtual tree if_statement (tree, tree condition, tree then_block,
+ tree else_block, Location)
+ = 0;
+
+ // infinite loop expressions
+ virtual tree loop_expression (tree body, Location) = 0;
+
+ // exit expressions
+ virtual tree exit_expression (tree condition, Location) = 0;
+
+ // Create a single statement from two statements.
+ virtual tree compound_statement (tree, tree) = 0;
+
+ // Create a single statement from a list of statements.
+ virtual tree statement_list (const std::vector<tree> &) = 0;
+
+ // Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if
+ // an exception occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and
+ // if not NULL, it will always be executed. This is used for handling defers
+ // in Go functions. In C++, the resulting code is of this form:
+ // try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; }
+ virtual tree exception_handler_statement (tree bstat, tree except_stmt,
+ tree finally_stmt, Location)
+ = 0;
+
+ // Blocks.
+
+ // Create a block. The frontend will call this function when it
+ // starts converting a block within a function. FUNCTION is the
+ // current function. ENCLOSING is the enclosing block; it will be
+ // NULL for the top-level block in a function. VARS is the list of
+ // local variables defined within this block; each entry will be
+ // created by the local_variable function. START_LOCATION is the
+ // location of the start of the block, more or less the location of
+ // the initial curly brace. END_LOCATION is the location of the end
+ // of the block, more or less the location of the final curly brace.
+ // The statements will be added after the block is created.
+ virtual tree block (tree function, tree enclosing,
+ const std::vector<Bvariable *> &vars,
+ Location start_location, Location end_location)
+ = 0;
+
+ // Add the statements to a block. The block is created first. Then
+ // the statements are created. Then the statements are added to the
+ // block. This will called exactly once per block. The vector may
+ // be empty if there are no statements.
+ virtual void block_add_statements (tree, const std::vector<tree> &) = 0;
+
+ // Variables.
+
+ // Create an error variable. This is used for cases which should
+ // not occur in a correct program, in order to keep the compilation
+ // going without crashing.
+ virtual Bvariable *error_variable () = 0;
+
+ // Create a global variable. NAME is the package-qualified name of
+ // the variable. ASM_NAME is the encoded identifier for the
+ // variable, incorporating the package, and made safe for the
+ // assembler. BTYPE is the type of the variable. IS_EXTERNAL is
+ // true if the variable is defined in some other package. IS_HIDDEN
+ // is true if the variable is not exported (name begins with a lower
+ // case letter). IN_UNIQUE_SECTION is true if the variable should
+ // be put into a unique section if possible; this is intended to
+ // permit the linker to garbage collect the variable if it is not
+ // referenced. LOCATION is where the variable was defined.
+ virtual Bvariable *global_variable (const std::string &name,
+ const std::string &asm_name, tree btype,
+ bool is_external, bool is_hidden,
+ bool in_unique_section, Location location)
+ = 0;
+
+ // A global variable will 1) be initialized to zero, or 2) be
+ // initialized to a constant value, or 3) be initialized in the init
+ // function. In case 2, the frontend will call
+ // global_variable_set_init to set the initial value. If this is
+ // not called, the backend should initialize a global variable to 0.
+ // The init function may then assign a value to it.
+ virtual void global_variable_set_init (Bvariable *, tree) = 0;
+
+ // Create a local variable. The frontend will create the local
+ // variables first, and then create the block which contains them.
+ // FUNCTION is the function in which the variable is defined. NAME
+ // is the name of the variable. TYPE is the type. DECL_VAR, if not
+ // null, gives the location at which the value of this variable may
+ // be found, typically used to create an inner-scope reference to an
+ // outer-scope variable, to extend the lifetime of the variable beyond
+ // the inner scope. IS_ADDRESS_TAKEN is true if the address of this
+ // variable is taken (this implies that the address does not escape
+ // the function, as otherwise the variable would be on the heap).
+ // LOCATION is where the variable is defined. For each local variable
+ // the frontend will call init_statement to set the initial value.
+ virtual Bvariable *local_variable (tree function, const std::string &name,
+ tree type, Bvariable *decl_var,
+ Location location)
+ = 0;
+
+ // Create a function parameter. This is an incoming parameter, not
+ // a result parameter (result parameters are treated as local
+ // variables). The arguments are as for local_variable.
+ virtual Bvariable *parameter_variable (tree function, const std::string &name,
+ tree type, Location location)
+ = 0;
+
+ // Create a static chain parameter. This is the closure parameter.
+ virtual Bvariable *static_chain_variable (tree function,
+ const std::string &name, tree type,
+ Location location)
+ = 0;
+
+ // Create a temporary variable. A temporary variable has no name,
+ // just a type. We pass in FUNCTION and BLOCK in case they are
+ // needed. If INIT is not NULL, the variable should be initialized
+ // to that value. Otherwise the initial value is irrelevant--the
+ // backend does not have to explicitly initialize it to zero.
+ // ADDRESS_IS_TAKEN is true if the programs needs to take the
+ // address of this temporary variable. LOCATION is the location of
+ // the statement or expression which requires creating the temporary
+ // variable, and may not be very useful. This function should
+ // return a variable which can be referenced later and should set
+ // *PSTATEMENT to a statement which initializes the variable.
+ virtual Bvariable *temporary_variable (tree, tree, tree, tree init,
+ bool address_is_taken,
+ Location location, tree *pstatement)
+ = 0;
+
+ // Labels.
+
+ // Create a new label. NAME will be empty if this is a label
+ // created by the frontend for a loop construct. The location is
+ // where the label is defined.
+ virtual tree label (tree, const std::string &name, Location) = 0;
+
+ // Create a statement which defines a label. This statement will be
+ // put into the codestream at the point where the label should be
+ // defined.
+ virtual tree label_definition_statement (tree) = 0;
+
+ // Create a goto statement to a label.
+ virtual tree goto_statement (tree, Location) = 0;
+
+ // Create an expression for the address of a label. This is used to
+ // get the return address of a deferred function which may call
+ // recover.
+ virtual tree label_address (tree, Location) = 0;
+
+ // Functions.
+
+ // Bit flags to pass to the function method.
+
+ // Set if this is a function declaration rather than a definition;
+ // the definition will be in another compilation unit.
+ static const unsigned int function_is_declaration = 1 << 0;
+
+ // Set if the function should never be inlined because they call
+ // recover and must be visible for correct panic recovery.
+ static const unsigned int function_is_uninlinable = 1 << 1;
+
+ // Set if the function does not return. This is set for the
+ // implementation of panic.
+ static const unsigned int function_does_not_return = 1 << 2;
+
+ // Set if the function should be put in a unique section if
+ // possible. This is used for field tracking.
+ static const unsigned int function_in_unique_section = 1 << 3;
+
+ // Declare or define a function of FNTYPE.
+ // NAME is the Go name of the function. ASM_NAME, if not the empty
+ // string, is the name that should be used in the symbol table; this
+ // will be non-empty if a magic extern comment is used. FLAGS is
+ // bit flags described above.
+ virtual tree function (tree fntype, const std::string &name,
+ const std::string &asm_name, unsigned int flags,
+ Location)
+ = 0;
+
+ // Create a statement that runs all deferred calls for FUNCTION. This should
+ // be a statement that looks like this in C++:
+ // finish:
+ // try { DEFER_RETURN; } catch { CHECK_DEFER; goto finish; }
+ virtual tree function_defer_statement (tree function, tree undefer,
+ tree check_defer, Location)
+ = 0;
+
+ // Record PARAM_VARS as the variables to use for the parameters of FUNCTION.
+ // This will only be called for a function definition. Returns true on
+ // success, false on failure.
+ virtual bool
+ function_set_parameters (tree function,
+ const std::vector<Bvariable *> &param_vars)
+ = 0;
+
+ // Utility.
+
+ // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS,
+ // FUNCTION_DECLS, and VARIABLE_DECLS declared globally.
+ virtual void
+ write_global_definitions (const std::vector<tree> &type_decls,
+ const std::vector<tree> &constant_decls,
+ const std::vector<tree> &function_decls,
+ const std::vector<Bvariable *> &variable_decls)
+ = 0;
+
+ // Write SIZE bytes of export data from BYTES to the proper
+ // section in the output object file.
+ virtual void write_export_data (const char *bytes, unsigned int size) = 0;
+};
+
+#endif // RUST_BACKEND_H
diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc
new file mode 100644
index 00000000000..3a682fc0127
--- /dev/null
+++ b/gcc/rust/rust-gcc.cc
@@ -0,0 +1,2718 @@
+// rust-gcc.cc -- Rust frontend to gcc IR.
+// Copyright (C) 2011-2022 Free Software Foundation, Inc.
+// Contributed by Ian Lance Taylor, Google.
+// forked from gccgo
+
+// 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-system.h"
+
+// This has to be included outside of extern "C", so we have to
+// include it here before tree.h includes it later.
+#include <gmp.h>
+
+#include "tree.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "tree-iterator.h"
+#include "tm.h"
+#include "function.h"
+#include "cgraph.h"
+#include "convert.h"
+#include "gimple-expr.h"
+#include "gimplify.h"
+#include "langhooks.h"
+#include "toplev.h"
+#include "output.h"
+#include "realmpfr.h"
+#include "builtins.h"
+#include "print-tree.h"
+#include "attribs.h"
+
+#include "rust-location.h"
+#include "rust-linemap.h"
+#include "rust-backend.h"
+#include "rust-object-export.h"
+
+#include "backend/rust-tree.h"
+
+// TODO: this will have to be significantly modified to work with Rust
+
+// Bvariable is a bit more complicated, because of zero-sized types.
+// The GNU linker does not permit dynamic variables with zero size.
+// When we see such a variable, we generate a version of the type with
+// non-zero size. However, when referring to the global variable, we
+// want an expression of zero size; otherwise, if, say, the global
+// variable is passed to a function, we will be passing a
+// non-zero-sized value to a zero-sized value, which can lead to a
+// miscompilation.
+
+class Bvariable
+{
+public:
+ Bvariable (tree t) : t_ (t), orig_type_ (NULL) {}
+
+ Bvariable (tree t, tree orig_type) : t_ (t), orig_type_ (orig_type) {}
+
+ // Get the tree for use as an expression.
+ tree get_tree (Location) const;
+
+ // Get the actual decl;
+ tree get_decl () const { return this->t_; }
+
+private:
+ tree t_;
+ tree orig_type_;
+};
+
+// Get the tree of a variable for use as an expression. If this is a
+// zero-sized global, create an expression that refers to the decl but
+// has zero size.
+tree
+Bvariable::get_tree (Location location) const
+{
+ if (this->t_ == error_mark_node)
+ return error_mark_node;
+
+ TREE_USED (this->t_) = 1;
+ if (this->orig_type_ == NULL || TREE_TYPE (this->t_) == this->orig_type_)
+ {
+ return this->t_;
+ }
+
+ // Return *(orig_type*)&decl. */
+ tree t = build_fold_addr_expr_loc (location.gcc_location (), this->t_);
+ t = fold_build1_loc (location.gcc_location (), NOP_EXPR,
+ build_pointer_type (this->orig_type_), t);
+ return build_fold_indirect_ref_loc (location.gcc_location (), t);
+}
+
+// This file implements the interface between the Rust frontend proper
+// and the gcc IR. This implements specific instantiations of
+// abstract classes defined by the Rust frontend proper. The Rust
+// frontend proper class methods of these classes to generate the
+// backend representation.
+
+class Gcc_backend : public Backend
+{
+public:
+ Gcc_backend ();
+
+ void debug (tree t) { debug_tree (t); };
+ void debug (Bvariable *t) { debug_tree (t->get_decl ()); };
+
+ tree get_identifier_node (const std::string &str)
+ {
+ return get_identifier_with_length (str.data (), str.length ());
+ }
+
+ // Types.
+
+ tree unit_type ()
+ {
+ static tree unit_type;
+ if (unit_type == nullptr)
+ {
+ auto unit_type_node = struct_type ({});
+ unit_type = named_type ("()", unit_type_node,
+ ::Linemap::predeclared_location ());
+ }
+
+ return unit_type;
+ }
+
+ tree bool_type () { return boolean_type_node; }
+
+ tree char_type () { return char_type_node; }
+
+ tree wchar_type ()
+ {
+ tree wchar = make_unsigned_type (32);
+ TYPE_STRING_FLAG (wchar) = 1;
+ return wchar;
+ }
+
+ int get_pointer_size ();
+
+ tree raw_str_type ();
+
+ tree integer_type (bool, int);
+
+ tree float_type (int);
+
+ tree complex_type (int);
+
+ tree pointer_type (tree);
+
+ tree reference_type (tree);
+
+ tree immutable_type (tree);
+
+ tree function_type (const typed_identifier &,
+ const std::vector<typed_identifier> &,
+ const std::vector<typed_identifier> &, tree,
+ const Location);
+
+ tree function_type_varadic (const typed_identifier &,
+ const std::vector<typed_identifier> &,
+ const std::vector<typed_identifier> &, tree,
+ const Location);
+
+ tree function_ptr_type (tree, const std::vector<tree> &, Location);
+
+ tree struct_type (const std::vector<typed_identifier> &);
+
+ tree union_type (const std::vector<typed_identifier> &);
+
+ tree array_type (tree, tree);
+
+ tree named_type (const std::string &, tree, Location);
+
+ int64_t type_size (tree);
+
+ int64_t type_alignment (tree);
+
+ int64_t type_field_alignment (tree);
+
+ int64_t type_field_offset (tree, size_t index);
+
+ // Expressions.
+
+ tree zero_expression (tree);
+
+ tree unit_expression () { return integer_zero_node; }
+
+ tree var_expression (Bvariable *var, Location);
+
+ tree integer_constant_expression (tree type, mpz_t val);
+
+ tree float_constant_expression (tree type, mpfr_t val);
+
+ tree complex_constant_expression (tree type, mpc_t val);
+
+ tree string_constant_expression (const std::string &val);
+
+ tree wchar_constant_expression (wchar_t c);
+
+ tree char_constant_expression (char c);
+
+ tree boolean_constant_expression (bool val);
+
+ tree real_part_expression (tree bcomplex, Location);
+
+ tree imag_part_expression (tree bcomplex, Location);
+
+ tree complex_expression (tree breal, tree bimag, Location);
+
+ tree convert_expression (tree type, tree expr, Location);
+
+ tree struct_field_expression (tree, size_t, Location);
+
+ tree compound_expression (tree, tree, Location);
+
+ tree conditional_expression (tree, tree, tree, tree, tree, Location);
+
+ tree negation_expression (NegationOperator op, tree expr, Location);
+
+ tree arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op,
+ tree left, tree right, Location);
+
+ tree comparison_expression (ComparisonOperator op, tree left, tree right,
+ Location);
+
+ tree lazy_boolean_expression (LazyBooleanOperator op, tree left, tree right,
+ Location);
+
+ tree constructor_expression (tree, bool, const std::vector<tree> &, int,
+ Location);
+
+ tree array_constructor_expression (tree, const std::vector<unsigned long> &,
+ const std::vector<tree> &, Location);
+
+ tree array_initializer (tree, tree, tree, tree, tree, tree *, Location);
+
+ tree array_index_expression (tree array, tree index, Location);
+
+ tree call_expression (tree fn, const std::vector<tree> &args,
+ tree static_chain, Location);
+
+ // Statements.
+
+ tree init_statement (tree, Bvariable *var, tree init);
+
+ tree assignment_statement (tree lhs, tree rhs, Location);
+
+ tree return_statement (tree, const std::vector<tree> &, Location);
+
+ tree if_statement (tree, tree condition, tree then_block, tree else_block,
+ Location);
+
+ tree compound_statement (tree, tree);
+
+ tree statement_list (const std::vector<tree> &);
+
+ tree exception_handler_statement (tree bstat, tree except_stmt,
+ tree finally_stmt, Location);
+
+ tree loop_expression (tree body, Location);
+
+ tree exit_expression (tree condition, Location);
+
+ // Blocks.
+
+ tree block (tree, tree, const std::vector<Bvariable *> &, Location, Location);
+
+ void block_add_statements (tree, const std::vector<tree> &);
+
+ // Variables.
+
+ Bvariable *error_variable () { return new Bvariable (error_mark_node); }
+
+ Bvariable *global_variable (const std::string &var_name,
+ const std::string &asm_name, tree type,
+ bool is_external, bool is_hidden,
+ bool in_unique_section, Location location);
+
+ void global_variable_set_init (Bvariable *, tree);
+
+ Bvariable *local_variable (tree, const std::string &, tree, Bvariable *,
+ Location);
+
+ Bvariable *parameter_variable (tree, const std::string &, tree, Location);
+
+ Bvariable *static_chain_variable (tree, const std::string &, tree, Location);
+
+ Bvariable *temporary_variable (tree, tree, tree, tree, bool, Location,
+ tree *);
+
+ // Labels.
+
+ tree label (tree, const std::string &name, Location);
+
+ tree label_definition_statement (tree);
+
+ tree goto_statement (tree, Location);
+
+ tree label_address (tree, Location);
+
+ // Functions.
+
+ tree function (tree fntype, const std::string &name,
+ const std::string &asm_name, unsigned int flags, Location);
+
+ tree function_defer_statement (tree function, tree undefer, tree defer,
+ Location);
+
+ bool function_set_parameters (tree function,
+ const std::vector<Bvariable *> &);
+
+ void write_global_definitions (const std::vector<tree> &,
+ const std::vector<tree> &,
+ const std::vector<tree> &,
+ const std::vector<Bvariable *> &);
+
+ void write_export_data (const char *bytes, unsigned int size);
+
+private:
+ tree fill_in_fields (tree, const std::vector<typed_identifier> &);
+
+ tree fill_in_array (tree, tree, tree);
+
+ tree non_zero_size_type (tree);
+
+ tree convert_tree (tree, tree, Location);
+};
+
+// A helper function to create a GCC identifier from a C++ string.
+
+static inline tree
+get_identifier_from_string (const std::string &str)
+{
+ return get_identifier_with_length (str.data (), str.length ());
+}
+
+// Define the built-in functions that are exposed to GCCRust.
+
+Gcc_backend::Gcc_backend ()
+{
+ /* We need to define the fetch_and_add functions, since we use them
+ for ++ and --. */
+ // tree t = this->integer_type (true, BITS_PER_UNIT)->get_tree ();
+ // tree p = build_pointer_type (build_qualified_type (t, TYPE_QUAL_VOLATILE));
+ // this->define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_1,
+ // "__sync_fetch_and_add_1",
+ // NULL, build_function_type_list (t, p, t, NULL_TREE), 0);
+
+ // t = this->integer_type (true, BITS_PER_UNIT * 2)->get_tree ();
+ // p = build_pointer_type (build_qualified_type (t, TYPE_QUAL_VOLATILE));
+ // this->define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_2,
+ // "__sync_fetch_and_add_2",
+ // NULL, build_function_type_list (t, p, t, NULL_TREE), 0);
+
+ // t = this->integer_type (true, BITS_PER_UNIT * 4)->get_tree ();
+ // p = build_pointer_type (build_qualified_type (t, TYPE_QUAL_VOLATILE));
+ // this->define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_4,
+ // "__sync_fetch_and_add_4",
+ // NULL, build_function_type_list (t, p, t, NULL_TREE), 0);
+
+ // t = this->integer_type (true, BITS_PER_UNIT * 8)->get_tree ();
+ // p = build_pointer_type (build_qualified_type (t, TYPE_QUAL_VOLATILE));
+ // this->define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_8,
+ // "__sync_fetch_and_add_8",
+ // NULL, build_function_type_list (t, p, t, NULL_TREE), 0);
+
+ // // We use __builtin_expect for magic import functions.
+ // this->define_builtin (BUILT_IN_EXPECT, "__builtin_expect", NULL,
+ // build_function_type_list (long_integer_type_node,
+ // long_integer_type_node,
+ // long_integer_type_node,
+ // NULL_TREE),
+ // builtin_const);
+
+ // // We use __builtin_memcmp for struct comparisons.
+ // this->define_builtin (BUILT_IN_MEMCMP, "__builtin_memcmp", "memcmp",
+ // build_function_type_list (integer_type_node,
+ // const_ptr_type_node,
+ // const_ptr_type_node,
+ // size_type_node, NULL_TREE),
+ // 0);
+
+ // // We use __builtin_memmove for copying data.
+ // this->define_builtin (BUILT_IN_MEMMOVE, "__builtin_memmove", "memmove",
+ // build_function_type_list (void_type_node, ptr_type_node,
+ // const_ptr_type_node,
+ // size_type_node, NULL_TREE),
+ // 0);
+
+ // // We use __builtin_memset for zeroing data.
+ // this->define_builtin (BUILT_IN_MEMSET, "__builtin_memset", "memset",
+ // build_function_type_list (void_type_node, ptr_type_node,
+ // integer_type_node,
+ // size_type_node, NULL_TREE),
+ // 0);
+
+ // // Used by runtime/internal/sys and math/bits.
+ // this->define_builtin (BUILT_IN_CTZ, "__builtin_ctz", "ctz",
+ // build_function_type_list (integer_type_node,
+ // unsigned_type_node,
+ // NULL_TREE),
+ // builtin_const);
+ // this->define_builtin (BUILT_IN_CTZLL, "__builtin_ctzll", "ctzll",
+ // build_function_type_list (integer_type_node,
+ // long_long_unsigned_type_node,
+ // NULL_TREE),
+ // builtin_const);
+ // this->define_builtin (BUILT_IN_CLZ, "__builtin_clz", "clz",
+ // build_function_type_list (integer_type_node,
+ // unsigned_type_node,
+ // NULL_TREE),
+ // builtin_const);
+ // this->define_builtin (BUILT_IN_CLZLL, "__builtin_clzll", "clzll",
+ // build_function_type_list (integer_type_node,
+ // long_long_unsigned_type_node,
+ // NULL_TREE),
+ // builtin_const);
+ // this->define_builtin (BUILT_IN_POPCOUNT, "__builtin_popcount", "popcount",
+ // build_function_type_list (integer_type_node,
+ // unsigned_type_node,
+ // NULL_TREE),
+ // builtin_const);
+ // this->define_builtin (BUILT_IN_POPCOUNTLL, "__builtin_popcountll",
+ // "popcountll",
+ // build_function_type_list (integer_type_node,
+ // long_long_unsigned_type_node,
+ // NULL_TREE),
+ // builtin_const);
+ // this->define_builtin (BUILT_IN_BSWAP16, "__builtin_bswap16", "bswap16",
+ // build_function_type_list (uint16_type_node,
+ // uint16_type_node, NULL_TREE),
+ // builtin_const);
+ // this->define_builtin (BUILT_IN_BSWAP32, "__builtin_bswap32", "bswap32",
+ // build_function_type_list (uint32_type_node,
+ // uint32_type_node, NULL_TREE),
+ // builtin_const);
+ // this->define_builtin (BUILT_IN_BSWAP64, "__builtin_bswap64", "bswap64",
+ // build_function_type_list (uint64_type_node,
+ // uint64_type_node, NULL_TREE),
+ // builtin_const);
+
+ // We provide some functions for the math library.
+
+ // We use __builtin_return_address in the thunk we build for
+ // functions which call recover, and for runtime.getcallerpc.
+ // t = build_function_type_list (ptr_type_node, unsigned_type_node,
+ // NULL_TREE); this->define_builtin (BUILT_IN_RETURN_ADDRESS,
+ // "__builtin_return_address",
+ // NULL, t, 0);
+
+ // The runtime calls __builtin_dwarf_cfa for runtime.getcallersp.
+ // t = build_function_type_list (ptr_type_node, NULL_TREE);
+ // this->define_builtin (BUILT_IN_DWARF_CFA, "__builtin_dwarf_cfa", NULL, t,
+ // 0);
+
+ // The runtime calls __builtin_extract_return_addr when recording
+ // the address to which a function returns.
+ // this->define_builtin (
+ // BUILT_IN_EXTRACT_RETURN_ADDR, "__builtin_extract_return_addr", NULL,
+ // build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE), 0);
+
+ // The compiler uses __builtin_trap for some exception handling
+ // cases.
+ // this->define_builtin (BUILT_IN_TRAP, "__builtin_trap", NULL,
+ // build_function_type (void_type_node, void_list_node),
+ // builtin_noreturn);
+
+ // The runtime uses __builtin_prefetch.
+ // this->define_builtin (BUILT_IN_PREFETCH, "__builtin_prefetch", NULL,
+ // build_varargs_function_type_list (void_type_node,
+ // const_ptr_type_node,
+ // NULL_TREE),
+ // builtin_novops);
+
+ // The compiler uses __builtin_unreachable for cases that cannot
+ // occur.
+ // this->define_builtin (BUILT_IN_UNREACHABLE, "__builtin_unreachable", NULL,
+ // build_function_type (void_type_node, void_list_node),
+ // builtin_const | builtin_noreturn);
+
+ // We provide some atomic functions.
+ // t = build_function_type_list (uint32_type_node, ptr_type_node,
+ // integer_type_node, NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_LOAD_4, "__atomic_load_4", NULL, t,
+ // 0);
+
+ // t = build_function_type_list (uint64_type_node, ptr_type_node,
+ // integer_type_node, NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_LOAD_8, "__atomic_load_8", NULL, t,
+ // 0);
+
+ // t = build_function_type_list (void_type_node, ptr_type_node,
+ // uint32_type_node,
+ // integer_type_node, NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_STORE_4, "__atomic_store_4", NULL, t,
+ // 0);
+
+ // t = build_function_type_list (void_type_node, ptr_type_node,
+ // uint64_type_node,
+ // integer_type_node, NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_STORE_8, "__atomic_store_8", NULL, t,
+ // 0);
+
+ // t = build_function_type_list (uint32_type_node, ptr_type_node,
+ // uint32_type_node, integer_type_node, NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_EXCHANGE_4, "__atomic_exchange_4",
+ // NULL,
+ // t, 0);
+
+ // t = build_function_type_list (uint64_type_node, ptr_type_node,
+ // uint64_type_node, integer_type_node, NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_EXCHANGE_8, "__atomic_exchange_8",
+ // NULL,
+ // t, 0);
+
+ // t = build_function_type_list (boolean_type_node, ptr_type_node,
+ // ptr_type_node,
+ // uint32_type_node, boolean_type_node,
+ // integer_type_node, integer_type_node,
+ // NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4,
+ // "__atomic_compare_exchange_4", NULL, t, 0);
+
+ // t = build_function_type_list (boolean_type_node, ptr_type_node,
+ // ptr_type_node,
+ // uint64_type_node, boolean_type_node,
+ // integer_type_node, integer_type_node,
+ // NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8,
+ // "__atomic_compare_exchange_8", NULL, t, 0);
+
+ // t = build_function_type_list (uint32_type_node, ptr_type_node,
+ // uint32_type_node, integer_type_node, NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_ADD_FETCH_4, "__atomic_add_fetch_4",
+ // NULL, t, 0);
+
+ // t = build_function_type_list (uint64_type_node, ptr_type_node,
+ // uint64_type_node, integer_type_node, NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_ADD_FETCH_8, "__atomic_add_fetch_8",
+ // NULL, t, 0);
+
+ // t = build_function_type_list (unsigned_char_type_node, ptr_type_node,
+ // unsigned_char_type_node, integer_type_node,
+ // NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_AND_FETCH_1, "__atomic_and_fetch_1",
+ // NULL, t, 0);
+ // this->define_builtin (BUILT_IN_ATOMIC_FETCH_AND_1, "__atomic_fetch_and_1",
+ // NULL, t, 0);
+
+ // t = build_function_type_list (unsigned_char_type_node, ptr_type_node,
+ // unsigned_char_type_node, integer_type_node,
+ // NULL_TREE);
+ // this->define_builtin (BUILT_IN_ATOMIC_OR_FETCH_1, "__atomic_or_fetch_1",
+ // NULL,
+ // t, 0);
+ // this->define_builtin (BUILT_IN_ATOMIC_FETCH_OR_1, "__atomic_fetch_or_1",
+ // NULL,
+ // t, 0);
+}
+
+// Get an unnamed integer type.
+
+int
+Gcc_backend::get_pointer_size ()
+{
+ return POINTER_SIZE;
+}
+
+tree
+Gcc_backend::raw_str_type ()
+{
+ tree char_ptr = build_pointer_type (char_type_node);
+ tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
+ return const_char_type;
+}
+
+tree
+Gcc_backend::integer_type (bool is_unsigned, int bits)
+{
+ tree type;
+ if (is_unsigned)
+ {
+ if (bits == INT_TYPE_SIZE)
+ type = unsigned_type_node;
+ else if (bits == SHORT_TYPE_SIZE)
+ type = short_unsigned_type_node;
+ else if (bits == LONG_TYPE_SIZE)
+ type = long_unsigned_type_node;
+ else if (bits == LONG_LONG_TYPE_SIZE)
+ type = long_long_unsigned_type_node;
+ else
+ type = make_unsigned_type (bits);
+ }
+ else
+ {
+ if (bits == INT_TYPE_SIZE)
+ type = integer_type_node;
+ else if (bits == SHORT_TYPE_SIZE)
+ type = short_integer_type_node;
+ else if (bits == LONG_TYPE_SIZE)
+ type = long_integer_type_node;
+ else if (bits == LONG_LONG_TYPE_SIZE)
+ type = long_long_integer_type_node;
+ else
+ type = make_signed_type (bits);
+ }
+ return type;
+}
+
+// Get an unnamed float type.
+
+tree
+Gcc_backend::float_type (int bits)
+{
+ tree type;
+ if (bits == FLOAT_TYPE_SIZE)
+ type = float_type_node;
+ else if (bits == DOUBLE_TYPE_SIZE)
+ type = double_type_node;
+ else if (bits == LONG_DOUBLE_TYPE_SIZE)
+ type = long_double_type_node;
+ else
+ {
+ type = make_node (REAL_TYPE);
+ TYPE_PRECISION (type) = bits;
+ layout_type (type);
+ }
+ return type;
+}
+
+// Get an unnamed complex type.
+
+tree
+Gcc_backend::complex_type (int bits)
+{
+ tree type;
+ if (bits == FLOAT_TYPE_SIZE * 2)
+ type = complex_float_type_node;
+ else if (bits == DOUBLE_TYPE_SIZE * 2)
+ type = complex_double_type_node;
+ else if (bits == LONG_DOUBLE_TYPE_SIZE * 2)
+ type = complex_long_double_type_node;
+ else
+ {
+ type = make_node (REAL_TYPE);
+ TYPE_PRECISION (type) = bits / 2;
+ layout_type (type);
+ type = build_complex_type (type);
+ }
+ return type;
+}
+
+// Get a pointer type.
+
+tree
+Gcc_backend::pointer_type (tree to_type)
+{
+ if (to_type == error_mark_node)
+ return error_mark_node;
+ tree type = build_pointer_type (to_type);
+ return type;
+}
+
+// Get a reference type.
+
+tree
+Gcc_backend::reference_type (tree to_type)
+{
+ if (to_type == error_mark_node)
+ return error_mark_node;
+ tree type = build_reference_type (to_type);
+ return type;
+}
+
+// Get immutable type
+
+tree
+Gcc_backend::immutable_type (tree base)
+{
+ if (base == error_mark_node)
+ return error_mark_node;
+ tree constified = build_qualified_type (base, TYPE_QUAL_CONST);
+ return constified;
+}
+
+// Make a function type.
+
+tree
+Gcc_backend::function_type (const typed_identifier &receiver,
+ const std::vector<typed_identifier> &parameters,
+ const std::vector<typed_identifier> &results,
+ tree result_struct, Location)
+{
+ tree args = NULL_TREE;
+ tree *pp = &args;
+ if (receiver.type != NULL_TREE)
+ {
+ tree t = receiver.type;
+ if (t == error_mark_node)
+ return error_mark_node;
+ *pp = tree_cons (NULL_TREE, t, NULL_TREE);
+ pp = &TREE_CHAIN (*pp);
+ }
+
+ for (std::vector<typed_identifier>::const_iterator p = parameters.begin ();
+ p != parameters.end (); ++p)
+ {
+ tree t = p->type;
+ if (t == error_mark_node)
+ return error_mark_node;
+ *pp = tree_cons (NULL_TREE, t, NULL_TREE);
+ pp = &TREE_CHAIN (*pp);
+ }
+
+ // Varargs is handled entirely at the Rust level. When converted to
+ // GENERIC functions are not varargs.
+ *pp = void_list_node;
+
+ tree result;
+ if (results.empty ())
+ result = void_type_node;
+ else if (results.size () == 1)
+ result = results.front ().type;
+ else
+ {
+ gcc_assert (result_struct != NULL);
+ result = result_struct;
+ }
+ if (result == error_mark_node)
+ return error_mark_node;
+
+ // The libffi library cannot represent a zero-sized object. To
+ // avoid causing confusion on 32-bit SPARC, we treat a function that
+ // returns a zero-sized value as returning void. That should do no
+ // harm since there is no actual value to be returned. See
+ // https://gcc.gnu.org/PR72814 for details.
+ if (result != void_type_node && int_size_in_bytes (result) == 0)
+ result = void_type_node;
+
+ tree fntype = build_function_type (result, args);
+ if (fntype == error_mark_node)
+ return error_mark_node;
+
+ return build_pointer_type (fntype);
+}
+
+tree
+Gcc_backend::function_type_varadic (
+ const typed_identifier &receiver,
+ const std::vector<typed_identifier> &parameters,
+ const std::vector<typed_identifier> &results, tree result_struct, Location)
+{
+ size_t n = parameters.size () + (receiver.type != NULL_TREE ? 1 : 0);
+ tree *args = XALLOCAVEC (tree, n);
+ size_t offs = 0;
+
+ if (receiver.type != NULL_TREE)
+ {
+ tree t = receiver.type;
+ if (t == error_mark_node)
+ return error_mark_node;
+
+ args[offs++] = t;
+ }
+
+ for (std::vector<typed_identifier>::const_iterator p = parameters.begin ();
+ p != parameters.end (); ++p)
+ {
+ tree t = p->type;
+ if (t == error_mark_node)
+ return error_mark_node;
+ args[offs++] = t;
+ }
+
+ tree result;
+ if (results.empty ())
+ result = void_type_node;
+ else if (results.size () == 1)
+ result = results.front ().type;
+ else
+ {
+ gcc_assert (result_struct != NULL_TREE);
+ result = result_struct;
+ }
+ if (result == error_mark_node)
+ return error_mark_node;
+
+ // The libffi library cannot represent a zero-sized object. To
+ // avoid causing confusion on 32-bit SPARC, we treat a function that
+ // returns a zero-sized value as returning void. That should do no
+ // harm since there is no actual value to be returned. See
+ // https://gcc.gnu.org/PR72814 for details.
+ if (result != void_type_node && int_size_in_bytes (result) == 0)
+ result = void_type_node;
+
+ tree fntype = build_varargs_function_type_array (result, n, args);
+ if (fntype == error_mark_node)
+ return error_mark_node;
+
+ return build_pointer_type (fntype);
+}
+
+tree
+Gcc_backend::function_ptr_type (tree result_type,
+ const std::vector<tree> &parameters,
+ Location /* locus */)
+{
+ tree args = NULL_TREE;
+ tree *pp = &args;
+
+ for (auto &param : parameters)
+ {
+ if (param == error_mark_node)
+ return error_mark_node;
+
+ *pp = tree_cons (NULL_TREE, param, NULL_TREE);
+ pp = &TREE_CHAIN (*pp);
+ }
+
+ *pp = void_list_node;
+
+ tree result = result_type;
+ if (result != void_type_node && int_size_in_bytes (result) == 0)
+ result = void_type_node;
+
+ tree fntype = build_function_type (result, args);
+ if (fntype == error_mark_node)
+ return error_mark_node;
+
+ return build_pointer_type (fntype);
+}
+
+// Make a struct type.
+
+tree
+Gcc_backend::struct_type (const std::vector<typed_identifier> &fields)
+{
+ return this->fill_in_fields (make_node (RECORD_TYPE), fields);
+}
+
+// Make a union type.
+
+tree
+Gcc_backend::union_type (const std::vector<typed_identifier> &fields)
+{
+ return this->fill_in_fields (make_node (UNION_TYPE), fields);
+}
+
+// Fill in the fields of a struct or union type.
+
+tree
+Gcc_backend::fill_in_fields (tree fill,
+ const std::vector<typed_identifier> &fields)
+{
+ tree field_trees = NULL_TREE;
+ tree *pp = &field_trees;
+ for (std::vector<typed_identifier>::const_iterator p = fields.begin ();
+ p != fields.end (); ++p)
+ {
+ tree name_tree = get_identifier_from_string (p->name);
+ tree type_tree = p->type;
+ if (type_tree == error_mark_node)
+ return error_mark_node;
+ tree field = build_decl (p->location.gcc_location (), FIELD_DECL,
+ name_tree, type_tree);
+ DECL_CONTEXT (field) = fill;
+ *pp = field;
+ pp = &DECL_CHAIN (field);
+ }
+ TYPE_FIELDS (fill) = field_trees;
+ layout_type (fill);
+
+ // Because Rust permits converting between named struct types and
+ // equivalent struct types, for which we use VIEW_CONVERT_EXPR, and
+ // because we don't try to maintain TYPE_CANONICAL for struct types,
+ // we need to tell the middle-end to use structural equality.
+ SET_TYPE_STRUCTURAL_EQUALITY (fill);
+
+ return fill;
+}
+
+// Make an array type.
+
+tree
+Gcc_backend::array_type (tree element_type, tree length)
+{
+ return this->fill_in_array (make_node (ARRAY_TYPE), element_type, length);
+}
+
+// Fill in an array type.
+
+tree
+Gcc_backend::fill_in_array (tree fill, tree element_type, tree length_tree)
+{
+ if (element_type == error_mark_node || length_tree == error_mark_node)
+ return error_mark_node;
+
+ gcc_assert (TYPE_SIZE (element_type) != NULL_TREE);
+
+ length_tree = fold_convert (sizetype, length_tree);
+
+ // build_index_type takes the maximum index, which is one less than
+ // the length.
+ tree index_type_tree = build_index_type (
+ fold_build2 (MINUS_EXPR, sizetype, length_tree, size_one_node));
+
+ TREE_TYPE (fill) = element_type;
+ TYPE_DOMAIN (fill) = index_type_tree;
+ TYPE_ADDR_SPACE (fill) = TYPE_ADDR_SPACE (element_type);
+ layout_type (fill);
+
+ if (TYPE_STRUCTURAL_EQUALITY_P (element_type))
+ SET_TYPE_STRUCTURAL_EQUALITY (fill);
+ else if (TYPE_CANONICAL (element_type) != element_type
+ || TYPE_CANONICAL (index_type_tree) != index_type_tree)
+ TYPE_CANONICAL (fill) = build_array_type (TYPE_CANONICAL (element_type),
+ TYPE_CANONICAL (index_type_tree));
+
+ return fill;
+}
+
+// Return a named version of a type.
+
+tree
+Gcc_backend::named_type (const std::string &name, tree type, Location location)
+{
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ // The middle-end expects a basic type to have a name. In Rust every
+ // basic type will have a name. The first time we see a basic type,
+ // give it whatever Rust name we have at this point.
+ if (TYPE_NAME (type) == NULL_TREE
+ && location.gcc_location () == BUILTINS_LOCATION
+ && (TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == REAL_TYPE
+ || TREE_CODE (type) == COMPLEX_TYPE
+ || TREE_CODE (type) == BOOLEAN_TYPE))
+ {
+ tree decl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
+ get_identifier_from_string (name), type);
+ TYPE_NAME (type) = decl;
+ return type;
+ }
+
+ tree copy = build_variant_type_copy (type);
+ tree decl = build_decl (location.gcc_location (), TYPE_DECL,
+ get_identifier_from_string (name), copy);
+ DECL_ORIGINAL_TYPE (decl) = type;
+ TYPE_NAME (copy) = decl;
+ return copy;
+}
+
+// Return the size of a type.
+
+int64_t
+Gcc_backend::type_size (tree t)
+{
+ if (t == error_mark_node)
+ return 1;
+ if (t == void_type_node)
+ return 0;
+ t = TYPE_SIZE_UNIT (t);
+ gcc_assert (tree_fits_uhwi_p (t));
+ unsigned HOST_WIDE_INT val_wide = TREE_INT_CST_LOW (t);
+ int64_t ret = static_cast<int64_t> (val_wide);
+ if (ret < 0 || static_cast<unsigned HOST_WIDE_INT> (ret) != val_wide)
+ return -1;
+ return ret;
+}
+
+// Return the alignment of a type.
+
+int64_t
+Gcc_backend::type_alignment (tree t)
+{
+ if (t == error_mark_node)
+ return 1;
+ return TYPE_ALIGN_UNIT (t);
+}
+
+// Return the alignment of a struct field of type BTYPE.
+
+int64_t
+Gcc_backend::type_field_alignment (tree t)
+{
+ if (t == error_mark_node)
+ return 1;
+ return rust_field_alignment (t);
+}
+
+// Return the offset of a field in a struct.
+
+int64_t
+Gcc_backend::type_field_offset (tree struct_tree, size_t index)
+{
+ if (struct_tree == error_mark_node)
+ return 0;
+ gcc_assert (TREE_CODE (struct_tree) == RECORD_TYPE);
+ tree field = TYPE_FIELDS (struct_tree);
+ for (; index > 0; --index)
+ {
+ field = DECL_CHAIN (field);
+ gcc_assert (field != NULL_TREE);
+ }
+ HOST_WIDE_INT offset_wide = int_byte_position (field);
+ int64_t ret = static_cast<int64_t> (offset_wide);
+ gcc_assert (ret == offset_wide);
+ return ret;
+}
+
+// Return the zero value for a type.
+
+tree
+Gcc_backend::zero_expression (tree t)
+{
+ tree ret;
+ if (t == error_mark_node)
+ ret = error_mark_node;
+ else
+ ret = build_zero_cst (t);
+ return ret;
+}
+
+// An expression that references a variable.
+
+tree
+Gcc_backend::var_expression (Bvariable *var, Location location)
+{
+ return var->get_tree (location);
+}
+
+// Return a typed value as a constant integer.
+// This function does not release the memory of @val
+
+tree
+Gcc_backend::integer_constant_expression (tree t, mpz_t val)
+{
+ if (t == error_mark_node)
+ return error_mark_node;
+
+ tree ret = wide_int_to_tree (t, wi::from_mpz (t, val, true));
+ return ret;
+}
+
+// Return a typed value as a constant floating-point number.
+
+tree
+Gcc_backend::float_constant_expression (tree t, mpfr_t val)
+{
+ tree ret;
+ if (t == error_mark_node)
+ return error_mark_node;
+
+ REAL_VALUE_TYPE r1;
+ real_from_mpfr (&r1, val, t, GMP_RNDN);
+ REAL_VALUE_TYPE r2;
+ real_convert (&r2, TYPE_MODE (t), &r1);
+ ret = build_real (t, r2);
+ return ret;
+}
+
+// Return a typed real and imaginary value as a constant complex number.
+
+tree
+Gcc_backend::complex_constant_expression (tree t, mpc_t val)
+{
+ tree ret;
+ if (t == error_mark_node)
+ return error_mark_node;
+
+ REAL_VALUE_TYPE r1;
+ real_from_mpfr (&r1, mpc_realref (val), TREE_TYPE (t), GMP_RNDN);
+ REAL_VALUE_TYPE r2;
+ real_convert (&r2, TYPE_MODE (TREE_TYPE (t)), &r1);
+
+ REAL_VALUE_TYPE r3;
+ real_from_mpfr (&r3, mpc_imagref (val), TREE_TYPE (t), GMP_RNDN);
+ REAL_VALUE_TYPE r4;
+ real_convert (&r4, TYPE_MODE (TREE_TYPE (t)), &r3);
+
+ ret = build_complex (t, build_real (TREE_TYPE (t), r2),
+ build_real (TREE_TYPE (t), r4));
+ return ret;
+}
+
+// Make a constant string expression.
+
+tree
+Gcc_backend::string_constant_expression (const std::string &val)
+{
+ tree index_type = build_index_type (size_int (val.length ()));
+ tree const_char_type = build_qualified_type (char_type_node, TYPE_QUAL_CONST);
+ tree string_type = build_array_type (const_char_type, index_type);
+ TYPE_STRING_FLAG (string_type) = 1;
+ tree string_val = build_string (val.length (), val.data ());
+ TREE_TYPE (string_val) = string_type;
+
+ return string_val;
+}
+
+tree
+Gcc_backend::wchar_constant_expression (wchar_t c)
+{
+ return build_int_cst (this->wchar_type (), c);
+}
+
+tree
+Gcc_backend::char_constant_expression (char c)
+{
+ return build_int_cst (this->char_type (), c);
+}
+
+// Make a constant boolean expression.
+
+tree
+Gcc_backend::boolean_constant_expression (bool val)
+{
+ return val ? boolean_true_node : boolean_false_node;
+}
+
+// Return the real part of a complex expression.
+
+tree
+Gcc_backend::real_part_expression (tree complex_tree, Location location)
+{
+ if (complex_tree == error_mark_node)
+ return error_mark_node;
+ gcc_assert (COMPLEX_FLOAT_TYPE_P (TREE_TYPE (complex_tree)));
+ tree ret
+ = fold_build1_loc (location.gcc_location (), REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (complex_tree)), complex_tree);
+ return ret;
+}
+
+// Return the imaginary part of a complex expression.
+
+tree
+Gcc_backend::imag_part_expression (tree complex_tree, Location location)
+{
+ if (complex_tree == error_mark_node)
+ return error_mark_node;
+ gcc_assert (COMPLEX_FLOAT_TYPE_P (TREE_TYPE (complex_tree)));
+ tree ret
+ = fold_build1_loc (location.gcc_location (), IMAGPART_EXPR,
+ TREE_TYPE (TREE_TYPE (complex_tree)), complex_tree);
+ return ret;
+}
+
+// Make a complex expression given its real and imaginary parts.
+
+tree
+Gcc_backend::complex_expression (tree real_tree, tree imag_tree,
+ Location location)
+{
+ if (real_tree == error_mark_node || imag_tree == error_mark_node)
+ return error_mark_node;
+ gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (real_tree))
+ == TYPE_MAIN_VARIANT (TREE_TYPE (imag_tree)));
+ gcc_assert (SCALAR_FLOAT_TYPE_P (TREE_TYPE (real_tree)));
+ tree ret = fold_build2_loc (location.gcc_location (), COMPLEX_EXPR,
+ build_complex_type (TREE_TYPE (real_tree)),
+ real_tree, imag_tree);
+ return ret;
+}
+
+// An expression that converts an expression to a different type.
+
+tree
+Gcc_backend::convert_expression (tree type_tree, tree expr_tree,
+ Location location)
+{
+ if (type_tree == error_mark_node || expr_tree == error_mark_node
+ || TREE_TYPE (expr_tree) == error_mark_node)
+ return error_mark_node;
+
+ tree ret;
+ if (this->type_size (type_tree) == 0
+ || TREE_TYPE (expr_tree) == void_type_node)
+ {
+ // Do not convert zero-sized types.
+ ret = expr_tree;
+ }
+ else if (TREE_CODE (type_tree) == INTEGER_TYPE)
+ ret = convert_to_integer (type_tree, expr_tree);
+ else if (TREE_CODE (type_tree) == REAL_TYPE)
+ ret = convert_to_real (type_tree, expr_tree);
+ else if (TREE_CODE (type_tree) == COMPLEX_TYPE)
+ ret = convert_to_complex (type_tree, expr_tree);
+ else if (TREE_CODE (type_tree) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (expr_tree)) == INTEGER_TYPE)
+ ret = convert_to_pointer (type_tree, expr_tree);
+ else if (TREE_CODE (type_tree) == RECORD_TYPE
+ || TREE_CODE (type_tree) == ARRAY_TYPE)
+ ret = fold_build1_loc (location.gcc_location (), VIEW_CONVERT_EXPR,
+ type_tree, expr_tree);
+ else
+ ret = fold_convert_loc (location.gcc_location (), type_tree, expr_tree);
+
+ return ret;
+}
+
+// Return an expression for the field at INDEX in BSTRUCT.
+
+tree
+Gcc_backend::struct_field_expression (tree struct_tree, size_t index,
+ Location location)
+{
+ if (struct_tree == error_mark_node
+ || TREE_TYPE (struct_tree) == error_mark_node)
+ return error_mark_node;
+ gcc_assert (TREE_CODE (TREE_TYPE (struct_tree)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (struct_tree)) == UNION_TYPE);
+ tree field = TYPE_FIELDS (TREE_TYPE (struct_tree));
+ if (field == NULL_TREE)
+ {
+ // This can happen for a type which refers to itself indirectly
+ // and then turns out to be erroneous.
+ return error_mark_node;
+ }
+ for (unsigned int i = index; i > 0; --i)
+ {
+ field = DECL_CHAIN (field);
+ gcc_assert (field != NULL_TREE);
+ }
+ if (TREE_TYPE (field) == error_mark_node)
+ return error_mark_node;
+ tree ret = fold_build3_loc (location.gcc_location (), COMPONENT_REF,
+ TREE_TYPE (field), struct_tree, field, NULL_TREE);
+ if (TREE_CONSTANT (struct_tree))
+ TREE_CONSTANT (ret) = 1;
+ return ret;
+}
+
+// Return an expression that executes BSTAT before BEXPR.
+
+tree
+Gcc_backend::compound_expression (tree stat, tree expr, Location location)
+{
+ if (stat == error_mark_node || expr == error_mark_node)
+ return error_mark_node;
+ tree ret = fold_build2_loc (location.gcc_location (), COMPOUND_EXPR,
+ TREE_TYPE (expr), stat, expr);
+ return ret;
+}
+
+// Return an expression that executes THEN_EXPR if CONDITION is true, or
+// ELSE_EXPR otherwise.
+
+tree
+Gcc_backend::conditional_expression (tree, tree type_tree, tree cond_expr,
+ tree then_expr, tree else_expr,
+ Location location)
+{
+ if (type_tree == error_mark_node || cond_expr == error_mark_node
+ || then_expr == error_mark_node || else_expr == error_mark_node)
+ return error_mark_node;
+ tree ret = build3_loc (location.gcc_location (), COND_EXPR, type_tree,
+ cond_expr, then_expr, else_expr);
+ return ret;
+}
+
+/* Helper function that converts rust operators to equivalent GCC tree_code.
+ Note that CompoundAssignmentOperator don't get their corresponding tree_code,
+ because they get compiled away when we lower AST to HIR. */
+static enum tree_code
+operator_to_tree_code (NegationOperator op)
+{
+ switch (op)
+ {
+ case NegationOperator::NEGATE:
+ return NEGATE_EXPR;
+ case NegationOperator::NOT:
+ return TRUTH_NOT_EXPR;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Note that GCC tree code distinguishes floating point division and integer
+ division. These two types of division are represented as the same rust
+ operator, and can only be distinguished via context(i.e. the TREE_TYPE of the
+ operands). */
+static enum tree_code
+operator_to_tree_code (ArithmeticOrLogicalOperator op, bool floating_point)
+{
+ switch (op)
+ {
+ case ArithmeticOrLogicalOperator::ADD:
+ return PLUS_EXPR;
+ case ArithmeticOrLogicalOperator::SUBTRACT:
+ return MINUS_EXPR;
+ case ArithmeticOrLogicalOperator::MULTIPLY:
+ return MULT_EXPR;
+ case ArithmeticOrLogicalOperator::DIVIDE:
+ if (floating_point)
+ return RDIV_EXPR;
+ else
+ return TRUNC_DIV_EXPR;
+ case ArithmeticOrLogicalOperator::MODULUS:
+ return TRUNC_MOD_EXPR;
+ case ArithmeticOrLogicalOperator::BITWISE_AND:
+ return BIT_AND_EXPR;
+ case ArithmeticOrLogicalOperator::BITWISE_OR:
+ return BIT_IOR_EXPR;
+ case ArithmeticOrLogicalOperator::BITWISE_XOR:
+ return BIT_XOR_EXPR;
+ case ArithmeticOrLogicalOperator::LEFT_SHIFT:
+ return LSHIFT_EXPR;
+ case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
+ return RSHIFT_EXPR;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+static enum tree_code
+operator_to_tree_code (ComparisonOperator op)
+{
+ switch (op)
+ {
+ case ComparisonOperator::EQUAL:
+ return EQ_EXPR;
+ case ComparisonOperator::NOT_EQUAL:
+ return NE_EXPR;
+ case ComparisonOperator::GREATER_THAN:
+ return GT_EXPR;
+ case ComparisonOperator::LESS_THAN:
+ return LT_EXPR;
+ case ComparisonOperator::GREATER_OR_EQUAL:
+ return GE_EXPR;
+ case ComparisonOperator::LESS_OR_EQUAL:
+ return LE_EXPR;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+static enum tree_code
+operator_to_tree_code (LazyBooleanOperator op)
+{
+ switch (op)
+ {
+ case LazyBooleanOperator::LOGICAL_OR:
+ return TRUTH_ORIF_EXPR;
+ case LazyBooleanOperator::LOGICAL_AND:
+ return TRUTH_ANDIF_EXPR;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Helper function for deciding if a tree is a floating point node. */
+bool
+is_floating_point (tree t)
+{
+ auto tree_type = TREE_CODE (TREE_TYPE (t));
+ return tree_type == REAL_TYPE || tree_type == COMPLEX_TYPE;
+}
+
+// Return an expression for the negation operation OP EXPR.
+tree
+Gcc_backend::negation_expression (NegationOperator op, tree expr_tree,
+ Location location)
+{
+ /* Check if the expression is an error, in which case we return an error
+ expression. */
+ if (expr_tree == error_mark_node || TREE_TYPE (expr_tree) == error_mark_node)
+ return error_mark_node;
+
+ /* For negation operators, the resulting type should be the same as its
+ operand. */
+ auto tree_type = TREE_TYPE (expr_tree);
+ auto original_type = tree_type;
+ auto tree_code = operator_to_tree_code (op);
+
+ /* For floating point operations we may need to extend the precision of type.
+ For example, a 64-bit machine may not support operations on float32. */
+ bool floating_point = is_floating_point (expr_tree);
+ auto extended_type = NULL_TREE;
+ if (floating_point)
+ {
+ extended_type = excess_precision_type (tree_type);
+ if (extended_type != NULL_TREE)
+ {
+ expr_tree = convert (extended_type, expr_tree);
+ tree_type = extended_type;
+ }
+ }
+
+ /* Construct a new tree and build an expression from it. */
+ auto new_tree = fold_build1_loc (location.gcc_location (), tree_code,
+ tree_type, expr_tree);
+ if (floating_point && extended_type != NULL_TREE)
+ new_tree = convert (original_type, expr_tree);
+ return new_tree;
+}
+
+// Return an expression for the arithmetic or logical operation LEFT OP RIGHT.
+tree
+Gcc_backend::arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op,
+ tree left_tree, tree right_tree,
+ Location location)
+{
+ /* Check if either expression is an error, in which case we return an error
+ expression. */
+ if (left_tree == error_mark_node || right_tree == error_mark_node)
+ return error_mark_node;
+
+ /* We need to determine if we're doing floating point arithmetics of integer
+ arithmetics. */
+ bool floating_point = is_floating_point (left_tree);
+
+ /* For arithmetic or logical operators, the resulting type should be the same
+ as the lhs operand. */
+ auto tree_type = TREE_TYPE (left_tree);
+ auto original_type = tree_type;
+ auto tree_code = operator_to_tree_code (op, floating_point);
+
+ /* For floating point operations we may need to extend the precision of type.
+ For example, a 64-bit machine may not support operations on float32. */
+ auto extended_type = NULL_TREE;
+ if (floating_point)
+ {
+ extended_type = excess_precision_type (tree_type);
+ if (extended_type != NULL_TREE)
+ {
+ left_tree = convert (extended_type, left_tree);
+ right_tree = convert (extended_type, right_tree);
+ tree_type = extended_type;
+ }
+ }
+
+ /* Construct a new tree and build an expression from it. */
+ auto new_tree = fold_build2_loc (location.gcc_location (), tree_code,
+ tree_type, left_tree, right_tree);
+ TREE_CONSTANT (new_tree)
+ = TREE_CONSTANT (left_tree) && TREE_CONSTANT (right_tree);
+
+ if (floating_point && extended_type != NULL_TREE)
+ new_tree = convert (original_type, new_tree);
+ return new_tree;
+}
+
+// Return an expression for the comparison operation LEFT OP RIGHT.
+tree
+Gcc_backend::comparison_expression (ComparisonOperator op, tree left_tree,
+ tree right_tree, Location location)
+{
+ /* Check if either expression is an error, in which case we return an error
+ expression. */
+ if (left_tree == error_mark_node || right_tree == error_mark_node)
+ return error_mark_node;
+
+ /* For comparison operators, the resulting type should be boolean. */
+ auto tree_type = boolean_type_node;
+ auto tree_code = operator_to_tree_code (op);
+
+ /* Construct a new tree and build an expression from it. */
+ auto new_tree = fold_build2_loc (location.gcc_location (), tree_code,
+ tree_type, left_tree, right_tree);
+ return new_tree;
+}
+
+// Return an expression for the lazy boolean operation LEFT OP RIGHT.
+tree
+Gcc_backend::lazy_boolean_expression (LazyBooleanOperator op, tree left_tree,
+ tree right_tree, Location location)
+{
+ /* Check if either expression is an error, in which case we return an error
+ expression. */
+ if (left_tree == error_mark_node || right_tree == error_mark_node)
+ return error_mark_node;
+
+ /* For lazy boolean operators, the resulting type should be the same as the
+ rhs operand. */
+ auto tree_type = TREE_TYPE (right_tree);
+ auto tree_code = operator_to_tree_code (op);
+
+ /* Construct a new tree and build an expression from it. */
+ auto new_tree = fold_build2_loc (location.gcc_location (), tree_code,
+ tree_type, left_tree, right_tree);
+ return new_tree;
+}
+
+// Return an expression that constructs BTYPE with VALS.
+
+tree
+Gcc_backend::constructor_expression (tree type_tree, bool is_variant,
+ const std::vector<tree> &vals,
+ int union_index, Location location)
+{
+ if (type_tree == error_mark_node)
+ return error_mark_node;
+
+ vec<constructor_elt, va_gc> *init;
+ vec_alloc (init, vals.size ());
+
+ tree sink = NULL_TREE;
+ bool is_constant = true;
+ tree field = TYPE_FIELDS (type_tree);
+
+ if (is_variant)
+ {
+ gcc_assert (union_index != -1);
+ gcc_assert (TREE_CODE (type_tree) == UNION_TYPE);
+
+ for (int i = 0; i < union_index; i++)
+ {
+ gcc_assert (field != NULL_TREE);
+ field = DECL_CHAIN (field);
+ }
+
+ tree nested_ctor
+ = constructor_expression (TREE_TYPE (field), false, vals, -1, location);
+
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt *elt = init->quick_push (empty);
+ elt->index = field;
+ elt->value
+ = this->convert_tree (TREE_TYPE (field), nested_ctor, location);
+ if (!TREE_CONSTANT (elt->value))
+ is_constant = false;
+ }
+ else
+ {
+ if (union_index != -1)
+ {
+ gcc_assert (TREE_CODE (type_tree) == UNION_TYPE);
+ tree val = vals.front ();
+ for (int i = 0; i < union_index; i++)
+ {
+ gcc_assert (field != NULL_TREE);
+ field = DECL_CHAIN (field);
+ }
+ if (TREE_TYPE (field) == error_mark_node || val == error_mark_node
+ || TREE_TYPE (val) == error_mark_node)
+ return error_mark_node;
+
+ if (int_size_in_bytes (TREE_TYPE (field)) == 0)
+ {
+ // GIMPLE cannot represent indices of zero-sized types so
+ // trying to construct a map with zero-sized keys might lead
+ // to errors. Instead, we evaluate each expression that
+ // would have been added as a map element for its
+ // side-effects and construct an empty map.
+ append_to_statement_list (val, &sink);
+ }
+ else
+ {
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt *elt = init->quick_push (empty);
+ elt->index = field;
+ elt->value
+ = this->convert_tree (TREE_TYPE (field), val, location);
+ if (!TREE_CONSTANT (elt->value))
+ is_constant = false;
+ }
+ }
+ else
+ {
+ gcc_assert (TREE_CODE (type_tree) == RECORD_TYPE);
+ for (std::vector<tree>::const_iterator p = vals.begin ();
+ p != vals.end (); ++p, field = DECL_CHAIN (field))
+ {
+ gcc_assert (field != NULL_TREE);
+ tree val = (*p);
+ if (TREE_TYPE (field) == error_mark_node || val == error_mark_node
+ || TREE_TYPE (val) == error_mark_node)
+ return error_mark_node;
+
+ if (int_size_in_bytes (TREE_TYPE (field)) == 0)
+ {
+ // GIMPLE cannot represent indices of zero-sized types so
+ // trying to construct a map with zero-sized keys might lead
+ // to errors. Instead, we evaluate each expression that
+ // would have been added as a map element for its
+ // side-effects and construct an empty map.
+ append_to_statement_list (val, &sink);
+ continue;
+ }
+
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt *elt = init->quick_push (empty);
+ elt->index = field;
+ elt->value
+ = this->convert_tree (TREE_TYPE (field), val, location);
+ if (!TREE_CONSTANT (elt->value))
+ is_constant = false;
+ }
+ gcc_assert (field == NULL_TREE);
+ }
+ }
+
+ tree ret = build_constructor (type_tree, init);
+ if (is_constant)
+ TREE_CONSTANT (ret) = 1;
+ if (sink != NULL_TREE)
+ ret = fold_build2_loc (location.gcc_location (), COMPOUND_EXPR, type_tree,
+ sink, ret);
+ return ret;
+}
+
+tree
+Gcc_backend::array_constructor_expression (
+ tree type_tree, const std::vector<unsigned long> &indexes,
+ const std::vector<tree> &vals, Location location)
+{
+ if (type_tree == error_mark_node)
+ return error_mark_node;
+
+ gcc_assert (indexes.size () == vals.size ());
+
+ tree element_type = TREE_TYPE (type_tree);
+ HOST_WIDE_INT element_size = int_size_in_bytes (element_type);
+ vec<constructor_elt, va_gc> *init;
+ vec_alloc (init, element_size == 0 ? 0 : vals.size ());
+
+ tree sink = NULL_TREE;
+ bool is_constant = true;
+ for (size_t i = 0; i < vals.size (); ++i)
+ {
+ tree index = size_int (indexes[i]);
+ tree val = vals[i];
+
+ if (index == error_mark_node || val == error_mark_node)
+ return error_mark_node;
+
+ if (element_size == 0)
+ {
+ // GIMPLE cannot represent arrays of zero-sized types so trying
+ // to construct an array of zero-sized values might lead to errors.
+ // Instead, we evaluate each expression that would have been added as
+ // an array value for its side-effects and construct an empty array.
+ append_to_statement_list (val, &sink);
+ continue;
+ }
+
+ if (!TREE_CONSTANT (val))
+ is_constant = false;
+
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt *elt = init->quick_push (empty);
+ elt->index = index;
+ elt->value = val;
+ }
+
+ tree ret = build_constructor (type_tree, init);
+ if (is_constant)
+ TREE_CONSTANT (ret) = 1;
+ if (sink != NULL_TREE)
+ ret = fold_build2_loc (location.gcc_location (), COMPOUND_EXPR, type_tree,
+ sink, ret);
+ return ret;
+}
+
+// Build insns to create an array, initialize all elements of the array to
+// value, and return it
+tree
+Gcc_backend::array_initializer (tree fndecl, tree block, tree array_type,
+ tree length, tree value, tree *tmp,
+ Location locus)
+{
+ std::vector<tree> stmts;
+
+ // Temporary array we initialize with the desired value.
+ tree t = NULL_TREE;
+ Bvariable *tmp_array = this->temporary_variable (fndecl, block, array_type,
+ NULL_TREE, true, locus, &t);
+ tree arr = tmp_array->get_tree (locus);
+ stmts.push_back (t);
+
+ // Temporary for the array length used for initialization loop guard.
+ Bvariable *tmp_len = this->temporary_variable (fndecl, block, size_type_node,
+ length, true, locus, &t);
+ tree len = tmp_len->get_tree (locus);
+ stmts.push_back (t);
+
+ // Temporary variable for pointer used to initialize elements.
+ tree ptr_type = this->pointer_type (TREE_TYPE (array_type));
+ tree ptr_init
+ = build1_loc (locus.gcc_location (), ADDR_EXPR, ptr_type,
+ this->array_index_expression (arr, integer_zero_node, locus));
+ Bvariable *tmp_ptr = this->temporary_variable (fndecl, block, ptr_type,
+ ptr_init, false, locus, &t);
+ tree ptr = tmp_ptr->get_tree (locus);
+ stmts.push_back (t);
+
+ // push statement list for the loop
+ std::vector<tree> loop_stmts;
+
+ // Loop exit condition:
+ // if (length == 0) break;
+ t = this->comparison_expression (ComparisonOperator::EQUAL, len,
+ this->zero_expression (TREE_TYPE (len)),
+ locus);
+
+ t = this->exit_expression (t, locus);
+ loop_stmts.push_back (t);
+
+ // Assign value to the current pointer position
+ // *ptr = value;
+ t = this->assignment_statement (build_fold_indirect_ref (ptr), value, locus);
+ loop_stmts.push_back (t);
+
+ // Move pointer to next element
+ // ptr++;
+ tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptr_type));
+ t = build2 (POSTINCREMENT_EXPR, ptr_type, ptr, convert (ptr_type, size));
+ loop_stmts.push_back (t);
+
+ // Decrement loop counter.
+ // length--;
+ t = build2 (POSTDECREMENT_EXPR, TREE_TYPE (len), len,
+ convert (TREE_TYPE (len), integer_one_node));
+ loop_stmts.push_back (t);
+
+ // pop statments and finish loop
+ tree loop_body = this->statement_list (loop_stmts);
+ stmts.push_back (this->loop_expression (loop_body, locus));
+
+ // Return the temporary in the provided pointer and the statement list which
+ // initializes it.
+ *tmp = tmp_array->get_tree (locus);
+ return this->statement_list (stmts);
+}
+
+// Return an expression representing ARRAY[INDEX]
+
+tree
+Gcc_backend::array_index_expression (tree array_tree, tree index_tree,
+ Location location)
+{
+ if (array_tree == error_mark_node || TREE_TYPE (array_tree) == error_mark_node
+ || index_tree == error_mark_node)
+ return error_mark_node;
+
+ // A function call that returns a zero sized object will have been
+ // changed to return void. If we see void here, assume we are
+ // dealing with a zero sized type and just evaluate the operands.
+ tree ret;
+ if (TREE_TYPE (array_tree) != void_type_node)
+ ret = build4_loc (location.gcc_location (), ARRAY_REF,
+ TREE_TYPE (TREE_TYPE (array_tree)), array_tree,
+ index_tree, NULL_TREE, NULL_TREE);
+ else
+ ret = fold_build2_loc (location.gcc_location (), COMPOUND_EXPR,
+ void_type_node, array_tree, index_tree);
+
+ return ret;
+}
+
+// Create an expression for a call to FN_EXPR with FN_ARGS.
+tree
+Gcc_backend::call_expression (tree fn, const std::vector<tree> &fn_args,
+ tree chain_expr, Location location)
+{
+ if (fn == error_mark_node || TREE_TYPE (fn) == error_mark_node)
+ return error_mark_node;
+
+ gcc_assert (FUNCTION_POINTER_TYPE_P (TREE_TYPE (fn)));
+ tree rettype = TREE_TYPE (TREE_TYPE (TREE_TYPE (fn)));
+
+ size_t nargs = fn_args.size ();
+ tree *args = nargs == 0 ? NULL : new tree[nargs];
+ for (size_t i = 0; i < nargs; ++i)
+ {
+ args[i] = fn_args.at (i);
+ }
+
+ tree fndecl = fn;
+ if (TREE_CODE (fndecl) == ADDR_EXPR)
+ fndecl = TREE_OPERAND (fndecl, 0);
+
+ // This is to support builtin math functions when using 80387 math.
+ tree excess_type = NULL_TREE;
+ if (optimize && TREE_CODE (fndecl) == FUNCTION_DECL
+ && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)
+ && DECL_IS_UNDECLARED_BUILTIN (fndecl) && nargs > 0
+ && ((SCALAR_FLOAT_TYPE_P (rettype)
+ && SCALAR_FLOAT_TYPE_P (TREE_TYPE (args[0])))
+ || (COMPLEX_FLOAT_TYPE_P (rettype)
+ && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (args[0])))))
+ {
+ excess_type = excess_precision_type (TREE_TYPE (args[0]));
+ if (excess_type != NULL_TREE)
+ {
+ tree excess_fndecl
+ = mathfn_built_in (excess_type, DECL_FUNCTION_CODE (fndecl));
+ if (excess_fndecl == NULL_TREE)
+ excess_type = NULL_TREE;
+ else
+ {
+ fn = build_fold_addr_expr_loc (location.gcc_location (),
+ excess_fndecl);
+ for (size_t i = 0; i < nargs; ++i)
+ {
+ if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (args[i]))
+ || COMPLEX_FLOAT_TYPE_P (TREE_TYPE (args[i])))
+ args[i] = ::convert (excess_type, args[i]);
+ }
+ }
+ }
+ }
+
+ tree ret
+ = build_call_array_loc (location.gcc_location (),
+ excess_type != NULL_TREE ? excess_type : rettype,
+ fn, nargs, args);
+
+ // check for deprecated function usage
+ if (fndecl && TREE_DEPRECATED (fndecl))
+ {
+ // set up the call-site information for `warn_deprecated_use`
+ input_location = location.gcc_location ();
+ warn_deprecated_use (fndecl, NULL_TREE);
+ }
+
+ if (chain_expr)
+ CALL_EXPR_STATIC_CHAIN (ret) = chain_expr;
+
+ if (excess_type != NULL_TREE)
+ {
+ // Calling convert here can undo our excess precision change.
+ // That may or may not be a bug in convert_to_real.
+ ret = build1_loc (location.gcc_location (), NOP_EXPR, rettype, ret);
+ }
+
+ delete[] args;
+ return ret;
+}
+
+// Variable initialization.
+
+tree
+Gcc_backend::init_statement (tree, Bvariable *var, tree init_tree)
+{
+ tree var_tree = var->get_decl ();
+ if (var_tree == error_mark_node || init_tree == error_mark_node)
+ return error_mark_node;
+ gcc_assert (TREE_CODE (var_tree) == VAR_DECL);
+
+ // To avoid problems with GNU ld, we don't make zero-sized
+ // externally visible variables. That might lead us to doing an
+ // initialization of a zero-sized expression to a non-zero sized
+ // variable, or vice-versa. Avoid crashes by omitting the
+ // initializer. Such initializations don't mean anything anyhow.
+ if (int_size_in_bytes (TREE_TYPE (var_tree)) != 0 && init_tree != NULL_TREE
+ && TREE_TYPE (init_tree) != void_type_node
+ && int_size_in_bytes (TREE_TYPE (init_tree)) != 0)
+ {
+ DECL_INITIAL (var_tree) = init_tree;
+ init_tree = NULL_TREE;
+ }
+
+ tree ret = build1_loc (DECL_SOURCE_LOCATION (var_tree), DECL_EXPR,
+ void_type_node, var_tree);
+ if (init_tree != NULL_TREE)
+ ret = build2_loc (DECL_SOURCE_LOCATION (var_tree), COMPOUND_EXPR,
+ void_type_node, init_tree, ret);
+
+ return ret;
+}
+
+// Assignment.
+
+tree
+Gcc_backend::assignment_statement (tree lhs, tree rhs, Location location)
+{
+ if (lhs == error_mark_node || rhs == error_mark_node)
+ return error_mark_node;
+
+ // To avoid problems with GNU ld, we don't make zero-sized
+ // externally visible variables. That might lead us to doing an
+ // assignment of a zero-sized expression to a non-zero sized
+ // expression; avoid crashes here by avoiding assignments of
+ // zero-sized expressions. Such assignments don't really mean
+ // anything anyhow.
+ if (TREE_TYPE (lhs) == void_type_node
+ || int_size_in_bytes (TREE_TYPE (lhs)) == 0
+ || TREE_TYPE (rhs) == void_type_node
+ || int_size_in_bytes (TREE_TYPE (rhs)) == 0)
+ return this->compound_statement (lhs, rhs);
+
+ rhs = this->convert_tree (TREE_TYPE (lhs), rhs, location);
+
+ return fold_build2_loc (location.gcc_location (), MODIFY_EXPR, void_type_node,
+ lhs, rhs);
+}
+
+// Return.
+
+tree
+Gcc_backend::return_statement (tree fntree, const std::vector<tree> &vals,
+ Location location)
+{
+ if (fntree == error_mark_node)
+ return error_mark_node;
+ tree result = DECL_RESULT (fntree);
+ if (result == error_mark_node)
+ return error_mark_node;
+
+ // If the result size is zero bytes, we have set the function type
+ // to have a result type of void, so don't return anything.
+ // See the function_type method.
+ tree res_type = TREE_TYPE (result);
+ if (res_type == void_type_node || int_size_in_bytes (res_type) == 0)
+ {
+ tree stmt_list = NULL_TREE;
+ for (std::vector<tree>::const_iterator p = vals.begin ();
+ p != vals.end (); p++)
+ {
+ tree val = (*p);
+ if (val == error_mark_node)
+ return error_mark_node;
+ append_to_statement_list (val, &stmt_list);
+ }
+ tree ret = fold_build1_loc (location.gcc_location (), RETURN_EXPR,
+ void_type_node, NULL_TREE);
+ append_to_statement_list (ret, &stmt_list);
+ return stmt_list;
+ }
+
+ tree ret;
+ if (vals.empty ())
+ ret = fold_build1_loc (location.gcc_location (), RETURN_EXPR,
+ void_type_node, NULL_TREE);
+ else if (vals.size () == 1)
+ {
+ tree val = vals.front ();
+ if (val == error_mark_node)
+ return error_mark_node;
+ tree set = fold_build2_loc (location.gcc_location (), MODIFY_EXPR,
+ void_type_node, result, vals.front ());
+ ret = fold_build1_loc (location.gcc_location (), RETURN_EXPR,
+ void_type_node, set);
+ }
+ else
+ {
+ // To return multiple values, copy the values into a temporary
+ // variable of the right structure type, and then assign the
+ // temporary variable to the DECL_RESULT in the return
+ // statement.
+ tree stmt_list = NULL_TREE;
+ tree rettype = TREE_TYPE (result);
+
+ if (DECL_STRUCT_FUNCTION (fntree) == NULL)
+ push_struct_function (fntree);
+ else
+ push_cfun (DECL_STRUCT_FUNCTION (fntree));
+ tree rettmp = create_tmp_var (rettype, "RESULT");
+ pop_cfun ();
+
+ tree field = TYPE_FIELDS (rettype);
+ for (std::vector<tree>::const_iterator p = vals.begin ();
+ p != vals.end (); p++, field = DECL_CHAIN (field))
+ {
+ gcc_assert (field != NULL_TREE);
+ tree ref
+ = fold_build3_loc (location.gcc_location (), COMPONENT_REF,
+ TREE_TYPE (field), rettmp, field, NULL_TREE);
+ tree val = (*p);
+ if (val == error_mark_node)
+ return error_mark_node;
+ tree set = fold_build2_loc (location.gcc_location (), MODIFY_EXPR,
+ void_type_node, ref, (*p));
+ append_to_statement_list (set, &stmt_list);
+ }
+ gcc_assert (field == NULL_TREE);
+ tree set = fold_build2_loc (location.gcc_location (), MODIFY_EXPR,
+ void_type_node, result, rettmp);
+ tree ret_expr = fold_build1_loc (location.gcc_location (), RETURN_EXPR,
+ void_type_node, set);
+ append_to_statement_list (ret_expr, &stmt_list);
+ ret = stmt_list;
+ }
+ return ret;
+}
+
+// Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if an
+// error occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and if not
+// NULL, it will always be executed. This is used for handling defers in Rust
+// functions. In C++, the resulting code is of this form:
+// try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; }
+
+tree
+Gcc_backend::exception_handler_statement (tree try_stmt, tree except_stmt,
+ tree finally_stmt, Location location)
+{
+ if (try_stmt == error_mark_node || except_stmt == error_mark_node
+ || finally_stmt == error_mark_node)
+ return error_mark_node;
+
+ if (except_stmt != NULL_TREE)
+ try_stmt = build2_loc (location.gcc_location (), TRY_CATCH_EXPR,
+ void_type_node, try_stmt,
+ build2_loc (location.gcc_location (), CATCH_EXPR,
+ void_type_node, NULL, except_stmt));
+ if (finally_stmt != NULL_TREE)
+ try_stmt = build2_loc (location.gcc_location (), TRY_FINALLY_EXPR,
+ void_type_node, try_stmt, finally_stmt);
+ return try_stmt;
+}
+
+// If.
+
+tree
+Gcc_backend::if_statement (tree, tree cond_tree, tree then_tree, tree else_tree,
+ Location location)
+{
+ if (cond_tree == error_mark_node || then_tree == error_mark_node
+ || else_tree == error_mark_node)
+ return error_mark_node;
+ tree ret = build3_loc (location.gcc_location (), COND_EXPR, void_type_node,
+ cond_tree, then_tree, else_tree);
+ return ret;
+}
+
+// Loops
+
+tree
+Gcc_backend::loop_expression (tree body, Location locus)
+{
+ return fold_build1_loc (locus.gcc_location (), LOOP_EXPR, void_type_node,
+ body);
+}
+
+tree
+Gcc_backend::exit_expression (tree cond_tree, Location locus)
+{
+ return fold_build1_loc (locus.gcc_location (), EXIT_EXPR, void_type_node,
+ cond_tree);
+}
+
+// Pair of statements.
+
+tree
+Gcc_backend::compound_statement (tree s1, tree s2)
+{
+ tree stmt_list = NULL_TREE;
+ tree t = s1;
+ if (t == error_mark_node)
+ return error_mark_node;
+ append_to_statement_list (t, &stmt_list);
+ t = s2;
+ if (t == error_mark_node)
+ return error_mark_node;
+ append_to_statement_list (t, &stmt_list);
+
+ // If neither statement has any side effects, stmt_list can be NULL
+ // at this point.
+ if (stmt_list == NULL_TREE)
+ stmt_list = integer_zero_node;
+
+ return stmt_list;
+}
+
+// List of statements.
+
+tree
+Gcc_backend::statement_list (const std::vector<tree> &statements)
+{
+ tree stmt_list = NULL_TREE;
+ for (std::vector<tree>::const_iterator p = statements.begin ();
+ p != statements.end (); ++p)
+ {
+ tree t = (*p);
+ if (t == error_mark_node)
+ return error_mark_node;
+ append_to_statement_list (t, &stmt_list);
+ }
+ return stmt_list;
+}
+
+// Make a block. For some reason gcc uses a dual structure for
+// blocks: BLOCK tree nodes and BIND_EXPR tree nodes. Since the
+// BIND_EXPR node points to the BLOCK node, we store the BIND_EXPR in
+// the Bblock.
+
+tree
+Gcc_backend::block (tree fndecl, tree enclosing,
+ const std::vector<Bvariable *> &vars,
+ Location start_location, Location)
+{
+ tree block_tree = make_node (BLOCK);
+ if (enclosing == NULL)
+ {
+ gcc_assert (fndecl != NULL_TREE);
+
+ // We may have already created a block for local variables when
+ // we take the address of a parameter.
+ if (DECL_INITIAL (fndecl) == NULL_TREE)
+ {
+ BLOCK_SUPERCONTEXT (block_tree) = fndecl;
+ DECL_INITIAL (fndecl) = block_tree;
+ }
+ else
+ {
+ tree superblock_tree = DECL_INITIAL (fndecl);
+ BLOCK_SUPERCONTEXT (block_tree) = superblock_tree;
+ tree *pp;
+ for (pp = &BLOCK_SUBBLOCKS (superblock_tree); *pp != NULL_TREE;
+ pp = &BLOCK_CHAIN (*pp))
+ ;
+ *pp = block_tree;
+ }
+ }
+ else
+ {
+ tree superblock_tree = BIND_EXPR_BLOCK (enclosing);
+ gcc_assert (TREE_CODE (superblock_tree) == BLOCK);
+
+ BLOCK_SUPERCONTEXT (block_tree) = superblock_tree;
+ tree *pp;
+ for (pp = &BLOCK_SUBBLOCKS (superblock_tree); *pp != NULL_TREE;
+ pp = &BLOCK_CHAIN (*pp))
+ ;
+ *pp = block_tree;
+ }
+
+ tree *pp = &BLOCK_VARS (block_tree);
+ for (std::vector<Bvariable *>::const_iterator pv = vars.begin ();
+ pv != vars.end (); ++pv)
+ {
+ *pp = (*pv)->get_decl ();
+ if (*pp != error_mark_node)
+ pp = &DECL_CHAIN (*pp);
+ }
+ *pp = NULL_TREE;
+
+ TREE_USED (block_tree) = 1;
+
+ tree bind_tree
+ = build3_loc (start_location.gcc_location (), BIND_EXPR, void_type_node,
+ BLOCK_VARS (block_tree), NULL_TREE, block_tree);
+ TREE_SIDE_EFFECTS (bind_tree) = 1;
+ return bind_tree;
+}
+
+// Add statements to a block.
+
+void
+Gcc_backend::block_add_statements (tree bind_tree,
+ const std::vector<tree> &statements)
+{
+ tree stmt_list = NULL_TREE;
+ for (std::vector<tree>::const_iterator p = statements.begin ();
+ p != statements.end (); ++p)
+ {
+ tree s = (*p);
+ if (s != error_mark_node)
+ append_to_statement_list (s, &stmt_list);
+ }
+
+ gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
+ BIND_EXPR_BODY (bind_tree) = stmt_list;
+}
+
+// This is not static because we declare it with GTY(()) in rust-c.h.
+tree rust_non_zero_struct;
+
+// Return a type corresponding to TYPE with non-zero size.
+
+tree
+Gcc_backend::non_zero_size_type (tree type)
+{
+ if (int_size_in_bytes (type) != 0)
+ return type;
+
+ switch (TREE_CODE (type))
+ {
+ case RECORD_TYPE:
+ if (TYPE_FIELDS (type) != NULL_TREE)
+ {
+ tree ns = make_node (RECORD_TYPE);
+ tree field_trees = NULL_TREE;
+ tree *pp = &field_trees;
+ for (tree field = TYPE_FIELDS (type); field != NULL_TREE;
+ field = DECL_CHAIN (field))
+ {
+ tree ft = TREE_TYPE (field);
+ if (field == TYPE_FIELDS (type))
+ ft = non_zero_size_type (ft);
+ tree f = build_decl (DECL_SOURCE_LOCATION (field), FIELD_DECL,
+ DECL_NAME (field), ft);
+ DECL_CONTEXT (f) = ns;
+ *pp = f;
+ pp = &DECL_CHAIN (f);
+ }
+ TYPE_FIELDS (ns) = field_trees;
+ layout_type (ns);
+ return ns;
+ }
+
+ if (rust_non_zero_struct == NULL_TREE)
+ {
+ type = make_node (RECORD_TYPE);
+ tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+ get_identifier ("dummy"), boolean_type_node);
+ DECL_CONTEXT (field) = type;
+ TYPE_FIELDS (type) = field;
+ layout_type (type);
+ rust_non_zero_struct = type;
+ }
+ return rust_non_zero_struct;
+
+ case ARRAY_TYPE: {
+ tree element_type = non_zero_size_type (TREE_TYPE (type));
+ return build_array_type_nelts (element_type, 1);
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+
+ gcc_unreachable ();
+}
+
+// Convert EXPR_TREE to TYPE_TREE. Sometimes the same unnamed Rust type
+// can be created multiple times and thus have multiple tree
+// representations. Make sure this does not confuse the middle-end.
+
+tree
+Gcc_backend::convert_tree (tree type_tree, tree expr_tree, Location location)
+{
+ if (type_tree == TREE_TYPE (expr_tree))
+ return expr_tree;
+
+ if (type_tree == error_mark_node || expr_tree == error_mark_node
+ || TREE_TYPE (expr_tree) == error_mark_node)
+ return error_mark_node;
+
+ if (POINTER_TYPE_P (type_tree) || INTEGRAL_TYPE_P (type_tree)
+ || SCALAR_FLOAT_TYPE_P (type_tree) || COMPLEX_FLOAT_TYPE_P (type_tree))
+ return fold_convert_loc (location.gcc_location (), type_tree, expr_tree);
+ else if (TREE_CODE (type_tree) == RECORD_TYPE
+ || TREE_CODE (type_tree) == UNION_TYPE
+ || TREE_CODE (type_tree) == ARRAY_TYPE)
+ {
+ gcc_assert (int_size_in_bytes (type_tree)
+ == int_size_in_bytes (TREE_TYPE (expr_tree)));
+ if (TYPE_MAIN_VARIANT (type_tree)
+ == TYPE_MAIN_VARIANT (TREE_TYPE (expr_tree)))
+ return fold_build1_loc (location.gcc_location (), NOP_EXPR, type_tree,
+ expr_tree);
+ return fold_build1_loc (location.gcc_location (), VIEW_CONVERT_EXPR,
+ type_tree, expr_tree);
+ }
+
+ gcc_unreachable ();
+}
+
+// Make a global variable.
+
+Bvariable *
+Gcc_backend::global_variable (const std::string &var_name,
+ const std::string &asm_name, tree type_tree,
+ bool is_external, bool is_hidden,
+ bool in_unique_section, Location location)
+{
+ if (type_tree == error_mark_node)
+ return this->error_variable ();
+
+ // The GNU linker does not like dynamic variables with zero size.
+ tree orig_type_tree = type_tree;
+ if ((is_external || !is_hidden) && int_size_in_bytes (type_tree) == 0)
+ type_tree = this->non_zero_size_type (type_tree);
+
+ tree decl = build_decl (location.gcc_location (), VAR_DECL,
+ get_identifier_from_string (var_name), type_tree);
+ if (is_external)
+ DECL_EXTERNAL (decl) = 1;
+ else
+ TREE_STATIC (decl) = 1;
+ if (!is_hidden)
+ {
+ TREE_PUBLIC (decl) = 1;
+ SET_DECL_ASSEMBLER_NAME (decl, get_identifier_from_string (asm_name));
+ }
+ else
+ {
+ SET_DECL_ASSEMBLER_NAME (decl, get_identifier_from_string (asm_name));
+ }
+
+ TREE_USED (decl) = 1;
+
+ if (in_unique_section)
+ resolve_unique_section (decl, 0, 1);
+
+ rust_preserve_from_gc (decl);
+
+ return new Bvariable (decl, orig_type_tree);
+}
+
+// Set the initial value of a global variable.
+
+void
+Gcc_backend::global_variable_set_init (Bvariable *var, tree expr_tree)
+{
+ if (expr_tree == error_mark_node)
+ return;
+ gcc_assert (TREE_CONSTANT (expr_tree));
+ tree var_decl = var->get_decl ();
+ if (var_decl == error_mark_node)
+ return;
+ DECL_INITIAL (var_decl) = expr_tree;
+
+ // If this variable goes in a unique section, it may need to go into
+ // a different one now that DECL_INITIAL is set.
+ if (symtab_node::get (var_decl)
+ && symtab_node::get (var_decl)->implicit_section)
+ {
+ set_decl_section_name (var_decl, (const char *) NULL);
+ resolve_unique_section (var_decl, compute_reloc_for_constant (expr_tree),
+ 1);
+ }
+}
+
+// Make a local variable.
+
+Bvariable *
+Gcc_backend::local_variable (tree function, const std::string &name,
+ tree type_tree, Bvariable *decl_var,
+ Location location)
+{
+ if (type_tree == error_mark_node)
+ return this->error_variable ();
+ tree decl = build_decl (location.gcc_location (), VAR_DECL,
+ get_identifier_from_string (name), type_tree);
+ DECL_CONTEXT (decl) = function;
+
+ if (decl_var != NULL)
+ {
+ DECL_HAS_VALUE_EXPR_P (decl) = 1;
+ SET_DECL_VALUE_EXPR (decl, decl_var->get_decl ());
+ }
+ rust_preserve_from_gc (decl);
+ return new Bvariable (decl);
+}
+
+// Make a function parameter variable.
+
+Bvariable *
+Gcc_backend::parameter_variable (tree function, const std::string &name,
+ tree type_tree, Location location)
+{
+ if (type_tree == error_mark_node)
+ return this->error_variable ();
+ tree decl = build_decl (location.gcc_location (), PARM_DECL,
+ get_identifier_from_string (name), type_tree);
+ DECL_CONTEXT (decl) = function;
+ DECL_ARG_TYPE (decl) = type_tree;
+
+ rust_preserve_from_gc (decl);
+ return new Bvariable (decl);
+}
+
+// Make a static chain variable.
+
+Bvariable *
+Gcc_backend::static_chain_variable (tree fndecl, const std::string &name,
+ tree type_tree, Location location)
+{
+ if (type_tree == error_mark_node)
+ return this->error_variable ();
+ tree decl = build_decl (location.gcc_location (), PARM_DECL,
+ get_identifier_from_string (name), type_tree);
+ DECL_CONTEXT (decl) = fndecl;
+ DECL_ARG_TYPE (decl) = type_tree;
+ TREE_USED (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ TREE_READONLY (decl) = 1;
+
+ struct function *f = DECL_STRUCT_FUNCTION (fndecl);
+ if (f == NULL)
+ {
+ push_struct_function (fndecl);
+ pop_cfun ();
+ f = DECL_STRUCT_FUNCTION (fndecl);
+ }
+ gcc_assert (f->static_chain_decl == NULL);
+ f->static_chain_decl = decl;
+ DECL_STATIC_CHAIN (fndecl) = 1;
+
+ rust_preserve_from_gc (decl);
+ return new Bvariable (decl);
+}
+
+// Make a temporary variable.
+
+Bvariable *
+Gcc_backend::temporary_variable (tree fndecl, tree bind_tree, tree type_tree,
+ tree init_tree, bool is_address_taken,
+ Location location, tree *pstatement)
+{
+ gcc_assert (fndecl != NULL_TREE);
+ if (type_tree == error_mark_node || init_tree == error_mark_node
+ || fndecl == error_mark_node)
+ {
+ *pstatement = error_mark_node;
+ return this->error_variable ();
+ }
+
+ tree var;
+ // We can only use create_tmp_var if the type is not addressable.
+ if (!TREE_ADDRESSABLE (type_tree))
+ {
+ if (DECL_STRUCT_FUNCTION (fndecl) == NULL)
+ push_struct_function (fndecl);
+ else
+ push_cfun (DECL_STRUCT_FUNCTION (fndecl));
+
+ var = create_tmp_var (type_tree, "RUSTTMP");
+ pop_cfun ();
+ }
+ else
+ {
+ gcc_assert (bind_tree != NULL_TREE);
+ var = build_decl (location.gcc_location (), VAR_DECL,
+ create_tmp_var_name ("RUSTTMP"), type_tree);
+ DECL_ARTIFICIAL (var) = 1;
+ DECL_IGNORED_P (var) = 1;
+ TREE_USED (var) = 1;
+ DECL_CONTEXT (var) = fndecl;
+
+ // We have to add this variable to the BLOCK and the BIND_EXPR.
+ gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
+ tree block_tree = BIND_EXPR_BLOCK (bind_tree);
+ gcc_assert (TREE_CODE (block_tree) == BLOCK);
+ DECL_CHAIN (var) = BLOCK_VARS (block_tree);
+ BLOCK_VARS (block_tree) = var;
+ BIND_EXPR_VARS (bind_tree) = BLOCK_VARS (block_tree);
+ }
+
+ if (this->type_size (type_tree) != 0 && init_tree != NULL_TREE
+ && TREE_TYPE (init_tree) != void_type_node)
+ DECL_INITIAL (var) = this->convert_tree (type_tree, init_tree, location);
+
+ if (is_address_taken)
+ TREE_ADDRESSABLE (var) = 1;
+
+ *pstatement
+ = build1_loc (location.gcc_location (), DECL_EXPR, void_type_node, var);
+
+ // For a zero sized type, don't initialize VAR with BINIT, but still
+ // evaluate BINIT for its side effects.
+ if (init_tree != NULL_TREE
+ && (this->type_size (type_tree) == 0
+ || TREE_TYPE (init_tree) == void_type_node))
+ *pstatement = this->compound_statement (init_tree, *pstatement);
+
+ return new Bvariable (var);
+}
+
+// Make a label.
+
+tree
+Gcc_backend::label (tree func_tree, const std::string &name, Location location)
+{
+ tree decl;
+ if (name.empty ())
+ {
+ if (DECL_STRUCT_FUNCTION (func_tree) == NULL)
+ push_struct_function (func_tree);
+ else
+ push_cfun (DECL_STRUCT_FUNCTION (func_tree));
+
+ decl = create_artificial_label (location.gcc_location ());
+
+ pop_cfun ();
+ }
+ else
+ {
+ tree id = get_identifier_from_string (name);
+ decl
+ = build_decl (location.gcc_location (), LABEL_DECL, id, void_type_node);
+ DECL_CONTEXT (decl) = func_tree;
+ }
+ return decl;
+}
+
+// Make a statement which defines a label.
+
+tree
+Gcc_backend::label_definition_statement (tree label)
+{
+ return fold_build1_loc (DECL_SOURCE_LOCATION (label), LABEL_EXPR,
+ void_type_node, label);
+}
+
+// Make a goto statement.
+
+tree
+Gcc_backend::goto_statement (tree label, Location location)
+{
+ return fold_build1_loc (location.gcc_location (), GOTO_EXPR, void_type_node,
+ label);
+}
+
+// Get the address of a label.
+
+tree
+Gcc_backend::label_address (tree label, Location location)
+{
+ TREE_USED (label) = 1;
+ TREE_ADDRESSABLE (label) = 1;
+ tree ret
+ = fold_convert_loc (location.gcc_location (), ptr_type_node,
+ build_fold_addr_expr_loc (location.gcc_location (),
+ label));
+ return ret;
+}
+
+// Declare or define a new function.
+
+tree
+Gcc_backend::function (tree functype, const std::string &name,
+ const std::string &asm_name, unsigned int flags,
+ Location location)
+{
+ if (functype != error_mark_node)
+ {
+ gcc_assert (FUNCTION_POINTER_TYPE_P (functype));
+ functype = TREE_TYPE (functype);
+ }
+ tree id = get_identifier_from_string (name);
+ if (functype == error_mark_node || id == error_mark_node)
+ return error_mark_node;
+
+ tree decl
+ = build_decl (location.gcc_location (), FUNCTION_DECL, id, functype);
+ if (!asm_name.empty ())
+ SET_DECL_ASSEMBLER_NAME (decl, get_identifier_from_string (asm_name));
+
+ if ((flags & function_is_declaration) != 0)
+ DECL_EXTERNAL (decl) = 1;
+ else
+ {
+ tree restype = TREE_TYPE (functype);
+ tree resdecl = build_decl (location.gcc_location (), RESULT_DECL,
+ NULL_TREE, restype);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_CONTEXT (resdecl) = decl;
+ DECL_RESULT (decl) = resdecl;
+ }
+ if ((flags & function_is_uninlinable) != 0)
+ DECL_UNINLINABLE (decl) = 1;
+ if ((flags & function_does_not_return) != 0)
+ TREE_THIS_VOLATILE (decl) = 1;
+ if ((flags & function_in_unique_section) != 0)
+ resolve_unique_section (decl, 0, 1);
+
+ rust_preserve_from_gc (decl);
+ return decl;
+}
+
+// Create a statement that runs all deferred calls for FUNCTION. This should
+// be a statement that looks like this in C++:
+// finish:
+// try { UNDEFER; } catch { CHECK_DEFER; goto finish; }
+
+tree
+Gcc_backend::function_defer_statement (tree function, tree undefer_tree,
+ tree defer_tree, Location location)
+{
+ if (undefer_tree == error_mark_node || defer_tree == error_mark_node
+ || function == error_mark_node)
+ return error_mark_node;
+
+ if (DECL_STRUCT_FUNCTION (function) == NULL)
+ push_struct_function (function);
+ else
+ push_cfun (DECL_STRUCT_FUNCTION (function));
+
+ tree stmt_list = NULL;
+ tree label = this->label (function, "", location);
+ tree label_def = this->label_definition_statement (label);
+ append_to_statement_list (label_def, &stmt_list);
+
+ tree jump_stmt = this->goto_statement (label, location);
+ tree catch_body
+ = build2 (COMPOUND_EXPR, void_type_node, defer_tree, jump_stmt);
+ catch_body = build2 (CATCH_EXPR, void_type_node, NULL, catch_body);
+ tree try_catch
+ = build2 (TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body);
+ append_to_statement_list (try_catch, &stmt_list);
+ pop_cfun ();
+
+ return stmt_list;
+}
+
+// Record PARAM_VARS as the variables to use for the parameters of FUNCTION.
+// This will only be called for a function definition.
+
+bool
+Gcc_backend::function_set_parameters (
+ tree function, const std::vector<Bvariable *> &param_vars)
+{
+ if (function == error_mark_node)
+ return false;
+
+ tree params = NULL_TREE;
+ tree *pp = &params;
+ for (std::vector<Bvariable *>::const_iterator pv = param_vars.begin ();
+ pv != param_vars.end (); ++pv)
+ {
+ *pp = (*pv)->get_decl ();
+ gcc_assert (*pp != error_mark_node);
+ pp = &DECL_CHAIN (*pp);
+ }
+ *pp = NULL_TREE;
+ DECL_ARGUMENTS (function) = params;
+ return true;
+}
+
+// Write the definitions for all TYPE_DECLS, CONSTANT_DECLS,
+// FUNCTION_DECLS, and VARIABLE_DECLS declared globally, as well as
+// emit early debugging information.
+
+void
+Gcc_backend::write_global_definitions (
+ const std::vector<tree> &type_decls, const std::vector<tree> &constant_decls,
+ const std::vector<tree> &function_decls,
+ const std::vector<Bvariable *> &variable_decls)
+{
+ size_t count_definitions = type_decls.size () + constant_decls.size ()
+ + function_decls.size () + variable_decls.size ();
+
+ tree *defs = new tree[count_definitions];
+
+ // Convert all non-erroneous declarations into Gimple form.
+ size_t i = 0;
+ for (std::vector<Bvariable *>::const_iterator p = variable_decls.begin ();
+ p != variable_decls.end (); ++p)
+ {
+ tree v = (*p)->get_decl ();
+ if (v != error_mark_node)
+ {
+ defs[i] = v;
+ rust_preserve_from_gc (defs[i]);
+ ++i;
+ }
+ }
+
+ for (std::vector<tree>::const_iterator p = type_decls.begin ();
+ p != type_decls.end (); ++p)
+ {
+ tree type_tree = (*p);
+ if (type_tree != error_mark_node && IS_TYPE_OR_DECL_P (type_tree))
+ {
+ defs[i] = TYPE_NAME (type_tree);
+ gcc_assert (defs[i] != NULL);
+ rust_preserve_from_gc (defs[i]);
+ ++i;
+ }
+ }
+ for (std::vector<tree>::const_iterator p = constant_decls.begin ();
+ p != constant_decls.end (); ++p)
+ {
+ if ((*p) != error_mark_node)
+ {
+ defs[i] = (*p);
+ rust_preserve_from_gc (defs[i]);
+ ++i;
+ }
+ }
+ for (std::vector<tree>::const_iterator p = function_decls.begin ();
+ p != function_decls.end (); ++p)
+ {
+ tree decl = (*p);
+ if (decl != error_mark_node)
+ {
+ rust_preserve_from_gc (decl);
+ if (DECL_STRUCT_FUNCTION (decl) == NULL)
+ allocate_struct_function (decl, false);
+ dump_function (TDI_original, decl);
+ cgraph_node::finalize_function (decl, true);
+
+ defs[i] = decl;
+ ++i;
+ }
+ }
+
+ // Pass everything back to the middle-end.
+
+ wrapup_global_declarations (defs, i);
+
+ delete[] defs;
+}
+
+void
+Gcc_backend::write_export_data (const char *bytes, unsigned int size)
+{
+ rust_write_export_data (bytes, size);
+}
+
+// Return the backend generator.
+
+Backend *
+rust_get_backend ()
+{
+ return new Gcc_backend ();
+}