From: Philip Herron Date: Tue, 13 Jun 2023 18:14:27 +0000 (+0100) Subject: gccrs: fortify resolve_method_address to match the types X-Git-Tag: basepoints/gcc-15~2468 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77cd54e9dc3fae65d47d2f7c375c74cab362a0c9;p=thirdparty%2Fgcc.git gccrs: fortify resolve_method_address to match the types Fixes #2019 gcc/rust/ChangeLog: * backend/rust-compile-base.cc (HIRCompileBase::resolve_method_address): match the fntype to the candidate gcc/testsuite/ChangeLog: * rust/compile/issue-2019-2.rs: New test. * rust/compile/issue-2019-3.rs: New test. Signed-off-by: Philip Herron --- diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc index f034b8c7b0a4..4a95530f1488 100644 --- a/gcc/rust/backend/rust-compile-base.cc +++ b/gcc/rust/backend/rust-compile-base.cc @@ -770,6 +770,10 @@ HIRCompileBase::resolve_method_address (TyTy::FnType *fntype, TyTy::BaseType *receiver, Location expr_locus) { + rust_debug_loc (expr_locus, "resolve_method_address for %s and receiver %s", + fntype->debug_str ().c_str (), + receiver->debug_str ().c_str ()); + DefId id = fntype->get_id (); rust_assert (id != UNKNOWN_DEFID); @@ -823,13 +827,46 @@ HIRCompileBase::resolve_method_address (TyTy::FnType *fntype, ctx, fntype, true, expr_locus); } - // 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 + const Resolver::PathProbeCandidate *selectedCandidate = nullptr; + rust_debug_loc (expr_locus, "resolved to %lu candidates", candidates.size ()); + + // filter for the possible case of non fn type items + std::set filteredFunctionCandidates; + for (auto &candidate : candidates) + { + bool is_fntype = candidate.ty->get_kind () == TyTy::TypeKind::FNDEF; + if (!is_fntype) + continue; + + filteredFunctionCandidates.insert (candidate); + } + + // look for the exact fntype + for (auto &candidate : filteredFunctionCandidates) + { + bool compatable + = Resolver::types_compatable (TyTy::TyWithLocation (candidate.ty), + TyTy::TyWithLocation (fntype), expr_locus, + false); + + rust_debug_loc (candidate.locus, "candidate: %s vs %s compatable=%s", + candidate.ty->debug_str ().c_str (), + fntype->debug_str ().c_str (), + compatable ? "true" : "false"); + + if (compatable) + { + selectedCandidate = &candidate; + break; + } + } + + // FIXME eventually this should just return error mark node when we support + // going through all the passes + rust_assert (selectedCandidate != nullptr); - rust_assert (candidates.size () == 1); - auto &candidate = *candidates.begin (); + // lets compile it + const Resolver::PathProbeCandidate &candidate = *selectedCandidate; rust_assert (candidate.is_impl_candidate ()); rust_assert (candidate.ty->get_kind () == TyTy::TypeKind::FNDEF); TyTy::FnType *candidate_call = static_cast (candidate.ty); diff --git a/gcc/testsuite/rust/compile/issue-2019-2.rs b/gcc/testsuite/rust/compile/issue-2019-2.rs new file mode 100644 index 000000000000..37c8e30b1060 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-2019-2.rs @@ -0,0 +1,30 @@ +#[lang = "add"] +pub trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u32 { + type Output = u32; + + fn add(self, other: u32) -> u32 { + self + other + } +} + +impl<'a> Add for &'a u32 { + type Output = >::Output; + + fn add(self, other: u32) -> >::Output { + Add::add(*self, other) + } +} + +impl<'a> Add<&'a u32> for u32 { + type Output = >::Output; + + fn add(self, other: &'a u32) -> >::Output { + Add::add(self, *other) + } +} diff --git a/gcc/testsuite/rust/compile/issue-2019-3.rs b/gcc/testsuite/rust/compile/issue-2019-3.rs new file mode 100644 index 000000000000..67890388be31 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-2019-3.rs @@ -0,0 +1,59 @@ +macro_rules! forward_ref_binop { + (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { + forward_ref_binop!(impl $imp, $method for $t, $u, + #[stable(feature = "rust1", since = "1.0.0")]); + }; + (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => { + #[$attr] + impl<'a> $imp<$u> for &'a $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: $u) -> <$t as $imp<$u>>::Output { + $imp::$method(*self, other) + } + } + + #[$attr] + impl<'a> $imp<&'a $u> for $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { + $imp::$method(self, *other) + } + } + + #[$attr] + impl<'a, 'b> $imp<&'a $u> for &'b $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { + $imp::$method(*self, *other) + } + } + } +} + +#[lang = "add"] +pub trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +macro_rules! add_impl { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl Add for $t { + type Output = $t; + + fn add(self, other: $t) -> $t { self + other } + } + + forward_ref_binop! { impl Add, add for $t, $t } + )*) +} + +add_impl! { usize u8 u16 u32 u64 /*u128*/ isize i8 i16 i32 i64 /*i128*/ f32 f64 }