[gcc r14-7671] gccrs: fortify resolve_method_address to match the types

Arthur Cohen cohenarthur@gcc.gnu.org
Tue Jan 16 17:52:25 GMT 2024


https://gcc.gnu.org/g:77cd54e9dc3fae65d47d2f7c375c74cab362a0c9

commit r14-7671-g77cd54e9dc3fae65d47d2f7c375c74cab362a0c9
Author: Philip Herron <herron.philip@googlemail.com>
Date:   Tue Jun 13 19:14:27 2023 +0100

    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 <herron.philip@googlemail.com>

Diff:
---
 gcc/rust/backend/rust-compile-base.cc      | 49 ++++++++++++++++++++++---
 gcc/testsuite/rust/compile/issue-2019-2.rs | 30 +++++++++++++++
 gcc/testsuite/rust/compile/issue-2019-3.rs | 59 ++++++++++++++++++++++++++++++
 3 files changed, 132 insertions(+), 6 deletions(-)

diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc
index f034b8c7b0a..4a95530f148 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<Resolver::PathProbeCandidate> 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<TyTy::FnType *> (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 00000000000..37c8e30b106
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2019-2.rs
@@ -0,0 +1,30 @@
+#[lang = "add"]
+pub trait Add<RHS = Self> {
+    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<u32> for &'a u32 {
+    type Output = <u32 as Add<u32>>::Output;
+
+    fn add(self, other: u32) -> <u32 as Add<u32>>::Output {
+        Add::add(*self, other)
+    }
+}
+
+impl<'a> Add<&'a u32> for u32 {
+    type Output = <u32 as Add<u32>>::Output;
+
+    fn add(self, other: &'a u32) -> <u32 as Add<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 00000000000..67890388be3
--- /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<RHS = Self> {
+    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 }


More information about the Gcc-cvs mailing list