https://gcc.gnu.org/g:b26948774265990090afb12bf3c7fd8cefda4a64
commit r16-4866-gb26948774265990090afb12bf3c7fd8cefda4a64 Author: Philip Herron <[email protected]> Date: Wed Sep 3 12:27:36 2025 +0100 gccrs: fnptr types can hold onto generic params so it needs to handle substs 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]> Diff: --- gcc/rust/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(-) diff --git a/gcc/rust/typecheck/rust-substitution-mapper.cc b/gcc/rust/typecheck/rust-substitution-mapper.cc index c5b823eabcc7..958651e55939 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 9c1a84f5919a..ff84cfc9d111 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 973ada3bdc42..480a195b8683 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 000000000000..9f83835ee4a3 --- /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 000000000000..75d6b7c6407c --- /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(), +}
