https://gcc.gnu.org/g:792ce42cd3d44cc854c4fd389698abca35a1a039
commit r16-5352-g792ce42cd3d44cc854c4fd389698abca35a1a039 Author: Philip Herron <[email protected]> Date: Sun Nov 9 20:28:50 2025 +0000 gccrs: Support generic constant impl items Impl items can have constants defined which could in turn be generic this was not supported by gccrs and missed. So for example: impl<T> Foo<T> { const MAGIC: usize = mem::size_of::<T>(); } This is a normal type parameter but in order to setup the generics we need to create a synthetic TyTy::FnType so we can bind the parent's impl generics to the type system and it just works like any other generic item at that point. Then for example we have: impl<const N: usize> Foo<N> { const VALUE: usize = N; } Again we consistently bind the this const generic parameter the same way so the lazy evaluation of the generic can take place. gcc/rust/ChangeLog: * backend/rust-compile-item.cc (CompileItem::visit): support the synthetic function consts * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::Resolve): likewise * typecheck/rust-hir-type-check-implitem.cc (TypeCheckImplItem::visit): create the synth * typecheck/rust-tyty.h: new flag for synthetic constant gcc/testsuite/ChangeLog: * rust/execute/torture/const-generics-5.rs: New test. * rust/execute/torture/const-generics-6.rs: New test. * rust/execute/torture/const-generics-7.rs: New test. Signed-off-by: Philip Herron <[email protected]> Diff: --- gcc/rust/backend/rust-compile-item.cc | 11 +++++++++ gcc/rust/typecheck/rust-hir-type-check-expr.cc | 20 +++++++++++++--- gcc/rust/typecheck/rust-hir-type-check-implitem.cc | 28 ++++++++++++++++++++-- gcc/rust/typecheck/rust-tyty.h | 6 +++++ .../rust/execute/torture/const-generics-5.rs | 13 ++++++++++ .../rust/execute/torture/const-generics-6.rs | 15 ++++++++++++ .../rust/execute/torture/const-generics-7.rs | 22 +++++++++++++++++ 7 files changed, 110 insertions(+), 5 deletions(-) diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index b72e70d113ec..d9087104e46a 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -109,6 +109,17 @@ CompileItem::visit (HIR::ConstantItem &constant) // canonical path Resolver::CanonicalPath canonical_path = nr_ctx.to_canonical_path (mappings.get_nodeid ()); + if (constant_type->is<const TyTy::FnType> ()) + { + if (concrete == nullptr) + return; + + rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *concrete_fnty = static_cast<TyTy::FnType *> (concrete); + + concrete_fnty->override_context (); + constant_type = expr_type = concrete_fnty->get_return_type (); + } ctx->push_const_context (); tree const_expr diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 7885dfcf7463..1c00fd96d949 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -53,10 +53,19 @@ TypeCheckExpr::Resolve (HIR::Expr &expr) if (resolver.infered == nullptr) return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); - auto ref = expr.get_mappings ().get_hirid (); - resolver.infered->set_ref (ref); + if (resolver.infered->get_kind () != TyTy::TypeKind::CONST) + { + auto ref = expr.get_mappings ().get_hirid (); + resolver.infered->set_ref (ref); + } resolver.context->insert_type (expr.get_mappings (), resolver.infered); + if (auto fn = resolver.infered->try_as<const TyTy::FnType> ()) + { + if (fn->is_syn_constant ()) + resolver.infered = fn->get_return_type (); + } + return resolver.infered; } @@ -2358,7 +2367,12 @@ bool TypeCheckExpr::validate_arithmetic_type ( const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type) { - const TyTy::BaseType *type = tyty->destructure (); + auto type = tyty->destructure (); + if (type->get_kind () == TyTy::TypeKind::CONST) + { + auto base_const = type->as_const_type (); + type = base_const->get_specified_type (); + } // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators // this will change later when traits are added diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index e7f66327d02d..07fc010b0872 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -391,8 +391,32 @@ TypeCheckImplItem::visit (HIR::ConstantItem &constant) TyTy::TyWithLocation (type, constant.get_type ().get_locus ()), TyTy::TyWithLocation (expr_type, constant.get_expr ().get_locus ()), constant.get_locus ()); - context->insert_type (constant.get_mappings (), unified); - result = unified; + + if (substitutions.empty ()) + { + context->insert_type (constant.get_mappings (), unified); + result = unified; + return; + } + + // special case when this is a generic constant + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + CanonicalPath canonical_path + = nr_ctx.to_canonical_path (constant.get_mappings ().get_nodeid ()); + RustIdent ident{canonical_path, constant.get_locus ()}; + auto fnType = new TyTy::FnType ( + constant.get_mappings ().get_hirid (), + constant.get_mappings ().get_defid (), + constant.get_identifier ().as_string (), ident, + TyTy::FnType::FNTYPE_IS_SYN_CONST_FLAG, ABI::RUST, {}, unified, + std::move (substitutions), + TyTy::SubstitutionArgumentMappings::empty ( + context->get_lifetime_resolver ().get_num_bound_regions ()), + {}); + + context->insert_type (constant.get_mappings (), fnType); + result = fnType; } void diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 3236bf34a592..ed3cd76807cd 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -1050,6 +1050,7 @@ public: static const uint8_t FNTYPE_IS_METHOD_FLAG = 0x01; static const uint8_t FNTYPE_IS_EXTERN_FLAG = 0x02; static const uint8_t FNTYPE_IS_VARADIC_FLAG = 0X04; + static const uint8_t FNTYPE_IS_SYN_CONST_FLAG = 0X08; FnType (HirId ref, DefId id, std::string identifier, RustIdent ident, uint8_t flags, ABI abi, std::vector<FnParam> params, BaseType *type, @@ -1111,6 +1112,11 @@ public: bool is_variadic () const { return (flags & FNTYPE_IS_VARADIC_FLAG) != 0; } + bool is_syn_constant () const + { + return (flags & FNTYPE_IS_SYN_CONST_FLAG) != 0; + } + DefId get_id () const { return id; } // get the Self type for the method diff --git a/gcc/testsuite/rust/execute/torture/const-generics-5.rs b/gcc/testsuite/rust/execute/torture/const-generics-5.rs new file mode 100644 index 000000000000..fd3c6a2ce151 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const-generics-5.rs @@ -0,0 +1,13 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo<const N: usize>; + +impl<const N: usize> Foo<N> { + const VALUE: usize = N; +} + +fn main() -> i32 { + let val = Foo::<7>::VALUE; + val as i32 - 7 +} diff --git a/gcc/testsuite/rust/execute/torture/const-generics-6.rs b/gcc/testsuite/rust/execute/torture/const-generics-6.rs new file mode 100644 index 000000000000..325b58e387d7 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const-generics-6.rs @@ -0,0 +1,15 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo<const N: usize>; + +impl<const N: usize> Foo<N> { + const VALUE: usize = N; + const SQUARE: usize = N * N; +} + +fn main() -> i32 { + let a = Foo::<5>::VALUE; // 5 + let b = Foo::<5>::SQUARE; // 25 + (a + b) as i32 - 30 +} diff --git a/gcc/testsuite/rust/execute/torture/const-generics-7.rs b/gcc/testsuite/rust/execute/torture/const-generics-7.rs new file mode 100644 index 000000000000..afba0329a706 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const-generics-7.rs @@ -0,0 +1,22 @@ +#![feature(intrinsics)] + +#[lang = "sized"] +pub trait Sized {} + +mod mem { + extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] + pub fn size_of<T>() -> usize; + } +} + +struct Foo<T>; + +impl<T> Foo<T> { + const MAGIC: usize = mem::size_of::<T>(); +} + +fn main() -> i32 { + let sz = Foo::<u16>::MAGIC; + sz as i32 - 2 +}
