From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-x635.google.com (mail-ej1-x635.google.com [IPv6:2a00:1450:4864:20::635]) by sourceware.org (Postfix) with ESMTPS id 5BC533858D1E; Wed, 9 Nov 2022 18:08:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 5BC533858D1E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-x635.google.com with SMTP id kt23so48950240ejc.7; Wed, 09 Nov 2022 10:08:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=AzkOMhfvp5i0NLCRnrgpIdubXMS4mdeEHJOWq78phzI=; b=XlsSIHxnl3UHjDIfA9t+6sKCdKlXk2r6qO3qXekgM7UCDN6taBUpepEoOD3QOBm/P2 2urhTaxALGKvP/kXRifNTFMpDwqXkvhpNtgrpixw7l1/+C09ZsTVe7qXVqKuU2wJsHzA KOJiHC6r+68kRROpUJGijjXMSuAw4OIVPTatydivkEs760I/iz+w5N0upBeTMFQQMfK0 ZnWpDw6Sje1cFdWb6Le9zlmkWn+u7aDUtVIWDjp2zz2+wPgjO8pOgLcZDqqD+WQq/v0h s2NxpDFrZY2bmmpr34YbA3FiU48rVMTcGUpykOEU5tDEAgpHPNzUlaz7PaJ1YfgfWrn1 JeZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=AzkOMhfvp5i0NLCRnrgpIdubXMS4mdeEHJOWq78phzI=; b=5uJeY8s5HpyJh1fUisRpVrEDyLGeeSppRCXumTu6M3SD9FNVjcPQOaTafT6vZwR8+O cEGpl0cNci6A8OSAT2JvZo4hb7bubycTPHt4OwV9/z0p/hmXUijjPqvaJAcx8BYvRYQY FPJWgx0K+ckiUZgrrMLWI4t5C/kiXRgplJzdSoxZb9vgqP5/T1EKtQFYopoMMRhongoE D838+3pd9YJw9ySPB6BN5P2TNeJBxTsDfaE0HZ57sxyaHCjic2xePZoz+nOfU75CUvIF mbMa4L7/KPMpA6R0NLva71Egh4Otvf/e+tk3hiXTM+1gLzr5dRHIhaGpGMUL8Z495eU9 Aihw== X-Gm-Message-State: ACrzQf0/S+2zSIqSS8CeMXjn3Uhk5Q2y3B+0WIi04rA4kyL//yy/0h2h v1nJ5NsuZxktcW2xwYx6CqsLzPNdjajZAFi/Fbk= X-Google-Smtp-Source: AMsMyM5hohI9vTvu/zWgrfFFbDkEnrH13dkJ6B+MP+x6eHnY/YJCx18Y7rX5zSeBiMMmIsyxkA+L95HbLuKCLWbhA/A= X-Received: by 2002:a17:906:839a:b0:78d:f308:1cd with SMTP id p26-20020a170906839a00b0078df30801cdmr1473697ejx.754.1668017278099; Wed, 09 Nov 2022 10:07:58 -0800 (PST) MIME-Version: 1.0 References: <20221026081811.602573-1-arthur.cohen@embecosm.com> <20221026081811.602573-38-arthur.cohen@embecosm.com> In-Reply-To: <20221026081811.602573-38-arthur.cohen@embecosm.com> From: Richard Biener Date: Wed, 9 Nov 2022 19:07:45 +0100 Message-ID: Subject: Re: [PATCH Rust front-end v3 37/46] gccrs: Add HIR to GCC GENERIC lowering for all nodes To: arthur.cohen@embecosm.com Cc: gcc-patches@gcc.gnu.org, gcc-rust@gcc.gnu.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-8.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Wed, Oct 26, 2022 at 10:39 AM wrote: > > From: Philip Herron > > This patch implements the lowering mentionned in the previous patch for a= ll HIR nodes. > > Co-authored-by: David Faust > --- > gcc/rust/backend/rust-compile-block.cc | 158 + > gcc/rust/backend/rust-compile-block.h | 211 ++ > gcc/rust/backend/rust-compile-expr.cc | 2764 +++++++++++++++++ > gcc/rust/backend/rust-compile-expr.h | 148 + > gcc/rust/backend/rust-compile-extern.h | 172 + > gcc/rust/backend/rust-compile-fnparam.cc | 121 + > gcc/rust/backend/rust-compile-fnparam.h | 70 + > gcc/rust/backend/rust-compile-implitem.cc | 101 + > gcc/rust/backend/rust-compile-implitem.h | 91 + > gcc/rust/backend/rust-compile-intrinsic.cc | 515 +++ > gcc/rust/backend/rust-compile-intrinsic.h | 40 + > gcc/rust/backend/rust-compile-item.cc | 206 ++ > gcc/rust/backend/rust-compile-item.h | 88 + > gcc/rust/backend/rust-compile-pattern.cc | 333 ++ > gcc/rust/backend/rust-compile-pattern.h | 95 + > gcc/rust/backend/rust-compile-resolve-path.cc | 301 ++ > gcc/rust/backend/rust-compile-resolve-path.h | 73 + > gcc/rust/backend/rust-compile-stmt.cc | 115 + > gcc/rust/backend/rust-compile-stmt.h | 69 + > .../backend/rust-compile-struct-field-expr.cc | 81 + > .../backend/rust-compile-struct-field-expr.h | 46 + > gcc/rust/backend/rust-compile-type.cc | 713 +++++ > gcc/rust/backend/rust-compile-type.h | 79 + > gcc/rust/backend/rust-compile-var-decl.h | 95 + > 24 files changed, 6685 insertions(+) > create mode 100644 gcc/rust/backend/rust-compile-block.cc > create mode 100644 gcc/rust/backend/rust-compile-block.h > create mode 100644 gcc/rust/backend/rust-compile-expr.cc > create mode 100644 gcc/rust/backend/rust-compile-expr.h > create mode 100644 gcc/rust/backend/rust-compile-extern.h > create mode 100644 gcc/rust/backend/rust-compile-fnparam.cc > create mode 100644 gcc/rust/backend/rust-compile-fnparam.h > create mode 100644 gcc/rust/backend/rust-compile-implitem.cc > create mode 100644 gcc/rust/backend/rust-compile-implitem.h > create mode 100644 gcc/rust/backend/rust-compile-intrinsic.cc > create mode 100644 gcc/rust/backend/rust-compile-intrinsic.h > create mode 100644 gcc/rust/backend/rust-compile-item.cc > create mode 100644 gcc/rust/backend/rust-compile-item.h > create mode 100644 gcc/rust/backend/rust-compile-pattern.cc > create mode 100644 gcc/rust/backend/rust-compile-pattern.h > create mode 100644 gcc/rust/backend/rust-compile-resolve-path.cc > create mode 100644 gcc/rust/backend/rust-compile-resolve-path.h > create mode 100644 gcc/rust/backend/rust-compile-stmt.cc > create mode 100644 gcc/rust/backend/rust-compile-stmt.h > create mode 100644 gcc/rust/backend/rust-compile-struct-field-expr.cc > create mode 100644 gcc/rust/backend/rust-compile-struct-field-expr.h > create mode 100644 gcc/rust/backend/rust-compile-type.cc > create mode 100644 gcc/rust/backend/rust-compile-type.h > create mode 100644 gcc/rust/backend/rust-compile-var-decl.h > > diff --git a/gcc/rust/backend/rust-compile-block.cc b/gcc/rust/backend/ru= st-compile-block.cc > new file mode 100644 > index 00000000000..99674e2d1e7 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-block.cc > @@ -0,0 +1,158 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-block.h" > +#include "rust-compile-stmt.h" > +#include "rust-compile-expr.h" > + > +namespace Rust { > +namespace Compile { > + > +CompileBlock::CompileBlock (Context *ctx, Bvariable *result) > + : HIRCompileBase (ctx), translated (nullptr), result (result) > +{} > + > +tree > +CompileBlock::compile (HIR::BlockExpr *expr, Context *ctx, Bvariable *re= sult) > +{ > + CompileBlock compiler (ctx, result); > + compiler.visit (*expr); > + return compiler.translated; > +} > + > +void > +CompileBlock::visit (HIR::BlockExpr &expr) > +{ > + fncontext fnctx =3D ctx->peek_fn (); > + tree fndecl =3D fnctx.fndecl; > + Location start_location =3D expr.get_locus (); > + Location end_location =3D expr.get_end_locus (); > + auto body_mappings =3D expr.get_mappings (); > + > + Resolver::Rib *rib =3D nullptr; > + if (!ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (),= &rib)) > + { > + rust_fatal_error (expr.get_locus (), "failed to setup locals per b= lock"); > + return; > + } > + > + std::vector locals > + =3D compile_locals_for_block (ctx, *rib, fndecl); > + > + tree enclosing_scope =3D ctx->peek_enclosing_scope (); > + tree new_block =3D ctx->get_backend ()->block (fndecl, enclosing_scope= , locals, > + start_location, end_locati= on); > + ctx->push_block (new_block); > + > + for (auto &s : expr.get_statements ()) > + { > + auto compiled_expr =3D CompileStmt::Compile (s.get (), ctx); > + if (compiled_expr !=3D nullptr) > + { > + tree s =3D convert_to_void (compiled_expr, ICV_STATEMENT); > + ctx->add_statement (s); > + } > + } > + > + if (expr.has_expr ()) > + { > + // the previous passes will ensure this is a valid return or > + // a valid trailing expression > + tree compiled_expr =3D CompileExpr::Compile (expr.expr.get (), ctx= ); > + if (compiled_expr !=3D nullptr) > + { > + if (result =3D=3D nullptr) > + { > + ctx->add_statement (compiled_expr); > + } > + else > + { > + tree result_reference =3D ctx->get_backend ()->var_expressi= on ( > + result, expr.get_final_expr ()->get_locus ()); > + > + tree assignment > + =3D ctx->get_backend ()->assignment_statement (result_ref= erence, > + compiled_exp= r, > + expr.get_loc= us ()); > + ctx->add_statement (assignment); > + } > + } > + } > + > + ctx->pop_block (); > + translated =3D new_block; > +} > + > +void > +CompileConditionalBlocks::visit (HIR::IfExpr &expr) > +{ > + fncontext fnctx =3D ctx->peek_fn (); > + tree fndecl =3D fnctx.fndecl; > + tree condition_expr =3D CompileExpr::Compile (expr.get_if_condition ()= , ctx); > + tree then_block =3D CompileBlock::compile (expr.get_if_block (), ctx, = result); > + > + translated > + =3D ctx->get_backend ()->if_statement (fndecl, condition_expr, then_= block, > + NULL, expr.get_locus ()); > +} > + > +void > +CompileConditionalBlocks::visit (HIR::IfExprConseqElse &expr) > +{ > + fncontext fnctx =3D ctx->peek_fn (); > + tree fndecl =3D fnctx.fndecl; > + tree condition_expr =3D CompileExpr::Compile (expr.get_if_condition ()= , ctx); > + tree then_block =3D CompileBlock::compile (expr.get_if_block (), ctx, = result); > + tree else_block =3D CompileBlock::compile (expr.get_else_block (), ctx= , result); > + > + translated > + =3D ctx->get_backend ()->if_statement (fndecl, condition_expr, then_= block, > + else_block, expr.get_locus ()); > +} > + > +void > +CompileConditionalBlocks::visit (HIR::IfExprConseqIf &expr) > +{ > + fncontext fnctx =3D ctx->peek_fn (); > + tree fndecl =3D fnctx.fndecl; > + tree condition_expr =3D CompileExpr::Compile (expr.get_if_condition ()= , ctx); > + tree then_block =3D CompileBlock::compile (expr.get_if_block (), ctx, = result); > + > + // else block > + std::vector locals; > + Location start_location =3D expr.get_conseq_if_expr ()->get_locus (); > + Location end_location =3D expr.get_conseq_if_expr ()->get_locus (); //= FIXME > + tree enclosing_scope =3D ctx->peek_enclosing_scope (); > + tree else_block =3D ctx->get_backend ()->block (fndecl, enclosing_scop= e, locals, > + start_location, end_locat= ion); > + ctx->push_block (else_block); > + > + tree else_stmt_decl > + =3D CompileConditionalBlocks::compile (expr.get_conseq_if_expr (), c= tx, > + result); > + ctx->add_statement (else_stmt_decl); > + > + ctx->pop_block (); > + > + translated > + =3D ctx->get_backend ()->if_statement (fndecl, condition_expr, then_= block, > + else_block, expr.get_locus ()); > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-block.h b/gcc/rust/backend/rus= t-compile-block.h > new file mode 100644 > index 00000000000..cdd17f19ca2 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-block.h > @@ -0,0 +1,211 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_BLOCK > +#define RUST_COMPILE_BLOCK > + > +#include "rust-compile-base.h" > + > +namespace Rust { > +namespace Compile { > + > +class CompileBlock : private HIRCompileBase > +{ > +public: > + static tree compile (HIR::BlockExpr *expr, Context *ctx, Bvariable *re= sult); > + > +protected: > + void visit (HIR::BlockExpr &expr); > + > +private: > + CompileBlock (Context *ctx, Bvariable *result); > + > + tree translated; > + Bvariable *result; > +}; > + > +class CompileConditionalBlocks : public HIRCompileBase, > + public HIR::HIRExpressionVisitor > +{ > +public: > + static tree compile (HIR::IfExpr *expr, Context *ctx, Bvariable *resul= t) > + { > + CompileConditionalBlocks resolver (ctx, result); > + expr->accept_vis (resolver); > + return resolver.translated; > + } > + > + void visit (HIR::IfExpr &expr) override; > + void visit (HIR::IfExprConseqElse &expr) override; > + void visit (HIR::IfExprConseqIf &expr) override; > + > + // Empty visit for unused Expression HIR nodes. > + void visit (HIR::PathInExpression &) override {} > + void visit (HIR::QualifiedPathInExpression &) override {} > + void visit (HIR::ClosureExprInner &) override {} > + void visit (HIR::ClosureExprInnerTyped &) override {} > + void visit (HIR::StructExprFieldIdentifier &) override {} > + void visit (HIR::StructExprFieldIdentifierValue &) override {} > + void visit (HIR::StructExprFieldIndexValue &) override {} > + void visit (HIR::StructExprStruct &) override {} > + void visit (HIR::StructExprStructFields &) override {} > + void visit (HIR::LiteralExpr &) override {} > + void visit (HIR::BorrowExpr &) override {} > + void visit (HIR::DereferenceExpr &) override {} > + void visit (HIR::ErrorPropagationExpr &) override {} > + void visit (HIR::NegationExpr &) override {} > + void visit (HIR::ArithmeticOrLogicalExpr &) override {} > + void visit (HIR::ComparisonExpr &) override {} > + void visit (HIR::LazyBooleanExpr &) override {} > + void visit (HIR::TypeCastExpr &) override {} > + void visit (HIR::AssignmentExpr &) override {} > + void visit (HIR::CompoundAssignmentExpr &) override {} > + void visit (HIR::GroupedExpr &) override {} > + void visit (HIR::ArrayExpr &) override {} > + void visit (HIR::ArrayIndexExpr &) override {} > + void visit (HIR::TupleExpr &) override {} > + void visit (HIR::TupleIndexExpr &) override {} > + void visit (HIR::CallExpr &) override {} > + void visit (HIR::MethodCallExpr &) override {} > + void visit (HIR::FieldAccessExpr &) override {} > + void visit (HIR::BlockExpr &) override {} > + void visit (HIR::ContinueExpr &) override {} > + void visit (HIR::BreakExpr &) override {} > + void visit (HIR::RangeFromToExpr &) override {} > + void visit (HIR::RangeFromExpr &) override {} > + void visit (HIR::RangeToExpr &) override {} > + void visit (HIR::RangeFullExpr &) override {} > + void visit (HIR::RangeFromToInclExpr &) override {} > + void visit (HIR::RangeToInclExpr &) override {} > + void visit (HIR::ReturnExpr &) override {} > + void visit (HIR::UnsafeBlockExpr &) override {} > + void visit (HIR::LoopExpr &) override {} > + void visit (HIR::WhileLoopExpr &) override {} > + void visit (HIR::WhileLetLoopExpr &) override {} > + void visit (HIR::ForLoopExpr &) override {} > + void visit (HIR::IfExprConseqIfLet &) override {} > + void visit (HIR::IfLetExpr &) override {} > + void visit (HIR::IfLetExprConseqElse &) override {} > + void visit (HIR::IfLetExprConseqIf &) override {} > + void visit (HIR::IfLetExprConseqIfLet &) override {} > + void visit (HIR::MatchExpr &) override {} > + void visit (HIR::AwaitExpr &) override {} > + void visit (HIR::AsyncBlockExpr &) override {} > + > +private: > + CompileConditionalBlocks (Context *ctx, Bvariable *result) > + : HIRCompileBase (ctx), translated (nullptr), result (result) > + {} > + > + tree translated; > + Bvariable *result; > +}; > + > +class CompileExprWithBlock : public HIRCompileBase, > + public HIR::HIRExpressionVisitor > +{ > +public: > + static tree compile (HIR::ExprWithBlock *expr, Context *ctx, > + Bvariable *result) > + { > + CompileExprWithBlock resolver (ctx, result); > + expr->accept_vis (resolver); > + return resolver.translated; > + } > + > + void visit (HIR::IfExpr &expr) override > + { > + translated =3D CompileConditionalBlocks::compile (&expr, ctx, result= ); > + } > + > + void visit (HIR::IfExprConseqElse &expr) override > + { > + translated =3D CompileConditionalBlocks::compile (&expr, ctx, result= ); > + } > + > + void visit (HIR::IfExprConseqIf &expr) override > + { > + translated =3D CompileConditionalBlocks::compile (&expr, ctx, result= ); > + } > + > + // Empty visit for unused Expression HIR nodes. > + void visit (HIR::PathInExpression &) override {} > + void visit (HIR::QualifiedPathInExpression &) override {} > + void visit (HIR::ClosureExprInner &) override {} > + void visit (HIR::ClosureExprInnerTyped &) override {} > + void visit (HIR::StructExprFieldIdentifier &) override {} > + void visit (HIR::StructExprFieldIdentifierValue &) override {} > + void visit (HIR::StructExprFieldIndexValue &) override {} > + void visit (HIR::StructExprStruct &) override {} > + void visit (HIR::StructExprStructFields &) override {} > + void visit (HIR::LiteralExpr &) override {} > + void visit (HIR::BorrowExpr &) override {} > + void visit (HIR::DereferenceExpr &) override {} > + void visit (HIR::ErrorPropagationExpr &) override {} > + void visit (HIR::NegationExpr &) override {} > + void visit (HIR::ArithmeticOrLogicalExpr &) override {} > + void visit (HIR::ComparisonExpr &) override {} > + void visit (HIR::LazyBooleanExpr &) override {} > + void visit (HIR::TypeCastExpr &) override {} > + void visit (HIR::AssignmentExpr &) override {} > + void visit (HIR::CompoundAssignmentExpr &) override {} > + void visit (HIR::GroupedExpr &) override {} > + void visit (HIR::ArrayExpr &) override {} > + void visit (HIR::ArrayIndexExpr &) override {} > + void visit (HIR::TupleExpr &) override {} > + void visit (HIR::TupleIndexExpr &) override {} > + void visit (HIR::CallExpr &) override {} > + void visit (HIR::MethodCallExpr &) override {} > + void visit (HIR::FieldAccessExpr &) override {} > + void visit (HIR::BlockExpr &) override {} > + void visit (HIR::ContinueExpr &) override {} > + void visit (HIR::BreakExpr &) override {} > + void visit (HIR::RangeFromToExpr &) override {} > + void visit (HIR::RangeFromExpr &) override {} > + void visit (HIR::RangeToExpr &) override {} > + void visit (HIR::RangeFullExpr &) override {} > + void visit (HIR::RangeFromToInclExpr &) override {} > + void visit (HIR::RangeToInclExpr &) override {} > + void visit (HIR::ReturnExpr &) override {} > + void visit (HIR::UnsafeBlockExpr &) override {} > + void visit (HIR::LoopExpr &) override {} > + void visit (HIR::WhileLoopExpr &) override {} > + void visit (HIR::WhileLetLoopExpr &) override {} > + void visit (HIR::ForLoopExpr &) override {} > + void visit (HIR::IfExprConseqIfLet &) override {} > + void visit (HIR::IfLetExpr &) override {} > + void visit (HIR::IfLetExprConseqElse &) override {} > + void visit (HIR::IfLetExprConseqIf &) override {} > + void visit (HIR::IfLetExprConseqIfLet &) override {} > + void visit (HIR::MatchExpr &) override {} > + void visit (HIR::AwaitExpr &) override {} > + void visit (HIR::AsyncBlockExpr &) override {} > + > +private: > + CompileExprWithBlock (Context *ctx, Bvariable *result) > + : HIRCompileBase (ctx), translated (nullptr), result (result) > + {} > + > + tree translated; > + Bvariable *result; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_BLOCK > diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rus= t-compile-expr.cc > new file mode 100644 > index 00000000000..865ad250f2c > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-expr.cc > @@ -0,0 +1,2764 @@ > +// 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 AN= Y > +// 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 > +// . > + > +#include "rust-compile-expr.h" > +#include "rust-compile-struct-field-expr.h" > +#include "rust-hir-trait-resolve.h" > +#include "rust-hir-path-probe.h" > +#include "rust-hir-type-bounds.h" > +#include "rust-compile-pattern.h" > +#include "rust-compile-resolve-path.h" > +#include "rust-compile-block.h" > +#include "rust-compile-implitem.h" > +#include "rust-constexpr.h" > + > +#include "fold-const.h" > +#include "realmpfr.h" > +#include "convert.h" > +#include "print-tree.h" > + > +namespace Rust { > +namespace Compile { > + > +CompileExpr::CompileExpr (Context *ctx) > + : HIRCompileBase (ctx), translated (error_mark_node) > +{} > + > +tree > +CompileExpr::Compile (HIR::Expr *expr, Context *ctx) > +{ > + CompileExpr compiler (ctx); > + expr->accept_vis (compiler); > + return compiler.translated; > +} > + > +void > +CompileExpr::visit (HIR::TupleIndexExpr &expr) > +{ > + HIR::Expr *tuple_expr =3D expr.get_tuple_expr ().get (); > + TupleIndex index =3D expr.get_tuple_index (); > + > + tree receiver_ref =3D CompileExpr::Compile (tuple_expr, ctx); > + > + TyTy::BaseType *tuple_expr_ty =3D nullptr; > + bool ok > + =3D ctx->get_tyctx ()->lookup_type (tuple_expr->get_mappings ().get_= hirid (), > + &tuple_expr_ty); > + rust_assert (ok); > + > + // do we need to add an indirect reference > + if (tuple_expr_ty->get_kind () =3D=3D TyTy::TypeKind::REF) > + { > + tree indirect =3D indirect_expression (receiver_ref, expr.get_locu= s ()); > + receiver_ref =3D indirect; > + } > + > + translated > + =3D ctx->get_backend ()->struct_field_expression (receiver_ref, inde= x, > + expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::TupleExpr &expr) > +{ > + if (expr.is_unit ()) > + { > + translated =3D ctx->get_backend ()->unit_expression (); > + return; > + } > + > + TyTy::BaseType *tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &tyty)) > + { > + rust_fatal_error (expr.get_locus (), > + "did not resolve type for this TupleExpr"); > + return; > + } > + > + tree tuple_type =3D TyTyResolveCompile::compile (ctx, tyty); > + rust_assert (tuple_type !=3D nullptr); > + > + // this assumes all fields are in order from type resolution > + std::vector vals; > + for (auto &elem : expr.get_tuple_elems ()) > + { > + auto e =3D CompileExpr::Compile (elem.get (), ctx); > + vals.push_back (e); > + } > + > + translated > + =3D ctx->get_backend ()->constructor_expression (tuple_type, false, = vals, -1, > + expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::ReturnExpr &expr) > +{ > + auto fncontext =3D ctx->peek_fn (); > + > + std::vector retstmts; > + if (expr.has_return_expr ()) > + { > + tree compiled_expr =3D CompileExpr::Compile (expr.return_expr.get = (), ctx); > + rust_assert (compiled_expr !=3D nullptr); > + > + retstmts.push_back (compiled_expr); > + } > + > + auto s =3D ctx->get_backend ()->return_statement (fncontext.fndecl, re= tstmts, > + expr.get_locus ()); > + ctx->add_statement (s); > +} > + > +void > +CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) > +{ > + auto op =3D expr.get_expr_type (); > + auto lhs =3D CompileExpr::Compile (expr.get_lhs (), ctx); > + auto rhs =3D CompileExpr::Compile (expr.get_rhs (), ctx); > + > + // this might be an operator overload situation lets check > + TyTy::FnType *fntype; > + bool is_op_overload =3D ctx->get_tyctx ()->lookup_operator_overload ( > + expr.get_mappings ().get_hirid (), &fntype); > + if (is_op_overload) > + { > + auto lang_item_type > + =3D Analysis::RustLangItem::OperatorToLangItem (expr.get_expr_typ= e ()); > + translated =3D resolve_operator_overload (lang_item_type, expr, lh= s, rhs, > + expr.get_lhs (), expr.get_r= hs ()); > + return; > + } > + > + translated > + =3D ctx->get_backend ()->arithmetic_or_logical_expression (op, lhs, = rhs, > + expr.get_loc= us ()); Hmm, so 'translated' is some global state?! I guess I'll get to some nice toplevel comment elsewhere explaining how the lowering "visit" process work= s and generates GENERIC? The corresponding header at least doesn't have that= . > +} > + > +void > +CompileExpr::visit (HIR::CompoundAssignmentExpr &expr) > +{ > + auto op =3D expr.get_expr_type (); > + auto lhs =3D CompileExpr::Compile (expr.get_left_expr ().get (), ctx); > + auto rhs =3D CompileExpr::Compile (expr.get_right_expr ().get (), ctx)= ; > + > + // this might be an operator overload situation lets check > + TyTy::FnType *fntype; > + bool is_op_overload =3D ctx->get_tyctx ()->lookup_operator_overload ( > + expr.get_mappings ().get_hirid (), &fntype); > + if (is_op_overload) > + { > + auto lang_item_type > + =3D Analysis::RustLangItem::CompoundAssignmentOperatorToLangItem = ( > + expr.get_expr_type ()); > + auto compound_assignment > + =3D resolve_operator_overload (lang_item_type, expr, lhs, rhs, > + expr.get_left_expr ().get (), > + expr.get_right_expr ().get ()); > + ctx->add_statement (compound_assignment); > + > + return; > + } > + > + auto operator_expr > + =3D ctx->get_backend ()->arithmetic_or_logical_expression (op, lhs, = rhs, > + expr.get_loc= us ()); > + tree assignment OK, so this is 'tree' - that helps. All the 'auto' stuff just makes things random gibberish to a casual reviewer :/ > + =3D ctx->get_backend ()->assignment_statement (lhs, operator_expr, > + expr.get_locus ()); > + ctx->add_statement (assignment); > +} > + > +void > +CompileExpr::visit (HIR::NegationExpr &expr) > +{ > + auto op =3D expr.get_expr_type (); > + auto negated_expr =3D CompileExpr::Compile (expr.get_expr ().get (), c= tx); > + auto location =3D expr.get_locus (); > + > + // this might be an operator overload situation lets check > + TyTy::FnType *fntype; > + bool is_op_overload =3D ctx->get_tyctx ()->lookup_operator_overload ( > + expr.get_mappings ().get_hirid (), &fntype); > + if (is_op_overload) > + { > + auto lang_item_type > + =3D Analysis::RustLangItem::NegationOperatorToLangItem (op); > + translated > + =3D resolve_operator_overload (lang_item_type, expr, negated_expr= , > + nullptr, expr.get_expr ().get (), nu= llptr); > + return; > + } > + > + translated > + =3D ctx->get_backend ()->negation_expression (op, negated_expr, loca= tion); > +} > + > +void > +CompileExpr::visit (HIR::ComparisonExpr &expr) > +{ > + auto op =3D expr.get_expr_type (); > + auto lhs =3D CompileExpr::Compile (expr.get_lhs (), ctx); > + auto rhs =3D CompileExpr::Compile (expr.get_rhs (), ctx); > + auto location =3D expr.get_locus (); > + > + translated > + =3D ctx->get_backend ()->comparison_expression (op, lhs, rhs, locati= on); > +} > + > +void > +CompileExpr::visit (HIR::LazyBooleanExpr &expr) > +{ > + auto op =3D expr.get_expr_type (); > + auto lhs =3D CompileExpr::Compile (expr.get_lhs (), ctx); > + auto rhs =3D CompileExpr::Compile (expr.get_rhs (), ctx); > + auto location =3D expr.get_locus (); > + > + translated > + =3D ctx->get_backend ()->lazy_boolean_expression (op, lhs, rhs, loca= tion); > +} > + > +void > +CompileExpr::visit (HIR::TypeCastExpr &expr) > +{ > + TyTy::BaseType *type_to_cast_to_ty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &type_to_cast_to_ty)) > + { > + translated =3D error_mark_node; > + return; > + } > + > + TyTy::BaseType *casted_tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type ( > + expr.get_casted_expr ()->get_mappings ().get_hirid (), &casted_ty= ty)) > + { > + translated =3D error_mark_node; > + return; > + } > + > + auto type_to_cast_to =3D TyTyResolveCompile::compile (ctx, type_to_cas= t_to_ty); > + auto casted_expr =3D CompileExpr::Compile (expr.get_casted_expr ().get= (), ctx); > + > + std::vector *adjustments =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_cast_autoderef_mappings ( > + expr.get_mappings ().get_hirid (), &adjustments); > + if (ok) > + { > + casted_expr > + =3D resolve_adjustements (*adjustments, casted_expr, expr.get_loc= us ()); > + } > + > + translated > + =3D type_cast_expression (type_to_cast_to, casted_expr, expr.get_loc= us ()); > +} > + > +void > +CompileExpr::visit (HIR::IfExpr &expr) > +{ > + auto stmt =3D CompileConditionalBlocks::compile (&expr, ctx, nullptr); > + ctx->add_statement (stmt); > +} > + > +void > +CompileExpr::visit (HIR::IfExprConseqElse &expr) > +{ > + TyTy::BaseType *if_type =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &if_type)) > + { > + rust_error_at (expr.get_locus (), > + "failed to lookup type of IfExprConseqElse"); > + return; > + } > + > + Bvariable *tmp =3D NULL; > + bool needs_temp =3D !if_type->is_unit (); > + if (needs_temp) > + { > + fncontext fnctx =3D ctx->peek_fn (); > + tree enclosing_scope =3D ctx->peek_enclosing_scope (); > + tree block_type =3D TyTyResolveCompile::compile (ctx, if_type); > + > + bool is_address_taken =3D false; > + tree ret_var_stmt =3D nullptr; > + tmp =3D ctx->get_backend ()->temporary_variable ( > + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken= , > + expr.get_locus (), &ret_var_stmt); > + ctx->add_statement (ret_var_stmt); > + } > + > + auto stmt =3D CompileConditionalBlocks::compile (&expr, ctx, tmp); > + ctx->add_statement (stmt); > + > + if (tmp !=3D NULL) > + { > + translated =3D ctx->get_backend ()->var_expression (tmp, expr.get_= locus ()); > + } > +} > + > +void > +CompileExpr::visit (HIR::IfExprConseqIf &expr) > +{ > + TyTy::BaseType *if_type =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &if_type)) > + { > + rust_error_at (expr.get_locus (), > + "failed to lookup type of IfExprConseqElse"); > + return; > + } > + > + Bvariable *tmp =3D NULL; > + bool needs_temp =3D !if_type->is_unit (); > + if (needs_temp) > + { > + fncontext fnctx =3D ctx->peek_fn (); > + tree enclosing_scope =3D ctx->peek_enclosing_scope (); > + tree block_type =3D TyTyResolveCompile::compile (ctx, if_type); > + > + bool is_address_taken =3D false; > + tree ret_var_stmt =3D nullptr; > + tmp =3D ctx->get_backend ()->temporary_variable ( > + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken= , > + expr.get_locus (), &ret_var_stmt); > + ctx->add_statement (ret_var_stmt); > + } > + > + auto stmt =3D CompileConditionalBlocks::compile (&expr, ctx, tmp); > + ctx->add_statement (stmt); > + > + if (tmp !=3D NULL) > + { > + translated =3D ctx->get_backend ()->var_expression (tmp, expr.get_= locus ()); > + } > +} > + > +void > +CompileExpr::visit (HIR::BlockExpr &expr) > +{ > + TyTy::BaseType *block_tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &block_tyty)) > + { > + rust_error_at (expr.get_locus (), "failed to lookup type of BlockE= xpr"); > + return; > + } > + > + Bvariable *tmp =3D NULL; > + bool needs_temp =3D !block_tyty->is_unit (); > + if (needs_temp) > + { > + fncontext fnctx =3D ctx->peek_fn (); > + tree enclosing_scope =3D ctx->peek_enclosing_scope (); > + tree block_type =3D TyTyResolveCompile::compile (ctx, block_tyty); > + > + bool is_address_taken =3D false; > + tree ret_var_stmt =3D nullptr; > + tmp =3D ctx->get_backend ()->temporary_variable ( > + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken= , > + expr.get_locus (), &ret_var_stmt); > + ctx->add_statement (ret_var_stmt); > + } > + > + auto block_stmt =3D CompileBlock::compile (&expr, ctx, tmp); > + rust_assert (TREE_CODE (block_stmt) =3D=3D BIND_EXPR); > + ctx->add_statement (block_stmt); > + > + if (tmp !=3D NULL) > + { > + translated =3D ctx->get_backend ()->var_expression (tmp, expr.get_= locus ()); > + } > +} > + > +void > +CompileExpr::visit (HIR::UnsafeBlockExpr &expr) > +{ > + expr.get_block_expr ()->accept_vis (*this); > +} > + > +void > +CompileExpr::visit (HIR::StructExprStruct &struct_expr) > +{ > + TyTy::BaseType *tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (struct_expr.get_mappings ().get_h= irid (), > + &tyty)) > + { > + rust_error_at (struct_expr.get_locus (), "unknown type"); > + return; > + } > + > + rust_assert (tyty->is_unit ()); > + translated =3D ctx->get_backend ()->unit_expression (); > +} > + > +void > +CompileExpr::visit (HIR::StructExprStructFields &struct_expr) > +{ > + TyTy::BaseType *tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (struct_expr.get_mappings ().get_h= irid (), > + &tyty)) > + { > + rust_error_at (struct_expr.get_locus (), "unknown type"); > + return; > + } > + > + // it must be an ADT > + rust_assert (tyty->get_kind () =3D=3D TyTy::TypeKind::ADT); > + TyTy::ADTType *adt =3D static_cast (tyty); > + > + // what variant is it? > + int union_disriminator =3D struct_expr.union_index; > + TyTy::VariantDef *variant =3D nullptr; > + if (!adt->is_enum ()) > + { > + rust_assert (adt->number_of_variants () =3D=3D 1); > + variant =3D adt->get_variants ().at (0); > + } > + else > + { > + HirId variant_id; > + bool ok =3D ctx->get_tyctx ()->lookup_variant_definition ( > + struct_expr.get_struct_name ().get_mappings ().get_hirid (), > + &variant_id); > + rust_assert (ok); > + > + ok > + =3D adt->lookup_variant_by_id (variant_id, &variant, &union_disri= minator); > + rust_assert (ok); > + } > + > + // compile it > + tree compiled_adt_type =3D TyTyResolveCompile::compile (ctx, tyty); > + > + std::vector arguments; > + if (adt->is_union ()) > + { > + rust_assert (struct_expr.get_fields ().size () =3D=3D 1); > + > + // assignments are coercion sites so lets convert the rvalue if > + // necessary > + auto respective_field =3D variant->get_field_at_index (union_disri= minator); > + auto expected =3D respective_field->get_field_type (); > + > + // process arguments > + auto &argument =3D struct_expr.get_fields ().at (0); > + auto lvalue_locus > + =3D ctx->get_mappings ()->lookup_location (expected->get_ty_ref (= )); > + auto rvalue_locus =3D argument->get_locus (); > + auto rvalue =3D CompileStructExprField::Compile (argument.get (), = ctx); > + > + TyTy::BaseType *actual =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type ( > + argument->get_mappings ().get_hirid (), &actual); > + > + if (ok) > + { > + rvalue > + =3D coercion_site (argument->get_mappings ().get_hirid (), rv= alue, > + actual, expected, lvalue_locus, rvalue_locus= ); > + } > + > + // add it to the list > + arguments.push_back (rvalue); > + } > + else > + { > + // this assumes all fields are in order from type resolution and i= f a > + // base struct was specified those fields are filed via accesors > + for (size_t i =3D 0; i < struct_expr.get_fields ().size (); i++) > + { > + // assignments are coercion sites so lets convert the rvalue if > + // necessary > + auto respective_field =3D variant->get_field_at_index (i); > + auto expected =3D respective_field->get_field_type (); > + > + // process arguments > + auto &argument =3D struct_expr.get_fields ().at (i); > + auto lvalue_locus > + =3D ctx->get_mappings ()->lookup_location (expected->get_ty_r= ef ()); > + auto rvalue_locus =3D argument->get_locus (); > + auto rvalue =3D CompileStructExprField::Compile (argument.get (= ), ctx); > + > + TyTy::BaseType *actual =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type ( > + argument->get_mappings ().get_hirid (), &actual); > + > + // coerce it if required/possible see > + // compile/torture/struct_base_init_1.rs > + if (ok) > + { > + rvalue > + =3D coercion_site (argument->get_mappings ().get_hirid ()= , rvalue, > + actual, expected, lvalue_locus, rvalue_l= ocus); > + } > + > + // add it to the list > + arguments.push_back (rvalue); > + } > + } > + > + // the constructor depends on whether this is actually an enum or not = if > + // its an enum we need to setup the discriminator > + std::vector ctor_arguments; > + if (adt->is_enum ()) > + { > + HIR::Expr *discrim_expr =3D variant->get_discriminant (); > + tree discrim_expr_node =3D CompileExpr::Compile (discrim_expr, ctx= ); > + tree folded_discrim_expr =3D fold_expr (discrim_expr_node); > + tree qualifier =3D folded_discrim_expr; > + > + ctor_arguments.push_back (qualifier); > + } > + for (auto &arg : arguments) > + ctor_arguments.push_back (arg); > + > + translated =3D ctx->get_backend ()->constructor_expression ( > + compiled_adt_type, adt->is_enum (), ctor_arguments, union_disriminat= or, > + struct_expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::GroupedExpr &expr) > +{ > + translated =3D CompileExpr::Compile (expr.get_expr_in_parens ().get ()= , ctx); > +} > + > +void > +CompileExpr::visit (HIR::FieldAccessExpr &expr) > +{ > + HIR::Expr *receiver_expr =3D expr.get_receiver_expr ().get (); > + tree receiver_ref =3D CompileExpr::Compile (receiver_expr, ctx); > + > + // resolve the receiver back to ADT type > + TyTy::BaseType *receiver =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type ( > + expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receive= r)) > + { > + rust_error_at (expr.get_receiver_expr ()->get_locus (), > + "unresolved type for receiver"); > + return; > + } > + > + size_t field_index =3D 0; > + if (receiver->get_kind () =3D=3D TyTy::TypeKind::ADT) > + { > + TyTy::ADTType *adt =3D static_cast (receiver); > + rust_assert (!adt->is_enum ()); > + rust_assert (adt->number_of_variants () =3D=3D 1); > + > + TyTy::VariantDef *variant =3D adt->get_variants ().at (0); > + bool ok > + =3D variant->lookup_field (expr.get_field_name (), nullptr, &fiel= d_index); > + rust_assert (ok); > + } > + else if (receiver->get_kind () =3D=3D TyTy::TypeKind::REF) > + { > + TyTy::ReferenceType *r =3D static_cast (rec= eiver); > + TyTy::BaseType *b =3D r->get_base (); > + rust_assert (b->get_kind () =3D=3D TyTy::TypeKind::ADT); > + > + TyTy::ADTType *adt =3D static_cast (b); > + rust_assert (!adt->is_enum ()); > + rust_assert (adt->number_of_variants () =3D=3D 1); > + > + TyTy::VariantDef *variant =3D adt->get_variants ().at (0); > + bool ok > + =3D variant->lookup_field (expr.get_field_name (), nullptr, &fiel= d_index); > + rust_assert (ok); > + > + tree indirect =3D indirect_expression (receiver_ref, expr.get_locu= s ()); > + receiver_ref =3D indirect; > + } > + > + translated > + =3D ctx->get_backend ()->struct_field_expression (receiver_ref, fiel= d_index, > + expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::QualifiedPathInExpression &expr) > +{ > + translated =3D ResolvePathRef::Compile (expr, ctx); > +} > + > +void > +CompileExpr::visit (HIR::PathInExpression &expr) > +{ > + translated =3D ResolvePathRef::Compile (expr, ctx); > +} > + > +void > +CompileExpr::visit (HIR::LoopExpr &expr) > +{ > + TyTy::BaseType *block_tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &block_tyty)) > + { > + rust_error_at (expr.get_locus (), "failed to lookup type of BlockE= xpr"); > + return; > + } > + > + fncontext fnctx =3D ctx->peek_fn (); > + tree enclosing_scope =3D ctx->peek_enclosing_scope (); > + tree block_type =3D TyTyResolveCompile::compile (ctx, block_tyty); > + > + bool is_address_taken =3D false; > + tree ret_var_stmt =3D NULL_TREE; > + Bvariable *tmp =3D ctx->get_backend ()->temporary_variable ( > + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, > + expr.get_locus (), &ret_var_stmt); > + ctx->add_statement (ret_var_stmt); > + ctx->push_loop_context (tmp); > + > + if (expr.has_loop_label ()) > + { > + HIR::LoopLabel &loop_label =3D expr.get_loop_label (); > + tree label > + =3D ctx->get_backend ()->label (fnctx.fndecl, > + loop_label.get_lifetime ().get_name= (), > + loop_label.get_locus ()); > + tree label_decl =3D ctx->get_backend ()->label_definition_statemen= t (label); > + ctx->add_statement (label_decl); > + ctx->insert_label_decl ( > + loop_label.get_lifetime ().get_mappings ().get_hirid (), label); > + } > + > + tree loop_begin_label > + =3D ctx->get_backend ()->label (fnctx.fndecl, "", expr.get_locus ())= ; > + tree loop_begin_label_decl > + =3D ctx->get_backend ()->label_definition_statement (loop_begin_labe= l); > + ctx->add_statement (loop_begin_label_decl); > + ctx->push_loop_begin_label (loop_begin_label); > + > + tree code_block > + =3D CompileBlock::compile (expr.get_loop_block ().get (), ctx, nullp= tr); > + tree loop_expr > + =3D ctx->get_backend ()->loop_expression (code_block, expr.get_locus= ()); > + ctx->add_statement (loop_expr); > + > + ctx->pop_loop_context (); > + translated =3D ctx->get_backend ()->var_expression (tmp, expr.get_locu= s ()); > + > + ctx->pop_loop_begin_label (); > +} > + > +void > +CompileExpr::visit (HIR::WhileLoopExpr &expr) > +{ > + fncontext fnctx =3D ctx->peek_fn (); > + if (expr.has_loop_label ()) > + { > + HIR::LoopLabel &loop_label =3D expr.get_loop_label (); > + tree label > + =3D ctx->get_backend ()->label (fnctx.fndecl, > + loop_label.get_lifetime ().get_name= (), > + loop_label.get_locus ()); > + tree label_decl =3D ctx->get_backend ()->label_definition_statemen= t (label); > + ctx->add_statement (label_decl); > + ctx->insert_label_decl ( > + loop_label.get_lifetime ().get_mappings ().get_hirid (), label); > + } > + > + std::vector locals; > + Location start_location =3D expr.get_loop_block ()->get_locus (); > + Location end_location =3D expr.get_loop_block ()->get_locus (); // FIX= ME > + > + tree enclosing_scope =3D ctx->peek_enclosing_scope (); > + tree loop_block > + =3D ctx->get_backend ()->block (fnctx.fndecl, enclosing_scope, local= s, > + start_location, end_location); > + ctx->push_block (loop_block); > + > + tree loop_begin_label > + =3D ctx->get_backend ()->label (fnctx.fndecl, "", expr.get_locus ())= ; > + tree loop_begin_label_decl > + =3D ctx->get_backend ()->label_definition_statement (loop_begin_labe= l); > + ctx->add_statement (loop_begin_label_decl); > + ctx->push_loop_begin_label (loop_begin_label); > + > + tree condition > + =3D CompileExpr::Compile (expr.get_predicate_expr ().get (), ctx); > + tree exit_expr > + =3D ctx->get_backend ()->exit_expression (condition, expr.get_locus = ()); > + ctx->add_statement (exit_expr); > + > + tree code_block_stmt > + =3D CompileBlock::compile (expr.get_loop_block ().get (), ctx, nullp= tr); > + rust_assert (TREE_CODE (code_block_stmt) =3D=3D BIND_EXPR); > + ctx->add_statement (code_block_stmt); > + > + ctx->pop_loop_begin_label (); > + ctx->pop_block (); > + > + tree loop_expr > + =3D ctx->get_backend ()->loop_expression (loop_block, expr.get_locus= ()); > + ctx->add_statement (loop_expr); > +} > + > +void > +CompileExpr::visit (HIR::BreakExpr &expr) > +{ > + if (expr.has_break_expr ()) > + { > + tree compiled_expr =3D CompileExpr::Compile (expr.get_expr ().get = (), ctx); > + > + Bvariable *loop_result_holder =3D ctx->peek_loop_context (); > + tree result_reference > + =3D ctx->get_backend ()->var_expression (loop_result_holder, > + expr.get_expr ()->get_locu= s ()); > + > + tree assignment > + =3D ctx->get_backend ()->assignment_statement (result_reference, > + compiled_expr, > + expr.get_locus ()); > + ctx->add_statement (assignment); > + } > + > + if (expr.has_label ()) > + { > + NodeId resolved_node_id =3D UNKNOWN_NODEID; > + if (!ctx->get_resolver ()->lookup_resolved_label ( > + expr.get_label ().get_mappings ().get_nodeid (), &resolved_no= de_id)) > + { > + rust_error_at ( > + expr.get_label ().get_locus (), > + "failed to resolve compiled label for label %s", > + expr.get_label ().get_mappings ().as_string ().c_str ()); > + return; > + } > + > + HirId ref =3D UNKNOWN_HIRID; > + if (!ctx->get_mappings ()->lookup_node_to_hir (resolved_node_id, &= ref)) > + { > + rust_fatal_error (expr.get_locus (), "reverse lookup label fail= ure"); > + return; > + } > + > + tree label =3D NULL_TREE; > + if (!ctx->lookup_label_decl (ref, &label)) > + { > + rust_error_at (expr.get_label ().get_locus (), > + "failed to lookup compiled label"); > + return; > + } > + > + tree goto_label > + =3D ctx->get_backend ()->goto_statement (label, expr.get_locus ()= ); > + ctx->add_statement (goto_label); > + } > + else > + { > + tree exit_expr =3D ctx->get_backend ()->exit_expression ( > + ctx->get_backend ()->boolean_constant_expression (true), > + expr.get_locus ()); So I took the chance grepping for ->exit_expression and found tree Gcc_backend::exit_expression (tree cond_tree, Location locus) { return fold_build1_loc (locus.gcc_location (), EXIT_EXPR, void_type_node, cond_tree); } I can see how it might look "nicer" to type exit_expression (...) rather than open-coding the fold_build1_loc logic but for sure this "C++ abstracti= on" is a distraction from what the code actually does. At least to me ;) The same applies to much of the ranger code as well, so it seems GCC walks in this direction ... > + ctx->add_statement (exit_expr); > + } > +} > + > +void > +CompileExpr::visit (HIR::ContinueExpr &expr) > +{ > + tree label =3D ctx->peek_loop_begin_label (); > + if (expr.has_label ()) > + { > + NodeId resolved_node_id =3D UNKNOWN_NODEID; > + if (!ctx->get_resolver ()->lookup_resolved_label ( > + expr.get_label ().get_mappings ().get_nodeid (), &resolved_no= de_id)) > + { > + rust_error_at ( > + expr.get_label ().get_locus (), > + "failed to resolve compiled label for label %s", > + expr.get_label ().get_mappings ().as_string ().c_str ()); > + return; > + } > + > + HirId ref =3D UNKNOWN_HIRID; > + if (!ctx->get_mappings ()->lookup_node_to_hir (resolved_node_id, &= ref)) > + { > + rust_fatal_error (expr.get_locus (), "reverse lookup label fail= ure"); > + return; > + } > + > + if (!ctx->lookup_label_decl (ref, &label)) > + { > + rust_error_at (expr.get_label ().get_locus (), > + "failed to lookup compiled label"); > + return; > + } > + } > + > + translated =3D ctx->get_backend ()->goto_statement (label, expr.get_lo= cus ()); > +} > + > +void > +CompileExpr::visit (HIR::BorrowExpr &expr) > +{ > + tree main_expr =3D CompileExpr::Compile (expr.get_expr ().get (), ctx)= ; > + if (SLICE_TYPE_P (TREE_TYPE (main_expr))) > + { > + translated =3D main_expr; > + return; > + } > + > + TyTy::BaseType *tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &tyty)) > + return; > + > + translated =3D address_expression (main_expr, expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::DereferenceExpr &expr) > +{ > + TyTy::BaseType *tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &tyty)) > + { > + rust_fatal_error (expr.get_locus (), > + "did not resolve type for this TupleExpr"); > + return; > + } > + > + tree main_expr =3D CompileExpr::Compile (expr.get_expr ().get (), ctx)= ; > + > + // this might be an operator overload situation lets check > + TyTy::FnType *fntype; > + bool is_op_overload =3D ctx->get_tyctx ()->lookup_operator_overload ( > + expr.get_mappings ().get_hirid (), &fntype); > + if (is_op_overload) > + { > + auto lang_item_type =3D Analysis::RustLangItem::ItemType::DEREF; > + tree operator_overload_call > + =3D resolve_operator_overload (lang_item_type, expr, main_expr, n= ullptr, > + expr.get_expr ().get (), nullptr); > + > + // rust deref always returns a reference from this overload then w= e can > + // actually do the indirection > + main_expr =3D operator_overload_call; > + } > + > + tree expected_type =3D TyTyResolveCompile::compile (ctx, tyty); > + if (SLICE_TYPE_P (TREE_TYPE (main_expr)) && SLICE_TYPE_P (expected_typ= e)) > + { > + translated =3D main_expr; > + return; > + } > + > + translated =3D indirect_expression (main_expr, expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::LiteralExpr &expr) > +{ > + TyTy::BaseType *tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &tyty)) > + return; > + > + switch (expr.get_lit_type ()) > + { > + case HIR::Literal::BOOL: > + translated =3D compile_bool_literal (expr, tyty); > + return; > + > + case HIR::Literal::INT: > + translated =3D compile_integer_literal (expr, tyty); > + return; > + > + case HIR::Literal::FLOAT: > + translated =3D compile_float_literal (expr, tyty); > + return; > + > + case HIR::Literal::CHAR: > + translated =3D compile_char_literal (expr, tyty); > + return; > + > + case HIR::Literal::BYTE: > + translated =3D compile_byte_literal (expr, tyty); > + return; > + > + case HIR::Literal::STRING: > + translated =3D compile_string_literal (expr, tyty); > + return; > + > + case HIR::Literal::BYTE_STRING: > + translated =3D compile_byte_string_literal (expr, tyty); > + return; > + } > +} > + > +void > +CompileExpr::visit (HIR::AssignmentExpr &expr) > +{ > + auto lvalue =3D CompileExpr::Compile (expr.get_lhs (), ctx); > + auto rvalue =3D CompileExpr::Compile (expr.get_rhs (), ctx); > + > + // assignments are coercion sites so lets convert the rvalue if necess= ary > + TyTy::BaseType *expected =3D nullptr; > + TyTy::BaseType *actual =3D nullptr; > + > + bool ok; > + ok =3D ctx->get_tyctx ()->lookup_type ( > + expr.get_lhs ()->get_mappings ().get_hirid (), &expected); > + rust_assert (ok); > + > + ok =3D ctx->get_tyctx ()->lookup_type ( > + expr.get_rhs ()->get_mappings ().get_hirid (), &actual); > + rust_assert (ok); > + > + rvalue =3D coercion_site (expr.get_mappings ().get_hirid (), rvalue, a= ctual, > + expected, expr.get_lhs ()->get_locus (), > + expr.get_rhs ()->get_locus ()); > + > + tree assignment > + =3D ctx->get_backend ()->assignment_statement (lvalue, rvalue, > + expr.get_locus ()); > + > + ctx->add_statement (assignment); > +} > + > +// Helper for sort_tuple_patterns. > +// Determine whether Patterns a and b are really the same pattern. > +// FIXME: This is a nasty hack to avoid properly implementing a comparis= on > +// for Patterns, which we really probably do want at some point. > +static bool > +patterns_mergeable (HIR::Pattern *a, HIR::Pattern *b) > +{ > + if (!a || !b) > + return false; > + > + HIR::Pattern::PatternType pat_type =3D a->get_pattern_type (); > + if (b->get_pattern_type () !=3D pat_type) > + return false; > + > + switch (pat_type) > + { > + case HIR::Pattern::PatternType::PATH: { > + // FIXME: this is far too naive > + HIR::PathPattern &aref =3D *static_cast (a); > + HIR::PathPattern &bref =3D *static_cast (b); > + if (aref.get_num_segments () !=3D bref.get_num_segments ()) > + return false; > + > + const auto &asegs =3D aref.get_segments (); > + const auto &bsegs =3D bref.get_segments (); > + for (size_t i =3D 0; i < asegs.size (); i++) > + { > + if (asegs[i].as_string () !=3D bsegs[i].as_string ()) > + return false; > + } > + return true; > + } > + break; > + case HIR::Pattern::PatternType::LITERAL: { > + HIR::LiteralPattern &aref =3D *static_cast= (a); > + HIR::LiteralPattern &bref =3D *static_cast= (b); > + return aref.get_literal ().is_equal (bref.get_literal ()); > + } > + break; > + case HIR::Pattern::PatternType::IDENTIFIER: { > + // TODO > + } > + break; > + case HIR::Pattern::PatternType::WILDCARD: > + return true; > + break; > + > + // TODO > + > + default:; > + } > + return false; > +} > + > +// A little container for rearranging the patterns and cases in a match > +// expression while simplifying. > +struct PatternMerge > +{ > + std::unique_ptr wildcard; > + std::vector> heads; > + std::vector> cases; > +}; > + > +// Helper for simplify_tuple_match. > +// For each tuple pattern in a given match, pull out the first elt of th= e > +// tuple and construct a new MatchCase with the remaining tuple elts as = the > +// pattern. Return a mapping from each _unique_ first tuple element to a > +// vec of cases for a new match. > +// > +// FIXME: This used to be a std::map>, but it do= esn't > +// actually work like we want - the Pattern includes an HIR ID, which is= unique > +// per Pattern object. This means we don't have a good means for compari= ng > +// Patterns. It would probably be best to actually implement a means of > +// properly comparing patterns, and then use an actual map. > +// > +static struct PatternMerge > +sort_tuple_patterns (HIR::MatchExpr &expr) > +{ > + rust_assert (expr.get_scrutinee_expr ()->get_expression_type () > + =3D=3D HIR::Expr::ExprType::Tuple); > + > + struct PatternMerge result; > + result.wildcard =3D nullptr; > + result.heads =3D std::vector> (); > + result.cases =3D std::vector> (); > + > + for (auto &match_case : expr.get_match_cases ()) > + { > + HIR::MatchArm &case_arm =3D match_case.get_arm (); > + > + // FIXME: Note we are only dealing with the first pattern in the a= rm. > + // The patterns vector in the arm might hold many patterns, which = are the > + // patterns separated by the '|' token. Rustc abstracts these as "= Or" > + // patterns, and part of its simplification process is to get rid = of them. > + // We should get rid of the ORs too, maybe here or earlier than he= re? > + auto pat =3D case_arm.get_patterns ()[0]->clone_pattern (); > + > + // Record wildcards so we can add them in inner matches. > + if (pat->get_pattern_type () =3D=3D HIR::Pattern::PatternType::WIL= DCARD) > + { > + // The *whole* pattern is a wild card (_). > + result.wildcard > + =3D std::unique_ptr (new HIR::MatchCase (matc= h_case)); > + continue; > + } > + > + rust_assert (pat->get_pattern_type () > + =3D=3D HIR::Pattern::PatternType::TUPLE); > + > + auto ref =3D *static_cast (pat.get ()); > + > + rust_assert (ref.has_tuple_pattern_items ()); > + > + auto items > + =3D HIR::TuplePattern (ref).get_items ()->clone_tuple_pattern_ite= ms (); > + if (items->get_pattern_type () > + =3D=3D HIR::TuplePatternItems::TuplePatternItemType::MULTIPLE) > + { > + auto items_ref > + =3D *static_cast (items.get= ()); > + > + // Pop the first pattern out > + auto patterns =3D std::vector> ()= ; > + auto first =3D items_ref.get_patterns ()[0]->clone_pattern (); > + for (auto p =3D items_ref.get_patterns ().begin () + 1; > + p !=3D items_ref.get_patterns ().end (); p++) > + { > + patterns.push_back ((*p)->clone_pattern ()); > + } > + > + // if there is only one pattern left, don't make a tuple out of= it > + std::unique_ptr result_pattern; > + if (patterns.size () =3D=3D 1) > + { > + result_pattern =3D std::move (patterns[0]); > + } > + else > + { > + auto new_items =3D std::unique_ptr = ( > + new HIR::TuplePatternItemsMultiple (std::move (patterns))= ); > + > + // Construct a TuplePattern from the rest of the patterns > + result_pattern =3D std::unique_ptr ( > + new HIR::TuplePattern (ref.get_pattern_mappings (), > + std::move (new_items), > + ref.get_locus ())); > + } > + > + // I don't know why we need to make foo separately here but > + // using the { new_tuple } syntax in new_arm constructor does n= ot > + // compile. > + auto foo =3D std::vector> (); > + foo.emplace_back (std::move (result_pattern)); > + HIR::MatchArm new_arm (std::move (foo), Location (), nullptr, > + AST::AttrVec ()); > + > + HIR::MatchCase new_case (match_case.get_mappings (), new_arm, > + match_case.get_expr ()->clone_expr ())= ; > + > + bool pushed =3D false; > + for (size_t i =3D 0; i < result.heads.size (); i++) > + { > + if (patterns_mergeable (result.heads[i].get (), first.get (= ))) > + { > + result.cases[i].push_back (new_case); > + pushed =3D true; > + } > + } > + > + if (!pushed) > + { > + result.heads.push_back (std::move (first)); > + result.cases.push_back ({new_case}); > + } > + } > + else /* TuplePatternItemType::RANGED */ > + { > + // FIXME > + gcc_unreachable (); > + } > + } > + > + return result; > +} > + > +// Helper for CompileExpr::visit (HIR::MatchExpr). > +// Given a MatchExpr where the scrutinee is some kind of tuple, build an > +// equivalent match where only one element of the tuple is examined at a= time. > +// This resulting match can then be lowered to a SWITCH_EXPR tree direct= ly. > +// > +// The approach is as follows: > +// 1. Split the scrutinee and each pattern into the first (head) and the > +// rest (tail). > +// 2. Build a mapping of unique pattern heads to the cases (tail and exp= r) > +// that shared that pattern head in the original match. > +// (This is the job of sort_tuple_patterns ()). > +// 3. For each unique pattern head, build a new MatchCase where the patt= ern > +// is the unique head, and the expression is a new match where: > +// - The scrutinee is the tail of the original scrutinee > +// - The cases are are those built by the mapping in step 2, i.e. the > +// tails of the patterns and the corresponing expressions from the > +// original match expression. > +// 4. Do this recursively for each inner match, until there is nothing m= ore > +// to simplify. > +// 5. Build the resulting match which scrutinizes the head of the origin= al > +// scrutinee, using the cases built in step 3. > +static HIR::MatchExpr > +simplify_tuple_match (HIR::MatchExpr &expr) > +{ > + if (expr.get_scrutinee_expr ()->get_expression_type () > + !=3D HIR::Expr::ExprType::Tuple) > + return expr; > + > + auto ref =3D *static_cast (expr.get_scrutinee_expr (= ).get ()); > + > + auto &tail =3D ref.get_tuple_elems (); > + rust_assert (tail.size () > 1); > + > + auto head =3D std::move (tail[0]); > + tail.erase (tail.begin (), tail.begin () + 1); > + > + // e.g. > + // match (tupA, tupB, tupC) { > + // (a1, b1, c1) =3D> { blk1 }, > + // (a2, b2, c2) =3D> { blk2 }, > + // (a1, b3, c3) =3D> { blk3 }, > + // } > + // tail =3D (tupB, tupC) > + // head =3D tupA > + > + // Make sure the tail is only a tuple if it consists of at least 2 ele= ments. > + std::unique_ptr remaining; > + if (tail.size () =3D=3D 1) > + remaining =3D std::move (tail[0]); > + else > + remaining =3D std::unique_ptr ( > + new HIR::TupleExpr (ref.get_mappings (), std::move (tail), > + AST::AttrVec (), ref.get_outer_attrs (), > + ref.get_locus ())); > + > + // e.g. > + // a1 -> [(b1, c1) =3D> { blk1 }, > + // (b3, c3) =3D> { blk3 }] > + // a2 -> [(b2, c2) =3D> { blk2 }] > + struct PatternMerge map =3D sort_tuple_patterns (expr); > + > + std::vector cases; > + // Construct the inner match for each unique first elt of the tuple > + // patterns > + for (size_t i =3D 0; i < map.heads.size (); i++) > + { > + auto inner_match_cases =3D map.cases[i]; > + > + // If there is a wildcard at the outer match level, then need to > + // propegate the wildcard case into *every* inner match. > + // FIXME: It is probably not correct to add this unconditionally, = what if > + // we have a pattern like (a, _, c)? Then there is already a wildc= ard in > + // the inner matches, and having two will cause two 'default:' blo= cks > + // which is an error. > + if (map.wildcard !=3D nullptr) > + { > + inner_match_cases.push_back (*(map.wildcard.get ())); > + } > + > + // match (tupB, tupC) { > + // (b1, c1) =3D> { blk1 }, > + // (b3, c3) =3D> { blk3 } > + // } > + HIR::MatchExpr inner_match (expr.get_mappings (), > + remaining->clone_expr (), inner_match_c= ases, > + AST::AttrVec (), expr.get_outer_attrs (= ), > + expr.get_locus ()); > + > + inner_match =3D simplify_tuple_match (inner_match); > + > + auto outer_arm_pat =3D std::vector> = (); > + outer_arm_pat.emplace_back (map.heads[i]->clone_pattern ()); > + > + HIR::MatchArm outer_arm (std::move (outer_arm_pat), expr.get_locus= ()); > + > + // Need to move the inner match to the heap and put it in a unique= _ptr to > + // build the actual match case of the outer expression > + // auto inner_expr =3D std::unique_ptr (new HIR::MatchE= xpr > + // (inner_match)); > + auto inner_expr =3D inner_match.clone_expr (); > + > + // a1 =3D> match (tupB, tupC) { ... } > + HIR::MatchCase outer_case (expr.get_mappings (), outer_arm, > + std::move (inner_expr)); > + > + cases.push_back (outer_case); > + } > + > + // If there was a wildcard, make sure to include it at the outer match= level > + // too. > + if (map.wildcard !=3D nullptr) > + { > + cases.push_back (*(map.wildcard.get ())); > + } > + > + // match tupA { > + // a1 =3D> match (tupB, tupC) { > + // (b1, c1) =3D> { blk1 }, > + // (b3, c3) =3D> { blk3 } > + // } > + // a2 =3D> match (tupB, tupC) { > + // (b2, c2) =3D> { blk2 } > + // } > + // } > + HIR::MatchExpr outer_match (expr.get_mappings (), std::move (head), ca= ses, > + AST::AttrVec (), expr.get_outer_attrs (), > + expr.get_locus ()); > + > + return outer_match; > +} Lots of comments above! Good! Missed them elsewhere (in what you'd probab= ly call boilerplate code) > +// Helper for CompileExpr::visit (HIR::MatchExpr). > +// Check that the scrutinee of EXPR is a valid kind of expression to mat= ch on. > +// Return the TypeKind of the scrutinee if it is valid, or TyTy::TypeKin= d::ERROR > +// if not. > +static TyTy::TypeKind > +check_match_scrutinee (HIR::MatchExpr &expr, Context *ctx) > +{ > + TyTy::BaseType *scrutinee_expr_tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type ( > + expr.get_scrutinee_expr ()->get_mappings ().get_hirid (), > + &scrutinee_expr_tyty)) > + { > + return TyTy::TypeKind::ERROR; > + } > + > + TyTy::TypeKind scrutinee_kind =3D scrutinee_expr_tyty->get_kind (); > + rust_assert ((TyTy::is_primitive_type_kind (scrutinee_kind) > + && scrutinee_kind !=3D TyTy::TypeKind::NEVER) > + || scrutinee_kind =3D=3D TyTy::TypeKind::ADT > + || scrutinee_kind =3D=3D TyTy::TypeKind::TUPLE); > + > + if (scrutinee_kind =3D=3D TyTy::TypeKind::ADT) > + { > + // this will need to change but for now the first pass implementat= ion, > + // lets assert this is the case > + TyTy::ADTType *adt =3D static_cast (scrutinee_exp= r_tyty); > + rust_assert (adt->is_enum ()); > + rust_assert (adt->number_of_variants () > 0); > + } > + else if (scrutinee_kind =3D=3D TyTy::TypeKind::FLOAT) > + { > + // FIXME: CASE_LABEL_EXPR does not support floating point types. > + // Find another way to compile these. > + rust_sorry_at (expr.get_locus (), > + "match on floating-point types is not yet supported"= ); > + } > + > + TyTy::BaseType *expr_tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &expr_tyty)) > + { > + return TyTy::TypeKind::ERROR; > + } > + > + return scrutinee_kind; > +} > + > +void > +CompileExpr::visit (HIR::MatchExpr &expr) > +{ > + // https://gcc.gnu.org/onlinedocs/gccint/Basic-Statements.html#Basic-S= tatements > + // TODO > + // SWITCH_ALL_CASES_P is true if the switch includes a default label o= r the > + // case label ranges cover all possible values of the condition expres= sion > + > + /* Switch expression. > + > + TREE_TYPE is the original type of the condition, before any > + language required type conversions. It may be NULL, in which case > + the original type and final types are assumed to be the same. > + > + Operand 0 is the expression used to perform the branch, > + Operand 1 is the body of the switch, which probably contains > + CASE_LABEL_EXPRs. It may also be NULL, in which case operand 2 > + must not be NULL. */ > + // DEFTREECODE (SWITCH_EXPR, "switch_expr", tcc_statement, 2) > + > + /* Used to represent a case label. > + > + Operand 0 is CASE_LOW. It may be NULL_TREE, in which case the labe= l > + is a 'default' label. > + Operand 1 is CASE_HIGH. If it is NULL_TREE, the label is a simple > + (one-value) case label. If it is non-NULL_TREE, the case is a ra= nge. > + Operand 2 is CASE_LABEL, which has the corresponding LABEL_DECL. > + Operand 3 is CASE_CHAIN. This operand is only used in tree-cfg.cc = to > + speed up the lookup of case labels which use a particular edge in > + the control flow graph. */ > + // DEFTREECODE (CASE_LABEL_EXPR, "case_label_expr", tcc_statement, 4) The cut&paste from tree.def can probably be removed. > + TyTy::TypeKind scrutinee_kind =3D check_match_scrutinee (expr, ctx); > + if (scrutinee_kind =3D=3D TyTy::TypeKind::ERROR) > + { > + translated =3D error_mark_node; > + return; > + } > + > + TyTy::BaseType *expr_tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &expr_tyty)) > + { > + translated =3D error_mark_node; > + return; > + } > + > + fncontext fnctx =3D ctx->peek_fn (); > + Bvariable *tmp =3D NULL; > + bool needs_temp =3D !expr_tyty->is_unit (); > + if (needs_temp) > + { > + tree enclosing_scope =3D ctx->peek_enclosing_scope (); > + tree block_type =3D TyTyResolveCompile::compile (ctx, expr_tyty); > + > + bool is_address_taken =3D false; > + tree ret_var_stmt =3D nullptr; > + tmp =3D ctx->get_backend ()->temporary_variable ( > + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken= , > + expr.get_locus (), &ret_var_stmt); > + ctx->add_statement (ret_var_stmt); > + } > + > + // lets compile the scrutinee expression > + tree match_scrutinee_expr > + =3D CompileExpr::Compile (expr.get_scrutinee_expr ().get (), ctx); > + > + tree match_scrutinee_expr_qualifier_expr; > + if (TyTy::is_primitive_type_kind (scrutinee_kind)) > + { > + match_scrutinee_expr_qualifier_expr =3D match_scrutinee_expr; > + } > + else if (scrutinee_kind =3D=3D TyTy::TypeKind::ADT) > + { > + // need to access qualifier the field, if we use QUAL_UNION_TYPE t= his > + // would be DECL_QUALIFIER i think. For now this will just access = the > + // first record field and its respective qualifier because it will= always > + // be set because this is all a big special union > + tree scrutinee_first_record_expr > + =3D ctx->get_backend ()->struct_field_expression ( > + match_scrutinee_expr, 0, expr.get_scrutinee_expr ()->get_locus = ()); > + match_scrutinee_expr_qualifier_expr > + =3D ctx->get_backend ()->struct_field_expression ( > + scrutinee_first_record_expr, 0, > + expr.get_scrutinee_expr ()->get_locus ()); > + } > + else if (scrutinee_kind =3D=3D TyTy::TypeKind::TUPLE) > + { > + // match on tuple becomes a series of nested switches, with one le= vel > + // for each element of the tuple from left to right. > + auto exprtype =3D expr.get_scrutinee_expr ()->get_expression_type = (); > + switch (exprtype) > + { > + case HIR::Expr::ExprType::Tuple: { > + // Build an equivalent expression which is nicer to lower. > + HIR::MatchExpr outer_match =3D simplify_tuple_match (expr); > + > + // We've rearranged the match into something that lowers bett= er > + // to GENERIC trees. > + // For actually doing the lowering we need to compile the mat= ch > + // we've just made. But we're half-way through compiling the > + // original one. > + // ... > + // For now, let's just replace the original with the rearrang= ed one > + // we just made, and compile that instead. What could go wron= g? :) > + // > + // FIXME: What about when we decide a temporary is needed abo= ve? > + // We might have already pushed a statement for it tha= t > + // we no longer need. Probably need to rearrange the o= rder > + // of these steps. > + expr =3D outer_match; > + > + scrutinee_kind =3D check_match_scrutinee (expr, ctx); > + if (scrutinee_kind =3D=3D TyTy::TypeKind::ERROR) > + { > + translated =3D error_mark_node; > + return; > + } > + > + // Now compile the scrutinee of the simplified match. > + // FIXME: this part is duplicated from above. > + match_scrutinee_expr > + =3D CompileExpr::Compile (expr.get_scrutinee_expr ().get ()= , ctx); > + > + if (TyTy::is_primitive_type_kind (scrutinee_kind)) > + { > + match_scrutinee_expr_qualifier_expr =3D match_scrutinee_e= xpr; > + } > + else if (scrutinee_kind =3D=3D TyTy::TypeKind::ADT) > + { > + // need to access qualifier the field, if we use QUAL_UNI= ON_TYPE > + // this would be DECL_QUALIFIER i think. For now this wil= l just > + // access the first record field and its respective quali= fier > + // because it will always be set because this is all a bi= g > + // special union > + tree scrutinee_first_record_expr > + =3D ctx->get_backend ()->struct_field_expression ( > + match_scrutinee_expr, 0, > + expr.get_scrutinee_expr ()->get_locus ()); > + match_scrutinee_expr_qualifier_expr > + =3D ctx->get_backend ()->struct_field_expression ( > + scrutinee_first_record_expr, 0, > + expr.get_scrutinee_expr ()->get_locus ()); > + } > + else > + { > + // FIXME: There are other cases, but it better not be a T= uple > + gcc_unreachable (); > + } > + } > + break; > + > + case HIR::Expr::ExprType::Path: { > + // FIXME > + gcc_unreachable (); > + } > + break; > + > + default: > + gcc_unreachable (); > + } > + } > + else > + { > + // FIXME: match on other types of expressions not yet implemented. > + gcc_unreachable (); > + } > + > + // setup the end label so the cases can exit properly > + tree fndecl =3D fnctx.fndecl; > + Location end_label_locus =3D expr.get_locus (); // FIXME > + tree end_label > + =3D ctx->get_backend ()->label (fndecl, > + "" /* empty creates an artificial label= */, > + end_label_locus); > + tree end_label_decl_statement > + =3D ctx->get_backend ()->label_definition_statement (end_label); > + > + // setup the switch-body-block > + Location start_location; // FIXME > + Location end_location; // FIXME > + tree enclosing_scope =3D ctx->peek_enclosing_scope (); > + tree switch_body_block > + =3D ctx->get_backend ()->block (fndecl, enclosing_scope, {}, start_l= ocation, > + end_location); > + ctx->push_block (switch_body_block); > + > + for (auto &kase : expr.get_match_cases ()) > + { > + // for now lets just get single pattern's working > + HIR::MatchArm &kase_arm =3D kase.get_arm (); > + rust_assert (kase_arm.get_patterns ().size () > 0); > + > + // generate implicit label > + Location arm_locus =3D kase_arm.get_locus (); > + tree case_label =3D ctx->get_backend ()->label ( > + fndecl, "" /* empty creates an artificial label */, arm_locus); > + > + // setup the bindings for the block > + for (auto &kase_pattern : kase_arm.get_patterns ()) > + { > + tree switch_kase_expr > + =3D CompilePatternCaseLabelExpr::Compile (kase_pattern.get ()= , > + case_label, ctx); > + ctx->add_statement (switch_kase_expr); > + > + CompilePatternBindings::Compile (kase_pattern.get (), > + match_scrutinee_expr, ctx); > + } > + > + // compile the expr and setup the assignment if required when tmp = !=3D NULL > + tree kase_expr_tree =3D CompileExpr::Compile (kase.get_expr ().get= (), ctx); > + if (tmp !=3D NULL) > + { > + tree result_reference > + =3D ctx->get_backend ()->var_expression (tmp, arm_locus); > + tree assignment > + =3D ctx->get_backend ()->assignment_statement (result_referen= ce, > + kase_expr_tree, > + arm_locus); > + ctx->add_statement (assignment); > + } > + > + // go to end label > + tree goto_end_label =3D build1_loc (arm_locus.gcc_location (), GOT= O_EXPR, > + void_type_node, end_label); > + ctx->add_statement (goto_end_label); > + } > + > + // setup the switch expression > + tree match_body =3D ctx->pop_block (); > + tree match_expr_stmt > + =3D build2_loc (expr.get_locus ().gcc_location (), SWITCH_EXPR, > + TREE_TYPE (match_scrutinee_expr_qualifier_expr), > + match_scrutinee_expr_qualifier_expr, match_body); > + ctx->add_statement (match_expr_stmt); > + ctx->add_statement (end_label_decl_statement); > + > + if (tmp !=3D NULL) > + { > + translated =3D ctx->get_backend ()->var_expression (tmp, expr.get_= locus ()); > + } > +} > + > +void > +CompileExpr::visit (HIR::CallExpr &expr) > +{ > + TyTy::BaseType *tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type ( > + expr.get_fnexpr ()->get_mappings ().get_hirid (), &tyty)) > + { > + rust_error_at (expr.get_locus (), "unknown type"); > + return; > + } > + > + // must be a tuple constructor > + bool is_fn =3D tyty->get_kind () =3D=3D TyTy::TypeKind::FNDEF > + || tyty->get_kind () =3D=3D TyTy::TypeKind::FNPTR; > + bool is_adt_ctor =3D !is_fn; > + if (is_adt_ctor) > + { > + rust_assert (tyty->get_kind () =3D=3D TyTy::TypeKind::ADT); > + TyTy::ADTType *adt =3D static_cast (tyty); > + tree compiled_adt_type =3D TyTyResolveCompile::compile (ctx, tyty)= ; > + > + // what variant is it? > + int union_disriminator =3D -1; > + TyTy::VariantDef *variant =3D nullptr; > + if (!adt->is_enum ()) > + { > + rust_assert (adt->number_of_variants () =3D=3D 1); > + variant =3D adt->get_variants ().at (0); > + } > + else > + { > + HirId variant_id; > + bool ok =3D ctx->get_tyctx ()->lookup_variant_definition ( > + expr.get_fnexpr ()->get_mappings ().get_hirid (), &variant_id= ); > + rust_assert (ok); > + > + ok =3D adt->lookup_variant_by_id (variant_id, &variant, > + &union_disriminator); > + rust_assert (ok); > + } > + > + // this assumes all fields are in order from type resolution and i= f a > + // base struct was specified those fields are filed via accesors > + std::vector arguments; > + for (size_t i =3D 0; i < expr.get_arguments ().size (); i++) > + { > + auto &argument =3D expr.get_arguments ().at (i); > + auto rvalue =3D CompileExpr::Compile (argument.get (), ctx); > + > + // assignments are coercion sites so lets convert the rvalue if > + // necessary > + auto respective_field =3D variant->get_field_at_index (i); > + auto expected =3D respective_field->get_field_type (); > + > + TyTy::BaseType *actual =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type ( > + argument->get_mappings ().get_hirid (), &actual); > + rust_assert (ok); > + > + // coerce it if required > + Location lvalue_locus > + =3D ctx->get_mappings ()->lookup_location (expected->get_ty_r= ef ()); > + Location rvalue_locus =3D argument->get_locus (); > + rvalue > + =3D coercion_site (argument->get_mappings ().get_hirid (), rv= alue, > + actual, expected, lvalue_locus, rvalue_locus= ); > + > + // add it to the list > + arguments.push_back (rvalue); > + } > + > + // the constructor depends on whether this is actually an enum or = not if > + // its an enum we need to setup the discriminator > + std::vector ctor_arguments; > + if (adt->is_enum ()) > + { > + HIR::Expr *discrim_expr =3D variant->get_discriminant (); > + tree discrim_expr_node =3D CompileExpr::Compile (discrim_expr, = ctx); > + tree folded_discrim_expr =3D fold_expr (discrim_expr_node); > + tree qualifier =3D folded_discrim_expr; > + > + ctor_arguments.push_back (qualifier); > + } > + for (auto &arg : arguments) > + ctor_arguments.push_back (arg); > + > + translated =3D ctx->get_backend ()->constructor_expression ( > + compiled_adt_type, adt->is_enum (), ctor_arguments, union_disrimi= nator, > + expr.get_locus ()); > + > + return; > + } > + > + auto get_parameter_tyty_at_index > + =3D [] (const TyTy::BaseType *base, size_t index, > + TyTy::BaseType **result) -> bool { > + bool is_fn =3D base->get_kind () =3D=3D TyTy::TypeKind::FNDEF > + || base->get_kind () =3D=3D TyTy::TypeKind::FNPTR; > + rust_assert (is_fn); > + > + if (base->get_kind () =3D=3D TyTy::TypeKind::FNPTR) > + { > + const TyTy::FnPtr *fn =3D static_cast (base)= ; > + *result =3D fn->param_at (index); > + > + return true; > + } > + > + const TyTy::FnType *fn =3D static_cast (base); > + auto param =3D fn->param_at (index); > + *result =3D param.second; > + > + return true; > + }; > + > + bool is_varadic =3D false; > + if (tyty->get_kind () =3D=3D TyTy::TypeKind::FNDEF) > + { > + const TyTy::FnType *fn =3D static_cast (tyty= ); > + is_varadic =3D fn->is_varadic (); > + } > + > + size_t required_num_args; > + if (tyty->get_kind () =3D=3D TyTy::TypeKind::FNDEF) > + { > + const TyTy::FnType *fn =3D static_cast (tyty= ); > + required_num_args =3D fn->num_params (); > + } > + else > + { > + const TyTy::FnPtr *fn =3D static_cast (tyty); > + required_num_args =3D fn->num_params (); > + } > + > + std::vector args; > + for (size_t i =3D 0; i < expr.get_arguments ().size (); i++) > + { > + auto &argument =3D expr.get_arguments ().at (i); > + auto rvalue =3D CompileExpr::Compile (argument.get (), ctx); > + > + if (is_varadic && i >=3D required_num_args) > + { > + args.push_back (rvalue); > + continue; > + } > + > + // assignments are coercion sites so lets convert the rvalue if > + // necessary > + bool ok; > + TyTy::BaseType *expected =3D nullptr; > + ok =3D get_parameter_tyty_at_index (tyty, i, &expected); > + rust_assert (ok); > + > + TyTy::BaseType *actual =3D nullptr; > + ok =3D ctx->get_tyctx ()->lookup_type ( > + argument->get_mappings ().get_hirid (), &actual); > + rust_assert (ok); > + > + // coerce it if required > + Location lvalue_locus > + =3D ctx->get_mappings ()->lookup_location (expected->get_ty_ref (= )); > + Location rvalue_locus =3D argument->get_locus (); > + rvalue =3D coercion_site (argument->get_mappings ().get_hirid (), = rvalue, > + actual, expected, lvalue_locus, rvalue_locu= s); > + > + // add it to the list > + args.push_back (rvalue); > + } > + > + // must be a call to a function > + auto fn_address =3D CompileExpr::Compile (expr.get_fnexpr (), ctx); > + translated =3D ctx->get_backend ()->call_expression (fn_address, args,= nullptr, > + expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::MethodCallExpr &expr) > +{ > + // method receiver > + tree self =3D CompileExpr::Compile (expr.get_receiver ().get (), ctx); > + > + // lookup the resolved name > + NodeId resolved_node_id =3D UNKNOWN_NODEID; > + if (!ctx->get_resolver ()->lookup_resolved_name ( > + expr.get_mappings ().get_nodeid (), &resolved_node_id)) > + { > + rust_error_at (expr.get_locus (), "failed to lookup resolved Metho= dCall"); > + return; > + } > + > + // reverse lookup > + HirId ref; > + if (!ctx->get_mappings ()->lookup_node_to_hir (resolved_node_id, &ref)= ) > + { > + rust_fatal_error (expr.get_locus (), "reverse lookup failure"); > + return; > + } > + > + // lookup the expected function type > + TyTy::BaseType *lookup_fntype =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type ( > + expr.get_method_name ().get_mappings ().get_hirid (), &lookup_fntype= ); > + rust_assert (ok); > + rust_assert (lookup_fntype->get_kind () =3D=3D TyTy::TypeKind::FNDEF); > + TyTy::FnType *fntype =3D static_cast (lookup_fntype); > + > + TyTy::BaseType *receiver =3D nullptr; > + ok =3D ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hi= rid (), > + &receiver); > + rust_assert (ok); > + > + bool is_dyn_dispatch > + =3D receiver->get_root ()->get_kind () =3D=3D TyTy::TypeKind::DYNAMI= C; > + bool is_generic_receiver =3D receiver->get_kind () =3D=3D TyTy::TypeKi= nd::PARAM; > + if (is_generic_receiver) > + { > + TyTy::ParamType *p =3D static_cast (receiver); > + receiver =3D p->resolve (); > + } > + > + tree fn_expr =3D error_mark_node; > + if (is_dyn_dispatch) > + { > + const TyTy::DynamicObjectType *dyn > + =3D static_cast (receiver->get_r= oot ()); > + > + std::vector arguments; > + for (auto &arg : expr.get_arguments ()) > + arguments.push_back (arg.get ()); > + > + fn_expr > + =3D get_fn_addr_from_dyn (dyn, receiver, fntype, self, expr.get_l= ocus ()); > + self =3D get_receiver_from_dyn (dyn, receiver, fntype, self, > + expr.get_locus ()); > + } > + else > + { > + // lookup compiled functions since it may have already been compil= ed > + HIR::PathExprSegment method_name =3D expr.get_method_name (); > + HIR::PathIdentSegment segment_name =3D method_name.get_segment (); > + fn_expr > + =3D resolve_method_address (fntype, ref, receiver, segment_name, > + expr.get_mappings (), expr.get_locus ()= ); > + } > + > + // lookup the autoderef mappings > + HirId autoderef_mappings_id > + =3D expr.get_receiver ()->get_mappings ().get_hirid (); > + std::vector *adjustments =3D nullptr; > + ok =3D ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mapping= s_id, > + &adjustments); > + rust_assert (ok); > + > + // apply adjustments for the fn call > + self =3D resolve_adjustements (*adjustments, self, > + expr.get_receiver ()->get_locus ()); > + > + std::vector args; > + args.push_back (self); // adjusted self > + > + // normal args > + for (size_t i =3D 0; i < expr.get_arguments ().size (); i++) > + { > + auto &argument =3D expr.get_arguments ().at (i); > + auto rvalue =3D CompileExpr::Compile (argument.get (), ctx); > + > + // assignments are coercion sites so lets convert the rvalue if > + // necessary, offset from the already adjusted implicit self > + bool ok; > + TyTy::BaseType *expected =3D fntype->param_at (i + 1).second; > + > + TyTy::BaseType *actual =3D nullptr; > + ok =3D ctx->get_tyctx ()->lookup_type ( > + argument->get_mappings ().get_hirid (), &actual); > + rust_assert (ok); > + > + // coerce it if required > + Location lvalue_locus > + =3D ctx->get_mappings ()->lookup_location (expected->get_ty_ref (= )); > + Location rvalue_locus =3D argument->get_locus (); > + rvalue =3D coercion_site (argument->get_mappings ().get_hirid (), = rvalue, > + actual, expected, lvalue_locus, rvalue_locu= s); > + > + // add it to the list > + args.push_back (rvalue); > + } > + > + translated =3D ctx->get_backend ()->call_expression (fn_expr, args, nu= llptr, > + expr.get_locus ()); > +} > + > +tree > +CompileExpr::get_fn_addr_from_dyn (const TyTy::DynamicObjectType *dyn, > + TyTy::BaseType *receiver, > + TyTy::FnType *fntype, tree receiver_re= f, > + Location expr_locus) > +{ > + size_t offs =3D 0; > + const Resolver::TraitItemReference *ref =3D nullptr; > + for (auto &bound : dyn->get_object_items ()) > + { > + const Resolver::TraitItemReference *item =3D bound.first; > + auto t =3D item->get_tyty (); > + rust_assert (t->get_kind () =3D=3D TyTy::TypeKind::FNDEF); > + auto ft =3D static_cast (t); > + > + if (ft->get_id () =3D=3D fntype->get_id ()) > + { > + ref =3D item; > + break; > + } > + offs++; > + } > + > + if (ref =3D=3D nullptr) > + return error_mark_node; > + > + // get any indirection sorted out > + if (receiver->get_kind () =3D=3D TyTy::TypeKind::REF) > + { > + tree indirect =3D indirect_expression (receiver_ref, expr_locus); > + receiver_ref =3D indirect; > + } > + > + // cast it to the correct fntype > + tree expected_fntype =3D TyTyResolveCompile::compile (ctx, fntype, tru= e); > + tree idx =3D build_int_cst (size_type_node, offs); > + > + tree vtable_ptr > + =3D ctx->get_backend ()->struct_field_expression (receiver_ref, 1, > + expr_locus); > + tree vtable_array_access =3D build4_loc (expr_locus.gcc_location (), A= RRAY_REF, > + TREE_TYPE (TREE_TYPE (vtable_ptr= )), > + vtable_ptr, idx, NULL_TREE, NULL= _TREE); > + > + tree vcall > + =3D build3_loc (expr_locus.gcc_location (), OBJ_TYPE_REF, expected_f= ntype, > + vtable_array_access, receiver_ref, idx); > + > + return vcall; > +} > + > +tree > +CompileExpr::get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn, > + TyTy::BaseType *receiver, > + TyTy::FnType *fntype, tree receiver_r= ef, > + Location expr_locus) > +{ > + // get any indirection sorted out > + if (receiver->get_kind () =3D=3D TyTy::TypeKind::REF) > + { > + tree indirect =3D indirect_expression (receiver_ref, expr_locus); > + receiver_ref =3D indirect; > + } > + > + // access the offs + 1 for the fnptr and offs=3D0 for the reciever obj > + return ctx->get_backend ()->struct_field_expression (receiver_ref, 0, > + expr_locus); > +} > + > +tree > +CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref, > + TyTy::BaseType *receiver, > + HIR::PathIdentSegment &segment, > + Analysis::NodeMapping expr_mappings, > + Location expr_locus) > +{ > + // lookup compiled functions since it may have already been compiled > + tree fn =3D NULL_TREE; > + if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn)) > + { > + return address_expression (fn, expr_locus); > + } > + > + // Now we can try and resolve the address since this might be a forwar= d > + // declared function, generic function which has not be compiled yet o= r > + // its an not yet trait bound function > + HIR::ImplItem *resolved_item > + =3D ctx->get_mappings ()->lookup_hir_implitem (ref, nullptr); > + if (resolved_item !=3D nullptr) > + { > + if (!fntype->has_subsititions_defined ()) > + return CompileInherentImplItem::Compile (resolved_item, ctx); > + > + return CompileInherentImplItem::Compile (resolved_item, ctx, fntyp= e); > + } > + > + // it might be resolved to a trait item > + HIR::TraitItem *trait_item > + =3D ctx->get_mappings ()->lookup_hir_trait_item (ref); > + HIR::Trait *trait =3D ctx->get_mappings ()->lookup_trait_item_mapping = ( > + trait_item->get_mappings ().get_hirid ()); > + > + Resolver::TraitReference *trait_ref > + =3D &Resolver::TraitReference::error_node (); > + bool ok =3D ctx->get_tyctx ()->lookup_trait_reference ( > + trait->get_mappings ().get_defid (), &trait_ref); > + rust_assert (ok); > + > + // the type resolver can only resolve type bounds to their trait > + // item so its up to us to figure out if this path should resolve > + // to an trait-impl-block-item or if it can be defaulted to the > + // trait-impl-item's definition > + > + auto root =3D receiver->get_root (); > + std::vector candidates > + =3D Resolver::PathProbeType::Probe (root, segment, true /* probe_imp= ls */, > + false /* probe_bounds */, > + true /* ignore_mandatory_trait_item= s */); > + if (candidates.size () =3D=3D 0) > + { > + // this means we are defaulting back to the trait_item if > + // possible > + Resolver::TraitItemReference *trait_item_ref =3D nullptr; > + bool ok =3D trait_ref->lookup_hir_trait_item (*trait_item, &trait_= item_ref); > + rust_assert (ok); // found > + rust_assert (trait_item_ref->is_optional ()); // has definition > + > + // FIXME Optional means it has a definition and an associated > + // block which can be a default implementation, if it does not > + // contain an implementation we should actually return > + // error_mark_node > + > + return CompileTraitItem::Compile (trait_item_ref->get_hir_trait_it= em (), > + ctx, fntype, true, expr_locus); > + } > + else > + { > + // FIXME this will be a case to return error_mark_node, there is > + // an error scenario where a Trait Foo has a method Bar, but this > + // receiver does not implement this trait or has an incompatible > + // implementation and we should just return error_mark_node > + > + rust_assert (candidates.size () =3D=3D 1); > + auto &candidate =3D candidates.at (0); > + rust_assert (candidate.is_impl_candidate ()); > + rust_assert (candidate.ty->get_kind () =3D=3D TyTy::TypeKind::FNDE= F); > + TyTy::FnType *candidate_call =3D static_cast (cand= idate.ty); > + > + HIR::ImplItem *impl_item =3D candidate.item.impl.impl_item; > + if (!candidate_call->has_subsititions_defined ()) > + return CompileInherentImplItem::Compile (impl_item, ctx); > + > + TyTy::BaseType *monomorphized =3D candidate_call; > + if (candidate_call->needs_generic_substitutions ()) > + { > + TyTy::BaseType *infer_impl_call > + =3D candidate_call->infer_substitions (expr_locus); > + monomorphized =3D infer_impl_call->unify (fntype); > + } > + > + return CompileInherentImplItem::Compile (impl_item, ctx, monomorph= ized); > + } > +} > + > +tree > +CompileExpr::resolve_operator_overload ( > + Analysis::RustLangItem::ItemType lang_item_type, HIR::OperatorExprMeta= expr, > + tree lhs, tree rhs, HIR::Expr *lhs_expr, HIR::Expr *rhs_expr) > +{ > + TyTy::FnType *fntype; > + bool is_op_overload =3D ctx->get_tyctx ()->lookup_operator_overload ( > + expr.get_mappings ().get_hirid (), &fntype); > + rust_assert (is_op_overload); > + > + // lookup the resolved name > + NodeId resolved_node_id =3D UNKNOWN_NODEID; > + bool ok =3D ctx->get_resolver ()->lookup_resolved_name ( > + expr.get_mappings ().get_nodeid (), &resolved_node_id); > + rust_assert (ok); > + > + // reverse lookup > + HirId ref; > + ok =3D ctx->get_mappings ()->lookup_node_to_hir (resolved_node_id, &re= f); > + rust_assert (ok); > + > + TyTy::BaseType *receiver =3D nullptr; > + ok =3D ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hi= rid (), > + &receiver); > + rust_assert (ok); > + > + bool is_generic_receiver =3D receiver->get_kind () =3D=3D TyTy::TypeKi= nd::PARAM; > + if (is_generic_receiver) > + { > + TyTy::ParamType *p =3D static_cast (receiver); > + receiver =3D p->resolve (); > + } > + > + // lookup compiled functions since it may have already been compiled > + HIR::PathIdentSegment segment_name ( > + Analysis::RustLangItem::ToString (lang_item_type)); > + tree fn_expr > + =3D resolve_method_address (fntype, ref, receiver, segment_name, > + expr.get_mappings (), expr.get_locus ()); > + > + // lookup the autoderef mappings > + std::vector *adjustments =3D nullptr; > + ok =3D ctx->get_tyctx ()->lookup_autoderef_mappings ( > + expr.get_lvalue_mappings ().get_hirid (), &adjustments); > + rust_assert (ok); > + > + // apply adjustments for the fn call > + tree self =3D resolve_adjustements (*adjustments, lhs, lhs_expr->get_l= ocus ()); > + > + std::vector args; > + args.push_back (self); // adjusted self > + if (rhs !=3D nullptr) // can be null for negation_expr (unary ones) > + args.push_back (rhs); > + > + return ctx->get_backend ()->call_expression (fn_expr, args, nullptr, > + expr.get_locus ()); > +} > + > +tree > +CompileExpr::compile_bool_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty) > +{ > + rust_assert (expr.get_lit_type () =3D=3D HIR::Literal::BOOL); > + > + const auto literal_value =3D expr.get_literal (); > + bool bval =3D literal_value.as_string ().compare ("true") =3D=3D 0; > + return ctx->get_backend ()->boolean_constant_expression (bval); > +} > + > +tree > +CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty) > +{ > + rust_assert (expr.get_lit_type () =3D=3D HIR::Literal::INT); > + const auto literal_value =3D expr.get_literal (); > + > + tree type =3D TyTyResolveCompile::compile (ctx, tyty); > + > + mpz_t ival; > + if (mpz_init_set_str (ival, literal_value.as_string ().c_str (), 10) != =3D 0) > + { > + rust_error_at (expr.get_locus (), "bad number in literal"); > + return error_mark_node; > + } > + > + mpz_t type_min; > + mpz_t type_max; > + mpz_init (type_min); > + mpz_init (type_max); > + get_type_static_bounds (type, type_min, type_max); > + > + if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0) > + { > + rust_error_at (expr.get_locus (), > + "integer overflows the respective type %<%s%>", > + tyty->get_name ().c_str ()); > + return error_mark_node; > + } > + return double_int_to_tree (type, mpz_get_double_int (type, ival, true)= ); Instead of double_int_to_tree you maybe want the more modern wide_int_to_tree (type, wi::from_mpz (...)) since double-int.h is supposed to die (only fixed-point stuff uses it). I think you leak mpz_t here, you need to call mpz_clear on all mpz_t typed vars when done. > +} > + > +tree > +CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty) > +{ > + rust_assert (expr.get_lit_type () =3D=3D HIR::Literal::FLOAT); > + const auto literal_value =3D expr.get_literal (); > + > + mpfr_t fval; > + if (mpfr_init_set_str (fval, literal_value.as_string ().c_str (), 10, > + MPFR_RNDN) > + !=3D 0) > + { > + rust_error_at (expr.get_locus (), "bad number in literal"); > + return error_mark_node; > + } > + > + tree type =3D TyTyResolveCompile::compile (ctx, tyty); > + > + // taken from: > + // see go/gofrontend/expressions.cc:check_float_type > + mpfr_exp_t exp =3D mpfr_get_exp (fval); > + bool real_value_overflow =3D exp > TYPE_PRECISION (type); > + > + REAL_VALUE_TYPE r1; > + real_from_mpfr (&r1, fval, type, GMP_RNDN); > + REAL_VALUE_TYPE r2; > + real_convert (&r2, TYPE_MODE (type), &r1); > + > + tree real_value =3D build_real (type, r2); > + if (TREE_OVERFLOW (real_value) || real_value_overflow) > + { > + rust_error_at (expr.get_locus (), > + "decimal overflows the respective type %<%s%>", > + tyty->get_name ().c_str ()); > + return error_mark_node; > + } > + > + return real_value; again you probably leak memory of 'exp' > +} > + > +tree > +CompileExpr::compile_char_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty) > +{ > + rust_assert (expr.get_lit_type () =3D=3D HIR::Literal::CHAR); > + const auto literal_value =3D expr.get_literal (); > + > + // FIXME needs wchar_t > + char c =3D literal_value.as_string ().c_str ()[0]; > + return ctx->get_backend ()->wchar_constant_expression (c); > +} > + > +tree > +CompileExpr::compile_byte_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty) > +{ > + rust_assert (expr.get_lit_type () =3D=3D HIR::Literal::BYTE); > + const auto literal_value =3D expr.get_literal (); > + > + tree type =3D TyTyResolveCompile::compile (ctx, tyty); > + char c =3D literal_value.as_string ().c_str ()[0]; > + return build_int_cst (type, c); > +} > + > +tree > +CompileExpr::compile_string_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty) > +{ > + tree fat_pointer =3D TyTyResolveCompile::compile (ctx, tyty); > + > + rust_assert (expr.get_lit_type () =3D=3D HIR::Literal::STRING); > + const auto literal_value =3D expr.get_literal (); > + > + auto base =3D ctx->get_backend ()->string_constant_expression ( > + literal_value.as_string ()); > + tree data =3D address_expression (base, expr.get_locus ()); > + > + TyTy::BaseType *usize =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_builtin ("usize", &usize); > + rust_assert (ok); > + tree type =3D TyTyResolveCompile::compile (ctx, usize); > + > + mpz_t ival; > + mpz_init_set_ui (ival, literal_value.as_string ().size ()); > + tree size =3D double_int_to_tree (type, mpz_get_double_int (type, ival= , true)); Since size() is likely at most uint64_t a simple build_int_cstu (type, size= ()) might suffice, without the round-trip through mpz_t and double-int? > + > + return ctx->get_backend ()->constructor_expression (fat_pointer, false= , > + {data, size}, -1, > + expr.get_locus ()); > +} > + > +tree > +CompileExpr::compile_byte_string_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty) > +{ > + rust_assert (expr.get_lit_type () =3D=3D HIR::Literal::BYTE_STRING); > + > + // the type here is &[ty; capacity] > + rust_assert (tyty->get_kind () =3D=3D TyTy::TypeKind::REF); > + const auto ref_tyty =3D static_cast (tyty= ); > + auto base_tyty =3D ref_tyty->get_base (); > + rust_assert (base_tyty->get_kind () =3D=3D TyTy::TypeKind::ARRAY); > + auto array_tyty =3D static_cast (base_tyty); > + > + std::string value_str =3D expr.get_literal ().as_string (); > + std::vector vals; > + std::vector indexes; > + for (size_t i =3D 0; i < value_str.size (); i++) > + { > + char b =3D value_str.at (i); > + tree bb =3D ctx->get_backend ()->char_constant_expression (b); > + vals.push_back (bb); > + indexes.push_back (i); > + } > + > + tree array_type =3D TyTyResolveCompile::compile (ctx, array_tyty); > + tree constructed > + =3D ctx->get_backend ()->array_constructor_expression (array_type, i= ndexes, > + vals, > + expr.get_locus (= )); > + > + return address_expression (constructed, expr.get_locus ()); > +} > + > +tree > +CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree, > + Location location) > +{ > + if (type_to_cast_to =3D=3D error_mark_node || expr_tree =3D=3D error_m= ark_node > + || TREE_TYPE (expr_tree) =3D=3D error_mark_node) > + return error_mark_node; > + > + if (ctx->get_backend ()->type_size (type_to_cast_to) =3D=3D 0 > + || TREE_TYPE (expr_tree) =3D=3D void_type_node) > + { > + // Do not convert zero-sized types. > + return expr_tree; > + } > + else if (TREE_CODE (type_to_cast_to) =3D=3D INTEGER_TYPE) > + { > + tree cast =3D fold (convert_to_integer (type_to_cast_to, expr_tree= )); I think all the convert_to_* functions fold the result already > + // FIXME check for TREE_OVERFLOW? > + return cast; > + } > + else if (TREE_CODE (type_to_cast_to) =3D=3D REAL_TYPE) > + { > + tree cast =3D fold (convert_to_real (type_to_cast_to, expr_tree)); > + // FIXME > + // We might need to check that the tree is MAX val and thusly satu= rate it > + // to inf. we can get the bounds and check the value if its >=3D o= r <=3D to > + // the min and max bounds > + // > + // https://github.com/Rust-GCC/gccrs/issues/635 > + return cast; > + } > + else if (TREE_CODE (type_to_cast_to) =3D=3D COMPLEX_TYPE) > + { > + return fold (convert_to_complex (type_to_cast_to, expr_tree)); > + } > + else if (TREE_CODE (type_to_cast_to) =3D=3D POINTER_TYPE > + && TREE_CODE (TREE_TYPE (expr_tree)) =3D=3D INTEGER_TYPE) > + { > + return fold (convert_to_pointer (type_to_cast_to, expr_tree)); > + } > + else if (TREE_CODE (type_to_cast_to) =3D=3D RECORD_TYPE > + || TREE_CODE (type_to_cast_to) =3D=3D ARRAY_TYPE) > + { > + return fold_build1_loc (location.gcc_location (), VIEW_CONVERT_EXP= R, > + type_to_cast_to, expr_tree); > + } > + else if (TREE_CODE (type_to_cast_to) =3D=3D POINTER_TYPE > + && SLICE_TYPE_P (TREE_TYPE (expr_tree))) > + { > + // returning a raw cast using NOP_EXPR seems to resut in an ICE: > + // > + // Analyzing compilation unit > + // Performing interprocedural optimizations > + // <*free_lang_data> {heap 2644k} {heap 2644k} > + // {heap 2644k} {heap 2644k= }during > + // GIMPLE pass: cddce > + // In function =E2=80=98*T::as_ptr=E2=80=99: > + // rust1: internal compiler error: in propagate_necessity, at > + // tree-ssa-dce.cc:984 0x1d5b43e propagate_necessity > + // ../../gccrs/gcc/tree-ssa-dce.cc:984 > + // 0x1d5e180 perform_tree_ssa_dce > + // ../../gccrs/gcc/tree-ssa-dce.cc:1876 > + // 0x1d5e2c8 tree_ssa_cd_dce > + // ../../gccrs/gcc/tree-ssa-dce.cc:1920 > + // 0x1d5e49a execute > + // ../../gccrs/gcc/tree-ssa-dce.cc:1992 > + > + // this is returning the direct raw pointer of the slice an assume= s a very > + // specific layout > + return ctx->get_backend ()->struct_field_expression (expr_tree, 0, > + location); > + } > + > + return fold_convert_loc (location.gcc_location (), type_to_cast_to, > + expr_tree); > +} > + > +void > +CompileExpr::visit (HIR::ArrayExpr &expr) > +{ > + TyTy::BaseType *tyty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid ()= , > + &tyty)) > + { > + rust_fatal_error (expr.get_locus (), > + "did not resolve type for this array expr"); > + return; > + } > + > + tree array_type =3D TyTyResolveCompile::compile (ctx, tyty); > + if (TREE_CODE (array_type) !=3D ARRAY_TYPE) > + { > + translated =3D error_mark_node; > + return; > + } > + > + rust_assert (tyty->get_kind () =3D=3D TyTy::TypeKind::ARRAY); > + const TyTy::ArrayType &array_tyty > + =3D static_cast (*tyty); > + > + HIR::ArrayElems &elements =3D *expr.get_internal_elements (); > + switch (elements.get_array_expr_type ()) > + { > + case HIR::ArrayElems::ArrayExprType::VALUES: { > + HIR::ArrayElemsValues &elems > + =3D static_cast (elements); > + translated > + =3D array_value_expr (expr.get_locus (), array_tyty, array_type= , elems); > + } > + return; > + > + case HIR::ArrayElems::ArrayExprType::COPIED: > + HIR::ArrayElemsCopied &elems > + =3D static_cast (elements); > + translated > + =3D array_copied_expr (expr.get_locus (), array_tyty, array_type,= elems); > + } > +} > + > +tree > +CompileExpr::array_value_expr (Location expr_locus, > + const TyTy::ArrayType &array_tyty, > + tree array_type, HIR::ArrayElemsValues &el= ems) > +{ > + std::vector indexes; > + std::vector constructor; > + size_t i =3D 0; > + for (auto &elem : elems.get_values ()) > + { > + tree translated_expr =3D CompileExpr::Compile (elem.get (), ctx); > + constructor.push_back (translated_expr); > + indexes.push_back (i++); > + } > + > + return ctx->get_backend ()->array_constructor_expression (array_type, = indexes, > + constructor, > + expr_locus); > +} > + > +tree > +CompileExpr::array_copied_expr (Location expr_locus, > + const TyTy::ArrayType &array_tyty, > + tree array_type, HIR::ArrayElemsCopied &e= lems) > +{ > + // see gcc/cp/typeck2.cc:1369-1401 > + gcc_assert (TREE_CODE (array_type) =3D=3D ARRAY_TYPE); > + tree domain =3D TYPE_DOMAIN (array_type); > + if (!domain) > + return error_mark_node; > + > + if (!TREE_CONSTANT (TYPE_MAX_VALUE (domain))) > + { > + rust_error_at (expr_locus, "non const capacity domain %qT", array_= type); > + return error_mark_node; > + } > + > + tree capacity_expr =3D CompileExpr::Compile (elems.get_num_copies_expr= (), ctx); > + if (!TREE_CONSTANT (capacity_expr)) > + { > + rust_error_at (expr_locus, "non const num copies %qT", array_type)= ; > + return error_mark_node; > + } > + > + // get the compiled value > + tree translated_expr =3D CompileExpr::Compile (elems.get_elem_to_copy = (), ctx); > + > + tree max_domain =3D TYPE_MAX_VALUE (domain); > + tree min_domain =3D TYPE_MIN_VALUE (domain); > + > + auto max =3D wi::to_offset (max_domain); > + auto min =3D wi::to_offset (min_domain); As said in the other review TREE_CONSTANT isn't enough to ensure this works > + auto precision =3D TYPE_PRECISION (TREE_TYPE (domain)); > + auto sign =3D TYPE_SIGN (TREE_TYPE (domain)); > + unsigned HOST_WIDE_INT len > + =3D wi::ext (max - min + 1, precision, sign).to_uhwi (); > + > + // In a const context we must initialize the entire array, which entai= ls > + // allocating for each element. If the user wants a huge array, we wil= l OOM > + // and die horribly. > + if (ctx->const_context_p ()) > + { > + size_t idx =3D 0; > + std::vector indexes; > + std::vector constructor; > + for (unsigned HOST_WIDE_INT i =3D 0; i < len; i++) > + { > + constructor.push_back (translated_expr); > + indexes.push_back (idx++); > + } > + > + return ctx->get_backend ()->array_constructor_expression (array_ty= pe, > + indexes, > + construct= or, > + expr_locu= s); > + } > + > + else > + { > + // Create a new block scope in which to initialize the array > + tree fndecl =3D NULL_TREE; > + if (ctx->in_fn ()) > + fndecl =3D ctx->peek_fn ().fndecl; > + > + std::vector locals; > + tree enclosing_scope =3D ctx->peek_enclosing_scope (); > + tree init_block > + =3D ctx->get_backend ()->block (fndecl, enclosing_scope, locals, > + expr_locus, expr_locus); > + ctx->push_block (init_block); > + > + tree tmp; > + tree stmts > + =3D ctx->get_backend ()->array_initializer (fndecl, init_block, > + array_type, capacity_ex= pr, > + translated_expr, &tmp, > + expr_locus); > + ctx->add_statement (stmts); > + > + tree block =3D ctx->pop_block (); > + > + // The result is a compound expression which creates a temporary a= rray, > + // initializes all the elements in a loop, and then yeilds the arr= ay. > + return ctx->get_backend ()->compound_expression (block, tmp, expr_= locus); > + } > +} > + > +tree > +HIRCompileBase::resolve_adjustements ( > + std::vector &adjustments, tree expression, > + Location locus) > +{ > + tree e =3D expression; > + for (auto &adjustment : adjustments) > + { > + switch (adjustment.get_type ()) > + { > + case Resolver::Adjustment::AdjustmentType::ERROR: > + return error_mark_node; > + > + case Resolver::Adjustment::AdjustmentType::IMM_REF: > + case Resolver::Adjustment::AdjustmentType::MUT_REF: { > + if (!SLICE_TYPE_P (TREE_TYPE (e))) > + { > + e =3D address_expression (e, locus); > + } > + } > + break; > + > + case Resolver::Adjustment::AdjustmentType::DEREF: > + case Resolver::Adjustment::AdjustmentType::DEREF_MUT: > + e =3D resolve_deref_adjustment (adjustment, e, locus); > + break; > + > + case Resolver::Adjustment::AdjustmentType::INDIRECTION: > + e =3D resolve_indirection_adjustment (adjustment, e, locus); > + break; > + > + case Resolver::Adjustment::AdjustmentType::UNSIZE: > + e =3D resolve_unsized_adjustment (adjustment, e, locus); > + break; > + } > + } > + > + return e; > +} > + > +tree > +HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustme= nt, > + tree expression, Location locus= ) > +{ > + rust_assert (adjustment.is_deref_adjustment () > + || adjustment.is_deref_mut_adjustment ()); > + rust_assert (adjustment.has_operator_overload ()); > + > + TyTy::FnType *lookup =3D adjustment.get_deref_operator_fn (); > + HIR::ImplItem *resolved_item =3D adjustment.get_deref_hir_item (); > + > + tree fn_address =3D error_mark_node; > + if (!lookup->has_subsititions_defined ()) > + fn_address =3D CompileInherentImplItem::Compile (resolved_item, ctx,= nullptr, > + true, locus); > + else > + fn_address =3D CompileInherentImplItem::Compile (resolved_item, ctx,= lookup, > + true, locus); > + > + // does it need a reference to call > + tree adjusted_argument =3D expression; > + bool needs_borrow =3D adjustment.get_deref_adjustment_type () > + !=3D Resolver::Adjustment::AdjustmentType::ERROR; > + if (needs_borrow) > + { > + adjusted_argument =3D address_expression (expression, locus); > + } > + > + // make the call > + return ctx->get_backend ()->call_expression (fn_address, {adjusted_arg= ument}, > + nullptr, locus); > +} > + > +tree > +HIRCompileBase::resolve_indirection_adjustment ( > + Resolver::Adjustment &adjustment, tree expression, Location locus) > +{ > + return indirect_expression (expression, locus); > +} > + > +tree > +HIRCompileBase::resolve_unsized_adjustment (Resolver::Adjustment &adjust= ment, > + tree expression, Location loc= us) > +{ > + bool expect_slice > + =3D adjustment.get_expected ()->get_kind () =3D=3D TyTy::TypeKind::S= LICE; > + bool expect_dyn > + =3D adjustment.get_expected ()->get_kind () =3D=3D TyTy::TypeKind::D= YNAMIC; > + > + // assumes this is an array > + tree expr_type =3D TREE_TYPE (expression); > + if (expect_slice) > + { > + rust_assert (TREE_CODE (expr_type) =3D=3D ARRAY_TYPE); > + return resolve_unsized_slice_adjustment (adjustment, expression, l= ocus); > + } > + > + rust_assert (expect_dyn); > + return resolve_unsized_dyn_adjustment (adjustment, expression, locus); > +} > + > +tree > +HIRCompileBase::resolve_unsized_slice_adjustment ( > + Resolver::Adjustment &adjustment, tree expression, Location locus) > +{ > + // assumes this is an array > + tree expr_type =3D TREE_TYPE (expression); > + rust_assert (TREE_CODE (expr_type) =3D=3D ARRAY_TYPE); > + > + // takes an array and returns a fat-pointer so this becomes a construc= tor > + // expression > + rust_assert (adjustment.get_expected ()->get_kind () > + =3D=3D TyTy::TypeKind::SLICE); > + tree fat_pointer > + =3D TyTyResolveCompile::compile (ctx, adjustment.get_expected ()); > + > + // make a constructor for this > + tree data =3D address_expression (expression, locus); > + > + // fetch the size from the domain > + tree domain =3D TYPE_DOMAIN (expr_type); > + unsigned HOST_WIDE_INT array_size > + =3D wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain)) > + - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1, > + TYPE_PRECISION (TREE_TYPE (domain)), > + TYPE_SIGN (TREE_TYPE (domain))) > + .to_uhwi (); see that other review > + tree size =3D build_int_cst (size_type_node, array_size); build_int_cstu > + > + return ctx->get_backend ()->constructor_expression (fat_pointer, false= , > + {data, size}, -1, l= ocus); > +} > + > +tree > +HIRCompileBase::resolve_unsized_dyn_adjustment ( > + Resolver::Adjustment &adjustment, tree expression, Location locus) > +{ > + tree rvalue =3D expression; > + Location rvalue_locus =3D locus; > + > + const TyTy::BaseType *actual =3D adjustment.get_actual (); > + const TyTy::BaseType *expected =3D adjustment.get_expected (); > + > + const TyTy::DynamicObjectType *dyn > + =3D static_cast (expected); > + > + rust_debug ("resolve_unsized_dyn_adjustment actual=3D{%s} dyn=3D{%s}", > + actual->debug_str ().c_str (), dyn->debug_str ().c_str ()); > + > + return coerce_to_dyn_object (rvalue, actual, dyn, rvalue_locus); > +} > + > +void > +CompileExpr::visit (HIR::RangeFromToExpr &expr) > +{ > + tree from =3D CompileExpr::Compile (expr.get_from_expr ().get (), ctx)= ; > + tree to =3D CompileExpr::Compile (expr.get_to_expr ().get (), ctx); > + if (from =3D=3D error_mark_node || to =3D=3D error_mark_node) > + { > + translated =3D error_mark_node; > + return; > + } > + > + TyTy::BaseType *tyty =3D nullptr; > + bool ok > + =3D ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (= ), &tyty); > + rust_assert (ok); > + > + tree adt =3D TyTyResolveCompile::compile (ctx, tyty); > + > + // make the constructor > + translated > + =3D ctx->get_backend ()->constructor_expression (adt, false, {from, = to}, -1, > + expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::RangeFromExpr &expr) > +{ > + tree from =3D CompileExpr::Compile (expr.get_from_expr ().get (), ctx)= ; > + if (from =3D=3D error_mark_node) > + { > + translated =3D error_mark_node; > + return; > + } > + > + TyTy::BaseType *tyty =3D nullptr; > + bool ok > + =3D ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (= ), &tyty); > + rust_assert (ok); > + > + tree adt =3D TyTyResolveCompile::compile (ctx, tyty); > + > + // make the constructor > + translated > + =3D ctx->get_backend ()->constructor_expression (adt, false, {from},= -1, > + expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::RangeToExpr &expr) > +{ > + tree to =3D CompileExpr::Compile (expr.get_to_expr ().get (), ctx); > + if (to =3D=3D error_mark_node) > + { > + translated =3D error_mark_node; > + return; > + } > + > + TyTy::BaseType *tyty =3D nullptr; > + bool ok > + =3D ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (= ), &tyty); > + rust_assert (ok); > + > + tree adt =3D TyTyResolveCompile::compile (ctx, tyty); > + > + // make the constructor > + translated > + =3D ctx->get_backend ()->constructor_expression (adt, false, {to}, -= 1, > + expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::RangeFullExpr &expr) > +{ > + TyTy::BaseType *tyty =3D nullptr; > + bool ok > + =3D ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (= ), &tyty); > + rust_assert (ok); > + > + tree adt =3D TyTyResolveCompile::compile (ctx, tyty); > + translated =3D ctx->get_backend ()->constructor_expression (adt, false= , {}, -1, > + expr.get_locu= s ()); > +} > + > +void > +CompileExpr::visit (HIR::RangeFromToInclExpr &expr) > +{ > + tree from =3D CompileExpr::Compile (expr.get_from_expr ().get (), ctx)= ; > + tree to =3D CompileExpr::Compile (expr.get_to_expr ().get (), ctx); > + if (from =3D=3D error_mark_node || to =3D=3D error_mark_node) > + { > + translated =3D error_mark_node; > + return; > + } > + > + TyTy::BaseType *tyty =3D nullptr; > + bool ok > + =3D ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (= ), &tyty); > + rust_assert (ok); > + > + tree adt =3D TyTyResolveCompile::compile (ctx, tyty); > + > + // make the constructor > + translated > + =3D ctx->get_backend ()->constructor_expression (adt, false, {from, = to}, -1, > + expr.get_locus ()); > +} > + > +void > +CompileExpr::visit (HIR::ArrayIndexExpr &expr) > +{ > + tree array_reference =3D CompileExpr::Compile (expr.get_array_expr (),= ctx); > + tree index =3D CompileExpr::Compile (expr.get_index_expr (), ctx); > + > + // this might be an core::ops::index lang item situation > + TyTy::FnType *fntype; > + bool is_op_overload =3D ctx->get_tyctx ()->lookup_operator_overload ( > + expr.get_mappings ().get_hirid (), &fntype); > + if (is_op_overload) > + { > + auto lang_item_type =3D Analysis::RustLangItem::ItemType::INDEX; > + tree operator_overload_call > + =3D resolve_operator_overload (lang_item_type, expr, array_refere= nce, > + index, expr.get_array_expr (), > + expr.get_index_expr ()); > + > + tree actual_type =3D TREE_TYPE (operator_overload_call); > + bool can_indirect =3D TYPE_PTR_P (actual_type) || TYPE_REF_P (actu= al_type); > + if (!can_indirect) > + { > + // nothing to do > + translated =3D operator_overload_call; > + return; > + } > + > + // rust deref always returns a reference from this overload then w= e can > + // actually do the indirection > + translated > + =3D indirect_expression (operator_overload_call, expr.get_locus (= )); > + return; > + } > + > + // lets check if the array is a reference type then we can add an > + // indirection if required > + TyTy::BaseType *array_expr_ty =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type ( > + expr.get_array_expr ()->get_mappings ().get_hirid (), &array_expr_ty= ); > + rust_assert (ok); > + > + // do we need to add an indirect reference > + if (array_expr_ty->get_kind () =3D=3D TyTy::TypeKind::REF) > + { > + array_reference > + =3D indirect_expression (array_reference, expr.get_locus ()); > + } > + > + translated > + =3D ctx->get_backend ()->array_index_expression (array_reference, in= dex, > + expr.get_locus ()); > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust= -compile-expr.h > new file mode 100644 > index 00000000000..4c1f95ade29 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-expr.h > @@ -0,0 +1,148 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_EXPR > +#define RUST_COMPILE_EXPR > + > +#include "rust-compile-base.h" > + > +namespace Rust { > +namespace Compile { > + > +class CompileExpr : private HIRCompileBase, protected HIR::HIRExpression= Visitor > +{ > +public: > + static tree Compile (HIR::Expr *expr, Context *ctx); > + > + void visit (HIR::TupleIndexExpr &expr) override; > + void visit (HIR::TupleExpr &expr) override; > + void visit (HIR::ReturnExpr &expr) override; > + void visit (HIR::CallExpr &expr) override; > + void visit (HIR::MethodCallExpr &expr) override; > + void visit (HIR::LiteralExpr &expr) override; > + void visit (HIR::AssignmentExpr &expr) override; > + void visit (HIR::CompoundAssignmentExpr &expr) override; > + void visit (HIR::ArrayIndexExpr &expr) override; > + void visit (HIR::ArrayExpr &expr) override; > + void visit (HIR::ArithmeticOrLogicalExpr &expr) override; > + void visit (HIR::ComparisonExpr &expr) override; > + void visit (HIR::LazyBooleanExpr &expr) override; > + void visit (HIR::NegationExpr &expr) override; > + void visit (HIR::TypeCastExpr &expr) override; > + void visit (HIR::IfExpr &expr) override; > + void visit (HIR::IfExprConseqIf &expr) override; > + void visit (HIR::IfExprConseqElse &expr) override; > + void visit (HIR::BlockExpr &expr) override; > + void visit (HIR::UnsafeBlockExpr &expr) override; > + void visit (HIR::StructExprStruct &struct_expr) override; > + void visit (HIR::StructExprStructFields &struct_expr) override; > + void visit (HIR::GroupedExpr &expr) override; > + void visit (HIR::FieldAccessExpr &expr) override; > + void visit (HIR::QualifiedPathInExpression &expr) override; > + void visit (HIR::PathInExpression &expr) override; > + void visit (HIR::LoopExpr &expr) override; > + void visit (HIR::WhileLoopExpr &expr) override; > + void visit (HIR::BreakExpr &expr) override; > + void visit (HIR::ContinueExpr &expr) override; > + void visit (HIR::BorrowExpr &expr) override; > + void visit (HIR::DereferenceExpr &expr) override; > + void visit (HIR::MatchExpr &expr) override; > + void visit (HIR::RangeFromToExpr &expr) override; > + void visit (HIR::RangeFromExpr &expr) override; > + void visit (HIR::RangeToExpr &expr) override; > + void visit (HIR::RangeFullExpr &expr) override; > + void visit (HIR::RangeFromToInclExpr &expr) override; > + > + // Empty visit for unused Expression HIR nodes. > + void visit (HIR::ClosureExprInner &) override {} > + void visit (HIR::ClosureExprInnerTyped &) override {} > + void visit (HIR::StructExprFieldIdentifier &) override {} > + void visit (HIR::StructExprFieldIdentifierValue &) override {} > + void visit (HIR::StructExprFieldIndexValue &) override {} > + void visit (HIR::ErrorPropagationExpr &) override {} > + void visit (HIR::RangeToInclExpr &) override {} > + void visit (HIR::WhileLetLoopExpr &) override {} > + void visit (HIR::ForLoopExpr &) override {} > + void visit (HIR::IfExprConseqIfLet &) override {} > + void visit (HIR::IfLetExpr &) override {} > + void visit (HIR::IfLetExprConseqElse &) override {} > + void visit (HIR::IfLetExprConseqIf &) override {} > + void visit (HIR::IfLetExprConseqIfLet &) override {} > + void visit (HIR::AwaitExpr &) override {} > + void visit (HIR::AsyncBlockExpr &) override {} > + > +protected: > + tree get_fn_addr_from_dyn (const TyTy::DynamicObjectType *dyn, > + TyTy::BaseType *receiver, TyTy::FnType *fnty= pe, > + tree receiver_ref, Location expr_locus); > + > + tree get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn, > + TyTy::BaseType *receiver, TyTy::FnType *fnt= ype, > + tree receiver_ref, Location expr_locus); > + > + tree resolve_method_address (TyTy::FnType *fntype, HirId ref, > + TyTy::BaseType *receiver, > + HIR::PathIdentSegment &segment, > + Analysis::NodeMapping expr_mappings, > + Location expr_locus); > + > + tree > + resolve_operator_overload (Analysis::RustLangItem::ItemType lang_item_= type, > + HIR::OperatorExprMeta expr, tree lhs, tree r= hs, > + HIR::Expr *lhs_expr, HIR::Expr *rhs_expr); > + > + tree compile_bool_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty); > + > + tree compile_integer_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty); > + > + tree compile_float_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty); > + > + tree compile_char_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty); > + > + tree compile_byte_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty); > + > + tree compile_string_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty); > + > + tree compile_byte_string_literal (const HIR::LiteralExpr &expr, > + const TyTy::BaseType *tyty); > + > + tree type_cast_expression (tree type_to_cast_to, tree expr, Location l= ocus); > + > + tree array_value_expr (Location expr_locus, const TyTy::ArrayType &arr= ay_tyty, > + tree array_type, HIR::ArrayElemsValues &elems); > + > + tree array_copied_expr (Location expr_locus, > + const TyTy::ArrayType &array_tyty, tree array_t= ype, > + HIR::ArrayElemsCopied &elems); > + > +private: > + CompileExpr (Context *ctx); > + > + tree translated; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_EXPR > diff --git a/gcc/rust/backend/rust-compile-extern.h b/gcc/rust/backend/ru= st-compile-extern.h > new file mode 100644 > index 00000000000..45a507e03be > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-extern.h > @@ -0,0 +1,172 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_EXTERN_ITEM > +#define RUST_COMPILE_EXTERN_ITEM > + > +#include "rust-compile-base.h" > +#include "rust-compile-intrinsic.h" > + > +namespace Rust { > +namespace Compile { > + > +class CompileExternItem : public HIRCompileBase, > + public HIR::HIRExternalItemVisitor > +{ > +public: > + static tree compile (HIR::ExternalItem *item, Context *ctx, > + TyTy::BaseType *concrete =3D nullptr, > + bool is_query_mode =3D false, > + Location ref_locus =3D Location ()) > + { > + CompileExternItem compiler (ctx, concrete, ref_locus); > + item->accept_vis (compiler); > + > + if (is_query_mode && compiler.reference =3D=3D error_mark_node) > + rust_internal_error_at (ref_locus, "failed to compile extern item:= %s", > + item->as_string ().c_str ()); > + > + return compiler.reference; > + } > + > + void visit (HIR::ExternalStaticItem &item) override > + { > + // check if its already been compiled > + Bvariable *lookup =3D ctx->get_backend ()->error_variable (); > + if (ctx->lookup_var_decl (item.get_mappings ().get_hirid (), &lookup= )) > + { > + reference =3D ctx->get_backend ()->var_expression (lookup, ref_lo= cus); > + return; > + } > + > + TyTy::BaseType *resolved_type =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type (item.get_mappings ().get= _hirid (), > + &resolved_type); > + rust_assert (ok); > + > + std::string name =3D item.get_item_name (); > + // FIXME this is assuming C ABI > + std::string asm_name =3D name; > + > + tree type =3D TyTyResolveCompile::compile (ctx, resolved_type); > + bool is_external =3D true; > + bool is_hidden =3D false; > + bool in_unique_section =3D false; > + > + Bvariable *static_global > + =3D ctx->get_backend ()->global_variable (name, asm_name, type, is= _external, > + is_hidden, in_unique_sectio= n, > + item.get_locus ()); > + ctx->insert_var_decl (item.get_mappings ().get_hirid (), static_glob= al); > + ctx->push_var (static_global); > + > + reference =3D ctx->get_backend ()->var_expression (static_global, re= f_locus); > + } > + > + void visit (HIR::ExternalFunctionItem &function) override > + { > + TyTy::BaseType *fntype_tyty; > + if (!ctx->get_tyctx ()->lookup_type (function.get_mappings ().get_hi= rid (), > + &fntype_tyty)) > + { > + rust_fatal_error (function.get_locus (), > + "failed to lookup function type"); > + return; > + } > + > + rust_assert (fntype_tyty->get_kind () =3D=3D TyTy::TypeKind::FNDEF); > + TyTy::FnType *fntype =3D static_cast (fntype_tyty); > + if (fntype->has_subsititions_defined ()) > + { > + // we cant do anything for this only when it is used and a concre= te type > + // is given > + if (concrete =3D=3D nullptr) > + return; > + else > + { > + rust_assert (concrete->get_kind () =3D=3D TyTy::TypeKind::FND= EF); > + fntype =3D static_cast (concrete); > + } > + } > + > + // items can be forward compiled which means we may not need to invo= ke this > + // code. We might also have already compiled this generic function a= s well. > + tree lookup =3D NULL_TREE; > + if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup, > + fntype->get_id (), fntype)) > + { > + reference =3D address_expression (lookup, ref_locus); > + return; > + } > + > + if (fntype->has_subsititions_defined ()) > + { > + // override the Hir Lookups for the substituions in this context > + fntype->override_context (); > + } > + > + if (fntype->get_abi () =3D=3D ABI::INTRINSIC) > + { > + Intrinsics compile (ctx); > + tree fndecl =3D compile.compile (fntype); > + ctx->insert_function_decl (fntype, fndecl); > + return; > + } > + > + tree compiled_fn_type =3D TyTyResolveCompile::compile (ctx, fntype); > + std::string ir_symbol_name =3D function.get_item_name (); > + std::string asm_name =3D function.get_item_name (); > + if (fntype->get_abi () =3D=3D ABI::RUST) > + { > + // then we need to get the canonical path of it and mangle it > + const Resolver::CanonicalPath *canonical_path =3D nullptr; > + bool ok =3D ctx->get_mappings ()->lookup_canonical_path ( > + function.get_mappings ().get_nodeid (), &canonical_path); > + rust_assert (ok); > + > + ir_symbol_name =3D canonical_path->get () + fntype->subst_as_stri= ng (); > + asm_name =3D ctx->mangle_item (fntype, *canonical_path); > + } > + > + const unsigned int flags =3D Backend::function_is_declaration; > + tree fndecl > + =3D ctx->get_backend ()->function (compiled_fn_type, ir_symbol_nam= e, > + asm_name, flags, function.get_locu= s ()); > + TREE_PUBLIC (fndecl) =3D 1; > + setup_abi_options (fndecl, fntype->get_abi ()); > + > + ctx->insert_function_decl (fntype, fndecl); > + > + reference =3D address_expression (fndecl, ref_locus); > + } > + > +private: > + CompileExternItem (Context *ctx, TyTy::BaseType *concrete, Location re= f_locus) > + : HIRCompileBase (ctx), concrete (concrete), reference (error_mark_n= ode), > + ref_locus (ref_locus) > + {} > + > + TyTy::BaseType *concrete; > + tree reference; > + Location ref_locus; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_EXTERN_ITEM > diff --git a/gcc/rust/backend/rust-compile-fnparam.cc b/gcc/rust/backend/= rust-compile-fnparam.cc > new file mode 100644 > index 00000000000..3f0ec82b625 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-fnparam.cc > @@ -0,0 +1,121 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-fnparam.h" > +#include "rust-compile-pattern.h" > + > +#include "gimple-expr.h" > + > +namespace Rust { > +namespace Compile { > + > +CompileFnParam::CompileFnParam (Context *ctx, tree fndecl, tree decl_typ= e, > + Location locus) > + : HIRCompileBase (ctx), fndecl (fndecl), decl_type (decl_type), locus = (locus), > + compiled_param (ctx->get_backend ()->error_variable ()) > +{} > + > +Bvariable * > +CompileFnParam::compile (Context *ctx, tree fndecl, HIR::FunctionParam *= param, > + tree decl_type, Location locus) > +{ > + CompileFnParam compiler (ctx, fndecl, decl_type, locus); > + param->get_param_name ()->accept_vis (compiler); > + return compiler.compiled_param; > +} > + > +Bvariable * > +CompileFnParam::compile (Context *ctx, tree fndecl, HIR::Pattern *param, > + tree decl_type, Location locus) > +{ > + CompileFnParam compiler (ctx, fndecl, decl_type, locus); > + param->accept_vis (compiler); > + return compiler.compiled_param; > +} > + > +void > +CompileFnParam::visit (HIR::IdentifierPattern &pattern) > +{ > + if (!pattern.is_mut ()) > + decl_type =3D ctx->get_backend ()->immutable_type (decl_type); > + > + compiled_param > + =3D ctx->get_backend ()->parameter_variable (fndecl, > + pattern.get_identifier (), > + decl_type, locus); > +} > + > +void > +CompileFnParam::visit (HIR::WildcardPattern &pattern) > +{ > + decl_type =3D ctx->get_backend ()->immutable_type (decl_type); > + > + compiled_param > + =3D ctx->get_backend ()->parameter_variable (fndecl, "_", decl_type,= locus); > +} > + > +void > +CompileFnParam::visit (HIR::StructPattern &pattern) > +{ > + // generate the anon param > + tree tmp_ident =3D create_tmp_var_name ("RSTPRM"); > + std::string cpp_str_identifier =3D std::string (IDENTIFIER_POINTER (tm= p_ident)); > + > + decl_type =3D ctx->get_backend ()->immutable_type (decl_type); > + compiled_param > + =3D ctx->get_backend ()->parameter_variable (fndecl, cpp_str_identif= ier, > + decl_type, locus); > + > + // setup the pattern bindings > + tree anon_param =3D ctx->get_backend ()->var_expression (compiled_para= m, locus); > + CompilePatternBindings::Compile (&pattern, anon_param, ctx); > +} > + > +void > +CompileFnParam::visit (HIR::TupleStructPattern &pattern) > +{ > + // generate the anon param > + tree tmp_ident =3D create_tmp_var_name ("RSTPRM"); > + std::string cpp_str_identifier =3D std::string (IDENTIFIER_POINTER (tm= p_ident)); > + > + decl_type =3D ctx->get_backend ()->immutable_type (decl_type); > + compiled_param > + =3D ctx->get_backend ()->parameter_variable (fndecl, cpp_str_identif= ier, > + decl_type, locus); > + > + // setup the pattern bindings > + tree anon_param =3D ctx->get_backend ()->var_expression (compiled_para= m, locus); > + CompilePatternBindings::Compile (&pattern, anon_param, ctx); > +} > + > +Bvariable * > +CompileSelfParam::compile (Context *ctx, tree fndecl, HIR::SelfParam &se= lf, > + tree decl_type, Location locus) > +{ > + bool is_immutable > + =3D self.get_self_kind () =3D=3D HIR::SelfParam::ImplicitSelfKind::I= MM > + || self.get_self_kind () =3D=3D HIR::SelfParam::ImplicitSelfKind::= IMM_REF; > + if (is_immutable) > + decl_type =3D ctx->get_backend ()->immutable_type (decl_type); > + > + return ctx->get_backend ()->parameter_variable (fndecl, "self", decl_t= ype, > + locus); > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-fnparam.h b/gcc/rust/backend/r= ust-compile-fnparam.h > new file mode 100644 > index 00000000000..0dbbd99ef08 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-fnparam.h > @@ -0,0 +1,70 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_FNPARAM > +#define RUST_COMPILE_FNPARAM > + > +#include "rust-compile-base.h" > + > +namespace Rust { > +namespace Compile { > + > +class CompileFnParam : private HIRCompileBase, protected HIR::HIRPattern= Visitor > +{ > +public: > + static Bvariable *compile (Context *ctx, tree fndecl, > + HIR::FunctionParam *param, tree decl_type, > + Location locus); > + static Bvariable *compile (Context *ctx, tree fndecl, HIR::Pattern *pa= ram, > + tree decl_type, Location locus); > + > + void visit (HIR::IdentifierPattern &pattern) override; > + void visit (HIR::WildcardPattern &pattern) override; > + void visit (HIR::StructPattern &) override; > + void visit (HIR::TupleStructPattern &) override; > + > + // Empty visit for unused Pattern HIR nodes. > + void visit (HIR::GroupedPattern &) override {} > + void visit (HIR::LiteralPattern &) override {} > + void visit (HIR::PathInExpression &) override {} > + void visit (HIR::QualifiedPathInExpression &) override {} > + void visit (HIR::RangePattern &) override {} > + void visit (HIR::ReferencePattern &) override {} > + void visit (HIR::SlicePattern &) override {} > + void visit (HIR::TuplePattern &) override {} > + > +private: > + CompileFnParam (Context *ctx, tree fndecl, tree decl_type, Location lo= cus); > + > + tree fndecl; > + tree decl_type; > + Location locus; > + Bvariable *compiled_param; > +}; > + > +class CompileSelfParam : private HIRCompileBase > +{ > +public: > + static Bvariable *compile (Context *ctx, tree fndecl, HIR::SelfParam &= self, > + tree decl_type, Location locus); > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_FNPARAM > diff --git a/gcc/rust/backend/rust-compile-implitem.cc b/gcc/rust/backend= /rust-compile-implitem.cc > new file mode 100644 > index 00000000000..d0f70a70228 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-implitem.cc > @@ -0,0 +1,101 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-implitem.h" > +#include "rust-compile-expr.h" > +#include "rust-compile-fnparam.h" > + > +namespace Rust { > +namespace Compile { > + > +void > +CompileTraitItem::visit (HIR::TraitItemConst &constant) > +{ > + rust_assert (concrete !=3D nullptr); > + TyTy::BaseType *resolved_type =3D concrete; > + > + const Resolver::CanonicalPath *canonical_path =3D nullptr; > + bool ok =3D ctx->get_mappings ()->lookup_canonical_path ( > + constant.get_mappings ().get_nodeid (), &canonical_path); > + rust_assert (ok); > + > + HIR::Expr *const_value_expr =3D constant.get_expr ().get (); > + tree const_expr > + =3D compile_constant_item (ctx, resolved_type, canonical_path, > + const_value_expr, constant.get_locus ()); > + ctx->push_const (const_expr); > + ctx->insert_const_decl (constant.get_mappings ().get_hirid (), const_e= xpr); > + > + reference =3D const_expr; > +} > + > +void > +CompileTraitItem::visit (HIR::TraitItemFunc &func) > +{ > + rust_assert (func.has_block_defined ()); > + > + rust_assert (concrete->get_kind () =3D=3D TyTy::TypeKind::FNDEF); > + TyTy::FnType *fntype =3D static_cast (concrete); > + fntype->monomorphize (); > + > + // items can be forward compiled which means we may not need to invoke= this > + // code. We might also have already compiled this generic function as = well. > + tree lookup =3D NULL_TREE; > + if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup, > + fntype->get_id (), fntype)) > + { > + // has this been added to the list then it must be finished > + if (ctx->function_completed (lookup)) > + { > + tree dummy =3D NULL_TREE; > + if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy)) > + { > + ctx->insert_function_decl (fntype, lookup); > + } > + > + reference =3D address_expression (lookup, ref_locus); > + return; > + } > + } > + > + if (fntype->has_subsititions_defined ()) > + { > + // override the Hir Lookups for the substituions in this context > + fntype->override_context (); > + } > + > + const Resolver::CanonicalPath *canonical_path =3D nullptr; > + bool ok =3D ctx->get_mappings ()->lookup_canonical_path ( > + func.get_mappings ().get_nodeid (), &canonical_path); > + rust_assert (ok); > + > + // FIXME: How do we get the proper visibility here? > + auto vis =3D HIR::Visibility (HIR::Visibility::VisType::PUBLIC); > + HIR::TraitFunctionDecl &function =3D func.get_decl (); > + tree fndecl > + =3D compile_function (ctx, function.get_function_name (), > + function.get_self (), function.get_function_param= s (), > + function.get_qualifiers (), vis, > + func.get_outer_attrs (), func.get_locus (), > + func.get_block_expr ().get (), canonical_path, fn= type, > + function.has_return_type ()); > + reference =3D address_expression (fndecl, ref_locus); > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-implitem.h b/gcc/rust/backend/= rust-compile-implitem.h > new file mode 100644 > index 00000000000..ac9478af150 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-implitem.h > @@ -0,0 +1,91 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_IMPLITEM_H > +#define RUST_COMPILE_IMPLITEM_H > + > +#include "rust-compile-item.h" > +#include "rust-compile-expr.h" > +#include "rust-compile-fnparam.h" > + > +namespace Rust { > +namespace Compile { > + > +// this is a proxy for HIR::ImplItem's back to use the normel HIR::Item = path > +class CompileInherentImplItem : public CompileItem > +{ > +public: > + static tree Compile (HIR::ImplItem *item, Context *ctx, > + TyTy::BaseType *concrete =3D nullptr, > + bool is_query_mode =3D false, > + Location ref_locus =3D Location ()) > + { > + CompileInherentImplItem compiler (ctx, concrete, ref_locus); > + item->accept_vis (compiler); > + > + if (is_query_mode && compiler.reference =3D=3D error_mark_node) > + rust_internal_error_at (ref_locus, "failed to compile impl item: %= s", > + item->as_string ().c_str ()); > + > + return compiler.reference; > + } > + > +private: > + CompileInherentImplItem (Context *ctx, TyTy::BaseType *concrete, > + Location ref_locus) > + : CompileItem (ctx, concrete, ref_locus) > + {} > +}; > + > +class CompileTraitItem : public HIRCompileBase, public HIR::HIRTraitItem= Visitor > +{ > +public: > + static tree Compile (HIR::TraitItem *item, Context *ctx, > + TyTy::BaseType *concrete, bool is_query_mode =3D f= alse, > + Location ref_locus =3D Location ()) > + { > + CompileTraitItem compiler (ctx, concrete, ref_locus); > + item->accept_vis (compiler); > + > + if (is_query_mode && compiler.reference =3D=3D error_mark_node) > + rust_internal_error_at (ref_locus, "failed to compile trait item: = %s", > + item->as_string ().c_str ()); > + > + return compiler.reference; > + } > + > + void visit (HIR::TraitItemConst &constant) override; > + void visit (HIR::TraitItemFunc &func) override; > + > + void visit (HIR::TraitItemType &typ) override {} > + > +private: > + CompileTraitItem (Context *ctx, TyTy::BaseType *concrete, Location ref= _locus) > + : HIRCompileBase (ctx), concrete (concrete), reference (error_mark_n= ode), > + ref_locus (ref_locus) > + {} > + > + TyTy::BaseType *concrete; > + tree reference; > + Location ref_locus; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_IMPLITEM_H > diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backen= d/rust-compile-intrinsic.cc > new file mode 100644 > index 00000000000..61084b90f33 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-intrinsic.cc > @@ -0,0 +1,515 @@ > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-intrinsic.h" > +#include "fold-const.h" > +#include "langhooks.h" > +#include "rust-compile-context.h" > +#include "rust-compile-type.h" > +#include "rust-compile-fnparam.h" > +#include "rust-builtins.h" > +#include "rust-diagnostics.h" > +#include "rust-location.h" > +#include "rust-tree.h" > +#include "tree-core.h" > +#include "print-tree.h" > + > +namespace Rust { > +namespace Compile { > + > +static tree > +offset_handler (Context *ctx, TyTy::FnType *fntype); > +static tree > +sizeof_handler (Context *ctx, TyTy::FnType *fntype); > +static tree > +transmute_handler (Context *ctx, TyTy::FnType *fntype); > +static tree > +rotate_handler (Context *ctx, TyTy::FnType *fntype, tree_code op); > +static tree > +wrapping_op_handler (Context *ctx, TyTy::FnType *fntype, tree_code op); > +static tree > +copy_nonoverlapping_handler (Context *ctx, TyTy::FnType *fntype); > + > +static inline tree > +rotate_left_handler (Context *ctx, TyTy::FnType *fntype) > +{ > + return rotate_handler (ctx, fntype, LROTATE_EXPR); > +} > +static inline tree > +rotate_right_handler (Context *ctx, TyTy::FnType *fntype) > +{ > + return rotate_handler (ctx, fntype, RROTATE_EXPR); > +} > + > +static inline tree > +wrapping_add_handler (Context *ctx, TyTy::FnType *fntype) > +{ > + return wrapping_op_handler (ctx, fntype, PLUS_EXPR); > +} > +static inline tree > +wrapping_sub_handler (Context *ctx, TyTy::FnType *fntype) > +{ > + return wrapping_op_handler (ctx, fntype, MINUS_EXPR); > +} > +static inline tree > +wrapping_mul_handler (Context *ctx, TyTy::FnType *fntype) > +{ > + return wrapping_op_handler (ctx, fntype, MULT_EXPR); > +} > + > +static const std::map + std::function> > + generic_intrinsics =3D {{"offset", &offset_handler}, > + {"size_of", &sizeof_handler}, > + {"transmute", &transmute_handler}, > + {"rotate_left", &rotate_left_handler}, > + {"rotate_right", &rotate_right_handler}, > + {"wrapping_add", &wrapping_add_handler}, > + {"wrapping_sub", &wrapping_sub_handler}, > + {"wrapping_mul", &wrapping_mul_handler}, > + {"copy_nonoverlapping", ©_nonoverlapping_hand= ler}}; > + > +Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {} > + > +tree > +Intrinsics::compile (TyTy::FnType *fntype) > +{ > + rust_assert (fntype->get_abi () =3D=3D ABI::INTRINSIC); > + > + tree builtin =3D error_mark_node; > + BuiltinsContext &builtin_ctx =3D BuiltinsContext::get (); > + if (builtin_ctx.lookup_simple_builtin (fntype->get_identifier (), &bui= ltin)) > + return builtin; > + > + // is it an generic builtin? > + auto it =3D generic_intrinsics.find (fntype->get_identifier ()); > + if (it !=3D generic_intrinsics.end ()) > + return it->second (ctx, fntype); > + > + Location locus =3D ctx->get_mappings ()->lookup_location (fntype->get_= ref ()); > + rust_error_at (locus, "unknown builtin intrinsic: %s", > + fntype->get_identifier ().c_str ()); > + > + return error_mark_node; > +} > + > +/** > + * Items can be forward compiled which means we may not need to invoke t= his > + * code. We might also have already compiled this generic function as we= ll. > + */ > +static bool > +check_for_cached_intrinsic (Context *ctx, TyTy::FnType *fntype, tree *lo= okup) > +{ > + if (ctx->lookup_function_decl (fntype->get_ty_ref (), lookup, > + fntype->get_id (), fntype)) > + { > + // Has this been added to the list? Then it must be finished > + if (ctx->function_completed (*lookup)) > + { > + tree dummy =3D NULL_TREE; > + if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy)) > + ctx->insert_function_decl (fntype, *lookup); > + return true; > + } > + } > + > + return false; > +} > + > +/** > + * Maybe override the Hir Lookups for the substituions in this context > + */ > +static void > +maybe_override_ctx (TyTy::FnType *fntype) > +{ > + if (fntype->has_subsititions_defined ()) > + fntype->override_context (); > +} > + > +/** > + * Compile and setup a function's parameters > + */ > +static void > +compile_fn_params (Context *ctx, TyTy::FnType *fntype, tree fndecl, > + std::vector *compiled_param_variables, > + std::vector *compiled_param_types =3D nul= lptr) > +{ > + for (auto &parm : fntype->get_params ()) > + { > + auto &referenced_param =3D parm.first; > + auto ¶m_tyty =3D parm.second; > + auto compiled_param_type =3D TyTyResolveCompile::compile (ctx, par= am_tyty); > + > + Location param_locus =3D referenced_param->get_locus (); > + Bvariable *compiled_param_var > + =3D CompileFnParam::compile (ctx, fndecl, referenced_param, > + compiled_param_type, param_locus); > + > + compiled_param_variables->push_back (compiled_param_var); > + if (compiled_param_types) > + compiled_param_types->push_back (compiled_param_type); > + } > +} > + > +static tree > +compile_intrinsic_function (Context *ctx, TyTy::FnType *fntype) > +{ > + maybe_override_ctx (fntype); > + > + const Resolver::CanonicalPath &canonical_path =3D fntype->get_ident ()= .path; > + > + tree compiled_fn_type =3D TyTyResolveCompile::compile (ctx, fntype); > + std::string ir_symbol_name > + =3D canonical_path.get () + fntype->subst_as_string (); > + std::string asm_name =3D ctx->mangle_item (fntype, canonical_path); > + > + unsigned int flags =3D 0; > + tree fndecl > + =3D ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name,= asm_name, > + flags, fntype->get_ident ().locus); > + > + TREE_PUBLIC (fndecl) =3D 0; > + TREE_READONLY (fndecl) =3D 1; > + DECL_ARTIFICIAL (fndecl) =3D 1; > + DECL_EXTERNAL (fndecl) =3D 0; > + DECL_DECLARED_INLINE_P (fndecl) =3D 1; > + > + return fndecl; > +} > + > +static void > +enter_intrinsic_block (Context *ctx, tree fndecl) > +{ > + tree enclosing_scope =3D NULL_TREE; > + Location start_location =3D Location (); > + Location end_location =3D Location (); > + > + auto block =3D ctx->get_backend ()->block (fndecl, enclosing_scope, {}= , > + start_location, end_location); > + > + ctx->push_block (block); > +} > + > +static void > +finalize_intrinsic_block (Context *ctx, tree fndecl) > +{ > + tree bind_tree =3D ctx->pop_block (); > + > + gcc_assert (TREE_CODE (bind_tree) =3D=3D BIND_EXPR); > + > + DECL_SAVED_TREE (fndecl) =3D bind_tree; > + > + ctx->push_function (fndecl); > +} > + > +static tree > +offset_handler (Context *ctx, TyTy::FnType *fntype) > +{ > + // offset intrinsic has two params dst pointer and offset isize > + rust_assert (fntype->get_params ().size () =3D=3D 2); > + > + auto fndecl =3D compile_intrinsic_function (ctx, fntype); > + > + std::vector param_vars; > + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); > + > + auto &dst_param =3D param_vars.at (0); > + auto &size_param =3D param_vars.at (1); > + rust_assert (param_vars.size () =3D=3D 2); > + if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)= ) > + return error_mark_node; > + > + enter_intrinsic_block (ctx, fndecl); > + > + // BUILTIN offset FN BODY BEGIN > + tree dst =3D ctx->get_backend ()->var_expression (dst_param, Location = ()); > + tree size =3D ctx->get_backend ()->var_expression (size_param, Locatio= n ()); > + tree pointer_offset_expr > + =3D pointer_offset_expression (dst, size, BUILTINS_LOCATION); > + auto return_statement > + =3D ctx->get_backend ()->return_statement (fndecl, {pointer_offset_e= xpr}, > + Location ()); > + ctx->add_statement (return_statement); > + // BUILTIN offset FN BODY END > + > + finalize_intrinsic_block (ctx, fndecl); > + > + return fndecl; > +} > + > +static tree > +sizeof_handler (Context *ctx, TyTy::FnType *fntype) > +{ > + // size_of has _zero_ parameters its parameter is the generic one > + rust_assert (fntype->get_params ().size () =3D=3D 0); > + > + tree lookup =3D NULL_TREE; > + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) > + return lookup; > + > + auto fndecl =3D compile_intrinsic_function (ctx, fntype); > + > + // get the template parameter type tree fn size_of(); > + rust_assert (fntype->get_num_substitutions () =3D=3D 1); > + auto ¶m_mapping =3D fntype->get_substs ().at (0); > + const TyTy::ParamType *param_tyty =3D param_mapping.get_param_ty (); > + TyTy::BaseType *resolved_tyty =3D param_tyty->resolve (); > + tree template_parameter_type > + =3D TyTyResolveCompile::compile (ctx, resolved_tyty); > + > + enter_intrinsic_block (ctx, fndecl); > + > + // BUILTIN size_of FN BODY BEGIN > + tree size_expr =3D TYPE_SIZE_UNIT (template_parameter_type); > + auto return_statement > + =3D ctx->get_backend ()->return_statement (fndecl, {size_expr}, Loca= tion ()); > + ctx->add_statement (return_statement); > + // BUILTIN size_of FN BODY END > + > + finalize_intrinsic_block (ctx, fndecl); > + > + return fndecl; > +} > + > +static tree > +transmute_handler (Context *ctx, TyTy::FnType *fntype) > +{ > + // transmute intrinsic has one parameter > + rust_assert (fntype->get_params ().size () =3D=3D 1); > + > + tree lookup =3D NULL_TREE; > + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) > + return lookup; > + > + auto fndecl =3D compile_intrinsic_function (ctx, fntype); > + > + std::vector param_vars; > + std::vector compiled_types; > + compile_fn_params (ctx, fntype, fndecl, ¶m_vars, &compiled_types); > + > + if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)= ) > + return error_mark_node; > + > + // param to convert > + Bvariable *convert_me_param =3D param_vars.at (0); > + tree convert_me_expr > + =3D ctx->get_backend ()->var_expression (convert_me_param, Location = ()); > + > + // check for transmute pre-conditions > + tree target_type_expr =3D TREE_TYPE (DECL_RESULT (fndecl)); > + tree source_type_expr =3D compiled_types.at (0); > + tree target_size_expr =3D TYPE_SIZE (target_type_expr); > + tree source_size_expr =3D TYPE_SIZE (source_type_expr); > + // for some reason, unit types and other zero-sized types return NULL = for the > + // size expressions > + unsigned HOST_WIDE_INT target_size > + =3D target_size_expr ? TREE_INT_CST_LOW (target_size_expr) : 0; > + unsigned HOST_WIDE_INT source_size > + =3D source_size_expr ? TREE_INT_CST_LOW (source_size_expr) : 0; > + > + // size check for concrete types > + // TODO(liushuyu): check alignment for pointers; check for dependently= -sized > + // types > + if (target_size !=3D source_size) > + { > + rust_error_at (fntype->get_locus (), > + "cannot transmute between types of different sizes, = or " > + "dependently-sized types"); > + rust_inform (fntype->get_ident ().locus, "source type: %qs (%lu bi= ts)", > + fntype->get_params ().at (0).second->as_string ().c_st= r (), > + (unsigned long) source_size); > + rust_inform (fntype->get_ident ().locus, "target type: %qs (%lu bi= ts)", > + fntype->get_return_type ()->as_string ().c_str (), > + (unsigned long) target_size); > + } > + > + enter_intrinsic_block (ctx, fndecl); > + > + // BUILTIN transmute FN BODY BEGIN > + > + // Return *((orig_type*)&decl) */ > + > + tree t > + =3D build_fold_addr_expr_loc (Location ().gcc_location (), convert_m= e_expr); > + t =3D fold_build1_loc (Location ().gcc_location (), NOP_EXPR, > + build_pointer_type (target_type_expr), t); > + tree result_expr > + =3D build_fold_indirect_ref_loc (Location ().gcc_location (), t); > + > + auto return_statement > + =3D ctx->get_backend ()->return_statement (fndecl, {result_expr}, > + Location ()); > + ctx->add_statement (return_statement); > + // BUILTIN transmute FN BODY END > + > + finalize_intrinsic_block (ctx, fndecl); > + > + return fndecl; > +} > + > +static tree > +rotate_handler (Context *ctx, TyTy::FnType *fntype, tree_code op) > +{ > + // rotate intrinsic has two parameter > + rust_assert (fntype->get_params ().size () =3D=3D 2); > + > + tree lookup =3D NULL_TREE; > + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) > + return lookup; > + > + auto fndecl =3D compile_intrinsic_function (ctx, fntype); > + > + // setup the params > + std::vector param_vars; > + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); > + > + auto &x_param =3D param_vars.at (0); > + auto &y_param =3D param_vars.at (1); > + rust_assert (param_vars.size () =3D=3D 2); > + if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)= ) > + return error_mark_node; > + > + enter_intrinsic_block (ctx, fndecl); > + > + // BUILTIN rotate FN BODY BEGIN > + tree x =3D ctx->get_backend ()->var_expression (x_param, Location ()); > + tree y =3D ctx->get_backend ()->var_expression (y_param, Location ()); > + tree rotate_expr > + =3D fold_build2_loc (BUILTINS_LOCATION, op, TREE_TYPE (x), x, y); > + auto return_statement > + =3D ctx->get_backend ()->return_statement (fndecl, {rotate_expr}, > + Location ()); > + ctx->add_statement (return_statement); > + // BUILTIN rotate FN BODY END > + > + finalize_intrinsic_block (ctx, fndecl); > + > + return fndecl; > +} > + > +/** > + * pub fn wrapping_{add, sub, mul}(lhs: T, rhs: T) -> T; > + */ > +static tree > +wrapping_op_handler (Context *ctx, TyTy::FnType *fntype, tree_code op) > +{ > + // wrapping_ intrinsics have two parameter > + rust_assert (fntype->get_params ().size () =3D=3D 2); > + > + tree lookup =3D NULL_TREE; > + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) > + return lookup; > + > + auto fndecl =3D compile_intrinsic_function (ctx, fntype); > + > + // setup the params > + std::vector param_vars; > + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); > + > + auto &lhs_param =3D param_vars.at (0); > + auto &rhs_param =3D param_vars.at (1); > + > + if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)= ) > + return error_mark_node; > + > + enter_intrinsic_block (ctx, fndecl); > + > + // BUILTIN wrapping_ FN BODY BEGIN > + auto lhs =3D ctx->get_backend ()->var_expression (lhs_param, Location = ()); > + auto rhs =3D ctx->get_backend ()->var_expression (rhs_param, Location = ()); > + > + // Operations are always wrapping in Rust, as we have -fwrapv enabled = by > + // default. The difference between a wrapping_{add, sub, mul} and a re= gular > + // arithmetic operation is that these intrinsics do not panic - they a= lways > + // carry over. > + auto wrap_expr =3D build2 (op, TREE_TYPE (lhs), lhs, rhs); > + > + auto return_statement > + =3D ctx->get_backend ()->return_statement (fndecl, {wrap_expr}, Loca= tion ()); > + ctx->add_statement (return_statement); > + // BUILTIN wrapping_ FN BODY END > + > + finalize_intrinsic_block (ctx, fndecl); > + > + return fndecl; > +} > + > +/** > + * fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); > + */ > +static tree > +copy_nonoverlapping_handler (Context *ctx, TyTy::FnType *fntype) > +{ > + rust_assert (fntype->get_params ().size () =3D=3D 3); > + rust_assert (fntype->get_num_substitutions () =3D=3D 1); > + > + tree lookup =3D NULL_TREE; > + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) > + return lookup; > + > + auto fndecl =3D compile_intrinsic_function (ctx, fntype); > + > + // Most intrinsic functions are pure - not `copy_nonoverlapping` > + TREE_READONLY (fndecl) =3D 0; > + TREE_SIDE_EFFECTS (fndecl) =3D 1; > + > + // setup the params > + std::vector param_vars; > + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); > + > + if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)= ) > + return error_mark_node; > + > + enter_intrinsic_block (ctx, fndecl); > + > + // BUILTIN copy_nonoverlapping BODY BEGIN > + > + auto src =3D ctx->get_backend ()->var_expression (param_vars[0], Locat= ion ()); > + auto dst =3D ctx->get_backend ()->var_expression (param_vars[1], Locat= ion ()); > + auto count =3D ctx->get_backend ()->var_expression (param_vars[2], Loc= ation ()); > + > + // We want to create the following statement > + // memcpy(dst, src, size_of::()); > + // so > + // memcpy(dst, src, size_expr); > + > + auto *resolved_ty =3D fntype->get_substs ().at (0).get_param_ty ()->re= solve (); > + auto param_type =3D TyTyResolveCompile::compile (ctx, resolved_ty); > + > + tree size_expr > + =3D build2 (MULT_EXPR, size_type_node, TYPE_SIZE_UNIT (param_type), = count); > + > + tree memcpy_raw =3D nullptr; > + BuiltinsContext::get ().lookup_simple_builtin ("memcpy", &memcpy_raw); > + rust_assert (memcpy_raw); > + auto memcpy > + =3D build_fold_addr_expr_loc (Location ().gcc_location (), memcpy_ra= w); > + > + auto copy_call > + =3D ctx->get_backend ()->call_expression (memcpy, {dst, src, size_ex= pr}, > + nullptr, Location ()); > + > + ctx->add_statement (copy_call); > + > + // BUILTIN copy_nonoverlapping BODY END > + > + finalize_intrinsic_block (ctx, fndecl); > + > + return fndecl; > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-intrinsic.h b/gcc/rust/backend= /rust-compile-intrinsic.h > new file mode 100644 > index 00000000000..dceb0864fd4 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-intrinsic.h > @@ -0,0 +1,40 @@ > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_INTRINSIC > +#define RUST_COMPILE_INTRINSIC > + > +#include "rust-compile-context.h" > +#include "langhooks.h" > + > +namespace Rust { > +namespace Compile { > + > +class Intrinsics > +{ > +public: > + Intrinsics (Context *ctx); > + > + tree compile (TyTy::FnType *fntype); > + > +private: > + Context *ctx; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_INTRINSIC > diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rus= t-compile-item.cc > new file mode 100644 > index 00000000000..ceba51c2d27 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-item.cc > @@ -0,0 +1,206 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-item.h" > +#include "rust-compile-implitem.h" > +#include "rust-compile-expr.h" > +#include "rust-compile-extern.h" > +#include "rust-constexpr.h" > + > +namespace Rust { > +namespace Compile { > + > +void > +CompileItem::visit (HIR::StaticItem &var) > +{ > + // have we already compiled this? > + Bvariable *static_decl_ref =3D nullptr; > + if (ctx->lookup_var_decl (var.get_mappings ().get_hirid (), &static_de= cl_ref)) > + { > + reference > + =3D ctx->get_backend ()->var_expression (static_decl_ref, ref_loc= us); > + return; > + } > + > + TyTy::BaseType *resolved_type =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type (var.get_mappings ().get_hi= rid (), > + &resolved_type); > + rust_assert (ok); > + > + tree type =3D TyTyResolveCompile::compile (ctx, resolved_type); > + tree value =3D CompileExpr::Compile (var.get_expr (), ctx); > + > + const Resolver::CanonicalPath *canonical_path =3D nullptr; > + ok =3D ctx->get_mappings ()->lookup_canonical_path ( > + var.get_mappings ().get_nodeid (), &canonical_path); > + rust_assert (ok); > + > + std::string name =3D canonical_path->get (); > + std::string asm_name =3D ctx->mangle_item (resolved_type, *canonical_p= ath); > + > + bool is_external =3D false; > + bool is_hidden =3D false; > + bool in_unique_section =3D true; > + > + Bvariable *static_global > + =3D ctx->get_backend ()->global_variable (name, asm_name, type, is_e= xternal, > + is_hidden, in_unique_section, > + var.get_locus ()); > + ctx->get_backend ()->global_variable_set_init (static_global, value); > + > + ctx->insert_var_decl (var.get_mappings ().get_hirid (), static_global)= ; > + ctx->push_var (static_global); > + > + reference =3D ctx->get_backend ()->var_expression (static_global, ref_= locus); > +} > + > +void > +CompileItem::visit (HIR::ConstantItem &constant) > +{ > + if (ctx->lookup_const_decl (constant.get_mappings ().get_hirid (), > + &reference)) > + return; > + > + // resolve the type > + TyTy::BaseType *resolved_type =3D nullptr; > + bool ok > + =3D ctx->get_tyctx ()->lookup_type (constant.get_mappings ().get_hir= id (), > + &resolved_type); > + rust_assert (ok); > + > + // canonical path > + const Resolver::CanonicalPath *canonical_path =3D nullptr; > + ok =3D ctx->get_mappings ()->lookup_canonical_path ( > + constant.get_mappings ().get_nodeid (), &canonical_path); > + rust_assert (ok); > + > + HIR::Expr *const_value_expr =3D constant.get_expr (); > + ctx->push_const_context (); > + tree const_expr > + =3D compile_constant_item (ctx, resolved_type, canonical_path, > + const_value_expr, constant.get_locus ()); > + ctx->pop_const_context (); > + > + ctx->push_const (const_expr); > + ctx->insert_const_decl (constant.get_mappings ().get_hirid (), const_e= xpr); > + reference =3D const_expr; > +} > + > +void > +CompileItem::visit (HIR::Function &function) > +{ > + TyTy::BaseType *fntype_tyty; > + if (!ctx->get_tyctx ()->lookup_type (function.get_mappings ().get_hiri= d (), > + &fntype_tyty)) > + { > + rust_fatal_error (function.get_locus (), > + "failed to lookup function type"); > + return; > + } > + > + rust_assert (fntype_tyty->get_kind () =3D=3D TyTy::TypeKind::FNDEF); > + TyTy::FnType *fntype =3D static_cast (fntype_tyty); > + if (fntype->has_subsititions_defined ()) > + { > + // we cant do anything for this only when it is used and a concret= e type > + // is given > + if (concrete =3D=3D nullptr) > + return; > + else > + { > + rust_assert (concrete->get_kind () =3D=3D TyTy::TypeKind::FNDEF= ); > + fntype =3D static_cast (concrete); > + fntype->monomorphize (); > + } > + } > + > + // items can be forward compiled which means we may not need to invoke= this > + // code. We might also have already compiled this generic function as = well. > + tree lookup =3D NULL_TREE; > + if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup, > + fntype->get_id (), fntype)) > + { > + // has this been added to the list then it must be finished > + if (ctx->function_completed (lookup)) > + { > + tree dummy =3D NULL_TREE; > + if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy)) > + { > + ctx->insert_function_decl (fntype, lookup); > + } > + > + reference =3D address_expression (lookup, ref_locus); > + return; > + } > + } > + > + if (fntype->has_subsititions_defined ()) > + { > + // override the Hir Lookups for the substituions in this context > + fntype->override_context (); > + } > + > + const Resolver::CanonicalPath *canonical_path =3D nullptr; > + bool ok =3D ctx->get_mappings ()->lookup_canonical_path ( > + function.get_mappings ().get_nodeid (), &canonical_path); > + rust_assert (ok); > + > + tree fndecl > + =3D compile_function (ctx, function.get_function_name (), > + function.get_self_param (), > + function.get_function_params (), > + function.get_qualifiers (), function.get_visibili= ty (), > + function.get_outer_attrs (), function.get_locus (= ), > + function.get_definition ().get (), canonical_path= , > + fntype, function.has_function_return_type ()); > + reference =3D address_expression (fndecl, ref_locus); > +} > + > +void > +CompileItem::visit (HIR::ImplBlock &impl_block) > +{ > + TyTy::BaseType *self_lookup =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type ( > + impl_block.get_type ()->get_mappings ().get_hirid (), &self_looku= p)) > + { > + rust_error_at (impl_block.get_locus (), "failed to resolve type of= impl"); > + return; > + } > + > + for (auto &impl_item : impl_block.get_impl_items ()) > + CompileInherentImplItem::Compile (impl_item.get (), ctx); > +} > + > +void > +CompileItem::visit (HIR::ExternBlock &extern_block) > +{ > + for (auto &item : extern_block.get_extern_items ()) > + { > + CompileExternItem::compile (item.get (), ctx, concrete); > + } > +} > + > +void > +CompileItem::visit (HIR::Module &module) > +{ > + for (auto &item : module.get_items ()) > + CompileItem::compile (item.get (), ctx); > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust= -compile-item.h > new file mode 100644 > index 00000000000..3c12f1040fc > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-item.h > @@ -0,0 +1,88 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_ITEM > +#define RUST_COMPILE_ITEM > + > +#include "rust-compile-base.h" > + > +namespace Rust { > +namespace Compile { > + > +class CompileItem : private HIRCompileBase, protected HIR::HIRStmtVisito= r > +{ > +protected: > +public: > + static tree compile (HIR::Item *item, Context *ctx, > + TyTy::BaseType *concrete =3D nullptr, > + bool is_query_mode =3D false, > + Location ref_locus =3D Location ()) > + { > + CompileItem compiler (ctx, concrete, ref_locus); > + item->accept_vis (compiler); > + > + if (is_query_mode && compiler.reference =3D=3D error_mark_node) > + rust_internal_error_at (ref_locus, "failed to compile item: %s", > + item->as_string ().c_str ()); > + > + return compiler.reference; > + } > + > + void visit (HIR::StaticItem &var) override; > + void visit (HIR::ConstantItem &constant) override; > + void visit (HIR::Function &function) override; > + void visit (HIR::ImplBlock &impl_block) override; > + void visit (HIR::ExternBlock &extern_block) override; > + void visit (HIR::Module &module) override; > + > + // Empty visit for unused Stmt HIR nodes. > + void visit (HIR::TupleStruct &) override {} > + void visit (HIR::EnumItem &) override {} > + void visit (HIR::EnumItemTuple &) override {} > + void visit (HIR::EnumItemStruct &) override {} > + void visit (HIR::EnumItemDiscriminant &) override {} > + void visit (HIR::TypePathSegmentFunction &) override {} > + void visit (HIR::TypePath &) override {} > + void visit (HIR::QualifiedPathInType &) override {} > + void visit (HIR::ExternCrate &) override {} > + void visit (HIR::UseDeclaration &) override {} > + void visit (HIR::TypeAlias &) override {} > + void visit (HIR::StructStruct &) override {} > + void visit (HIR::Enum &) override {} > + void visit (HIR::Union &) override {} > + void visit (HIR::Trait &) override {} > + void visit (HIR::EmptyStmt &) override {} > + void visit (HIR::LetStmt &) override {} > + void visit (HIR::ExprStmtWithoutBlock &) override {} > + void visit (HIR::ExprStmtWithBlock &) override {} > + > +protected: > + CompileItem (Context *ctx, TyTy::BaseType *concrete, Location ref_locu= s) > + : HIRCompileBase (ctx), concrete (concrete), reference (error_mark_n= ode), > + ref_locus (ref_locus) > + {} > + > + TyTy::BaseType *concrete; > + tree reference; > + Location ref_locus; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_ITEM > diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/= rust-compile-pattern.cc > new file mode 100644 > index 00000000000..1d8eda1a577 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-pattern.cc > @@ -0,0 +1,333 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-pattern.h" > +#include "rust-compile-expr.h" > +#include "rust-compile-resolve-path.h" > +#include "rust-constexpr.h" > + > +namespace Rust { > +namespace Compile { > + > +void > +CompilePatternCaseLabelExpr::visit (HIR::PathInExpression &pattern) > +{ > + // lookup the type > + TyTy::BaseType *lookup =3D nullptr; > + bool ok > + =3D ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hiri= d (), > + &lookup); > + rust_assert (ok); > + > + // this must be an enum > + rust_assert (lookup->get_kind () =3D=3D TyTy::TypeKind::ADT); > + TyTy::ADTType *adt =3D static_cast (lookup); > + rust_assert (adt->is_enum ()); > + > + // lookup the variant > + HirId variant_id; > + ok =3D ctx->get_tyctx ()->lookup_variant_definition ( > + pattern.get_mappings ().get_hirid (), &variant_id); > + rust_assert (ok); > + > + TyTy::VariantDef *variant =3D nullptr; > + ok =3D adt->lookup_variant_by_id (variant_id, &variant); > + rust_assert (ok); > + > + HIR::Expr *discrim_expr =3D variant->get_discriminant (); > + tree discrim_expr_node =3D CompileExpr::Compile (discrim_expr, ctx); > + tree folded_discrim_expr =3D fold_expr (discrim_expr_node); > + tree case_low =3D folded_discrim_expr; > + > + case_label_expr > + =3D build_case_label (case_low, NULL_TREE, associated_case_label); > +} > + > +void > +CompilePatternCaseLabelExpr::visit (HIR::StructPattern &pattern) > +{ > + CompilePatternCaseLabelExpr::visit (pattern.get_path ()); > +} > + > +void > +CompilePatternCaseLabelExpr::visit (HIR::TupleStructPattern &pattern) > +{ > + CompilePatternCaseLabelExpr::visit (pattern.get_path ()); > +} > + > +void > +CompilePatternCaseLabelExpr::visit (HIR::WildcardPattern &pattern) > +{ > + // operand 0 being NULL_TREE signifies this is the default case label = see: > + // tree.def for documentation for CASE_LABEL_EXPR > + case_label_expr > + =3D build_case_label (NULL_TREE, NULL_TREE, associated_case_label); > +} > + > +void > +CompilePatternCaseLabelExpr::visit (HIR::LiteralPattern &pattern) > +{ > + // Compile the literal > + HIR::LiteralExpr *litexpr > + =3D new HIR::LiteralExpr (pattern.get_pattern_mappings (), > + pattern.get_literal (), pattern.get_locus (), > + std::vector ()); > + > + // Note: Floating point literals are currently accepted but will likel= y be > + // forbidden in LiteralPatterns in a future version of Rust. > + // See: https://github.com/rust-lang/rust/issues/41620 > + // For now, we cannot compile them anyway as CASE_LABEL_EXPR does not = support > + // floating point types. > + if (pattern.get_literal ().get_lit_type () =3D=3D HIR::Literal::LitTyp= e::FLOAT) > + { > + rust_sorry_at (pattern.get_locus (), "floating-point literal in pa= ttern"); > + } > + > + tree lit =3D CompileExpr::Compile (litexpr, ctx); > + > + case_label_expr =3D build_case_label (lit, NULL_TREE, associated_case_= label); > +} > + > +static tree > +compile_range_pattern_bound (HIR::RangePatternBound *bound, > + Analysis::NodeMapping mappings, Location loc= us, > + Context *ctx) > +{ > + tree result =3D NULL_TREE; > + switch (bound->get_bound_type ()) > + { > + case HIR::RangePatternBound::RangePatternBoundType::LITERAL: { > + HIR::RangePatternBoundLiteral &ref > + =3D *static_cast (bound); > + > + HIR::LiteralExpr *litexpr > + =3D new HIR::LiteralExpr (mappings, ref.get_literal (), locus, > + std::vector ()); > + > + result =3D CompileExpr::Compile (litexpr, ctx); > + } > + break; > + > + case HIR::RangePatternBound::RangePatternBoundType::PATH: { > + HIR::RangePatternBoundPath &ref > + =3D *static_cast (bound); > + > + result =3D ResolvePathRef::Compile (ref.get_path (), ctx); > + > + // If the path resolves to a const expression, fold it. > + result =3D fold_expr (result); > + } > + break; > + > + case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: { > + HIR::RangePatternBoundQualPath &ref > + =3D *static_cast (bound); > + > + result =3D ResolvePathRef::Compile (ref.get_qualified_path (), ct= x); > + > + // If the path resolves to a const expression, fold it. > + result =3D fold_expr (result); > + } > + } > + > + return result; > +} > + > +void > +CompilePatternCaseLabelExpr::visit (HIR::RangePattern &pattern) > +{ > + tree upper =3D compile_range_pattern_bound (pattern.get_upper_bound ()= .get (), > + pattern.get_pattern_mappings = (), > + pattern.get_locus (), ctx); > + tree lower =3D compile_range_pattern_bound (pattern.get_lower_bound ()= .get (), > + pattern.get_pattern_mappings = (), > + pattern.get_locus (), ctx); > + > + case_label_expr =3D build_case_label (lower, upper, associated_case_la= bel); > +} > + > +// setup the bindings > + > +void > +CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) > +{ > + // lookup the type > + TyTy::BaseType *lookup =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type ( > + pattern.get_path ().get_mappings ().get_hirid (), &lookup); > + rust_assert (ok); > + > + // this must be an enum > + rust_assert (lookup->get_kind () =3D=3D TyTy::TypeKind::ADT); > + TyTy::ADTType *adt =3D static_cast (lookup); > + rust_assert (adt->number_of_variants () > 0); > + > + int variant_index =3D 0; > + TyTy::VariantDef *variant =3D adt->get_variants ().at (0); > + if (adt->is_enum ()) > + { > + HirId variant_id =3D UNKNOWN_HIRID; > + bool ok =3D ctx->get_tyctx ()->lookup_variant_definition ( > + pattern.get_path ().get_mappings ().get_hirid (), &variant_id); > + rust_assert (ok); > + > + ok =3D adt->lookup_variant_by_id (variant_id, &variant, &variant_i= ndex); > + rust_assert (ok); > + } > + > + rust_assert (variant->get_variant_type () > + =3D=3D TyTy::VariantDef::VariantType::TUPLE); > + > + std::unique_ptr &items =3D pattern.get_items ()= ; > + switch (items->get_item_type ()) > + { > + case HIR::TupleStructItems::RANGE: { > + // TODO > + gcc_unreachable (); > + } > + break; > + > + case HIR::TupleStructItems::NO_RANGE: { > + HIR::TupleStructItemsNoRange &items_no_range > + =3D static_cast (*items.get ())= ; > + > + rust_assert (items_no_range.get_patterns ().size () > + =3D=3D variant->num_fields ()); > + > + if (adt->is_enum ()) > + { > + // we are offsetting by + 1 here since the first field in the= record > + // is always the discriminator > + size_t tuple_field_index =3D 1; > + for (auto &pattern : items_no_range.get_patterns ()) > + { > + tree variant_accessor > + =3D ctx->get_backend ()->struct_field_expression ( > + match_scrutinee_expr, variant_index, pattern->get_loc= us ()); > + > + tree binding =3D ctx->get_backend ()->struct_field_expres= sion ( > + variant_accessor, tuple_field_index++, pattern->get_loc= us ()); > + > + ctx->insert_pattern_binding ( > + pattern->get_pattern_mappings ().get_hirid (), binding)= ; > + } > + } > + else > + { > + size_t tuple_field_index =3D 0; > + for (auto &pattern : items_no_range.get_patterns ()) > + { > + tree variant_accessor =3D match_scrutinee_expr; > + > + tree binding =3D ctx->get_backend ()->struct_field_expres= sion ( > + variant_accessor, tuple_field_index++, pattern->get_loc= us ()); > + > + ctx->insert_pattern_binding ( > + pattern->get_pattern_mappings ().get_hirid (), binding)= ; > + } > + } > + } > + break; > + } > +} > + > +void > +CompilePatternBindings::visit (HIR::StructPattern &pattern) > +{ > + // lookup the type > + TyTy::BaseType *lookup =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type ( > + pattern.get_path ().get_mappings ().get_hirid (), &lookup); > + rust_assert (ok); > + > + // this must be an enum > + rust_assert (lookup->get_kind () =3D=3D TyTy::TypeKind::ADT); > + TyTy::ADTType *adt =3D static_cast (lookup); > + rust_assert (adt->number_of_variants () > 0); > + > + int variant_index =3D 0; > + TyTy::VariantDef *variant =3D adt->get_variants ().at (0); > + if (adt->is_enum ()) > + { > + HirId variant_id =3D UNKNOWN_HIRID; > + bool ok =3D ctx->get_tyctx ()->lookup_variant_definition ( > + pattern.get_path ().get_mappings ().get_hirid (), &variant_id); > + rust_assert (ok); > + > + ok =3D adt->lookup_variant_by_id (variant_id, &variant, &variant_i= ndex); > + rust_assert (ok); > + } > + > + rust_assert (variant->get_variant_type () > + =3D=3D TyTy::VariantDef::VariantType::STRUCT); > + > + auto &struct_pattern_elems =3D pattern.get_struct_pattern_elems (); > + for (auto &field : struct_pattern_elems.get_struct_pattern_fields ()) > + { > + switch (field->get_item_type ()) > + { > + case HIR::StructPatternField::ItemType::TUPLE_PAT: { > + // TODO > + gcc_unreachable (); > + } > + break; > + > + case HIR::StructPatternField::ItemType::IDENT_PAT: { > + // TODO > + gcc_unreachable (); > + } > + break; > + > + case HIR::StructPatternField::ItemType::IDENT: { > + HIR::StructPatternFieldIdent &ident > + =3D static_cast (*field.get= ()); > + > + size_t offs =3D 0; > + ok > + =3D variant->lookup_field (ident.get_identifier (), nullptr= , &offs); > + rust_assert (ok); > + > + tree binding =3D error_mark_node; > + if (adt->is_enum ()) > + { > + tree variant_accessor > + =3D ctx->get_backend ()->struct_field_expression ( > + match_scrutinee_expr, variant_index, ident.get_locus = ()); > + > + // we are offsetting by + 1 here since the first field in= the > + // record is always the discriminator > + binding =3D ctx->get_backend ()->struct_field_expression = ( > + variant_accessor, offs + 1, ident.get_locus ()); > + } > + else > + { > + tree variant_accessor =3D match_scrutinee_expr; > + binding =3D ctx->get_backend ()->struct_field_expression = ( > + variant_accessor, offs, ident.get_locus ()); > + } > + > + ctx->insert_pattern_binding (ident.get_mappings ().get_hirid = (), > + binding); > + } > + break; > + } > + } > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/r= ust-compile-pattern.h > new file mode 100644 > index 00000000000..0eb5d61249b > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-pattern.h > @@ -0,0 +1,95 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-base.h" > + > +namespace Rust { > +namespace Compile { > + > +class CompilePatternCaseLabelExpr : public HIRCompileBase, > + public HIR::HIRPatternVisitor > +{ > +public: > + static tree Compile (HIR::Pattern *pattern, tree associated_case_label= , > + Context *ctx) > + { > + CompilePatternCaseLabelExpr compiler (ctx, associated_case_label); > + pattern->accept_vis (compiler); > + return compiler.case_label_expr; > + } > + > + void visit (HIR::PathInExpression &pattern) override; > + void visit (HIR::StructPattern &pattern) override; > + void visit (HIR::TupleStructPattern &pattern) override; > + void visit (HIR::WildcardPattern &pattern) override; > + void visit (HIR::RangePattern &pattern) override; > + > + // Empty visit for unused Pattern HIR nodes. > + void visit (HIR::GroupedPattern &) override {} > + void visit (HIR::IdentifierPattern &) override {} > + void visit (HIR::LiteralPattern &) override; > + void visit (HIR::QualifiedPathInExpression &) override {} > + void visit (HIR::ReferencePattern &) override {} > + void visit (HIR::SlicePattern &) override {} > + void visit (HIR::TuplePattern &) override {} > + > + CompilePatternCaseLabelExpr (Context *ctx, tree associated_case_label) > + : HIRCompileBase (ctx), case_label_expr (error_mark_node), > + associated_case_label (associated_case_label) > + {} > + > + tree case_label_expr; > + tree associated_case_label; > +}; > + > +class CompilePatternBindings : public HIRCompileBase, > + public HIR::HIRPatternVisitor > +{ > +public: > + static void Compile (HIR::Pattern *pattern, tree match_scrutinee_expr, > + Context *ctx) > + { > + CompilePatternBindings compiler (ctx, match_scrutinee_expr); > + pattern->accept_vis (compiler); > + } > + > + void visit (HIR::StructPattern &pattern) override; > + void visit (HIR::TupleStructPattern &pattern) override; > + > + // Empty visit for unused Pattern HIR nodes. > + void visit (HIR::GroupedPattern &) override {} > + void visit (HIR::IdentifierPattern &) override {} > + void visit (HIR::LiteralPattern &) override {} > + void visit (HIR::PathInExpression &) override {} > + void visit (HIR::QualifiedPathInExpression &) override {} > + void visit (HIR::RangePattern &) override {} > + void visit (HIR::ReferencePattern &) override {} > + void visit (HIR::SlicePattern &) override {} > + void visit (HIR::TuplePattern &) override {} > + void visit (HIR::WildcardPattern &) override {} > + > +protected: > + CompilePatternBindings (Context *ctx, tree match_scrutinee_expr) > + : HIRCompileBase (ctx), match_scrutinee_expr (match_scrutinee_expr) > + {} > + > + tree match_scrutinee_expr; > +}; > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/bac= kend/rust-compile-resolve-path.cc > new file mode 100644 > index 00000000000..4fb3d540257 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-resolve-path.cc > @@ -0,0 +1,301 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-resolve-path.h" > +#include "rust-compile-intrinsic.h" > +#include "rust-compile-item.h" > +#include "rust-compile-implitem.h" > +#include "rust-compile-expr.h" > +#include "rust-hir-trait-resolve.h" > +#include "rust-hir-path-probe.h" > +#include "rust-compile-extern.h" > +#include "rust-constexpr.h" > + > +namespace Rust { > +namespace Compile { > + > +void > +ResolvePathRef::visit (HIR::QualifiedPathInExpression &expr) > +{ > + resolved =3D resolve (expr.get_final_segment ().get_segment (), > + expr.get_mappings (), expr.get_locus (), true); > +} > + > +void > +ResolvePathRef::visit (HIR::PathInExpression &expr) > +{ > + resolved =3D resolve (expr.get_final_segment ().get_segment (), > + expr.get_mappings (), expr.get_locus (), false); > +} > + > +tree > +ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment, > + const Analysis::NodeMapping &mappings, > + Location expr_locus, bool is_qualified_path) > +{ > + TyTy::BaseType *lookup =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lo= okup); > + rust_assert (ok); > + > + // need to look up the reference for this identifier > + NodeId ref_node_id =3D UNKNOWN_NODEID; > + if (!ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (= ), > + &ref_node_id)) > + { > + // this can fail because it might be a Constructor for something > + // in that case the caller should attempt ResolvePathType::Compile > + > + // it might be an enum data-less enum variant > + if (lookup->get_kind () !=3D TyTy::TypeKind::ADT) > + return error_mark_node; > + > + TyTy::ADTType *adt =3D static_cast (lookup); > + > + // it might be a unit-struct > + if (adt->is_unit ()) > + { > + return ctx->get_backend ()->unit_expression (); > + } > + > + if (!adt->is_enum ()) > + return error_mark_node; > + > + HirId variant_id; > + if (!ctx->get_tyctx ()->lookup_variant_definition (mappings.get_hi= rid (), > + &variant_id)) > + return error_mark_node; > + > + int union_disriminator =3D -1; > + TyTy::VariantDef *variant =3D nullptr; > + if (!adt->lookup_variant_by_id (variant_id, &variant, > + &union_disriminator)) > + return error_mark_node; > + > + // this can only be for discriminant variants the others are built= up > + // using call-expr or struct-init > + rust_assert (variant->get_variant_type () > + =3D=3D TyTy::VariantDef::VariantType::NUM); > + > + // we need the actual gcc type > + tree compiled_adt_type =3D TyTyResolveCompile::compile (ctx, adt); > + > + // make the ctor for the union > + HIR::Expr *discrim_expr =3D variant->get_discriminant (); > + tree discrim_expr_node =3D CompileExpr::Compile (discrim_expr, ctx= ); > + tree folded_discrim_expr =3D fold_expr (discrim_expr_node); > + tree qualifier =3D folded_discrim_expr; > + > + return ctx->get_backend ()->constructor_expression (compiled_adt_t= ype, > + true, {qualifie= r}, > + union_disrimina= tor, > + expr_locus); > + } > + > + HirId ref; > + if (!ctx->get_mappings ()->lookup_node_to_hir (ref_node_id, &ref)) > + { > + rust_error_at (expr_locus, "reverse call path lookup failure"); > + return error_mark_node; > + } > + > + // might be a constant > + tree constant_expr; > + if (ctx->lookup_const_decl (ref, &constant_expr)) > + { > + TREE_USED (constant_expr) =3D 1; > + return constant_expr; > + } > + > + // this might be a variable reference or a function reference > + Bvariable *var =3D nullptr; > + if (ctx->lookup_var_decl (ref, &var)) > + { > + // TREE_USED is setup in the gcc abstraction here > + return ctx->get_backend ()->var_expression (var, expr_locus); > + } > + > + // might be a match pattern binding > + tree binding =3D error_mark_node; > + if (ctx->lookup_pattern_binding (ref, &binding)) > + { > + TREE_USED (binding) =3D 1; > + return binding; > + } > + > + // it might be a function call > + if (lookup->get_kind () =3D=3D TyTy::TypeKind::FNDEF) > + { > + TyTy::FnType *fntype =3D static_cast (lookup); > + tree fn =3D NULL_TREE; > + if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn)) > + { > + TREE_USED (fn) =3D 1; > + return address_expression (fn, expr_locus); > + } > + else if (fntype->get_abi () =3D=3D ABI::INTRINSIC) > + { > + Intrinsics compile (ctx); > + fn =3D compile.compile (fntype); > + TREE_USED (fn) =3D 1; > + return address_expression (fn, expr_locus); > + } > + } > + > + // let the query system figure it out > + tree resolved_item =3D query_compile (ref, lookup, final_segment, mapp= ings, > + expr_locus, is_qualified_path); > + if (resolved_item !=3D error_mark_node) > + { > + TREE_USED (resolved_item) =3D 1; > + } > + return resolved_item; > +} > + > +tree > +HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup, > + const HIR::PathIdentSegment &final_segment= , > + const Analysis::NodeMapping &mappings, > + Location expr_locus, bool is_qualified_pat= h) > +{ > + HIR::Item *resolved_item =3D ctx->get_mappings ()->lookup_hir_item (re= f); > + HirId parent_block; > + HIR::ExternalItem *resolved_extern_item > + =3D ctx->get_mappings ()->lookup_hir_extern_item (ref, &parent_block= ); > + bool is_hir_item =3D resolved_item !=3D nullptr; > + bool is_hir_extern_item =3D resolved_extern_item !=3D nullptr; > + if (is_hir_item) > + { > + if (!lookup->has_subsititions_defined ()) > + return CompileItem::compile (resolved_item, ctx, nullptr, true, > + expr_locus); > + else > + return CompileItem::compile (resolved_item, ctx, lookup, true, > + expr_locus); > + } > + else if (is_hir_extern_item) > + { > + if (!lookup->has_subsititions_defined ()) > + return CompileExternItem::compile (resolved_extern_item, ctx, nul= lptr, > + true, expr_locus); > + else > + return CompileExternItem::compile (resolved_extern_item, ctx, loo= kup, > + true, expr_locus); > + } > + else > + { > + HirId parent_impl_id =3D UNKNOWN_HIRID; > + HIR::ImplItem *resolved_item > + =3D ctx->get_mappings ()->lookup_hir_implitem (ref, &parent_impl_= id); > + bool is_impl_item =3D resolved_item !=3D nullptr; > + if (is_impl_item) > + { > + rust_assert (parent_impl_id !=3D UNKNOWN_HIRID); > + HIR::Item *impl_ref > + =3D ctx->get_mappings ()->lookup_hir_item (parent_impl_id); > + rust_assert (impl_ref !=3D nullptr); > + HIR::ImplBlock *impl =3D static_cast (impl_re= f); > + > + TyTy::BaseType *self =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type ( > + impl->get_type ()->get_mappings ().get_hirid (), &self); > + rust_assert (ok); > + > + if (!lookup->has_subsititions_defined ()) > + return CompileInherentImplItem::Compile (resolved_item, ctx, > + nullptr, true, expr_= locus); > + else > + return CompileInherentImplItem::Compile (resolved_item, ctx, = lookup, > + true, expr_locus); > + } > + else > + { > + // it might be resolved to a trait item > + HIR::TraitItem *trait_item > + =3D ctx->get_mappings ()->lookup_hir_trait_item (ref); > + HIR::Trait *trait =3D ctx->get_mappings ()->lookup_trait_item_m= apping ( > + trait_item->get_mappings ().get_hirid ()); > + > + Resolver::TraitReference *trait_ref > + =3D &Resolver::TraitReference::error_node (); > + bool ok =3D ctx->get_tyctx ()->lookup_trait_reference ( > + trait->get_mappings ().get_defid (), &trait_ref); > + rust_assert (ok); > + > + TyTy::BaseType *receiver =3D nullptr; > + ok =3D ctx->get_tyctx ()->lookup_receiver (mappings.get_hirid (= ), > + &receiver); > + rust_assert (ok); > + > + if (receiver->get_kind () =3D=3D TyTy::TypeKind::PARAM) > + { > + TyTy::ParamType *p =3D static_cast (rece= iver); > + receiver =3D p->resolve (); > + } > + > + // the type resolver can only resolve type bounds to their trai= t > + // item so its up to us to figure out if this path should resol= ve > + // to an trait-impl-block-item or if it can be defaulted to the > + // trait-impl-item's definition > + std::vector candidates > + =3D Resolver::PathProbeImplTrait::Probe (receiver, final_segm= ent, > + trait_ref); > + if (candidates.size () =3D=3D 0) > + { > + // this means we are defaulting back to the trait_item if > + // possible > + Resolver::TraitItemReference *trait_item_ref =3D nullptr; > + bool ok =3D trait_ref->lookup_hir_trait_item (*trait_item, > + &trait_item_ref= ); > + rust_assert (ok); // found > + rust_assert (trait_item_ref->is_optional ()); // has defini= tion > + > + return CompileTraitItem::Compile ( > + trait_item_ref->get_hir_trait_item (), ctx, lookup, true, > + expr_locus); > + } > + else > + { > + Resolver::PathProbeCandidate &candidate =3D candidates.at (= 0); > + rust_assert (candidate.is_impl_candidate ()); > + > + HIR::ImplBlock *impl =3D candidate.item.impl.parent; > + HIR::ImplItem *impl_item =3D candidate.item.impl.impl_item; > + > + TyTy::BaseType *self =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type ( > + impl->get_type ()->get_mappings ().get_hirid (), &self); > + rust_assert (ok); > + > + if (!lookup->has_subsititions_defined ()) > + return CompileInherentImplItem::Compile (impl_item, ctx, > + nullptr, true, > + expr_locus); > + else > + return CompileInherentImplItem::Compile (impl_item, ctx, = lookup, > + true, expr_locus= ); > + > + lookup->set_ty_ref (impl_item->get_impl_mappings ().get_hir= id ()); > + } > + } > + } > + > + return error_mark_node; > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-resolve-path.h b/gcc/rust/back= end/rust-compile-resolve-path.h > new file mode 100644 > index 00000000000..f0360bdc739 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-resolve-path.h > @@ -0,0 +1,73 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_RESOLVE_PATH > +#define RUST_COMPILE_RESOLVE_PATH > + > +#include "rust-compile-base.h" > + > +namespace Rust { > +namespace Compile { > + > +class ResolvePathRef : public HIRCompileBase, public HIR::HIRPatternVisi= tor > +{ > +public: > + static tree Compile (HIR::QualifiedPathInExpression &expr, Context *ct= x) > + { > + ResolvePathRef resolver (ctx); > + expr.accept_vis (resolver); > + return resolver.resolved; > + } > + > + static tree Compile (HIR::PathInExpression &expr, Context *ctx) > + { > + ResolvePathRef resolver (ctx); > + expr.accept_vis (resolver); > + return resolver.resolved; > + } > + > + void visit (HIR::PathInExpression &expr) override; > + void visit (HIR::QualifiedPathInExpression &expr) override; > + > + // Empty visit for unused Pattern HIR nodes. > + void visit (HIR::GroupedPattern &) override {} > + void visit (HIR::IdentifierPattern &) override {} > + void visit (HIR::LiteralPattern &) override {} > + void visit (HIR::RangePattern &) override {} > + void visit (HIR::ReferencePattern &) override {} > + void visit (HIR::SlicePattern &) override {} > + void visit (HIR::StructPattern &) override {} > + void visit (HIR::TuplePattern &) override {} > + void visit (HIR::TupleStructPattern &) override {} > + void visit (HIR::WildcardPattern &) override {} > + > + ResolvePathRef (Context *ctx) > + : HIRCompileBase (ctx), resolved (error_mark_node) > + {} > + > + tree resolve (const HIR::PathIdentSegment &final_segment, > + const Analysis::NodeMapping &mappings, Location locus, > + bool is_qualified_path); > + > + tree resolved; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_RESOLVE_PATH > diff --git a/gcc/rust/backend/rust-compile-stmt.cc b/gcc/rust/backend/rus= t-compile-stmt.cc > new file mode 100644 > index 00000000000..bfb25f12980 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-stmt.cc > @@ -0,0 +1,115 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-stmt.h" > +#include "rust-compile-expr.h" > + > +namespace Rust { > +namespace Compile { > + > +CompileStmt::CompileStmt (Context *ctx) > + : HIRCompileBase (ctx), translated (nullptr) > +{} > + > +tree > +CompileStmt::Compile (HIR::Stmt *stmt, Context *ctx) > +{ > + CompileStmt compiler (ctx); > + stmt->accept_vis (compiler); > + return compiler.translated; > +} > + > +void > +CompileStmt::visit (HIR::ExprStmtWithBlock &stmt) > +{ > + translated =3D CompileExpr::Compile (stmt.get_expr (), ctx); > +} > + > +void > +CompileStmt::visit (HIR::ExprStmtWithoutBlock &stmt) > +{ > + translated =3D CompileExpr::Compile (stmt.get_expr (), ctx); > +} > + > +void > +CompileStmt::visit (HIR::LetStmt &stmt) > +{ > + // nothing to do > + if (!stmt.has_init_expr ()) > + return; > + > + const HIR::Pattern &stmt_pattern =3D *stmt.get_pattern (); > + HirId stmt_id =3D stmt_pattern.get_pattern_mappings ().get_hirid (); > + > + TyTy::BaseType *ty =3D nullptr; > + if (!ctx->get_tyctx ()->lookup_type (stmt_id, &ty)) > + { > + // FIXME this should be an assertion instead > + rust_fatal_error (stmt.get_locus (), > + "failed to lookup variable declaration type"); > + return; > + } > + > + Bvariable *var =3D nullptr; > + if (!ctx->lookup_var_decl (stmt_id, &var)) > + { > + // FIXME this should be an assertion instead and use error mark no= de > + rust_fatal_error (stmt.get_locus (), > + "failed to lookup compiled variable declaration")= ; > + return; > + } > + > + tree init =3D CompileExpr::Compile (stmt.get_init_expr (), ctx); > + // FIXME use error_mark_node, check that CompileExpr returns error_mar= k_node > + // on failure and make this an assertion > + if (init =3D=3D nullptr) > + return; > + > + TyTy::BaseType *actual =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_type ( > + stmt.get_init_expr ()->get_mappings ().get_hirid (), &actual); > + rust_assert (ok); > + tree stmt_type =3D TyTyResolveCompile::compile (ctx, ty); > + > + Location lvalue_locus =3D stmt.get_pattern ()->get_locus (); > + Location rvalue_locus =3D stmt.get_init_expr ()->get_locus (); > + TyTy::BaseType *expected =3D ty; > + init =3D coercion_site (stmt.get_mappings ().get_hirid (), init, actua= l, > + expected, lvalue_locus, rvalue_locus); > + > + auto fnctx =3D ctx->peek_fn (); > + if (ty->is_unit ()) > + { > + ctx->add_statement (init); > + > + auto unit_type_init_expr > + =3D ctx->get_backend ()->constructor_expression (stmt_type, false= , {}, -1, > + rvalue_locus); > + auto s =3D ctx->get_backend ()->init_statement (fnctx.fndecl, var, > + unit_type_init_expr); > + ctx->add_statement (s); > + } > + else > + { > + auto s =3D ctx->get_backend ()->init_statement (fnctx.fndecl, var,= init); > + ctx->add_statement (s); > + } > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-stmt.h b/gcc/rust/backend/rust= -compile-stmt.h > new file mode 100644 > index 00000000000..a0ec8b26667 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-stmt.h > @@ -0,0 +1,69 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_STMT > +#define RUST_COMPILE_STMT > + > +#include "rust-compile-base.h" > + > +namespace Rust { > +namespace Compile { > + > +class CompileStmt : private HIRCompileBase, protected HIR::HIRStmtVisito= r > +{ > +public: > + static tree Compile (HIR::Stmt *stmt, Context *ctx); > + > + void visit (HIR::ExprStmtWithBlock &stmt) override; > + void visit (HIR::ExprStmtWithoutBlock &stmt) override; > + void visit (HIR::LetStmt &stmt) override; > + > + // Empty visit for unused Stmt HIR nodes. > + void visit (HIR::TupleStruct &) override {} > + void visit (HIR::EnumItem &) override {} > + void visit (HIR::EnumItemTuple &) override {} > + void visit (HIR::EnumItemStruct &) override {} > + void visit (HIR::EnumItemDiscriminant &) override {} > + void visit (HIR::TypePathSegmentFunction &) override {} > + void visit (HIR::TypePath &) override {} > + void visit (HIR::QualifiedPathInType &) override {} > + void visit (HIR::Module &) override {} > + void visit (HIR::ExternCrate &) override {} > + void visit (HIR::UseDeclaration &) override {} > + void visit (HIR::Function &) override {} > + void visit (HIR::TypeAlias &) override {} > + void visit (HIR::StructStruct &) override {} > + void visit (HIR::Enum &) override {} > + void visit (HIR::Union &) override {} > + void visit (HIR::ConstantItem &) override {} > + void visit (HIR::StaticItem &) override {} > + void visit (HIR::Trait &) override {} > + void visit (HIR::ImplBlock &) override {} > + void visit (HIR::ExternBlock &) override {} > + void visit (HIR::EmptyStmt &) override {} > + > +private: > + CompileStmt (Context *ctx); > + > + tree translated; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_STMT > diff --git a/gcc/rust/backend/rust-compile-struct-field-expr.cc b/gcc/rus= t/backend/rust-compile-struct-field-expr.cc > new file mode 100644 > index 00000000000..c9a2811f611 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-struct-field-expr.cc > @@ -0,0 +1,81 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-struct-field-expr.h" > +#include "rust-compile-expr.h" > + > +namespace Rust { > +namespace Compile { > + > +CompileStructExprField::CompileStructExprField (Context *ctx) > + : HIRCompileBase (ctx), translated (error_mark_node) > +{} > + > +tree > +CompileStructExprField::Compile (HIR::StructExprField *field, Context *c= tx) > +{ > + CompileStructExprField compiler (ctx); > + switch (field->get_kind ()) > + { > + case HIR::StructExprField::StructExprFieldKind::IDENTIFIER: > + compiler.visit (static_cast (*fi= eld)); > + break; > + > + case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE: > + compiler.visit ( > + static_cast (*field)); > + break; > + > + case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE: > + compiler.visit (static_cast (*fi= eld)); > + break; > + } > + return compiler.translated; > +} > + > +void > +CompileStructExprField::visit (HIR::StructExprFieldIdentifierValue &fiel= d) > +{ > + translated =3D CompileExpr::Compile (field.get_value (), ctx); > +} > + > +void > +CompileStructExprField::visit (HIR::StructExprFieldIndexValue &field) > +{ > + translated =3D CompileExpr::Compile (field.get_value (), ctx); > +} > + > +void > +CompileStructExprField::visit (HIR::StructExprFieldIdentifier &field) > +{ > + // we can make the field look like a path expr to take advantage of ex= isting > + // code > + > + Analysis::NodeMapping mappings_copy1 =3D field.get_mappings (); > + Analysis::NodeMapping mappings_copy2 =3D field.get_mappings (); > + > + HIR::PathIdentSegment ident_seg (field.get_field_name ()); > + HIR::PathExprSegment seg (mappings_copy1, ident_seg, field.get_locus (= ), > + HIR::GenericArgs::create_empty ()); > + HIR::PathInExpression expr (mappings_copy2, {seg}, field.get_locus (),= false, > + {}); > + translated =3D CompileExpr::Compile (&expr, ctx); > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-struct-field-expr.h b/gcc/rust= /backend/rust-compile-struct-field-expr.h > new file mode 100644 > index 00000000000..bc5da080dfe > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-struct-field-expr.h > @@ -0,0 +1,46 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_STRUCT_FIELD_EXPR > +#define RUST_COMPILE_STRUCT_FIELD_EXPR > + > +#include "rust-compile-base.h" > + > +namespace Rust { > +namespace Compile { > + > +class CompileStructExprField : private HIRCompileBase > +{ > +public: > + static tree Compile (HIR::StructExprField *field, Context *ctx); > + > +protected: > + void visit (HIR::StructExprFieldIdentifierValue &field); > + void visit (HIR::StructExprFieldIndexValue &field); > + void visit (HIR::StructExprFieldIdentifier &field); > + > +private: > + CompileStructExprField (Context *ctx); > + > + tree translated; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_STRUCT_FIELD_EXPR > diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rus= t-compile-type.cc > new file mode 100644 > index 00000000000..eced909673e > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-type.cc > @@ -0,0 +1,713 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#include "rust-compile-type.h" > +#include "rust-compile-expr.h" > +#include "rust-constexpr.h" > + > +#include "tree.h" > + > +namespace Rust { > +namespace Compile { > + > +static const std::string RUST_ENUM_DISR_FIELD_NAME =3D "RUST$ENUM$DISR"; > + > +TyTyResolveCompile::TyTyResolveCompile (Context *ctx, bool trait_object_= mode) > + : ctx (ctx), trait_object_mode (trait_object_mode), > + translated (error_mark_node), recurisve_ops (0) > +{} > + > +tree > +TyTyResolveCompile::compile (Context *ctx, const TyTy::BaseType *ty, > + bool trait_object_mode) > +{ > + TyTyResolveCompile compiler (ctx, trait_object_mode); > + ty->accept_vis (compiler); > + > + if (compiler.translated !=3D error_mark_node > + && TYPE_NAME (compiler.translated) !=3D NULL) > + { > + // canonicalize the type > + compiler.translated =3D ctx->insert_compiled_type (compiler.transl= ated); > + } > + > + return compiler.translated; > +} > + > +// see: gcc/c/c-decl.cc:8230-8241 > +// https://github.com/Rust-GCC/gccrs/blob/0024bc2f028369b871a65ceb11b2fd= dfb0f9c3aa/gcc/c/c-decl.c#L8229-L8241 > +tree > +TyTyResolveCompile::get_implicit_enumeral_node_type (Context *ctx) > +{ > + // static tree enum_node =3D NULL_TREE; > + // if (enum_node =3D=3D NULL_TREE) > + // { > + // enum_node =3D make_node (ENUMERAL_TYPE); > + // SET_TYPE_MODE (enum_node, TYPE_MODE (unsigned_type_node)); > + // SET_TYPE_ALIGN (enum_node, TYPE_ALIGN (unsigned_type_node)); > + // TYPE_USER_ALIGN (enum_node) =3D 0; > + // TYPE_UNSIGNED (enum_node) =3D 1; > + // TYPE_PRECISION (enum_node) =3D TYPE_PRECISION (unsigned_type_no= de); > + // TYPE_MIN_VALUE (enum_node) =3D TYPE_MIN_VALUE (unsigned_type_no= de); > + // TYPE_MAX_VALUE (enum_node) =3D TYPE_MAX_VALUE (unsigned_type_no= de); > + > + // // tree identifier =3D ctx->get_backend ()->get_identifier_node > + // // ("enumeral"); tree enum_decl > + // // =3D build_decl (BUILTINS_LOCATION, TYPE_DECL, identifier, > + // enum_node); > + // // TYPE_NAME (enum_node) =3D enum_decl; > + // } > + // return enum_node; > + > + static tree enum_node =3D NULL_TREE; > + if (enum_node =3D=3D NULL_TREE) > + { > + enum_node =3D ctx->get_backend ()->named_type ( > + "enumeral", ctx->get_backend ()->integer_type (false, 64), > + Linemap::predeclared_location ()); > + } > + return enum_node; > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::ErrorType &) > +{ > + translated =3D error_mark_node; > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::InferType &) > +{ > + translated =3D error_mark_node; > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::ClosureType &) > +{ > + gcc_unreachable (); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::ProjectionType &type) > +{ > + type.get ()->accept_vis (*this); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::PlaceholderType &type) > +{ > + type.resolve ()->accept_vis (*this); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::ParamType ¶m) > +{ > + if (recurisve_ops++ >=3D rust_max_recursion_depth) > + { > + rust_error_at (Location (), > + "% count exceeds limit of %i (use = " > + "% to increase the li= mit)", > + rust_max_recursion_depth); > + translated =3D error_mark_node; > + return; > + } > + > + param.resolve ()->accept_vis (*this); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::FnType &type) > +{ > + Backend::typed_identifier receiver; > + std::vector parameters; > + std::vector results; > + > + if (!type.get_return_type ()->is_unit ()) > + { > + auto hir_type =3D type.get_return_type (); > + auto ret =3D TyTyResolveCompile::compile (ctx, hir_type, trait_obj= ect_mode); > + results.push_back (Backend::typed_identifier ( > + "_", ret, > + ctx->get_mappings ()->lookup_location (hir_type->get_ref ()))); > + } > + > + for (auto ¶m_pair : type.get_params ()) > + { > + auto param_tyty =3D param_pair.second; > + auto compiled_param_type > + =3D TyTyResolveCompile::compile (ctx, param_tyty, trait_object_mo= de); > + > + auto compiled_param =3D Backend::typed_identifier ( > + param_pair.first->as_string (), compiled_param_type, > + ctx->get_mappings ()->lookup_location (param_tyty->get_ref ())); > + > + parameters.push_back (compiled_param); > + } > + > + if (!type.is_varadic ()) > + translated > + =3D ctx->get_backend ()->function_type (receiver, parameters, resu= lts, NULL, > + type.get_ident ().locus); > + else > + translated > + =3D ctx->get_backend ()->function_type_varadic (receiver, paramete= rs, > + results, NULL, > + type.get_ident ().loc= us); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::FnPtr &type) > +{ > + tree result_type =3D TyTyResolveCompile::compile (ctx, type.get_return= _type ()); > + > + std::vector parameters; > + > + auto ¶ms =3D type.get_params (); > + for (auto &p : params) > + { > + tree pty =3D TyTyResolveCompile::compile (ctx, p.get_tyty ()); > + parameters.push_back (pty); > + } > + > + translated =3D ctx->get_backend ()->function_ptr_type (result_type, pa= rameters, > + type.get_ident ().= locus); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::ADTType &type) > +{ > + tree type_record =3D error_mark_node; > + if (!type.is_enum ()) > + { > + rust_assert (type.number_of_variants () =3D=3D 1); > + > + TyTy::VariantDef &variant =3D *type.get_variants ().at (0); > + std::vector fields; > + for (size_t i =3D 0; i < variant.num_fields (); i++) > + { > + const TyTy::StructFieldType *field =3D variant.get_field_at_ind= ex (i); > + tree compiled_field_ty > + =3D TyTyResolveCompile::compile (ctx, field->get_field_type (= )); > + > + Backend::typed_identifier f (field->get_name (), compiled_field= _ty, > + ctx->get_mappings ()->lookup_locat= ion ( > + type.get_ty_ref ())); > + fields.push_back (std::move (f)); > + } > + > + type_record =3D type.is_union () > + ? ctx->get_backend ()->union_type (fields) > + : ctx->get_backend ()->struct_type (fields); > + } > + else > + { > + // see: > + // https://github.com/bminor/binutils-gdb/blob/527b8861cd472385fa9= 160a91dd6d65a25c41987/gdb/dwarf2/read.c#L9010-L9241 > + // > + // enums are actually a big union so for example the rust enum: > + // > + // enum AnEnum { > + // A, > + // B, > + // C (char), > + // D { x: i64, y: i64 }, > + // } > + // > + // we actually turn this into > + // > + // union { > + // struct A { int RUST$ENUM$DISR; }; <- this is a data-less vari= ant > + // struct B { int RUST$ENUM$DISR; }; <- this is a data-less vari= ant > + // struct C { int RUST$ENUM$DISR; char __0; }; > + // struct D { int RUST$ENUM$DISR; i64 x; i64 y; }; > + // } > + // > + // Ada, qual_union_types might still work for this but I am not 10= 0% sure. > + // I ran into some issues lets reuse our normal union and ask Ada = people > + // about it. > + > + std::vector variant_records; > + for (auto &variant : type.get_variants ()) > + { > + std::vector fields; > + > + // add in the qualifier field for the variant > + tree enumeral_type > + =3D TyTyResolveCompile::get_implicit_enumeral_node_type (ctx)= ; > + Backend::typed_identifier f (RUST_ENUM_DISR_FIELD_NAME, enumera= l_type, > + ctx->get_mappings ()->lookup_locat= ion ( > + variant->get_id ())); > + fields.push_back (std::move (f)); > + > + // compile the rest of the fields > + for (size_t i =3D 0; i < variant->num_fields (); i++) > + { > + const TyTy::StructFieldType *field > + =3D variant->get_field_at_index (i); > + tree compiled_field_ty > + =3D TyTyResolveCompile::compile (ctx, field->get_field_ty= pe ()); > + > + std::string field_name =3D field->get_name (); > + if (variant->get_variant_type () > + =3D=3D TyTy::VariantDef::VariantType::TUPLE) > + field_name =3D "__" + field->get_name (); > + > + Backend::typed_identifier f ( > + field_name, compiled_field_ty, > + ctx->get_mappings ()->lookup_location (type.get_ty_ref ()= )); > + fields.push_back (std::move (f)); > + } > + > + tree variant_record =3D ctx->get_backend ()->struct_type (field= s); > + tree named_variant_record =3D ctx->get_backend ()->named_type ( > + variant->get_ident ().path.get (), variant_record, > + variant->get_ident ().locus); > + > + // set the qualifier to be a builtin > + DECL_ARTIFICIAL (TYPE_FIELDS (variant_record)) =3D 1; > + > + // add them to the list > + variant_records.push_back (named_variant_record); > + } > + > + // now we need to make the actual union, but first we need to make > + // named_type TYPE_DECL's out of the variants > + > + size_t i =3D 0; > + std::vector enum_fields; > + for (auto &variant_record : variant_records) > + { > + TyTy::VariantDef *variant =3D type.get_variants ().at (i++); > + std::string implicit_variant_name =3D variant->get_identifier (= ); > + > + Backend::typed_identifier f (implicit_variant_name, variant_rec= ord, > + ctx->get_mappings ()->lookup_locat= ion ( > + type.get_ty_ref ())); > + enum_fields.push_back (std::move (f)); > + } > + > + // finally make the union or the enum > + type_record =3D ctx->get_backend ()->union_type (enum_fields); > + } > + > + // Handle repr options > + // TODO: "packed" should only narrow type alignment and "align" should= only > + // widen it. Do we need to check and enforce this here, or is it taken= care of > + // later on in the gcc middle-end? > + TyTy::ADTType::ReprOptions repr =3D type.get_repr_options (); > + if (repr.pack) > + { > + TYPE_PACKED (type_record) =3D 1; > + if (repr.pack > 1) > + { > + SET_TYPE_ALIGN (type_record, repr.pack * 8); > + TYPE_USER_ALIGN (type_record) =3D 1; > + } > + } > + else if (repr.align) > + { > + SET_TYPE_ALIGN (type_record, repr.align * 8); > + TYPE_USER_ALIGN (type_record) =3D 1; > + } > + > + std::string named_struct_str > + =3D type.get_ident ().path.get () + type.subst_as_string (); > + translated =3D ctx->get_backend ()->named_type (named_struct_str, type= _record, > + type.get_ident ().locus); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::TupleType &type) > +{ > + if (type.num_fields () =3D=3D 0) > + { > + translated =3D ctx->get_backend ()->unit_type (); > + return; > + } > + > + // create implicit struct > + std::vector fields; > + for (size_t i =3D 0; i < type.num_fields (); i++) > + { > + TyTy::BaseType *field =3D type.get_field (i); > + tree compiled_field_ty =3D TyTyResolveCompile::compile (ctx, field= ); > + > + // rustc uses the convention __N, where N is an integer, to > + // name the fields of a tuple. We follow this as well, > + // because this is used by GDB. One further reason to prefer > + // this, rather than simply emitting the integer, is that this > + // approach makes it simpler to use a C-only debugger, or > + // GDB's C mode, when debugging Rust. > + Backend::typed_identifier f ("__" + std::to_string (i), compiled_f= ield_ty, > + ctx->get_mappings ()->lookup_location = ( > + type.get_ty_ref ())); > + fields.push_back (std::move (f)); > + } > + > + tree struct_type_record =3D ctx->get_backend ()->struct_type (fields); > + translated > + =3D ctx->get_backend ()->named_type (type.as_string (), struct_type_= record, > + type.get_ident ().locus); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::ArrayType &type) > +{ > + tree element_type > + =3D TyTyResolveCompile::compile (ctx, type.get_element_type ()); > + tree capacity_expr =3D CompileExpr::Compile (&type.get_capacity_expr (= ), ctx); > + tree folded_capacity_expr =3D fold_expr (capacity_expr); > + > + translated > + =3D ctx->get_backend ()->array_type (element_type, folded_capacity_e= xpr); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::SliceType &type) > +{ > + tree type_record =3D create_slice_type_record (type); > + > + std::string named_struct_str > + =3D std::string ("[") + type.get_element_type ()->get_name () + "]"; > + translated =3D ctx->get_backend ()->named_type (named_struct_str, type= _record, > + type.get_ident ().locus); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::BoolType &type) > +{ > + translated > + =3D ctx->get_backend ()->named_type ("bool", > + ctx->get_backend ()->bool_type (), > + Linemap::predeclared_location ()); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::IntType &type) > +{ > + switch (type.get_int_kind ()) > + { > + case TyTy::IntType::I8: > + translated =3D ctx->get_backend ()->named_type ( > + "i8", ctx->get_backend ()->integer_type (false, 8), > + Linemap::predeclared_location ()); > + return; > + > + case TyTy::IntType::I16: > + translated =3D ctx->get_backend ()->named_type ( > + "i16", ctx->get_backend ()->integer_type (false, 16), > + Linemap::predeclared_location ()); > + return; > + > + case TyTy::IntType::I32: > + translated =3D ctx->get_backend ()->named_type ( > + "i32", ctx->get_backend ()->integer_type (false, 32), > + Linemap::predeclared_location ()); > + return; > + > + case TyTy::IntType::I64: > + translated =3D ctx->get_backend ()->named_type ( > + "i64", ctx->get_backend ()->integer_type (false, 64), > + Linemap::predeclared_location ()); > + return; > + > + case TyTy::IntType::I128: > + translated =3D ctx->get_backend ()->named_type ( > + "i128", ctx->get_backend ()->integer_type (false, 128), > + Linemap::predeclared_location ()); > + return; > + } > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::UintType &type) > +{ > + switch (type.get_uint_kind ()) > + { > + case TyTy::UintType::U8: > + translated =3D ctx->get_backend ()->named_type ( > + "u8", ctx->get_backend ()->integer_type (true, 8), > + Linemap::predeclared_location ()); > + return; > + > + case TyTy::UintType::U16: > + translated =3D ctx->get_backend ()->named_type ( > + "u16", ctx->get_backend ()->integer_type (true, 16), > + Linemap::predeclared_location ()); > + return; > + > + case TyTy::UintType::U32: > + translated =3D ctx->get_backend ()->named_type ( > + "u32", ctx->get_backend ()->integer_type (true, 32), > + Linemap::predeclared_location ()); > + return; > + > + case TyTy::UintType::U64: > + translated =3D ctx->get_backend ()->named_type ( > + "u64", ctx->get_backend ()->integer_type (true, 64), > + Linemap::predeclared_location ()); > + return; > + > + case TyTy::UintType::U128: > + translated =3D ctx->get_backend ()->named_type ( > + "u128", ctx->get_backend ()->integer_type (true, 128), > + Linemap::predeclared_location ()); > + return; > + } > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::FloatType &type) > +{ > + switch (type.get_float_kind ()) > + { > + case TyTy::FloatType::F32: > + translated > + =3D ctx->get_backend ()->named_type ("f32", > + ctx->get_backend ()->float_typ= e (32), > + Linemap::predeclared_location = ()); > + return; > + > + case TyTy::FloatType::F64: > + translated > + =3D ctx->get_backend ()->named_type ("f64", > + ctx->get_backend ()->float_typ= e (64), > + Linemap::predeclared_location = ()); > + return; > + } > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::USizeType &type) > +{ > + translated =3D ctx->get_backend ()->named_type ( > + "usize", > + ctx->get_backend ()->integer_type ( > + true, ctx->get_backend ()->get_pointer_size ()), > + Linemap::predeclared_location ()); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::ISizeType &type) > +{ > + translated =3D ctx->get_backend ()->named_type ( > + "isize", > + ctx->get_backend ()->integer_type ( > + false, ctx->get_backend ()->get_pointer_size ()), > + Linemap::predeclared_location ()); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::CharType &type) > +{ > + translated > + =3D ctx->get_backend ()->named_type ("char", > + ctx->get_backend ()->wchar_type ()= , > + Linemap::predeclared_location ()); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::ReferenceType &type) > +{ > + const TyTy::SliceType *slice =3D nullptr; > + const TyTy::StrType *str =3D nullptr; > + if (type.is_dyn_slice_type (&slice)) > + { > + tree type_record =3D create_slice_type_record (*slice); > + std::string dyn_slice_type_str > + =3D std::string (type.is_mutable () ? "&mut " : "&") + "[" > + + slice->get_element_type ()->get_name () + "]"; > + > + translated > + =3D ctx->get_backend ()->named_type (dyn_slice_type_str, type_rec= ord, > + slice->get_locus ()); > + > + return; > + } > + else if (type.is_dyn_str_type (&str)) > + { > + tree type_record =3D create_str_type_record (*str); > + std::string dyn_str_type_str > + =3D std::string (type.is_mutable () ? "&mut " : "&") + "str"; > + > + translated > + =3D ctx->get_backend ()->named_type (dyn_str_type_str, type_recor= d, > + str->get_locus ()); > + > + return; > + } > + > + tree base_compiled_type > + =3D TyTyResolveCompile::compile (ctx, type.get_base (), trait_object= _mode); > + if (type.is_mutable ()) > + { > + translated =3D ctx->get_backend ()->reference_type (base_compiled_= type); > + } > + else > + { > + auto base =3D ctx->get_backend ()->immutable_type (base_compiled_t= ype); > + translated =3D ctx->get_backend ()->reference_type (base); > + } > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::PointerType &type) > +{ > + const TyTy::SliceType *slice =3D nullptr; > + const TyTy::StrType *str =3D nullptr; > + if (type.is_dyn_slice_type (&slice)) > + { > + tree type_record =3D create_slice_type_record (*slice); > + std::string dyn_slice_type_str > + =3D std::string (type.is_mutable () ? "*mut " : "*const ") + "[" > + + slice->get_element_type ()->get_name () + "]"; > + > + translated > + =3D ctx->get_backend ()->named_type (dyn_slice_type_str, type_rec= ord, > + slice->get_locus ()); > + > + return; > + } > + else if (type.is_dyn_str_type (&str)) > + { > + tree type_record =3D create_str_type_record (*str); > + std::string dyn_str_type_str > + =3D std::string (type.is_mutable () ? "*mut " : "*const ") + "str= "; > + > + translated > + =3D ctx->get_backend ()->named_type (dyn_str_type_str, type_recor= d, > + str->get_locus ()); > + > + return; > + } > + > + tree base_compiled_type > + =3D TyTyResolveCompile::compile (ctx, type.get_base (), trait_object= _mode); > + if (type.is_mutable ()) > + { > + translated =3D ctx->get_backend ()->pointer_type (base_compiled_ty= pe); > + } > + else > + { > + auto base =3D ctx->get_backend ()->immutable_type (base_compiled_t= ype); > + translated =3D ctx->get_backend ()->pointer_type (base); > + } > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::StrType &type) > +{ > + tree raw_str =3D create_str_type_record (type); > + translated > + =3D ctx->get_backend ()->named_type ("str", raw_str, > + Linemap::predeclared_location ()); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::NeverType &) > +{ > + translated =3D ctx->get_backend ()->unit_type (); > +} > + > +void > +TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type) > +{ > + if (trait_object_mode) > + { > + translated =3D ctx->get_backend ()->integer_type ( > + true, ctx->get_backend ()->get_pointer_size ()); > + return; > + } > + > + // create implicit struct > + auto items =3D type.get_object_items (); > + std::vector fields; > + > + tree uint =3D ctx->get_backend ()->integer_type ( > + true, ctx->get_backend ()->get_pointer_size ()); > + tree uintptr_ty =3D build_pointer_type (uint); > + > + Backend::typed_identifier f ("pointer", uintptr_ty, > + ctx->get_mappings ()->lookup_location ( > + type.get_ty_ref ())); > + fields.push_back (std::move (f)); > + > + tree vtable_size =3D build_int_cst (size_type_node, items.size ()); > + tree vtable_type =3D ctx->get_backend ()->array_type (uintptr_ty, vtab= le_size); > + Backend::typed_identifier vtf ("vtable", vtable_type, > + ctx->get_mappings ()->lookup_location ( > + type.get_ty_ref ())); > + fields.push_back (std::move (vtf)); > + > + tree type_record =3D ctx->get_backend ()->struct_type (fields); > + translated =3D ctx->get_backend ()->named_type (type.get_name (), type= _record, > + type.get_ident ().locus); > +} > + > +tree > +TyTyResolveCompile::create_slice_type_record (const TyTy::SliceType &typ= e) > +{ > + // lookup usize > + TyTy::BaseType *usize =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_builtin ("usize", &usize); > + rust_assert (ok); > + > + tree element_type > + =3D TyTyResolveCompile::compile (ctx, type.get_element_type ()); > + tree data_field_ty =3D build_pointer_type (element_type); > + Backend::typed_identifier data_field ("data", data_field_ty, > + type.get_locus ()); > + > + tree len_field_ty =3D TyTyResolveCompile::compile (ctx, usize); > + Backend::typed_identifier len_field ("len", len_field_ty, type.get_loc= us ()); > + > + tree record =3D ctx->get_backend ()->struct_type ({data_field, len_fie= ld}); > + SLICE_FLAG (record) =3D 1; > + TYPE_MAIN_VARIANT (record) =3D ctx->insert_main_variant (record); > + > + return record; > +} > + > +tree > +TyTyResolveCompile::create_str_type_record (const TyTy::StrType &type) > +{ > + // lookup usize > + TyTy::BaseType *usize =3D nullptr; > + bool ok =3D ctx->get_tyctx ()->lookup_builtin ("usize", &usize); > + rust_assert (ok); > + > + tree char_ptr =3D build_pointer_type (char_type_node); > + tree const_char_type =3D build_qualified_type (char_ptr, TYPE_QUAL_CON= ST); > + > + tree element_type =3D const_char_type; > + tree data_field_ty =3D build_pointer_type (element_type); > + Backend::typed_identifier data_field ("data", data_field_ty, > + type.get_locus ()); > + > + tree len_field_ty =3D TyTyResolveCompile::compile (ctx, usize); > + Backend::typed_identifier len_field ("len", len_field_ty, type.get_loc= us ()); > + > + tree record =3D ctx->get_backend ()->struct_type ({data_field, len_fie= ld}); > + SLICE_FLAG (record) =3D 1; > + TYPE_MAIN_VARIANT (record) =3D ctx->insert_main_variant (record); > + > + return record; > +} > + > +} // namespace Compile > +} // namespace Rust > diff --git a/gcc/rust/backend/rust-compile-type.h b/gcc/rust/backend/rust= -compile-type.h > new file mode 100644 > index 00000000000..b52fd71bf6b > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-type.h > @@ -0,0 +1,79 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_TYPE > +#define RUST_COMPILE_TYPE > + > +#include "rust-compile-context.h" > + > +namespace Rust { > +namespace Compile { > + > +class TyTyResolveCompile : protected TyTy::TyConstVisitor > +{ > +public: > + static tree compile (Context *ctx, const TyTy::BaseType *ty, > + bool trait_object_mode =3D false); > + > + static tree get_implicit_enumeral_node_type (Context *ctx); > + > + void visit (const TyTy::InferType &) override; > + void visit (const TyTy::ADTType &) override; > + void visit (const TyTy::TupleType &) override; > + void visit (const TyTy::FnType &) override; > + void visit (const TyTy::FnPtr &) override; > + void visit (const TyTy::ArrayType &) override; > + void visit (const TyTy::SliceType &) override; > + void visit (const TyTy::BoolType &) override; > + void visit (const TyTy::IntType &) override; > + void visit (const TyTy::UintType &) override; > + void visit (const TyTy::FloatType &) override; > + void visit (const TyTy::USizeType &) override; > + void visit (const TyTy::ISizeType &) override; > + void visit (const TyTy::ErrorType &) override; > + void visit (const TyTy::CharType &) override; > + void visit (const TyTy::ReferenceType &) override; > + void visit (const TyTy::PointerType &) override; > + void visit (const TyTy::ParamType &) override; > + void visit (const TyTy::StrType &) override; > + void visit (const TyTy::NeverType &) override; > + void visit (const TyTy::PlaceholderType &) override; > + void visit (const TyTy::ProjectionType &) override; > + void visit (const TyTy::DynamicObjectType &) override; > + void visit (const TyTy::ClosureType &) override; > + > +public: > + static hashval_t type_hasher (tree type); > + > +protected: > + tree create_slice_type_record (const TyTy::SliceType &type); > + tree create_str_type_record (const TyTy::StrType &type); > + > +private: > + TyTyResolveCompile (Context *ctx, bool trait_object_mode); > + > + Context *ctx; > + bool trait_object_mode; > + tree translated; > + int recurisve_ops; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_TYPE > diff --git a/gcc/rust/backend/rust-compile-var-decl.h b/gcc/rust/backend/= rust-compile-var-decl.h > new file mode 100644 > index 00000000000..e2ee05b8163 > --- /dev/null > +++ b/gcc/rust/backend/rust-compile-var-decl.h > @@ -0,0 +1,95 @@ > +// Copyright (C) 2020-2022 Free Software Foundation, Inc. > + > +// This file is part of GCC. > + > +// GCC is free software; you can redistribute it and/or modify it under > +// the terms of the GNU General Public License as published by the Free > +// Software Foundation; either version 3, or (at your option) any later > +// version. > + > +// GCC is distributed in the hope that it will be useful, but WITHOUT AN= Y > +// 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 > +// . > + > +#ifndef RUST_COMPILE_VAR_DECL > +#define RUST_COMPILE_VAR_DECL > + > +#include "rust-compile-base.h" > +#include "rust-hir-visitor.h" > + > +namespace Rust { > +namespace Compile { > + > +class CompileVarDecl : public HIRCompileBase, public HIR::HIRPatternVisi= tor > +{ > + using HIR::HIRPatternVisitor::visit; > + > +public: > + static ::Bvariable *compile (tree fndecl, tree translated_type, > + HIR::Pattern *pattern, Context *ctx) > + { > + CompileVarDecl compiler (ctx, fndecl, translated_type); > + pattern->accept_vis (compiler); > + return compiler.compiled_variable; > + } > + > + void visit (HIR::IdentifierPattern &pattern) override > + { > + if (!pattern.is_mut ()) > + translated_type =3D ctx->get_backend ()->immutable_type (translate= d_type); > + > + compiled_variable > + =3D ctx->get_backend ()->local_variable (fndecl, pattern.get_ident= ifier (), > + translated_type, NULL /*decl= _var*/, > + pattern.get_locus ()); > + > + HirId stmt_id =3D pattern.get_pattern_mappings ().get_hirid (); > + ctx->insert_var_decl (stmt_id, compiled_variable); > + } > + > + void visit (HIR::WildcardPattern &pattern) override > + { > + translated_type =3D ctx->get_backend ()->immutable_type (translated_= type); > + > + compiled_variable > + =3D ctx->get_backend ()->local_variable (fndecl, "_", translated_t= ype, > + NULL /*decl_var*/, > + pattern.get_locus ()); > + > + HirId stmt_id =3D pattern.get_pattern_mappings ().get_hirid (); > + ctx->insert_var_decl (stmt_id, compiled_variable); > + } > + > + // Empty visit for unused Pattern HIR nodes. > + void visit (HIR::GroupedPattern &) override {} > + void visit (HIR::LiteralPattern &) override {} > + void visit (HIR::PathInExpression &) override {} > + void visit (HIR::QualifiedPathInExpression &) override {} > + void visit (HIR::RangePattern &) override {} > + void visit (HIR::ReferencePattern &) override {} > + void visit (HIR::SlicePattern &) override {} > + void visit (HIR::StructPattern &) override {} > + void visit (HIR::TuplePattern &) override {} > + void visit (HIR::TupleStructPattern &) override {} > + > +private: > + CompileVarDecl (Context *ctx, tree fndecl, tree translated_type) > + : HIRCompileBase (ctx), fndecl (fndecl), translated_type (translated= _type), > + compiled_variable (ctx->get_backend ()->error_variable ()) > + {} > + > + tree fndecl; > + tree translated_type; > + > + Bvariable *compiled_variable; > +}; > + > +} // namespace Compile > +} // namespace Rust > + > +#endif // RUST_COMPILE_VAR_DECL Again I think this part of the Rust frontend is OK to merge. I would have appreciated some high-level overview of the compilation process but I can't find anything in the rust/ directory or gcc/doc. There seems to be a 'visit' pattern everywhere and I think I got an idea on how the rust IR -> GENERIC translation works, still at which points (global) types, data and functions are "compiled" isn't clear to me. Given we have multiple IRs I suppose we parse the whole unit, translate it in whole and only as a last step do the rust IR -> GENERIC translation after which we are finished? Thanks, Richard. > -- > 2.37.2 >