From: Philip Herron <[email protected]>

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]>
---
 gcc/rust/backend/rust-compile-item.cc         | 11 ++++++++
 .../typecheck/rust-hir-type-check-expr.cc     | 20 +++++++++++--
 .../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(-)
 create mode 100644 gcc/testsuite/rust/execute/torture/const-generics-5.rs
 create mode 100644 gcc/testsuite/rust/execute/torture/const-generics-6.rs
 create mode 100644 gcc/testsuite/rust/execute/torture/const-generics-7.rs

diff --git a/gcc/rust/backend/rust-compile-item.cc 
b/gcc/rust/backend/rust-compile-item.cc
index b72e70d113e..d9087104e46 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 7885dfcf746..1c00fd96d94 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 e7f66327d02..07fc010b087 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 3236bf34a59..ed3cd76807c 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 00000000000..fd3c6a2ce15
--- /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 00000000000..325b58e387d
--- /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 00000000000..afba0329a70
--- /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
+}
-- 
2.50.1

Reply via email to