From: Philip Herron <[email protected]>

This patch adds support to recursively walk fnptr types to do generic
substitutions.

Fixes Rust-GCC/gccrs#4090

gcc/rust/ChangeLog:

        * typecheck/rust-substitution-mapper.cc (SubstMapperInternal::visit): 
handle fnptr
        * typecheck/rust-tyty.cc (FnPtr::handle_substitions): new
        * typecheck/rust-tyty.h: likewise

gcc/testsuite/ChangeLog:

        * rust/compile/issue-4090-1.rs: New test.
        * rust/compile/issue-4090-2.rs: New test.

Signed-off-by: Philip Herron <[email protected]>
---
 .../typecheck/rust-substitution-mapper.cc     | 10 +--
 gcc/rust/typecheck/rust-tyty.cc               | 34 +++++++++
 gcc/rust/typecheck/rust-tyty.h                |  2 +
 gcc/testsuite/rust/compile/issue-4090-1.rs    | 68 ++++++++++++++++++
 gcc/testsuite/rust/compile/issue-4090-2.rs    | 71 +++++++++++++++++++
 5 files changed, 180 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-4090-1.rs
 create mode 100644 gcc/testsuite/rust/compile/issue-4090-2.rs

diff --git a/gcc/rust/typecheck/rust-substitution-mapper.cc 
b/gcc/rust/typecheck/rust-substitution-mapper.cc
index c5b823eabcc..958651e5593 100644
--- a/gcc/rust/typecheck/rust-substitution-mapper.cc
+++ b/gcc/rust/typecheck/rust-substitution-mapper.cc
@@ -310,15 +310,15 @@ SubstMapperInternal::visit (TyTy::SliceType &type)
 {
   resolved = type.handle_substitions (mappings);
 }
-
-// nothing to do for these
 void
-SubstMapperInternal::visit (TyTy::InferType &type)
+SubstMapperInternal::visit (TyTy::FnPtr &type)
 {
-  resolved = type.clone ();
+  resolved = type.handle_substitions (mappings);
 }
+
+// nothing to do for these
 void
-SubstMapperInternal::visit (TyTy::FnPtr &type)
+SubstMapperInternal::visit (TyTy::InferType &type)
 {
   resolved = type.clone ();
 }
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 9c1a84f5919..ff84cfc9d11 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -2314,6 +2314,40 @@ FnPtr::clone () const
                    get_unsafety (), get_combined_refs ());
 }
 
+FnPtr *
+FnPtr::handle_substitions (SubstitutionArgumentMappings &mappings)
+{
+  auto &mappings_table = Analysis::Mappings::get ();
+
+  auto fn = clone ()->as<FnPtr> ();
+  fn->set_ref (mappings_table.get_next_hir_id ());
+  fn->set_ty_ref (mappings_table.get_next_hir_id ());
+
+  if (!fn->result_type.get_tyty ()->is_concrete ())
+    {
+      BaseType *concrete
+       = Resolver::SubstMapperInternal::Resolve (fn->result_type.get_tyty (),
+                                                 mappings);
+      fn->result_type
+       = TyVar::subst_covariant_var (fn->result_type.get_tyty (), concrete);
+    }
+
+  for (size_t i = 0; i < fn->params.size (); i++)
+    {
+      TyVar &field = fn->params.at (i);
+      if (!field.get_tyty ()->is_concrete ())
+       {
+         BaseType *concrete
+           = Resolver::SubstMapperInternal::Resolve (field.get_tyty (),
+                                                     mappings);
+         fn->params[i]
+           = TyVar::subst_covariant_var (field.get_tyty (), concrete);
+       }
+    }
+
+  return fn;
+}
+
 void
 ClosureType::accept_vis (TyVisitor &vis)
 {
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 973ada3bdc4..480a195b868 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -1101,6 +1101,8 @@ public:
 
   Unsafety get_unsafety () const { return unsafety; }
 
+  FnPtr *handle_substitions (SubstitutionArgumentMappings &mappings);
+
 private:
   std::vector<TyVar> params;
   TyVar result_type;
diff --git a/gcc/testsuite/rust/compile/issue-4090-1.rs 
b/gcc/testsuite/rust/compile/issue-4090-1.rs
new file mode 100644
index 00000000000..9f83835ee4a
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-4090-1.rs
@@ -0,0 +1,68 @@
+mod core {
+    mod marker {
+        #[lang = "sized"]
+        pub trait Sized {}
+
+        #[lang = "phantom_data"]
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub struct PhantomData<T: ?Sized>;
+
+        #[unstable(feature = "structural_match", issue = "31434")]
+        #[lang = "structural_teq"]
+        pub trait StructuralEq {
+            // Empty.
+        }
+
+        #[unstable(feature = "structural_match", issue = "31434")]
+        #[lang = "structural_peq"]
+        pub trait StructuralPartialEq {
+            // Empty.
+        }
+    }
+
+    pub mod cmp {
+        use super::marker::Sized;
+
+        #[lang = "eq"]
+        pub trait PartialEq<Rhs: ?Sized = Self> {
+            fn eq(&self, other: &Rhs) -> bool;
+
+            fn ne(&self, other: &Rhs) -> bool {
+                !self.eq(other)
+            }
+        }
+
+        pub trait Eq: PartialEq<Self> {
+            fn assert_receiver_is_total_eq(&self) {}
+        }
+    }
+
+    pub mod ptr {
+
+        use super::cmp::{Eq, PartialEq};
+
+        macro_rules! fnptr_impls_safety_abi {
+            ($FnTy: ty, $($Arg: ident),*) => {
+                #[stable(feature = "fnptr_impls", since = "1.4.0")]
+                impl<Ret, $($Arg),*> PartialEq for $FnTy {
+                    #[inline]
+                    fn eq(&self, other: &Self) -> bool {
+                        *self as usize == *other as usize
+                    }
+                }
+
+                #[stable(feature = "fnptr_impls", since = "1.4.0")]
+                impl<Ret, $($Arg),*> Eq for $FnTy {}
+
+            }
+        }
+
+        fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, }
+    }
+}
+
+#[derive(PartialEq, Eq)]
+struct AllowedBelow {
+    // { dg-warning "struct is never constructed" "" { target *-*-* } .-1 }
+    f: fn(),
+}
diff --git a/gcc/testsuite/rust/compile/issue-4090-2.rs 
b/gcc/testsuite/rust/compile/issue-4090-2.rs
new file mode 100644
index 00000000000..75d6b7c6407
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-4090-2.rs
@@ -0,0 +1,71 @@
+mod core {
+    mod marker {
+        #[lang = "sized"]
+        pub trait Sized {}
+
+        #[lang = "phantom_data"]
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub struct PhantomData<T: ?Sized>;
+
+        #[unstable(feature = "structural_match", issue = "31434")]
+        #[lang = "structural_teq"]
+        pub trait StructuralEq {
+            // Empty.
+        }
+
+        #[unstable(feature = "structural_match", issue = "31434")]
+        #[lang = "structural_peq"]
+        pub trait StructuralPartialEq {
+            // Empty.
+        }
+    }
+
+    pub mod cmp {
+        use super::marker::Sized;
+
+        #[lang = "eq"]
+        pub trait PartialEq<Rhs: ?Sized = Self> {
+            fn eq(&self, other: &Rhs) -> bool;
+
+            fn ne(&self, other: &Rhs) -> bool {
+                !self.eq(other)
+            }
+        }
+
+        pub trait Eq: PartialEq<Self> {
+            fn assert_receiver_is_total_eq(&self) {}
+        }
+    }
+
+    pub mod ptr {
+
+        use super::cmp::{Eq, PartialEq};
+
+        macro_rules! fnptr_impls_safety_abi {
+            ($FnTy: ty, $($Arg: ident),*) => {
+                #[stable(feature = "fnptr_impls", since = "1.4.0")]
+                impl<Ret, $($Arg),*> PartialEq for $FnTy {
+                    #[inline]
+                    fn eq(&self, other: &Self) -> bool {
+                        *self as usize == *other as usize
+                    }
+                }
+
+                #[stable(feature = "fnptr_impls", since = "1.4.0")]
+                impl<Ret, $($Arg),*> Eq for $FnTy {}
+
+            }
+        }
+
+        fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, }
+        fnptr_impls_safety_abi! { extern "C" fn() -> Ret, }
+        fnptr_impls_safety_abi! { unsafe extern "Rust" fn() -> Ret, }
+        fnptr_impls_safety_abi! { unsafe extern "C" fn() -> Ret, }
+    }
+}
+
+#[derive(PartialEq, Eq)]
+struct AllowedBelow {
+    // { dg-warning "struct is never constructed" "" { target *-*-* } .-1 }
+    f: fn(),
+}
-- 
2.50.1

Reply via email to