]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: fnptr types can hold onto generic params so it needs to handle substs
authorPhilip Herron <herron.philip@googlemail.com>
Wed, 3 Sep 2025 11:27:36 +0000 (12:27 +0100)
committerArthur Cohen <arthur.cohen@embecosm.com>
Thu, 30 Oct 2025 20:30:52 +0000 (21:30 +0100)
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 <herron.philip@googlemail.com>
gcc/rust/typecheck/rust-substitution-mapper.cc
gcc/rust/typecheck/rust-tyty.cc
gcc/rust/typecheck/rust-tyty.h
gcc/testsuite/rust/compile/issue-4090-1.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/issue-4090-2.rs [new file with mode: 0644]

index c5b823eabcc7b2d258557bdff7618427561348c4..958651e559393a614bc8b77612932092ad5cb29b 100644 (file)
@@ -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 ();
 }
index 9c1a84f5919a271e63ea7c32adbfa2244ae71963..ff84cfc9d111e9f788769d9625d8a14368e47d94 100644 (file)
@@ -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)
 {
index 973ada3bdc42c856eb49d36468e3e72ad0245bba..480a195b8683b98510f0627c21942bf5069198a4 100644 (file)
@@ -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 (file)
index 0000000..9f83835
--- /dev/null
@@ -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 (file)
index 0000000..75d6b7c
--- /dev/null
@@ -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(),
+}