aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-10-05 14:50:29 +0100
committerPhilip Herron <philip.herron@embecosm.com>2021-10-05 15:09:09 +0100
commitf6a04f38d51f6ca4319219f101e3f58660b128dc (patch)
tree755b5bebd0b063be0464510d00bef0886a9aa03c /gcc
parent591b43e42e7f63841ce46fdd4f2760e47b6a7b0d (diff)
downloadgcc-f6a04f38d51f6ca4319219f101e3f58660b128dc.zip
gcc-f6a04f38d51f6ca4319219f101e3f58660b128dc.tar.gz
gcc-f6a04f38d51f6ca4319219f101e3f58660b128dc.tar.bz2
Ensure we emit the code for coercion sites on CallExpr and MethodCallExpr
When we coerce the types of arguments to the parameters of functions for example we must store the actual type of the argument at that HIR ID not the coerced ones. This gives the backend a chance to then figure out when to actually implement any coercion site code. such as computing the dynamic objects. Fixes: #700
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/backend/rust-compile-expr.h22
-rw-r--r--gcc/rust/backend/rust-compile.cc111
-rw-r--r--gcc/testsuite/rust/execute/torture/coercion1.rs43
-rw-r--r--gcc/testsuite/rust/execute/torture/coercion2.rs41
4 files changed, 199 insertions, 18 deletions
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h
index eb245dc..b1a0f07 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -363,12 +363,28 @@ public:
void visit (HIR::AssignmentExpr &expr) override
{
fncontext fn = ctx->peek_fn ();
- auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
- auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
+ auto lvalue = CompileExpr::Compile (expr.get_lhs (), ctx);
+ auto rvalue = CompileExpr::Compile (expr.get_rhs (), ctx);
+
+ // assignments are coercion sites so lets convert the rvalue if necessary
+ TyTy::BaseType *expected = nullptr;
+ TyTy::BaseType *actual = nullptr;
+
+ bool ok;
+ ok = ctx->get_tyctx ()->lookup_type (
+ expr.get_lhs ()->get_mappings ().get_hirid (), &expected);
+ rust_assert (ok);
+
+ ok = ctx->get_tyctx ()->lookup_type (
+ expr.get_rhs ()->get_mappings ().get_hirid (), &actual);
+ rust_assert (ok);
+
+ rvalue = coercion_site (rvalue, actual, expected, expr.get_locus ());
Bstatement *assignment
- = ctx->get_backend ()->assignment_statement (fn.fndecl, lhs, rhs,
+ = ctx->get_backend ()->assignment_statement (fn.fndecl, lvalue, rvalue,
expr.get_locus ());
+
ctx->add_statement (assignment);
}
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index d1fd064..23a035f 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -69,39 +69,120 @@ CompileExpr::visit (HIR::CallExpr &expr)
|| tyty->get_kind () == TyTy::TypeKind::FNPTR;
if (!is_fn)
{
- Btype *type = TyTyResolveCompile::compile (ctx, tyty);
+ rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
+ Btype *compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty);
// this assumes all fields are in order from type resolution and if a
// base struct was specified those fields are filed via accesors
std::vector<Bexpression *> vals;
- for (auto &argument : expr.get_arguments ())
+ for (size_t i = 0; i < expr.get_arguments ().size (); i++)
{
- Bexpression *e = CompileExpr::Compile (argument.get (), ctx);
- vals.push_back (e);
+ auto &argument = expr.get_arguments ().at (i);
+ auto rvalue = CompileExpr::Compile (argument.get (), ctx);
+
+ // assignments are coercion sites so lets convert the rvalue if
+ // necessary
+ auto respective_field = adt->get_field (i);
+ auto expected = respective_field->get_field_type ();
+
+ TyTy::BaseType *actual = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_type (
+ argument->get_mappings ().get_hirid (), &actual);
+ rust_assert (ok);
+
+ // coerce it if required
+ rvalue = coercion_site (rvalue, actual, expected, expr.get_locus ());
+
+ // add it to the list
+ vals.push_back (rvalue);
}
translated
- = ctx->get_backend ()->constructor_expression (type, vals, -1,
- expr.get_locus ());
+ = ctx->get_backend ()->constructor_expression (compiled_adt_type, vals,
+ -1, expr.get_locus ());
}
else
{
- // must be a call to a function
- Bexpression *fn = CompileExpr::Compile (expr.get_fnexpr (), ctx);
- rust_assert (fn != nullptr);
+ auto get_parameter_tyty_at_index
+ = [] (const TyTy::BaseType *base, size_t index,
+ TyTy::BaseType **result) -> bool {
+ bool is_fn = base->get_kind () == TyTy::TypeKind::FNDEF
+ || base->get_kind () == TyTy::TypeKind::FNPTR;
+ rust_assert (is_fn);
+
+ if (base->get_kind () == TyTy::TypeKind::FNPTR)
+ {
+ const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (base);
+ *result = fn->param_at (index);
+
+ return true;
+ }
+
+ const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (base);
+ auto param = fn->param_at (index);
+ *result = param.second;
+
+ return true;
+ };
+
+ bool is_varadic = false;
+ if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty);
+ is_varadic = fn->is_varadic ();
+ }
+
+ size_t required_num_args;
+ if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty);
+ required_num_args = fn->num_params ();
+ }
+ else
+ {
+ const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (tyty);
+ required_num_args = fn->num_params ();
+ }
std::vector<Bexpression *> args;
- for (auto &argument : expr.get_arguments ())
+ for (size_t i = 0; i < expr.get_arguments ().size (); i++)
{
- Bexpression *compiled_expr
- = CompileExpr::Compile (argument.get (), ctx);
- args.push_back (compiled_expr);
+ auto &argument = expr.get_arguments ().at (i);
+ auto rvalue = CompileExpr::Compile (argument.get (), ctx);
+
+ if (is_varadic && i >= required_num_args)
+ {
+ args.push_back (rvalue);
+ continue;
+ }
+
+ // assignments are coercion sites so lets convert the rvalue if
+ // necessary
+ bool ok;
+ TyTy::BaseType *expected = nullptr;
+ ok = get_parameter_tyty_at_index (tyty, i, &expected);
+ rust_assert (ok);
+
+ TyTy::BaseType *actual = nullptr;
+ ok = ctx->get_tyctx ()->lookup_type (
+ argument->get_mappings ().get_hirid (), &actual);
+ rust_assert (ok);
+
+ // coerce it if required
+ rvalue = coercion_site (rvalue, actual, expected, expr.get_locus ());
+
+ // add it to the list
+ args.push_back (rvalue);
}
+ // must be a call to a function
+ auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx);
auto fncontext = ctx->peek_fn ();
translated
- = ctx->get_backend ()->call_expression (fncontext.fndecl, fn, args,
- nullptr, expr.get_locus ());
+ = ctx->get_backend ()->call_expression (fncontext.fndecl, fn_address,
+ args, nullptr,
+ expr.get_locus ());
}
}
diff --git a/gcc/testsuite/rust/execute/torture/coercion1.rs b/gcc/testsuite/rust/execute/torture/coercion1.rs
new file mode 100644
index 0000000..dff9809
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/coercion1.rs
@@ -0,0 +1,43 @@
+/* { dg-output "123\n123\n" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+struct Foo(i32);
+trait Bar {
+ fn baz(&self);
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+}
+
+impl Bar for Foo {
+ fn baz(&self) {
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+ unsafe {
+ let a = "%i\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, self.0);
+ }
+ }
+}
+
+fn static_dispatch<T: Bar>(t: &T) {
+ t.baz();
+}
+
+fn dynamic_dispatch(t: &dyn Bar) {
+ t.baz();
+}
+
+fn main() -> i32 {
+ let a;
+ a = Foo(123);
+ static_dispatch(&a);
+
+ let b: &dyn Bar;
+ b = &a;
+ dynamic_dispatch(b);
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/coercion2.rs b/gcc/testsuite/rust/execute/torture/coercion2.rs
new file mode 100644
index 0000000..e404954
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/coercion2.rs
@@ -0,0 +1,41 @@
+/* { dg-output "123\n123\n" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+struct Foo(i32);
+trait Bar {
+ fn baz(&self);
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+}
+
+impl Bar for Foo {
+ fn baz(&self) {
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+ unsafe {
+ let a = "%i\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, self.0);
+ }
+ }
+}
+
+fn static_dispatch<T: Bar>(t: &T) {
+ t.baz();
+}
+
+fn dynamic_dispatch(t: &dyn Bar) {
+ t.baz();
+}
+
+fn main() -> i32 {
+ let a;
+ a = &Foo(123);
+
+ static_dispatch(a);
+ dynamic_dispatch(a);
+
+ 0
+}