diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-10-05 14:50:29 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-10-05 15:09:09 +0100 |
commit | f6a04f38d51f6ca4319219f101e3f58660b128dc (patch) | |
tree | 755b5bebd0b063be0464510d00bef0886a9aa03c /gcc | |
parent | 591b43e42e7f63841ce46fdd4f2760e47b6a7b0d (diff) | |
download | gcc-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.h | 22 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile.cc | 111 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/coercion1.rs | 43 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/coercion2.rs | 41 |
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 +} |