From f3bf1f293d9c6cab7ccebdaa96433208f2c79057 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 26 Jul 2021 22:15:41 +0100 Subject: [PATCH 1/5] Add resolution for extern function items --- gcc/rust/resolve/rust-ast-resolve-item.h | 2 +- gcc/rust/resolve/rust-ast-resolve.cc | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h index ccf3872ac044..539229d60fa2 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.h +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -619,7 +619,7 @@ class ResolveExternItem : public ResolverBase private: ResolveExternItem () : ResolverBase (UNKNOWN_NODEID) {} -}; // namespace Resolver +}; } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index 9cc833ff3ba2..06a341a0586a 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -637,7 +637,9 @@ ResolveItem::resolve_impl_item (AST::InherentImplItem *item, void ResolveItem::resolve_extern_item (AST::ExternalItem *item) -{} +{ + ResolveExternItem::go (item); +} } // namespace Resolver } // namespace Rust From defe97ea4dfd5d0e77ec2a8401c987772d96884f Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 26 Jul 2021 22:15:53 +0100 Subject: [PATCH 2/5] Add mappings for external items --- gcc/rust/hir/rust-ast-lower-extern.h | 14 ++++++++---- gcc/rust/hir/rust-ast-lower-item.h | 10 +++++---- gcc/rust/hir/tree/rust-hir-item.h | 32 +++++++++++++++++++++++++--- gcc/rust/util/rust-hir-map.cc | 24 +++++++++++++++++++++ gcc/rust/util/rust-hir-map.h | 6 ++++++ 5 files changed, 75 insertions(+), 11 deletions(-) diff --git a/gcc/rust/hir/rust-ast-lower-extern.h b/gcc/rust/hir/rust-ast-lower-extern.h index 1cc0c8e47285..4ea0019d7195 100644 --- a/gcc/rust/hir/rust-ast-lower-extern.h +++ b/gcc/rust/hir/rust-ast-lower-extern.h @@ -47,8 +47,6 @@ class ASTLoweringExternItem : public ASTLoweringBase Analysis::NodeMapping mapping (crate_num, item.get_node_id (), mappings->get_next_hir_id (crate_num), mappings->get_next_localdef_id (crate_num)); - mappings->insert_location (crate_num, mapping.get_hirid (), - item.get_locus ()); HIR::ExternalStaticItem *static_item = new HIR::ExternalStaticItem (mapping, item.get_identifier (), @@ -58,6 +56,11 @@ class ASTLoweringExternItem : public ASTLoweringBase item.get_locus ()); translated = static_item; + + mappings->insert_hir_extern_item (crate_num, mapping.get_hirid (), + translated); + mappings->insert_location (crate_num, mapping.get_hirid (), + item.get_locus ()); } void visit (AST::ExternalFunctionItem &function) override @@ -97,8 +100,6 @@ class ASTLoweringExternItem : public ASTLoweringBase Analysis::NodeMapping mapping (crate_num, function.get_node_id (), mappings->get_next_hir_id (crate_num), mappings->get_next_localdef_id (crate_num)); - mappings->insert_location (crate_num, mapping.get_hirid (), - function.get_locus ()); HIR::ExternalFunctionItem *function_item = new HIR::ExternalFunctionItem ( mapping, function.get_identifier (), std::move (generic_params), @@ -107,6 +108,11 @@ class ASTLoweringExternItem : public ASTLoweringBase function.get_outer_attrs (), function.get_locus ()); translated = function_item; + + mappings->insert_hir_extern_item (crate_num, mapping.get_hirid (), + translated); + mappings->insert_location (crate_num, mapping.get_hirid (), + function.get_locus ()); } private: diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h index e53b739747ec..80ca29859fba 100644 --- a/gcc/rust/hir/rust-ast-lower-item.h +++ b/gcc/rust/hir/rust-ast-lower-item.h @@ -571,10 +571,6 @@ class ASTLoweringItem : public ASTLoweringBase mappings->get_next_hir_id (crate_num), mappings->get_next_localdef_id (crate_num)); - mappings->insert_defid_mapping (mapping.get_defid (), translated); - mappings->insert_location (crate_num, mapping.get_hirid (), - extern_block.get_locus ()); - HIR::ExternBlock *hir_extern_block = new HIR::ExternBlock (mapping, extern_block.get_abi (), std::move (extern_items), std::move (vis), @@ -583,6 +579,12 @@ class ASTLoweringItem : public ASTLoweringBase extern_block.get_locus ()); translated = hir_extern_block; + + mappings->insert_defid_mapping (mapping.get_defid (), translated); + mappings->insert_hir_item (mapping.get_crate_num (), mapping.get_hirid (), + translated); + mappings->insert_location (crate_num, mapping.get_hirid (), + extern_block.get_locus ()); } private: diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index 6d53711942fd..7d976c5c991c 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -2713,6 +2713,8 @@ class ExternalItem Analysis::NodeMapping get_mappings () const { return mappings; } + Identifier get_item_name () const { return item_name; } + protected: ExternalItem (Analysis::NodeMapping mappings, Identifier item_name, Visibility vis, AST::AttrVec outer_attrs, Location locus) @@ -2746,9 +2748,6 @@ class ExternalItem // Clone function implementation as pure virtual method virtual ExternalItem *clone_external_item_impl () const = 0; - - // possibly make this public if required - std::string get_item_name () const { return item_name; } }; // A static item used in an extern block @@ -2790,6 +2789,8 @@ class ExternalStaticItem : public ExternalItem void accept_vis (HIRVisitor &vis) override; + std::unique_ptr &get_item_type () { return item_type; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2840,6 +2841,12 @@ struct NamedFunctionParam NamedFunctionParam &operator= (NamedFunctionParam &&other) = default; std::string as_string () const; + + Identifier get_param_name () const { return name; } + + std::unique_ptr &get_type () { return param_type; } + + Analysis::NodeMapping get_mappings () const { return mappings; } }; // A function item used in an extern block @@ -2920,6 +2927,20 @@ class ExternalFunctionItem : public ExternalItem void accept_vis (HIRVisitor &vis) override; + std::vector > &get_generic_params () + { + return generic_params; + } + + std::unique_ptr &get_return_type () { return return_type; } + + std::vector &get_function_params () + { + return function_params; + } + + bool is_variadic () const { return has_variadics; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2999,6 +3020,11 @@ class ExternBlock : public VisItem void accept_vis (HIRVisitor &vis) override; + std::vector > &get_extern_items () + { + return extern_items; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 9af77a9600ba..0dcb2e9df00f 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -283,6 +283,30 @@ Mappings::lookup_hir_trait_item (CrateNum crateNum, HirId id) return iy->second; } +void +Mappings::insert_hir_extern_item (CrateNum crateNum, HirId id, + HIR::ExternalItem *item) +{ + rust_assert (lookup_hir_extern_item (crateNum, id) == nullptr); + + hirExternItemMappings[crateNum][id] = item; + nodeIdToHirMappings[crateNum][item->get_mappings ().get_nodeid ()] = id; +} + +HIR::ExternalItem * +Mappings::lookup_hir_extern_item (CrateNum crateNum, HirId id) +{ + auto it = hirExternItemMappings.find (crateNum); + if (it == hirExternItemMappings.end ()) + return nullptr; + + auto iy = it->second.find (id); + if (iy == it->second.end ()) + return nullptr; + + return iy->second; +} + void Mappings::insert_hir_impl_block (CrateNum crateNum, HirId id, HIR::ImplBlock *item) diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 3789b57ab695..7e5449c70140 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -132,6 +132,10 @@ class Mappings HIR::TraitItem *item); HIR::TraitItem *lookup_hir_trait_item (CrateNum crateNum, HirId id); + void insert_hir_extern_item (CrateNum crateNum, HirId id, + HIR::ExternalItem *item); + HIR::ExternalItem *lookup_hir_extern_item (CrateNum crateNum, HirId id); + void insert_hir_impl_block (CrateNum crateNum, HirId id, HIR::ImplBlock *item); HIR::ImplBlock *lookup_hir_impl_block (CrateNum crateNum, HirId id); @@ -239,6 +243,8 @@ class Mappings std::map hirImplItemsToImplMappings; std::map > hirImplBlockMappings; std::map > hirTraitItemMappings; + std::map > + hirExternItemMappings; // location info std::map > locations; From b176f389161bbe30237ff29063697f8e0ccaa513 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 26 Jul 2021 22:16:21 +0100 Subject: [PATCH 3/5] Add flags for FnType FNTYPE_IS_METHOD_FLAG FNTYPE_IS_EXTERN_FLAG --- .../typecheck/rust-hir-type-check-implitem.h | 105 +++++++++++++++++- .../typecheck/rust-hir-type-check-toplevel.h | 14 ++- gcc/rust/typecheck/rust-tyty.cc | 2 +- gcc/rust/typecheck/rust-tyty.h | 20 ++-- 4 files changed, 125 insertions(+), 16 deletions(-) diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index 5f6fcd99cdc5..02e5ef19aecc 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -28,6 +28,101 @@ namespace Rust { namespace Resolver { +class TypeCheckTopLevelExternItem : public TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static void Resolve (HIR::ExternalItem *item) + { + TypeCheckTopLevelExternItem resolver; + item->accept_vis (resolver); + } + + void visit (HIR::ExternalStaticItem &item) override + { + TyTy::BaseType *actual_type + = TypeCheckType::Resolve (item.get_item_type ().get ()); + + context->insert_type (item.get_mappings (), actual_type); + } + + void visit (HIR::ExternalFunctionItem &function) override + { + std::vector substitutions; + if (function.has_generics ()) + { + for (auto &generic_param : function.get_generic_params ()) + { + switch (generic_param.get ()->get_kind ()) + { + case HIR::GenericParam::GenericKind::LIFETIME: + // Skipping Lifetime completely until better handling. + break; + + case HIR::GenericParam::GenericKind::TYPE: { + auto param_type + = TypeResolveGenericParam::Resolve (generic_param.get ()); + context->insert_type (generic_param->get_mappings (), + param_type); + + substitutions.push_back (TyTy::SubstitutionParamMapping ( + static_cast (*generic_param), + param_type)); + } + break; + } + } + } + + TyTy::BaseType *ret_type = nullptr; + if (!function.has_return_type ()) + ret_type = new TyTy::TupleType (function.get_mappings ().get_hirid ()); + else + { + auto resolved + = TypeCheckType::Resolve (function.get_return_type ().get ()); + if (resolved == nullptr) + { + rust_error_at (function.get_locus (), + "failed to resolve return type"); + return; + } + + ret_type = resolved->clone (); + ret_type->set_ref ( + function.get_return_type ()->get_mappings ().get_hirid ()); + } + + std::vector > params; + for (auto ¶m : function.get_function_params ()) + { + // get the name as well required for later on + auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ()); + + HIR::IdentifierPattern *param_pattern = new HIR::IdentifierPattern ( + param.get_param_name (), Location (), false, false, + std::unique_ptr (nullptr)); + + params.push_back ( + std::pair (param_pattern, + param_tyty)); + + context->insert_type (param.get_mappings (), param_tyty); + } + + auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), + function.get_mappings ().get_defid (), + function.get_item_name (), + FNTYPE_IS_EXTERN_FLAG, std::move (params), + ret_type, std::move (substitutions)); + context->insert_type (function.get_mappings (), fnType); + } + +private: + TypeCheckTopLevelExternItem () : TypeCheckBase () {} +}; + class TypeCheckTopLevelImplItem : public TypeCheckBase { using Rust::Resolver::TypeCheckBase::visit; @@ -134,11 +229,11 @@ class TypeCheckTopLevelImplItem : public TypeCheckBase context->insert_type (param.get_mappings (), param_tyty); } - auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), - function.get_mappings ().get_defid (), - function.get_function_name (), - function.is_method (), std::move (params), - ret_type, std::move (substitutions)); + auto fnType = new TyTy::FnType ( + function.get_mappings ().get_hirid (), + function.get_mappings ().get_defid (), function.get_function_name (), + function.is_method () ? FNTYPE_IS_METHOD_FLAG : FNTYPE_DEFAULT_FLAGS, + std::move (params), ret_type, std::move (substitutions)); context->insert_type (function.get_mappings (), fnType); } diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h index dd3dd751ad6c..18f3e7254164 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h +++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h @@ -230,9 +230,9 @@ class TypeCheckTopLevel : public TypeCheckBase auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), function.get_mappings ().get_defid (), - function.get_function_name (), false, - std::move (params), ret_type, - std::move (substitutions)); + function.get_function_name (), + FNTYPE_DEFAULT_FLAGS, std::move (params), + ret_type, std::move (substitutions)); context->insert_type (function.get_mappings (), fnType); } @@ -274,6 +274,14 @@ class TypeCheckTopLevel : public TypeCheckBase substitutions); } + void visit (HIR::ExternBlock &extern_block) override + { + for (auto &item : extern_block.get_extern_items ()) + { + TypeCheckTopLevelExternItem::Resolve (item.get ()); + } + } + private: TypeCheckTopLevel () : TypeCheckBase () {} }; diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index bb5d6c0bb154..64587daf2e55 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -816,7 +816,7 @@ FnType::clone () std::pair (p.first, p.second->clone ())); return new FnType (get_ref (), get_ty_ref (), get_id (), get_identifier (), - is_method_flag, std::move (cloned_params), + flags, std::move (cloned_params), get_return_type ()->clone (), clone_substs (), get_combined_refs ()); } diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index cecf69ad0f5d..0a087dfd40e8 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -970,14 +970,18 @@ class ADTType : public BaseType, public SubstitutionRef class FnType : public BaseType, public SubstitutionRef { public: - FnType (HirId ref, DefId id, std::string identifier, bool is_method, +#define FNTYPE_DEFAULT_FLAGS 0x00 +#define FNTYPE_IS_METHOD_FLAG 0x01 +#define FNTYPE_IS_EXTERN_FLAG 0x02 + + FnType (HirId ref, DefId id, std::string identifier, uint8_t flags, std::vector > params, BaseType *type, std::vector subst_refs, std::set refs = std::set ()) : BaseType (ref, ref, TypeKind::FNDEF, refs), SubstitutionRef (std::move (subst_refs), SubstitutionArgumentMappings::error ()), - params (std::move (params)), type (type), is_method_flag (is_method), + params (std::move (params)), type (type), flags (flags), identifier (identifier), id (id) { LocalDefId local_def_id = id & DEF_ID_LOCAL_DEF_MASK; @@ -985,15 +989,15 @@ class FnType : public BaseType, public SubstitutionRef } FnType (HirId ref, HirId ty_ref, DefId id, std::string identifier, - bool is_method, + uint8_t flags, std::vector > params, BaseType *type, std::vector subst_refs, std::set refs = std::set ()) : BaseType (ref, ty_ref, TypeKind::FNDEF, refs), SubstitutionRef (std::move (subst_refs), SubstitutionArgumentMappings::error ()), - params (params), type (type), is_method_flag (is_method), - identifier (identifier), id (id) + params (params), type (type), flags (flags), identifier (identifier), + id (id) { LocalDefId local_def_id = id & DEF_ID_LOCAL_DEF_MASK; rust_assert (local_def_id != UNKNOWN_LOCAL_DEFID); @@ -1022,9 +1026,11 @@ class FnType : public BaseType, public SubstitutionRef if (num_params () == 0) return false; - return is_method_flag; + return (flags & FNTYPE_IS_METHOD_FLAG) != 0; } + bool is_extern () const { return (flags & FNTYPE_IS_EXTERN_FLAG) != 0; } + DefId get_id () const { return id; } // get the Self type for the method @@ -1077,7 +1083,7 @@ class FnType : public BaseType, public SubstitutionRef private: std::vector > params; BaseType *type; - bool is_method_flag; + uint8_t flags; std::string identifier; DefId id; }; From 2818017d36f5c6279a2372b0a8efbe1f17b3f374 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 26 Jul 2021 22:34:14 +0100 Subject: [PATCH 4/5] Adds support for compilation of extern "C" functions. This adds extern block compilation support. It currently assumes the C abi and does not perform any name mangling. It does not support varadic arguments yet but its the initial support to get this working. Fixes #421 --- gcc/rust/backend/rust-compile-extern.h | 150 ++++++++++++++++++ gcc/rust/backend/rust-compile-item.h | 9 ++ .../rust/execute/torture/helloworld1.rs | 15 ++ 3 files changed, 174 insertions(+) create mode 100644 gcc/rust/backend/rust-compile-extern.h create mode 100644 gcc/testsuite/rust/execute/torture/helloworld1.rs diff --git a/gcc/rust/backend/rust-compile-extern.h b/gcc/rust/backend/rust-compile-extern.h new file mode 100644 index 000000000000..1eba011c6fac --- /dev/null +++ b/gcc/rust/backend/rust-compile-extern.h @@ -0,0 +1,150 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// . + +#ifndef RUST_COMPILE_EXTERN_ITEM +#define RUST_COMPILE_EXTERN_ITEM + +#include "rust-compile-base.h" +#include "rust-compile-tyty.h" +#include "rust-compile-implitem.h" +#include "rust-compile-var-decl.h" +#include "rust-compile-stmt.h" +#include "rust-compile-expr.h" +#include "rust-compile-fnparam.h" + +namespace Rust { +namespace Compile { + +class CompileExternItem : public HIRCompileBase +{ + using Rust::Compile::HIRCompileBase::visit; + +public: + static void compile (HIR::ExternalItem *item, Context *ctx, + bool compile_fns = true, + TyTy::BaseType *concrete = nullptr) + { + CompileExternItem compiler (ctx, compile_fns, concrete); + item->accept_vis (compiler); + } + + void visit (HIR::ExternalStaticItem &item) override + { + TyTy::BaseType *resolved_type = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type (item.get_mappings ().get_hirid (), + &resolved_type); + rust_assert (ok); + + std::string name = item.get_item_name (); + + // FIXME + // this is assuming C ABI + std::string asm_name = "_" + name; + + Btype *type = TyTyResolveCompile::compile (ctx, resolved_type); + bool is_external = true; + bool is_hidden = false; + bool in_unique_section = false; + + Bvariable *static_global + = ctx->get_backend ()->global_variable (name, asm_name, type, is_external, + is_hidden, in_unique_section, + item.get_locus ()); + ctx->insert_var_decl (item.get_mappings ().get_hirid (), static_global); + ctx->push_var (static_global); + } + + void visit (HIR::ExternalFunctionItem &function) override + { + if (!compile_fns) + return; + + TyTy::BaseType *fntype_tyty; + if (!ctx->get_tyctx ()->lookup_type (function.get_mappings ().get_hirid (), + &fntype_tyty)) + { + rust_fatal_error (function.get_locus (), + "failed to lookup function type"); + return; + } + + rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fntype = static_cast (fntype_tyty); + if (fntype->has_subsititions_defined ()) + { + // we cant do anything for this only when it is used and a concrete type + // is given + if (concrete == nullptr) + return; + else + { + rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF); + fntype = static_cast (concrete); + } + } + + // items can be forward compiled which means we may not need to invoke this + // code. We might also have already compiled this generic function as well. + Bfunction *lookup = nullptr; + if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup, fntype)) + { + // has this been added to the list then it must be finished + if (ctx->function_completed (lookup)) + { + Bfunction *dummy = nullptr; + if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy)) + ctx->insert_function_decl (fntype->get_ty_ref (), lookup, fntype); + + return; + } + } + + if (fntype->has_subsititions_defined ()) + { + // override the Hir Lookups for the substituions in this context + fntype->override_context (); + } + + ::Btype *compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype); + + const unsigned int flags + = Backend::function_is_declaration | Backend::function_is_visible; + + std::string ir_symbol_name = function.get_item_name (); + // FIXME this assumes C ABI + std::string asm_name = function.get_item_name (); + + Bfunction *fndecl + = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, + asm_name, flags, function.get_locus ()); + ctx->insert_function_decl (fntype->get_ty_ref (), fndecl, fntype); + } + +private: + CompileExternItem (Context *ctx, bool compile_fns, TyTy::BaseType *concrete) + : HIRCompileBase (ctx), compile_fns (compile_fns), concrete (concrete) + {} + + bool compile_fns; + TyTy::BaseType *concrete; +}; + +} // namespace Compile +} // namespace Rust + +#endif // RUST_COMPILE_EXTERN_ITEM diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h index eacfda90a79c..a6bc7f3f73bf 100644 --- a/gcc/rust/backend/rust-compile-item.h +++ b/gcc/rust/backend/rust-compile-item.h @@ -26,6 +26,7 @@ #include "rust-compile-stmt.h" #include "rust-compile-expr.h" #include "rust-compile-fnparam.h" +#include "rust-compile-extern.h" namespace Rust { namespace Compile { @@ -274,6 +275,14 @@ class CompileItem : public HIRCompileBase compile_fns); } + void visit (HIR::ExternBlock &extern_block) override + { + for (auto &item : extern_block.get_extern_items ()) + { + CompileExternItem::compile (item.get (), ctx, compile_fns, concrete); + } + } + private: CompileItem (Context *ctx, bool compile_fns, TyTy::BaseType *concrete) : HIRCompileBase (ctx), compile_fns (compile_fns), concrete (concrete) diff --git a/gcc/testsuite/rust/execute/torture/helloworld1.rs b/gcc/testsuite/rust/execute/torture/helloworld1.rs new file mode 100644 index 000000000000..d416efa33af6 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/helloworld1.rs @@ -0,0 +1,15 @@ +/* { dg-output "Hello World" }*/ +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + unsafe { + let a = "Hello World"; + let b = a as *const str; + let c = b as *const i8; + + puts(c); + } + 0 +} From 7f8adccb5056152edc4aacf08ce2ed040f076171 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Tue, 27 Jul 2021 14:33:52 +0100 Subject: [PATCH 5/5] Add support for varadic extern "c" functions like printf Varadic functions are only allowed in extern functions as far as I know. --- gcc/rust/backend/rust-compile-context.h | 11 +++- gcc/rust/backend/rust-compile-extern.h | 6 +- gcc/rust/backend/rust-compile-tyty.h | 12 +++- gcc/rust/rust-backend.h | 7 +++ gcc/rust/rust-gcc.cc | 61 +++++++++++++++++++ .../typecheck/rust-hir-type-check-implitem.h | 14 +++-- gcc/rust/typecheck/rust-tyty.cc | 41 +++++++++---- gcc/rust/typecheck/rust-tyty.h | 3 + .../rust/execute/torture/helloworld2.rs | 15 +++++ 9 files changed, 144 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/helloworld2.rs diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index bb4f0abbbf9e..0aaf084f04f0 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -371,9 +371,14 @@ class TyTyResolveCompile : public TyTy::TyVisitor parameters.push_back (compiled_param); } - translated = ctx->get_backend ()->function_type ( - receiver, parameters, results, NULL, - ctx->get_mappings ()->lookup_location (type.get_ref ())); + if (!type.is_varadic ()) + translated = ctx->get_backend ()->function_type ( + receiver, parameters, results, NULL, + ctx->get_mappings ()->lookup_location (type.get_ref ())); + else + translated = ctx->get_backend ()->function_type_varadic ( + receiver, parameters, results, NULL, + ctx->get_mappings ()->lookup_location (type.get_ref ())); } void visit (TyTy::FnPtr &type) override diff --git a/gcc/rust/backend/rust-compile-extern.h b/gcc/rust/backend/rust-compile-extern.h index 1eba011c6fac..a0ad2002bef7 100644 --- a/gcc/rust/backend/rust-compile-extern.h +++ b/gcc/rust/backend/rust-compile-extern.h @@ -51,10 +51,8 @@ class CompileExternItem : public HIRCompileBase rust_assert (ok); std::string name = item.get_item_name (); - - // FIXME - // this is assuming C ABI - std::string asm_name = "_" + name; + // FIXME this is assuming C ABI + std::string asm_name = name; Btype *type = TyTyResolveCompile::compile (ctx, resolved_type); bool is_external = true; diff --git a/gcc/rust/backend/rust-compile-tyty.h b/gcc/rust/backend/rust-compile-tyty.h index 2d0856ddde44..3ddc29ac1ab7 100644 --- a/gcc/rust/backend/rust-compile-tyty.h +++ b/gcc/rust/backend/rust-compile-tyty.h @@ -95,9 +95,15 @@ class TyTyCompile : public TyTy::TyVisitor parameters.push_back (compiled_param); } - translated - = backend->function_type (receiver, parameters, results, NULL, - mappings->lookup_location (type.get_ref ())); + if (!type.is_varadic ()) + translated + = backend->function_type (receiver, parameters, results, NULL, + mappings->lookup_location (type.get_ref ())); + else + translated + = backend->function_type_varadic (receiver, parameters, results, NULL, + mappings->lookup_location ( + type.get_ref ())); } void visit (TyTy::BoolType &) override diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index 1dd4aba12ca4..be23fd3d852c 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -163,6 +163,13 @@ class Backend Btype *result_struct, Location location) = 0; + virtual Btype * + function_type_varadic (const Btyped_identifier &receiver, + const std::vector ¶meters, + const std::vector &results, + Btype *result_struct, Location location) + = 0; + virtual Btype *function_ptr_type (Btype *result, const std::vector &praameters, Location location) diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 23a91ad9bcbc..44617a68d2a4 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -256,6 +256,11 @@ class Gcc_backend : public Backend const std::vector &, Btype *, const Location); + Btype *function_type_varadic (const Btyped_identifier &, + const std::vector &, + const std::vector &, Btype *, + const Location); + Btype *function_ptr_type (Btype *, const std::vector &, Location); Btype *struct_type (const std::vector &); @@ -1048,6 +1053,62 @@ Gcc_backend::function_type (const Btyped_identifier &receiver, return this->make_type (build_pointer_type (fntype)); } +Btype * +Gcc_backend::function_type_varadic ( + const Btyped_identifier &receiver, + const std::vector ¶meters, + const std::vector &results, Btype *result_struct, Location) +{ + size_t n = parameters.size () + (receiver.btype != NULL ? 1 : 0); + tree *args = XALLOCAVEC (tree, n); + size_t offs = 0; + + if (receiver.btype != NULL) + { + tree t = receiver.btype->get_tree (); + if (t == error_mark_node) + return this->error_type (); + + args[offs++] = t; + } + + for (std::vector::const_iterator p = parameters.begin (); + p != parameters.end (); ++p) + { + tree t = p->btype->get_tree (); + if (t == error_mark_node) + return this->error_type (); + args[offs++] = t; + } + + tree result; + if (results.empty ()) + result = void_type_node; + else if (results.size () == 1) + result = results.front ().btype->get_tree (); + else + { + gcc_assert (result_struct != NULL); + result = result_struct->get_tree (); + } + if (result == error_mark_node) + return this->error_type (); + + // The libffi library cannot represent a zero-sized object. To + // avoid causing confusion on 32-bit SPARC, we treat a function that + // returns a zero-sized value as returning void. That should do no + // harm since there is no actual value to be returned. See + // https://gcc.gnu.org/PR72814 for details. + if (result != void_type_node && int_size_in_bytes (result) == 0) + result = void_type_node; + + tree fntype = build_varargs_function_type_array (result, n, args); + if (fntype == error_mark_node) + return this->error_type (); + + return this->make_type (build_pointer_type (fntype)); +} + Btype * Gcc_backend::function_ptr_type (Btype *result_type, const std::vector ¶meters, diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index 02e5ef19aecc..65088be4d9cd 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -111,11 +111,15 @@ class TypeCheckTopLevelExternItem : public TypeCheckBase context->insert_type (param.get_mappings (), param_tyty); } - auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), - function.get_mappings ().get_defid (), - function.get_item_name (), - FNTYPE_IS_EXTERN_FLAG, std::move (params), - ret_type, std::move (substitutions)); + uint8_t flags = FNTYPE_IS_EXTERN_FLAG; + if (function.is_variadic ()) + flags |= FNTYPE_IS_VARADIC_FLAG; + + auto fnType + = new TyTy::FnType (function.get_mappings ().get_hirid (), + function.get_mappings ().get_defid (), + function.get_item_name (), flags, std::move (params), + ret_type, std::move (substitutions)); context->insert_type (function.get_mappings (), fnType); } diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 64587daf2e55..1ca28fae061f 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -2055,15 +2055,27 @@ TypeCheckCallExpr::visit (FnType &type) { if (call.num_params () != type.num_params ()) { - rust_error_at (call.get_locus (), - "unexpected number of arguments %lu expected %lu", - call.num_params (), type.num_params ()); - return; + if (type.is_varadic ()) + { + if (call.num_params () < type.num_params ()) + { + rust_error_at (call.get_locus (), + "unexpected number of arguments %lu expected %lu", + call.num_params (), type.num_params ()); + return; + } + } + else + { + rust_error_at (call.get_locus (), + "unexpected number of arguments %lu expected %lu", + call.num_params (), type.num_params ()); + return; + } } size_t i = 0; call.iterate_params ([&] (HIR::Expr *param) mutable -> bool { - auto fnparam = type.param_at (i); auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param, false); if (argument_expr_tyty == nullptr) { @@ -2072,12 +2084,19 @@ TypeCheckCallExpr::visit (FnType &type) return false; } - auto resolved_argument_type = fnparam.second->unify (argument_expr_tyty); - if (resolved_argument_type == nullptr) + auto resolved_argument_type = argument_expr_tyty; + + // it might be a varadic function + if (i < type.num_params ()) { - rust_error_at (param->get_locus_slow (), - "Type Resolution failure on parameter"); - return false; + auto fnparam = type.param_at (i); + resolved_argument_type = fnparam.second->unify (argument_expr_tyty); + if (resolved_argument_type == nullptr) + { + rust_error_at (param->get_locus_slow (), + "Type Resolution failure on parameter"); + return false; + } } context->insert_type (param->get_mappings (), resolved_argument_type); @@ -2086,7 +2105,7 @@ TypeCheckCallExpr::visit (FnType &type) return true; }); - if (i != call.num_params ()) + if (i < call.num_params ()) { rust_error_at (call.get_locus (), "unexpected number of arguments %lu expected %lu", i, diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 0a087dfd40e8..336d42b15f93 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -973,6 +973,7 @@ class FnType : public BaseType, public SubstitutionRef #define FNTYPE_DEFAULT_FLAGS 0x00 #define FNTYPE_IS_METHOD_FLAG 0x01 #define FNTYPE_IS_EXTERN_FLAG 0x02 +#define FNTYPE_IS_VARADIC_FLAG 0X04 FnType (HirId ref, DefId id, std::string identifier, uint8_t flags, std::vector > params, @@ -1031,6 +1032,8 @@ class FnType : public BaseType, public SubstitutionRef bool is_extern () const { return (flags & FNTYPE_IS_EXTERN_FLAG) != 0; } + bool is_varadic () const { return (flags & FNTYPE_IS_VARADIC_FLAG) != 0; } + DefId get_id () const { return id; } // get the Self type for the method diff --git a/gcc/testsuite/rust/execute/torture/helloworld2.rs b/gcc/testsuite/rust/execute/torture/helloworld2.rs new file mode 100644 index 000000000000..cc05f3798fac --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/helloworld2.rs @@ -0,0 +1,15 @@ +/* { dg-output "Hello World 123\n" }*/ +extern "C" { + fn printf(s: *const i8, ...); +} + +fn main() -> i32 { + unsafe { + let a = "Hello World %i\n"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, 123); + } + 0 +}