From 04549bf8c34cdb3ea435d8542f2cac6d46bcd30f Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Wed, 15 Sep 2021 16:16:55 +0100 Subject: Fix bug when calling method from generic reciever type-bound When we have a generic function with a specified type bound, this means the method resolution can only resolve this to the trait item. During code generation we must then monomorphize this and lookup the associated impl block item for this trait (if it exists) and call this function. Fixes #678 --- gcc/rust/backend/rust-compile.cc | 28 +++++++++++++++++----- gcc/testsuite/rust/execute/torture/trait4.rs | 36 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/trait4.rs (limited to 'gcc') diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index 5214b1d..f0e26dc 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -22,6 +22,7 @@ #include "rust-compile-struct-field-expr.h" #include "rust-hir-trait-resolve.h" #include "rust-hir-path-probe.h" +#include "rust-hir-dot-operator.h" namespace Rust { namespace Compile { @@ -171,10 +172,11 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) // item so its up to us to figure out if this path should resolve // to an trait-impl-block-item or if it can be defaulted to the // trait-impl-item's definition + + auto root = receiver->get_root (); std::vector candidates = Resolver::PathProbeType::Probe ( - receiver, expr.get_method_name ().get_segment (), true, false, - true); + root, expr.get_method_name ().get_segment (), true, false, true); if (candidates.size () == 0) { @@ -186,6 +188,11 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) rust_assert (ok); // found rust_assert (trait_item_ref->is_optional ()); // has definition + // FIXME Optional means it has a definition and an associated + // block which can be a default implementation, if it does not + // contain an implementation we should actually return + // error_mark_node + TyTy::BaseType *self_type = nullptr; if (!ctx->get_tyctx ()->lookup_type ( expr.get_receiver ()->get_mappings ().get_hirid (), @@ -209,10 +216,19 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) } else { - Resolver::PathProbeCandidate &candidate = candidates.at (0); - rust_assert (candidate.is_impl_candidate ()); - - HIR::ImplItem *impl_item = candidate.item.impl.impl_item; + std::vector adjustments; + Resolver::PathProbeCandidate *candidate + = Resolver::MethodResolution::Select (candidates, root, + adjustments); + + // FIXME this will be a case to return error_mark_node, there is + // an error scenario where a Trait Foo has a method Bar, but this + // receiver does not implement this trait or has an incompatible + // implementation and we should just return error_mark_node + rust_assert (candidate != nullptr); + rust_assert (candidate->is_impl_candidate ()); + + HIR::ImplItem *impl_item = candidate->item.impl.impl_item; TyTy::BaseType *self_type = nullptr; if (!ctx->get_tyctx ()->lookup_type ( diff --git a/gcc/testsuite/rust/execute/torture/trait4.rs b/gcc/testsuite/rust/execute/torture/trait4.rs new file mode 100644 index 0000000..8c9b740 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait4.rs @@ -0,0 +1,36 @@ +/* { dg-output "123\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 type_bound(t: &T) { + t.baz(); +} + +fn main() -> i32 { + let a; + + a = &Foo(123); + type_bound(a); + + 0 +} -- cgit v1.1