aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-07-27 14:33:52 +0100
committerPhilip Herron <philip.herron@embecosm.com>2021-07-27 14:33:52 +0100
commit7f8adccb5056152edc4aacf08ce2ed040f076171 (patch)
treefa41b5f161823fe6b43413370422f25414f8fcaa /gcc
parent2818017d36f5c6279a2372b0a8efbe1f17b3f374 (diff)
downloadgcc-7f8adccb5056152edc4aacf08ce2ed040f076171.zip
gcc-7f8adccb5056152edc4aacf08ce2ed040f076171.tar.gz
gcc-7f8adccb5056152edc4aacf08ce2ed040f076171.tar.bz2
Add support for varadic extern "c" functions like printf
Varadic functions are only allowed in extern functions as far as I know.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/backend/rust-compile-context.h11
-rw-r--r--gcc/rust/backend/rust-compile-extern.h6
-rw-r--r--gcc/rust/backend/rust-compile-tyty.h12
-rw-r--r--gcc/rust/rust-backend.h7
-rw-r--r--gcc/rust/rust-gcc.cc61
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.h14
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc41
-rw-r--r--gcc/rust/typecheck/rust-tyty.h3
-rw-r--r--gcc/testsuite/rust/execute/torture/helloworld2.rs15
9 files changed, 144 insertions, 26 deletions
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index bb4f0ab..0aaf084 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -371,9 +371,14 @@ public:
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 1eba011..a0ad200 100644
--- a/gcc/rust/backend/rust-compile-extern.h
+++ b/gcc/rust/backend/rust-compile-extern.h
@@ -51,10 +51,8 @@ public:
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 2d0856d..3ddc29a 100644
--- a/gcc/rust/backend/rust-compile-tyty.h
+++ b/gcc/rust/backend/rust-compile-tyty.h
@@ -95,9 +95,15 @@ public:
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 1dd4aba..be23fd3 100644
--- a/gcc/rust/rust-backend.h
+++ b/gcc/rust/rust-backend.h
@@ -163,6 +163,13 @@ public:
Btype *result_struct, Location location)
= 0;
+ virtual Btype *
+ function_type_varadic (const Btyped_identifier &receiver,
+ const std::vector<Btyped_identifier> &parameters,
+ const std::vector<Btyped_identifier> &results,
+ Btype *result_struct, Location location)
+ = 0;
+
virtual Btype *function_ptr_type (Btype *result,
const std::vector<Btype *> &praameters,
Location location)
diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc
index 23a91ad..44617a6 100644
--- a/gcc/rust/rust-gcc.cc
+++ b/gcc/rust/rust-gcc.cc
@@ -256,6 +256,11 @@ public:
const std::vector<Btyped_identifier> &, Btype *,
const Location);
+ Btype *function_type_varadic (const Btyped_identifier &,
+ const std::vector<Btyped_identifier> &,
+ const std::vector<Btyped_identifier> &, Btype *,
+ const Location);
+
Btype *function_ptr_type (Btype *, const std::vector<Btype *> &, Location);
Btype *struct_type (const std::vector<Btyped_identifier> &);
@@ -1049,6 +1054,62 @@ Gcc_backend::function_type (const Btyped_identifier &receiver,
}
Btype *
+Gcc_backend::function_type_varadic (
+ const Btyped_identifier &receiver,
+ const std::vector<Btyped_identifier> &parameters,
+ const std::vector<Btyped_identifier> &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<Btyped_identifier>::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<Btype *> &parameters,
Location /* locus */)
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
index 02e5ef1..65088be 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 @@ public:
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 64587da..1ca28fa 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 0a087df..336d42b 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -973,6 +973,7 @@ public:
#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<std::pair<HIR::Pattern *, BaseType *> > params,
@@ -1031,6 +1032,8 @@ public:
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 0000000..cc05f37
--- /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
+}