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