Skip to content

Commit e16958b

Browse files
committed
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 <herron.philip@googlemail.com>
1 parent 4425c97 commit e16958b

File tree

7 files changed

+110
-5
lines changed

7 files changed

+110
-5
lines changed

gcc/rust/backend/rust-compile-item.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,17 @@ CompileItem::visit (HIR::ConstantItem &constant)
109109
// canonical path
110110
Resolver::CanonicalPath canonical_path
111111
= nr_ctx.to_canonical_path (mappings.get_nodeid ());
112+
if (constant_type->is<const TyTy::FnType> ())
113+
{
114+
if (concrete == nullptr)
115+
return;
116+
117+
rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
118+
TyTy::FnType *concrete_fnty = static_cast<TyTy::FnType *> (concrete);
119+
120+
concrete_fnty->override_context ();
121+
constant_type = expr_type = concrete_fnty->get_return_type ();
122+
}
112123

113124
ctx->push_const_context ();
114125
tree const_expr

gcc/rust/typecheck/rust-hir-type-check-expr.cc

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,19 @@ TypeCheckExpr::Resolve (HIR::Expr &expr)
5353
if (resolver.infered == nullptr)
5454
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
5555

56-
auto ref = expr.get_mappings ().get_hirid ();
57-
resolver.infered->set_ref (ref);
56+
if (resolver.infered->get_kind () != TyTy::TypeKind::CONST)
57+
{
58+
auto ref = expr.get_mappings ().get_hirid ();
59+
resolver.infered->set_ref (ref);
60+
}
5861
resolver.context->insert_type (expr.get_mappings (), resolver.infered);
5962

63+
if (auto fn = resolver.infered->try_as<const TyTy::FnType> ())
64+
{
65+
if (fn->is_syn_constant ())
66+
resolver.infered = fn->get_return_type ();
67+
}
68+
6069
return resolver.infered;
6170
}
6271

@@ -2358,7 +2367,12 @@ bool
23582367
TypeCheckExpr::validate_arithmetic_type (
23592368
const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type)
23602369
{
2361-
const TyTy::BaseType *type = tyty->destructure ();
2370+
auto type = tyty->destructure ();
2371+
if (type->get_kind () == TyTy::TypeKind::CONST)
2372+
{
2373+
auto base_const = type->as_const_type ();
2374+
type = base_const->get_specified_type ();
2375+
}
23622376

23632377
// https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
23642378
// this will change later when traits are added

gcc/rust/typecheck/rust-hir-type-check-implitem.cc

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,32 @@ TypeCheckImplItem::visit (HIR::ConstantItem &constant)
391391
TyTy::TyWithLocation (type, constant.get_type ().get_locus ()),
392392
TyTy::TyWithLocation (expr_type, constant.get_expr ().get_locus ()),
393393
constant.get_locus ());
394-
context->insert_type (constant.get_mappings (), unified);
395-
result = unified;
394+
395+
if (substitutions.empty ())
396+
{
397+
context->insert_type (constant.get_mappings (), unified);
398+
result = unified;
399+
return;
400+
}
401+
402+
// special case when this is a generic constant
403+
auto &nr_ctx
404+
= Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
405+
CanonicalPath canonical_path
406+
= nr_ctx.to_canonical_path (constant.get_mappings ().get_nodeid ());
407+
RustIdent ident{canonical_path, constant.get_locus ()};
408+
auto fnType = new TyTy::FnType (
409+
constant.get_mappings ().get_hirid (),
410+
constant.get_mappings ().get_defid (),
411+
constant.get_identifier ().as_string (), ident,
412+
TyTy::FnType::FNTYPE_IS_SYN_CONST_FLAG, ABI::RUST, {}, unified,
413+
std::move (substitutions),
414+
TyTy::SubstitutionArgumentMappings::empty (
415+
context->get_lifetime_resolver ().get_num_bound_regions ()),
416+
{});
417+
418+
context->insert_type (constant.get_mappings (), fnType);
419+
result = fnType;
396420
}
397421

398422
void

gcc/rust/typecheck/rust-tyty.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,7 @@ class FnType : public CallableTypeInterface, public SubstitutionRef
10501050
static const uint8_t FNTYPE_IS_METHOD_FLAG = 0x01;
10511051
static const uint8_t FNTYPE_IS_EXTERN_FLAG = 0x02;
10521052
static const uint8_t FNTYPE_IS_VARADIC_FLAG = 0X04;
1053+
static const uint8_t FNTYPE_IS_SYN_CONST_FLAG = 0X08;
10531054

10541055
FnType (HirId ref, DefId id, std::string identifier, RustIdent ident,
10551056
uint8_t flags, ABI abi, std::vector<FnParam> params, BaseType *type,
@@ -1111,6 +1112,11 @@ class FnType : public CallableTypeInterface, public SubstitutionRef
11111112

11121113
bool is_variadic () const { return (flags & FNTYPE_IS_VARADIC_FLAG) != 0; }
11131114

1115+
bool is_syn_constant () const
1116+
{
1117+
return (flags & FNTYPE_IS_SYN_CONST_FLAG) != 0;
1118+
}
1119+
11141120
DefId get_id () const { return id; }
11151121

11161122
// get the Self type for the method
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#[lang = "sized"]
2+
trait Sized {}
3+
4+
struct Foo<const N: usize>;
5+
6+
impl<const N: usize> Foo<N> {
7+
const VALUE: usize = N;
8+
}
9+
10+
fn main() -> i32 {
11+
let val = Foo::<7>::VALUE;
12+
val as i32 - 7
13+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#[lang = "sized"]
2+
trait Sized {}
3+
4+
struct Foo<const N: usize>;
5+
6+
impl<const N: usize> Foo<N> {
7+
const VALUE: usize = N;
8+
const SQUARE: usize = N * N;
9+
}
10+
11+
fn main() -> i32 {
12+
let a = Foo::<5>::VALUE; // 5
13+
let b = Foo::<5>::SQUARE; // 25
14+
(a + b) as i32 - 30
15+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#![feature(intrinsics)]
2+
3+
#[lang = "sized"]
4+
pub trait Sized {}
5+
6+
mod mem {
7+
extern "rust-intrinsic" {
8+
#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
9+
pub fn size_of<T>() -> usize;
10+
}
11+
}
12+
13+
struct Foo<T>;
14+
15+
impl<T> Foo<T> {
16+
const MAGIC: usize = mem::size_of::<T>();
17+
}
18+
19+
fn main() -> i32 {
20+
let sz = Foo::<u16>::MAGIC;
21+
sz as i32 - 2
22+
}

0 commit comments

Comments
 (0)