]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Support generic constant impl items
authorPhilip Herron <herron.philip@googlemail.com>
Sun, 9 Nov 2025 20:28:50 +0000 (20:28 +0000)
committerArthur Cohen <arthur.cohen@embecosm.com>
Mon, 17 Nov 2025 14:58:19 +0000 (15:58 +0100)
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 <herron.philip@googlemail.com>
gcc/rust/backend/rust-compile-item.cc
gcc/rust/typecheck/rust-hir-type-check-expr.cc
gcc/rust/typecheck/rust-hir-type-check-implitem.cc
gcc/rust/typecheck/rust-tyty.h
gcc/testsuite/rust/execute/torture/const-generics-5.rs [new file with mode: 0644]
gcc/testsuite/rust/execute/torture/const-generics-6.rs [new file with mode: 0644]
gcc/testsuite/rust/execute/torture/const-generics-7.rs [new file with mode: 0644]

index b72e70d113ec73bb32b95cf7450ed8dd81380498..d9087104e46af87b26ea14d36a34d0547ec81a4f 100644 (file)
@@ -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
index 7885dfcf7463c721c84db42355db16d62e9e68b5..1c00fd96d949856312ba6431f9081ccbbb68ff2a 100644 (file)
@@ -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
index e7f66327d02ddbf6aaafab9ae00b4321e14932da..07fc010b087289a701218bc24bd3e459bb497041 100644 (file)
@@ -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
index 3236bf34a5925f48aac5bca1c35df35abf3e97a4..ed3cd76807cd1acdd5059c674023eb6760769db4 100644 (file)
@@ -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 (file)
index 0000000..fd3c6a2
--- /dev/null
@@ -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 (file)
index 0000000..325b58e
--- /dev/null
@@ -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 (file)
index 0000000..afba032
--- /dev/null
@@ -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
+}