From: Philip Herron Date: Wed, 3 Sep 2025 11:27:36 +0000 (+0100) Subject: gccrs: fnptr types can hold onto generic params so it needs to handle substs X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b26948774265990090afb12bf3c7fd8cefda4a64;p=thirdparty%2Fgcc.git 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 --- 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 (); + 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 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; + + #[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 { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + pub trait Eq: PartialEq { + 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 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 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; + + #[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 { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + pub trait Eq: PartialEq { + 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 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 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(), +}