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