From 7f8adccb5056152edc4aacf08ce2ed040f076171 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Tue, 27 Jul 2021 14:33:52 +0100 Subject: [PATCH] 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 +}