https://gcc.gnu.org/g:91126cb80e3dd8bad846461088c948c2b797dccc

commit r16-2986-g91126cb80e3dd8bad846461088c948c2b797dccc
Author: Philip Herron <herron.phi...@googlemail.com>
Date:   Sun Jul 27 21:47:54 2025 +0100

    gccrs: Add initial support for const generics
    
    In order to support const generics we map the declarations to a ConstType 
this
    means we reuse all our existing type coercion, unification code and generic
    substitutions code to support this with minimal impact.
    
    This patch adds support for:
    
    1. Default const generics
    2. Infer const generics
    3. ADTType suport
    4. unconstrained checks
    5. ensure types of the const generic and default
    6. validation if passing a const argument to a type argument
    
    Lots of test cases now work and new ones added. More work is needed to 
support this
    on functions and method resolution of impls like Foo<1> vs Foo<2> once 
thats in we
    can look to support some of the const generic array impls next.
    
    gcc/rust/ChangeLog:
    
            * backend/rust-compile-base.cc: useful debug
            * backend/rust-compile-stmt.cc (CompileStmt::visit): likewise
            * backend/rust-compile-type.cc (TyTyResolveCompile::visit): fold 
the capacity into ConstType
            * hir/tree/rust-hir-generic-param.h: make const
            * hir/tree/rust-hir-path.h: take into account const arguments now
            * typecheck/rust-hir-type-check-base.cc 
(TypeCheckBase::resolve_literal): needs const
            * typecheck/rust-hir-type-check-base.h: add error handling for 
const supported locations
            * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): 
const type the arrays
            * typecheck/rust-hir-type-check-implitem.cc 
(TypeCheckTopLevelExternItem::visit): update
            (TypeCheckImplItem::visit): likewise
            * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): 
likewise
            (TypeCheckItem::resolve_impl_block_substitutions): likewise
            * typecheck/rust-hir-type-check-pattern.cc 
(TypeCheckPattern::visit): wrap up const type
            * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): 
likewise
            (TypeResolveGenericParam::visit): likewise
            (TypeResolveGenericParam::apply_trait_bounds): remove HIR::Generic 
from Param
            * typecheck/rust-hir-type-check.cc 
(TraitItemReference::get_type_from_fn): cleanup
            * typecheck/rust-tyty-subst.cc 
(SubstitutionParamMapping::SubstitutionParamMapping):
            handle const generics
            (SubstitutionParamMapping::get_type_representation): likewise
            (SubstitutionParamMapping::param_has_default_ty): likewise
            (SubstitutionParamMapping::get_default_ty): likewise
            (SubstitutionRef::infer_substitions): likewise
            * typecheck/rust-tyty-subst.h: likewise
            * typecheck/rust-tyty-util.cc 
(TyVar::get_implicit_const_infer_var): new helper
            * typecheck/rust-tyty-util.h (class ConstType): likewise
            * typecheck/rust-tyty.cc (BaseType::is_concrete): check for array 
const concrete
            (ArrayType::as_string): update to const
            (ArrayType::handle_substitions): likewise
            (ParamType::ParamType): likewise
            (ParamType::get_generic_param): likewise
            (ParamType::clone): likewise
            (ConstType::ConstType): likewise
            (ConstType::set_value): likewise
            (ConstType::clone): likewise
            (ConstType::get_generic_param): likewise
            (generate_tree_str): new helper to pretty print gimple
            (ConstType::get_name): uses the generate_tree_str
            (ConstType::handle_substitions): handle const infer's
            * typecheck/rust-tyty.h (RUST_TYTY): likewise
            * typecheck/rust-unify.cc (UnifyRules::expect_array): likewise
            (UnifyRules::expect_const): likewise
    
    gcc/testsuite/ChangeLog:
    
            * rust/compile/const_generics_3.rs: this works now
            * rust/compile/const_generics_5.rs: likewise
            * rust/compile/const_generics_8.rs: move the failure to another 
test case
            * rust/compile/const_generics_10.rs: New test.
            * rust/compile/const_generics_11.rs: New test.
            * rust/compile/const_generics_12.rs: New test.
            * rust/compile/const_generics_13.rs: New test.
            * rust/compile/const_generics_14.rs: New test.
            * rust/compile/const_generics_15.rs: New test.
            * rust/compile/const_generics_16.rs: New test.
            * rust/compile/const_generics_9.rs: New test.
    
    Signed-off-by: Philip Herron <herron.phi...@googlemail.com>

Diff:
---
 gcc/rust/backend/rust-compile-base.cc              |   3 +
 gcc/rust/backend/rust-compile-stmt.cc              |   3 +
 gcc/rust/backend/rust-compile-type.cc              |   3 +-
 gcc/rust/hir/tree/rust-hir-generic-param.h         |   4 +-
 gcc/rust/hir/tree/rust-hir-path.h                  |   4 +-
 gcc/rust/typecheck/rust-hir-type-check-base.cc     |  71 +++++++++--
 gcc/rust/typecheck/rust-hir-type-check-base.h      |   2 +
 gcc/rust/typecheck/rust-hir-type-check-expr.cc     |  22 ++--
 gcc/rust/typecheck/rust-hir-type-check-implitem.cc |  11 +-
 gcc/rust/typecheck/rust-hir-type-check-item.cc     |  23 ++--
 gcc/rust/typecheck/rust-hir-type-check-pattern.cc  |   3 +-
 gcc/rust/typecheck/rust-hir-type-check-type.cc     |  49 +++++---
 gcc/rust/typecheck/rust-hir-type-check.cc          |   4 +-
 gcc/rust/typecheck/rust-tyty-subst.cc              | 140 ++++++++++++++++++---
 gcc/rust/typecheck/rust-tyty-subst.h               |   4 +-
 gcc/rust/typecheck/rust-tyty-util.cc               |  34 +++--
 gcc/rust/typecheck/rust-tyty-util.h                |   4 +
 gcc/rust/typecheck/rust-tyty.cc                    | 119 ++++++++++++------
 gcc/rust/typecheck/rust-tyty.h                     |  24 ++--
 gcc/rust/typecheck/rust-unify.cc                   |  80 ++++++++++--
 gcc/testsuite/rust/compile/const_generics_10.rs    |  32 +++++
 gcc/testsuite/rust/compile/const_generics_11.rs    |  14 +++
 gcc/testsuite/rust/compile/const_generics_12.rs    |  14 +++
 gcc/testsuite/rust/compile/const_generics_13.rs    |  11 ++
 gcc/testsuite/rust/compile/const_generics_14.rs    |  13 ++
 gcc/testsuite/rust/compile/const_generics_15.rs    |  16 +++
 gcc/testsuite/rust/compile/const_generics_16.rs    |  10 ++
 gcc/testsuite/rust/compile/const_generics_3.rs     |  25 ++--
 gcc/testsuite/rust/compile/const_generics_5.rs     |   4 +-
 gcc/testsuite/rust/compile/const_generics_8.rs     |   7 +-
 gcc/testsuite/rust/compile/const_generics_9.rs     |  13 ++
 31 files changed, 609 insertions(+), 157 deletions(-)

diff --git a/gcc/rust/backend/rust-compile-base.cc 
b/gcc/rust/backend/rust-compile-base.cc
index 8994520f16d5..73c34b269b7e 100644
--- a/gcc/rust/backend/rust-compile-base.cc
+++ b/gcc/rust/backend/rust-compile-base.cc
@@ -696,6 +696,9 @@ HIRCompileBase::compile_function (
   std::string ir_symbol_name
     = canonical_path.get () + fntype->subst_as_string ();
 
+  rust_debug_loc (locus, "--> Compiling [%s] - %s", ir_symbol_name.c_str (),
+                 fntype->get_name ().c_str ());
+
   // we don't mangle the main fn since we haven't implemented the main shim
   bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item
                    && canonical_path.size () <= 2;
diff --git a/gcc/rust/backend/rust-compile-stmt.cc 
b/gcc/rust/backend/rust-compile-stmt.cc
index a4b5a989fc47..b520baf9ab8c 100644
--- a/gcc/rust/backend/rust-compile-stmt.cc
+++ b/gcc/rust/backend/rust-compile-stmt.cc
@@ -58,6 +58,9 @@ CompileStmt::visit (HIR::LetStmt &stmt)
       return;
     }
 
+  rust_debug_loc (stmt.get_locus (), "   -> LetStmt %s",
+                 ty->as_string ().c_str ());
+
   // setup var decl nodes
   fncontext fnctx = ctx->peek_fn ();
   tree fndecl = fnctx.fndecl;
diff --git a/gcc/rust/backend/rust-compile-type.cc 
b/gcc/rust/backend/rust-compile-type.cc
index 2058ccd3aea8..0622954b2a28 100644
--- a/gcc/rust/backend/rust-compile-type.cc
+++ b/gcc/rust/backend/rust-compile-type.cc
@@ -476,7 +476,8 @@ TyTyResolveCompile::visit (const TyTy::ArrayType &type)
 {
   tree element_type
     = TyTyResolveCompile::compile (ctx, type.get_element_type ());
-  tree folded_capacity_expr = type.get_capacity ();
+  TyTy::ConstType *const_capacity = type.get_capacity ();
+  tree folded_capacity_expr = const_capacity->get_value ();
 
   // build_index_type takes the maximum index, which is one less than
   // the length.
diff --git a/gcc/rust/hir/tree/rust-hir-generic-param.h 
b/gcc/rust/hir/tree/rust-hir-generic-param.h
index 960de565c142..340b5c61ead3 100644
--- a/gcc/rust/hir/tree/rust-hir-generic-param.h
+++ b/gcc/rust/hir/tree/rust-hir-generic-param.h
@@ -150,7 +150,7 @@ public:
 
   location_t get_locus () const override final { return locus; };
 
-  bool has_default_expression () { return default_expression != nullptr; }
+  bool has_default_expression () const { return default_expression != nullptr; 
}
 
   std::string get_name () { return name; }
   Type &get_type ()
@@ -160,6 +160,8 @@ public:
   }
   Expr &get_default_expression () { return *default_expression; }
 
+  const Expr &get_default_expression () const { return *default_expression; }
+
 protected:
   /* Use covariance to implement clone function as returning this object rather
    * than base */
diff --git a/gcc/rust/hir/tree/rust-hir-path.h 
b/gcc/rust/hir/tree/rust-hir-path.h
index 5f88c6827bb1..4f296d868b49 100644
--- a/gcc/rust/hir/tree/rust-hir-path.h
+++ b/gcc/rust/hir/tree/rust-hir-path.h
@@ -132,6 +132,8 @@ public:
 
   std::unique_ptr<Expr> &get_expression () { return expression; }
 
+  location_t get_locus () const { return locus; }
+
 private:
   std::unique_ptr<Expr> expression;
   location_t locus;
@@ -150,7 +152,7 @@ public:
   bool has_generic_args () const
   {
     return !(lifetime_args.empty () && type_args.empty ()
-            && binding_args.empty ());
+            && binding_args.empty () && const_args.empty ());
   }
 
   GenericArgs (std::vector<Lifetime> lifetime_args,
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc 
b/gcc/rust/typecheck/rust-hir-type-check-base.cc
index cbb85bd4f4f3..5c7690a6e76d 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc
@@ -18,12 +18,14 @@
 
 #include "rust-hir-type-check-base.h"
 #include "rust-compile-base.h"
+#include "rust-hir-item.h"
 #include "rust-hir-type-check-expr.h"
 #include "rust-hir-type-check-type.h"
 #include "rust-hir-trait-resolve.h"
 #include "rust-type-util.h"
 #include "rust-attribute-values.h"
 #include "rust-tyty.h"
+#include "tree.h"
 
 namespace Rust {
 namespace Resolver {
@@ -34,12 +36,14 @@ TypeCheckBase::TypeCheckBase ()
 
 void
 TypeCheckBase::ResolveGenericParams (
+  const HIR::Item::ItemKind item_kind, location_t item_locus,
   const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
   std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign,
   ABI abi)
 {
   TypeCheckBase ctx;
-  ctx.resolve_generic_params (generic_params, substitutions, is_foreign, abi);
+  ctx.resolve_generic_params (item_kind, item_locus, generic_params,
+                             substitutions, is_foreign, abi);
 }
 
 static void
@@ -291,9 +295,18 @@ TypeCheckBase::resolve_literal (const 
Analysis::NodeMapping &expr_mappings,
        auto ctx = Compile::Context::get ();
        tree capacity = Compile::HIRCompileBase::query_compile_const_expr (
          ctx, expected_ty, *literal_capacity);
+
+       TyTy::ConstType *capacity_expr
+         = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "",
+                                expected_ty, capacity, {},
+                                literal_capacity->get_locus (),
+                                literal_capacity->get_mappings ().get_hirid (),
+                                literal_capacity->get_mappings ().get_hirid (),
+                                {});
+
        TyTy::ArrayType *array
-         = new TyTy::ArrayType (array_mapping.get_hirid (), locus, capacity,
-                                TyTy::TyVar (u8->get_ref ()));
+         = new TyTy::ArrayType (array_mapping.get_hirid (), locus,
+                                capacity_expr, TyTy::TyVar (u8->get_ref ()));
        context->insert_type (array_mapping, array);
 
        infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
@@ -442,6 +455,7 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec 
&attrs, location_t locus)
 
 void
 TypeCheckBase::resolve_generic_params (
+  const HIR::Item::ItemKind item_kind, location_t item_locus,
   const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
   std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign,
   ABI abi)
@@ -474,6 +488,27 @@ TypeCheckBase::resolve_generic_params (
 
            if (param.has_default_expression ())
              {
+               switch (item_kind)
+                 {
+                 case HIR::Item::ItemKind::Struct:
+                 case HIR::Item::ItemKind::Enum:
+                 case HIR::Item::ItemKind::TypeAlias:
+                 case HIR::Item::ItemKind::Trait:
+                 case HIR::Item::ItemKind::Union:
+                   break;
+
+                 default:
+                   {
+                     rich_location r (line_table, item_locus);
+                     r.add_fixit_remove (param.get_locus ());
+                     rust_error_at (
+                       r,
+                       "default values for const generic parameters are not "
+                       "allowed here");
+                   }
+                   break;
+                 }
+
                auto expr_type
                  = TypeCheckExpr::Resolve (param.get_default_expression ());
 
@@ -483,14 +518,34 @@ TypeCheckBase::resolve_generic_params (
                                 expr_type,
                                 param.get_default_expression ().get_locus ()),
                               param.get_locus ());
+
+               // fold the default value
+               auto ctx = Compile::Context::get ();
+               auto &expr = param.get_default_expression ();
+               tree default_value
+                 = Compile::HIRCompileBase::query_compile_const_expr (
+                   ctx, specified_type, expr);
+
+               TyTy::ConstType *default_const_decl
+                 = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value,
+                                        param.get_name (), specified_type,
+                                        default_value, {}, param.get_locus (),
+                                        expr.get_mappings ().get_hirid (),
+                                        expr.get_mappings ().get_hirid (), {});
+
+               context->insert_type (expr.get_mappings (), default_const_decl);
              }
 
-           context->insert_type (generic_param->get_mappings (),
-                                 specified_type);
+           TyTy::ConstType *const_decl
+             = new TyTy::ConstType (TyTy::ConstType::ConstKind::Decl,
+                                    param.get_name (), specified_type,
+                                    error_mark_node, {}, param.get_locus (),
+                                    param.get_mappings ().get_hirid (),
+                                    param.get_mappings ().get_hirid (), {});
 
-           // TODO for const generics
-           // TyTy::SubstitutionParamMapping p (*generic_param, param_type);
-           // substitutions.push_back (p);
+           context->insert_type (generic_param->get_mappings (), const_decl);
+           TyTy::SubstitutionParamMapping p (*generic_param, const_decl);
+           substitutions.push_back (p);
          }
          break;
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h 
b/gcc/rust/typecheck/rust-hir-type-check-base.h
index fc55516fab10..5934e57727f7 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.h
@@ -33,6 +33,7 @@ public:
   virtual ~TypeCheckBase () {}
 
   static void ResolveGenericParams (
+    const HIR::Item::ItemKind item_kind, location_t item_locus,
     const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
     std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool 
is_foreign,
     ABI abi);
@@ -61,6 +62,7 @@ protected:
                                                 location_t locus);
 
   void resolve_generic_params (
+    const HIR::Item::ItemKind item_kind, location_t item_locus,
     const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
     std::vector<TyTy::SubstitutionParamMapping> &substitutions,
     bool is_foreign = false, ABI abi = ABI::RUST);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc 
b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index 4a105e77d919..92912e835ad0 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -33,6 +33,7 @@
 #include "rust-type-util.h"
 #include "rust-immutable-name-resolution-context.h"
 #include "rust-compile-base.h"
+#include "tree.h"
 
 namespace Rust {
 namespace Resolver {
@@ -1058,6 +1059,10 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr)
 {
   auto &elements = expr.get_internal_elements ();
 
+  TyTy::BaseType *expected_ty = nullptr;
+  bool ok = context->lookup_builtin ("usize", &expected_ty);
+  rust_assert (ok);
+
   HIR::Expr *capacity_expr = nullptr;
   TyTy::BaseType *element_type = nullptr;
   TyTy::BaseType *capacity_type = nullptr;
@@ -1072,9 +1077,6 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr)
        auto capacity_expr_ty
          = TypeCheckExpr::Resolve (elems.get_num_copies_expr ());
 
-       TyTy::BaseType *expected_ty = nullptr;
-       bool ok = context->lookup_builtin ("usize", &expected_ty);
-       rust_assert (ok);
        context->insert_type (elems.get_num_copies_expr ().get_mappings (),
                              expected_ty);
 
@@ -1123,9 +1125,6 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr)
                                              UNDEF_LOCATION, {});
 
        // mark the type for this implicit node
-       TyTy::BaseType *expected_ty = nullptr;
-       bool ok = context->lookup_builtin ("usize", &expected_ty);
-       rust_assert (ok);
        context->insert_type (mapping, expected_ty);
        capacity_type = expected_ty;
       }
@@ -1135,12 +1134,17 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr)
   rust_assert (capacity_expr);
   rust_assert (capacity_type);
   auto ctx = Compile::Context::get ();
-  tree capacity
+  tree capacity_value
     = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type,
                                                         *capacity_expr);
+  HirId size_id = capacity_expr->get_mappings ().get_hirid ();
+  TyTy::ConstType *const_type
+    = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "", expected_ty,
+                          capacity_value, {}, capacity_expr->get_locus (),
+                          size_id, size_id);
   infered
     = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), expr.get_locus 
(),
-                          capacity, TyTy::TyVar (element_type->get_ref ()));
+                          const_type, TyTy::TyVar (element_type->get_ref ()));
 }
 
 // empty struct
@@ -1798,7 +1802,7 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr)
   TyTy::TyVar result_type
     = expr.has_return_type ()
        ? TyTy::TyVar (
-         TypeCheckType::Resolve (expr.get_return_type ())->get_ref ())
+           TypeCheckType::Resolve (expr.get_return_type ())->get_ref ())
        : TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
 
   // resolve the block
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc 
b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
index 76ff6903077d..c8544a1a9c27 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
@@ -70,7 +70,9 @@ TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem 
&function)
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
   if (function.has_generics ())
     {
-      resolve_generic_params (function.get_generic_params (), substitutions,
+      resolve_generic_params (HIR::Item::ItemKind::Function,
+                             function.get_locus (),
+                             function.get_generic_params (), substitutions,
                              true /*is_foreign*/, parent.get_abi ());
     }
 
@@ -200,7 +202,9 @@ TypeCheckImplItem::visit (HIR::Function &function)
   auto binder_pin = context->push_lifetime_binder ();
 
   if (function.has_generics ())
-    resolve_generic_params (function.get_generic_params (), substitutions);
+    resolve_generic_params (HIR::Item::ItemKind::Function,
+                           function.get_locus (),
+                           function.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
   for (auto &where_clause_item : function.get_where_clause ().get_items ())
@@ -397,7 +401,8 @@ TypeCheckImplItem::visit (HIR::TypeAlias &alias)
   auto binder_pin = context->push_lifetime_binder ();
 
   if (alias.has_generics ())
-    resolve_generic_params (alias.get_generic_params (), substitutions);
+    resolve_generic_params (HIR::Item::ItemKind::TypeAlias, alias.get_locus (),
+                           alias.get_generic_params (), substitutions);
 
   TyTy::BaseType *actual_type
     = TypeCheckType::Resolve (alias.get_type_aliased ());
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc 
b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index f104a1a56e81..3ba607bc5ab4 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -20,6 +20,7 @@
 #include "optional.h"
 #include "rust-canonical-path.h"
 #include "rust-diagnostics.h"
+#include "rust-hir-item.h"
 #include "rust-hir-type-check-enumitem.h"
 #include "rust-hir-type-check-implitem.h"
 #include "rust-hir-type-check-type.h"
@@ -167,7 +168,9 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl)
 
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
   if (struct_decl.has_generics ())
-    resolve_generic_params (struct_decl.get_generic_params (), substitutions);
+    resolve_generic_params (HIR::Item::ItemKind::Struct,
+                           struct_decl.get_locus (),
+                           struct_decl.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
   for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
@@ -238,7 +241,9 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl)
 
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
   if (struct_decl.has_generics ())
-    resolve_generic_params (struct_decl.get_generic_params (), substitutions);
+    resolve_generic_params (HIR::Item::ItemKind::Struct,
+                           struct_decl.get_locus (),
+                           struct_decl.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
   for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
@@ -304,7 +309,8 @@ TypeCheckItem::visit (HIR::Enum &enum_decl)
   auto lifetime_pin = context->push_clean_lifetime_resolver ();
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
   if (enum_decl.has_generics ())
-    resolve_generic_params (enum_decl.get_generic_params (), substitutions);
+    resolve_generic_params (HIR::Item::ItemKind::Enum, enum_decl.get_locus (),
+                           enum_decl.get_generic_params (), substitutions);
 
   // Process #[repr(X)] attribute, if any
   const AST::AttrVec &attrs = enum_decl.get_outer_attrs ();
@@ -364,7 +370,8 @@ TypeCheckItem::visit (HIR::Union &union_decl)
   auto lifetime_pin = context->push_clean_lifetime_resolver ();
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
   if (union_decl.has_generics ())
-    resolve_generic_params (union_decl.get_generic_params (), substitutions);
+    resolve_generic_params (HIR::Item::ItemKind::Union, union_decl.get_locus 
(),
+                           union_decl.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
   for (auto &where_clause_item : union_decl.get_where_clause ().get_items ())
@@ -512,8 +519,9 @@ TypeCheckItem::visit (HIR::Function &function)
   auto lifetime_pin = context->push_clean_lifetime_resolver ();
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
   if (function.has_generics ())
-    resolve_generic_params (function.get_generic_params (),
-                           substitutions); // TODO resolve constraints
+    resolve_generic_params (HIR::Item::ItemKind::Function,
+                           function.get_locus (),
+                           function.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
   for (auto &where_clause_item : function.get_where_clause ().get_items ())
@@ -700,7 +708,8 @@ TypeCheckItem::resolve_impl_block_substitutions 
(HIR::ImplBlock &impl_block,
 {
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
   if (impl_block.has_generics ())
-    resolve_generic_params (impl_block.get_generic_params (), substitutions);
+    resolve_generic_params (HIR::Item::ItemKind::Impl, impl_block.get_locus (),
+                           impl_block.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
   for (auto &where_clause_item : impl_block.get_where_clause ().get_items ())
diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc 
b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
index 2190faec7518..be926fcfddd3 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
@@ -641,7 +641,8 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern)
       {
        auto &array_ty_ty = static_cast<TyTy::ArrayType &> (*parent);
        parent_element_ty = array_ty_ty.get_element_type ();
-       tree cap = array_ty_ty.get_capacity ();
+       auto capacity = array_ty_ty.get_capacity ();
+       tree cap = capacity->get_value ();
        if (error_operand_p (cap))
          {
            rust_error_at (parent->get_locus (),
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc 
b/gcc/rust/typecheck/rust-hir-type-check-type.cc
index 21237f58868d..78037bdbd183 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -689,6 +689,7 @@ TypeCheckType::visit (HIR::ParenthesisedType &type)
 void
 TypeCheckType::visit (HIR::ArrayType &type)
 {
+  auto element_type = TypeCheckType::Resolve (type.get_element_type ());
   auto capacity_type = TypeCheckExpr::Resolve (type.get_size_expr ());
   if (capacity_type->get_kind () == TyTy::TypeKind::ERROR)
     return;
@@ -698,21 +699,38 @@ TypeCheckType::visit (HIR::ArrayType &type)
   rust_assert (ok);
   context->insert_type (type.get_size_expr ().get_mappings (), expected_ty);
 
-  unify_site (type.get_size_expr ().get_mappings ().get_hirid (),
-             TyTy::TyWithLocation (expected_ty),
-             TyTy::TyWithLocation (capacity_type,
-                                   type.get_size_expr ().get_locus ()),
-             type.get_size_expr ().get_locus ());
+  TyTy::ConstType *const_type = nullptr;
+  if (capacity_type->get_kind () == TyTy::TypeKind::CONST)
+    {
+      const_type = static_cast<TyTy::ConstType *> (capacity_type);
 
-  TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ());
+      unify_site (type.get_size_expr ().get_mappings ().get_hirid (),
+                 TyTy::TyWithLocation (expected_ty),
+                 TyTy::TyWithLocation (const_type->get_ty (),
+                                       type.get_size_expr ().get_locus ()),
+                 type.get_size_expr ().get_locus ());
+    }
+  else
+    {
+      HirId size_id = type.get_size_expr ().get_mappings ().get_hirid ();
+      unify_site (size_id, TyTy::TyWithLocation (expected_ty),
+                 TyTy::TyWithLocation (capacity_type,
+                                       type.get_size_expr ().get_locus ()),
+                 type.get_size_expr ().get_locus ());
+
+      auto ctx = Compile::Context::get ();
+      tree capacity_expr = Compile::HIRCompileBase::query_compile_const_expr (
+       ctx, capacity_type, type.get_size_expr ());
+
+      const_type = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "",
+                                       expected_ty, capacity_expr, {},
+                                       type.get_size_expr ().get_locus (),
+                                       size_id, size_id);
+    }
 
-  auto ctx = Compile::Context::get ();
-  tree capacity
-    = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type,
-                                                        type.get_size_expr ());
   translated
     = new TyTy::ArrayType (type.get_mappings ().get_hirid (), type.get_locus 
(),
-                          capacity, TyTy::TyVar (base->get_ref ()));
+                          const_type, TyTy::TyVar (element_type->get_ref ()));
 }
 
 void
@@ -849,10 +867,9 @@ TypeResolveGenericParam::visit (HIR::TypeParam &param)
   if (param.has_type ())
     TypeCheckType::Resolve (param.get_type ());
 
-  resolved
-    = new TyTy::ParamType (param.get_type_representation ().as_string (),
-                          param.get_locus (),
-                          param.get_mappings ().get_hirid (), param, {});
+  resolved = new TyTy::ParamType (param.get_type_representation ().as_string 
(),
+                                 param.get_locus (),
+                                 param.get_mappings ().get_hirid (), {});
 
   if (resolve_trait_bounds)
     apply_trait_bounds (param, resolved);
@@ -871,7 +888,7 @@ TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam 
&param,
       HirId implicit_id = mappings.get_next_hir_id ();
       TyTy::ParamType *p
        = new TyTy::ParamType (param.get_type_representation ().as_string (),
-                              param.get_locus (), implicit_id, param,
+                              param.get_locus (), implicit_id,
                               {} /*empty specified bounds*/);
       context->insert_implicit_type (implicit_id, p);
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc 
b/gcc/rust/typecheck/rust-hir-type-check.cc
index 6097c4e5be87..aba4ab55c6c4 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -161,7 +161,9 @@ TraitItemReference::get_type_from_fn (/*const*/ 
HIR::TraitItemFunc &fn) const
   HIR::TraitFunctionDecl &function = fn.get_decl ();
   if (function.has_generics ())
     {
-      TypeCheckBase::ResolveGenericParams (function.get_generic_params (),
+      TypeCheckBase::ResolveGenericParams (HIR::Item::ItemKind::Function,
+                                          fn.get_locus (),
+                                          function.get_generic_params (),
                                           substitutions, false /*is_foreign*/,
                                           ABI::RUST);
     }
diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc 
b/gcc/rust/typecheck/rust-tyty-subst.cc
index 01899d83435f..a47cde3b9664 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.cc
+++ b/gcc/rust/typecheck/rust-tyty-subst.cc
@@ -18,18 +18,22 @@
 
 #include "rust-tyty-subst.h"
 
+#include "rust-hir-generic-param.h"
 #include "rust-system.h"
 #include "rust-tyty.h"
 #include "rust-hir-type-check.h"
 #include "rust-substitution-mapper.h"
 #include "rust-hir-type-check-type.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-compile-base.h"
 #include "rust-type-util.h"
+#include "tree.h"
 
 namespace Rust {
 namespace TyTy {
 
 SubstitutionParamMapping::SubstitutionParamMapping (HIR::GenericParam &generic,
-                                                   ParamType *param)
+                                                   BaseGeneric *param)
   : generic (generic), param (param)
 {}
 
@@ -87,9 +91,7 @@ SubstitutionParamMapping::needs_substitution () const
 Identifier
 SubstitutionParamMapping::get_type_representation () const
 {
-  rust_assert (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE);
-  const auto &type_param = static_cast<const HIR::TypeParam &> (generic);
-  return type_param.get_type_representation ();
+  return param->get_symbol ();
 }
 
 location_t
@@ -101,20 +103,35 @@ SubstitutionParamMapping::get_param_locus () const
 bool
 SubstitutionParamMapping::param_has_default_ty () const
 {
-  if (generic.get_kind () != HIR::GenericParam::GenericKind::TYPE)
-    return false;
+  if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE)
+    {
+      const auto &type_param = static_cast<const HIR::TypeParam &> (generic);
+      return type_param.has_type ();
+    }
 
-  const auto &type_param = static_cast<const HIR::TypeParam &> (generic);
-  return type_param.has_type ();
+  rust_assert (generic.get_kind () == HIR::GenericParam::GenericKind::CONST);
+  const auto &const_param
+    = static_cast<const HIR::ConstGenericParam &> (generic);
+  return const_param.has_default_expression ();
 }
 
 BaseType *
 SubstitutionParamMapping::get_default_ty () const
 {
-  rust_assert (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE);
+  if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE)
+    {
+      const auto &type_param = static_cast<const HIR::TypeParam &> (generic);
+      TyVar var (type_param.get_type_mappings ().get_hirid ());
+      return var.get_tyty ();
+    }
 
-  const auto &type_param = static_cast<const HIR::TypeParam &> (generic);
-  TyVar var (type_param.get_type_mappings ().get_hirid ());
+  rust_assert (generic.get_kind () == HIR::GenericParam::GenericKind::CONST);
+  const auto &const_param
+    = static_cast<const HIR::ConstGenericParam &> (generic);
+  rust_assert (const_param.has_default_expression ());
+
+  const auto &expr = const_param.get_default_expression ();
+  TyVar var (expr.get_mappings ().get_hirid ());
   return var.get_tyty ();
 }
 
@@ -149,13 +166,15 @@ SubstitutionParamMapping::fill_param_ty (
       // delete param;
       param = static_cast<ParamType *> (type.clone ());
     }
-  else
+  else if (param->get_kind () == TypeKind::PARAM)
     {
+      auto &p = *static_cast<TyTy::ParamType *> (param);
+
       // check the substitution is compatible with bounds
       rust_debug_loc (locus,
                      "fill_param_ty bounds_compatible: param %s type %s",
                      param->get_name ().c_str (), type.get_name ().c_str ());
-      if (needs_bounds_check && !param->is_implicit_self_trait ())
+      if (needs_bounds_check && !p.is_implicit_self_trait ())
        {
          if (!param->bounds_compatible (type, locus, true))
            return false;
@@ -166,7 +185,7 @@ SubstitutionParamMapping::fill_param_ty (
        bound.handle_substitions (subst_mappings);
 
       param->set_ty_ref (type.get_ref ());
-      subst_mappings.on_param_subst (*param, arg);
+      subst_mappings.on_param_subst (p, arg);
     }
 
   return true;
@@ -704,7 +723,9 @@ SubstitutionRef::get_mappings_from_generic_args (
       return SubstitutionArgumentMappings::error ();
     }
 
-  if (args.get_type_args ().size () + offs < min_required_substitutions ())
+  size_t total_arguments
+    = args.get_type_args ().size () + args.get_const_args ().size () + offs;
+  if (total_arguments < min_required_substitutions ())
     {
       rich_location r (line_table, args.get_locus ());
       if (!substitutions.empty ())
@@ -747,12 +768,79 @@ SubstitutionRef::get_mappings_from_generic_args (
              return SubstitutionArgumentMappings::error ();
            }
        }
+      else if (generic.get_kind () == HIR::GenericParam::GenericKind::CONST)
+       {
+         if (!resolved->is<ConstType> ())
+           {
+             rich_location r (line_table, arg->get_locus ());
+             r.add_fixit_remove (arg->get_locus ());
+             rust_error_at (r, ErrorCode::E0747,
+                            "type provided when a constant was expected");
+             return SubstitutionArgumentMappings::error ();
+           }
+       }
 
       SubstitutionArg subst_arg (&param_mapping, resolved);
       offs++;
       mappings.push_back (std::move (subst_arg));
     }
 
+  for (auto &arg : args.get_const_args ())
+    {
+      auto &expr = *arg.get_expression ().get ();
+      BaseType *expr_type = Resolver::TypeCheckExpr::Resolve (expr);
+      if (expr_type == nullptr || expr_type->is<ErrorType> ())
+       return SubstitutionArgumentMappings::error ();
+
+      // validate this param is really a const generic
+      const auto &param_mapping = substitutions.at (offs);
+      const auto &generic = param_mapping.get_generic_param ();
+      if (generic.get_kind () != HIR::GenericParam::GenericKind::CONST)
+       {
+         rich_location r (line_table, arg.get_locus ());
+         r.add_fixit_remove (expr.get_locus ());
+         rust_error_at (r, "invalid position for a const generic argument");
+         return SubstitutionArgumentMappings::error ();
+       }
+
+      // get the const generic specified type
+      const auto base_generic = param_mapping.get_param_ty ();
+      rust_assert (base_generic->is<ConstType> ());
+      const auto const_param
+       = static_cast<const TyTy::ConstType *> (base_generic);
+      auto specified_type = const_param->get_ty ();
+
+      // validate this const generic is of the correct type
+      auto coereced_type
+       = Resolver::coercion_site (expr.get_mappings ().get_hirid (),
+                                  TyTy::TyWithLocation (specified_type),
+                                  TyTy::TyWithLocation (expr_type,
+                                                        expr.get_locus ()),
+                                  arg.get_locus ());
+      if (coereced_type->is<ErrorType> ())
+       return SubstitutionArgumentMappings::error ();
+
+      // const fold it
+      auto ctx = Compile::Context::get ();
+      tree folded
+       = Compile::HIRCompileBase::query_compile_const_expr (ctx, coereced_type,
+                                                            expr);
+
+      if (folded == error_mark_node)
+       return SubstitutionArgumentMappings::error ();
+
+      // create const type
+      auto const_value
+       = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "",
+                              coereced_type, folded, {}, expr.get_locus (),
+                              expr.get_mappings ().get_hirid (),
+                              expr.get_mappings ().get_hirid (), {});
+
+      SubstitutionArg subst_arg (&param_mapping, const_value);
+      offs++;
+      mappings.push_back (std::move (subst_arg));
+    }
+
   // we must need to fill out defaults
   size_t left_over
     = num_required_substitutions () - min_required_substitutions ();
@@ -798,22 +886,42 @@ SubstitutionRef::infer_substitions (location_t locus)
   std::map<std::string, BaseType *> argument_mappings;
   for (auto &p : get_substs ())
     {
+      rust_debug_loc (locus, "XXXXXXXXXXXXXXXXXXXXXX 1: [%s]",
+                     p.need_substitution () ? "true" : "false");
+      p.get_param_ty ()->debug ();
+
       if (p.needs_substitution ())
        {
+         const HIR::GenericParam &generic = p.get_generic_param ();
          const std::string &symbol = p.get_param_ty ()->get_symbol ();
          auto it = argument_mappings.find (symbol);
          bool have_mapping = it != argument_mappings.end ();
 
+         rust_debug_loc (locus, "XXXXXXXXXXXXXXX 2: [%s] [%s]",
+                         have_mapping ? "true" : "false", symbol.c_str ());
+
          if (have_mapping)
            {
              args.push_back (SubstitutionArg (&p, it->second));
            }
-         else
+         else if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE)
            {
              TyVar infer_var = TyVar::get_implicit_infer_var (locus);
              args.push_back (SubstitutionArg (&p, infer_var.get_tyty ()));
              argument_mappings[symbol] = infer_var.get_tyty ();
            }
+         else if (generic.get_kind () == HIR::GenericParam::GenericKind::CONST)
+           {
+             const auto const_param = p.get_param_ty ();
+             rust_assert (const_param->is<TyTy::ConstType> ());
+             const auto &const_type
+               = *static_cast<const TyTy::ConstType *> (const_param);
+
+             TyVar infer_var
+               = TyVar::get_implicit_const_infer_var (const_type, locus);
+             args.push_back (SubstitutionArg (&p, infer_var.get_tyty ()));
+             argument_mappings[symbol] = infer_var.get_tyty ();
+           }
        }
       else
        {
diff --git a/gcc/rust/typecheck/rust-tyty-subst.h 
b/gcc/rust/typecheck/rust-tyty-subst.h
index 0ac3ea73807d..69ef09896972 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.h
+++ b/gcc/rust/typecheck/rust-tyty-subst.h
@@ -46,7 +46,7 @@ class SubstitutionArgumentMappings;
 class SubstitutionParamMapping
 {
 public:
-  SubstitutionParamMapping (HIR::GenericParam &generic, ParamType *param);
+  SubstitutionParamMapping (HIR::GenericParam &generic, BaseGeneric *param);
 
   SubstitutionParamMapping (const SubstitutionParamMapping &other);
 
@@ -81,7 +81,7 @@ public:
 
 private:
   HIR::GenericParam &generic;
-  ParamType *param;
+  BaseGeneric *param;
 };
 
 /**
diff --git a/gcc/rust/typecheck/rust-tyty-util.cc 
b/gcc/rust/typecheck/rust-tyty-util.cc
index ff210ce69e67..4bc17231bf12 100644
--- a/gcc/rust/typecheck/rust-tyty-util.cc
+++ b/gcc/rust/typecheck/rust-tyty-util.cc
@@ -17,6 +17,8 @@
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-hir-type-check.h"
+#include "rust-mapping-common.h"
+#include "rust-system.h"
 #include "rust-tyty.h"
 
 namespace Rust {
@@ -47,14 +49,30 @@ TyVar::get_implicit_infer_var (location_t locus)
   auto &mappings = Analysis::Mappings::get ();
   auto context = Resolver::TypeCheckContext::get ();
 
-  InferType *infer = new InferType (mappings.get_next_hir_id (),
-                                   InferType::InferTypeKind::GENERAL,
-                                   InferType::TypeHint::Default (), locus);
-  context->insert_type (Analysis::NodeMapping (mappings.get_current_crate (),
-                                              UNKNOWN_NODEID,
-                                              infer->get_ref (),
-                                              UNKNOWN_LOCAL_DEFID),
-                       infer);
+  HirId next = mappings.get_next_hir_id ();
+  auto infer = new InferType (next, InferType::InferTypeKind::GENERAL,
+                             InferType::TypeHint::Default (), locus);
+
+  context->insert_implicit_type (infer->get_ref (), infer);
+  mappings.insert_location (infer->get_ref (), locus);
+
+  return TyVar (infer->get_ref ());
+}
+
+TyVar
+TyVar::get_implicit_const_infer_var (const ConstType &const_type,
+                                    location_t locus)
+{
+  auto &mappings = Analysis::Mappings::get ();
+  auto context = Resolver::TypeCheckContext::get ();
+
+  HirId next = mappings.get_next_hir_id ();
+  auto infer
+    = new ConstType (ConstType::ConstKind::Infer, const_type.get_symbol (),
+                    const_type.get_ty (), error_mark_node,
+                    const_type.get_specified_bounds (), locus, next, next, {});
+
+  context->insert_implicit_type (infer->get_ref (), infer);
   mappings.insert_location (infer->get_ref (), locus);
 
   return TyVar (infer->get_ref ());
diff --git a/gcc/rust/typecheck/rust-tyty-util.h 
b/gcc/rust/typecheck/rust-tyty-util.h
index cbb3e8e65a10..1c8fd7237911 100644
--- a/gcc/rust/typecheck/rust-tyty-util.h
+++ b/gcc/rust/typecheck/rust-tyty-util.h
@@ -25,6 +25,7 @@ namespace Rust {
 namespace TyTy {
 
 class BaseType;
+class ConstType;
 
 // this is a placeholder for types that can change like inference variables
 class TyVar
@@ -42,6 +43,9 @@ public:
 
   static TyVar get_implicit_infer_var (location_t locus);
 
+  static TyVar get_implicit_const_infer_var (const TyTy::ConstType &const_type,
+                                            location_t locus);
+
   static TyVar subst_covariant_var (TyTy::BaseType *orig,
                                    TyTy::BaseType *subst);
 
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 260926931f00..a87efb4e3815 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -19,6 +19,7 @@
 #include "rust-tyty.h"
 
 #include "optional.h"
+#include "rust-tyty-subst.h"
 #include "rust-tyty-visitor.h"
 #include "rust-hir-map.h"
 #include "rust-location.h"
@@ -31,10 +32,12 @@
 #include "rust-type-util.h"
 #include "rust-hir-type-bounds.h"
 #include "print-tree.h"
+#include "tree-pretty-print.h"
 
 #include "options.h"
 #include "rust-system.h"
 #include "tree.h"
+#include <string>
 
 namespace Rust {
 namespace TyTy {
@@ -829,7 +832,8 @@ BaseType::is_concrete () const
     }
   else if (auto arr = x->try_as<const ArrayType> ())
     {
-      return arr->get_element_type ()->is_concrete ();
+      return arr->get_element_type ()->is_concrete ()
+            && arr->get_capacity ()->is_concrete ();
     }
   else if (auto slice = x->try_as<const SliceType> ())
     {
@@ -858,6 +862,10 @@ BaseType::is_concrete () const
        return false;
       return closure->get_result_type ().is_concrete ();
     }
+  else if (auto const_type = x->try_as<const ConstType> ())
+    {
+      return const_type->get_value () != error_mark_node;
+    }
   else if (x->is<InferType> () || x->is<BoolType> () || x->is<CharType> ()
           || x->is<IntType> () || x->is<UintType> () || x->is<FloatType> ()
           || x->is<USizeType> () || x->is<ISizeType> () || x->is<NeverType> ()
@@ -2491,16 +2499,8 @@ ArrayType::accept_vis (TyConstVisitor &vis) const
 std::string
 ArrayType::as_string () const
 {
-  std::string capacity_str = "<error>";
-  if (!error_operand_p (capacity))
-    {
-      unsigned HOST_WIDE_INT length = wi::to_wide (capacity).to_uhwi ();
-
-      char buf[64];
-      snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_UNSIGNED, length);
-      capacity_str = std::string (buf);
-    }
-  return "[" + get_element_type ()->as_string () + "; " + capacity_str + "]";
+  return "[" + get_element_type ()->as_string () + "; " + capacity->as_string 
()
+        + "]";
 }
 
 bool
@@ -2556,6 +2556,13 @@ ArrayType::handle_substitions 
(SubstitutionArgumentMappings &mappings)
   BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings);
   ref->element_type = TyVar::subst_covariant_var (base, concrete);
 
+  // handle capacity type
+  auto cap = ref->get_capacity ();
+  BaseType *concrete_cap
+    = Resolver::SubstMapperInternal::Resolve (cap, mappings);
+  rust_assert (concrete_cap->get_kind () == TyTy::TypeKind::CONST);
+  ref->capacity = static_cast<TyTy::ConstType *> (concrete_cap);
+
   return ref;
 }
 
@@ -3412,33 +3419,26 @@ PointerType::handle_substitions 
(SubstitutionArgumentMappings &mappings)
 // PARAM Type
 
 ParamType::ParamType (std::string symbol, location_t locus, HirId ref,
-                     HIR::GenericParam &param,
                      std::vector<TypeBoundPredicate> specified_bounds,
                      std::set<HirId> refs)
   : BaseGeneric (ref, ref, KIND,
                 {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
                  locus},
                 specified_bounds, refs),
-    is_trait_self (false), symbol (symbol), param (param)
+    is_trait_self (false), symbol (symbol)
 {}
 
 ParamType::ParamType (bool is_trait_self, std::string symbol, location_t locus,
-                     HirId ref, HirId ty_ref, HIR::GenericParam &param,
+                     HirId ref, HirId ty_ref,
                      std::vector<TypeBoundPredicate> specified_bounds,
                      std::set<HirId> refs)
   : BaseGeneric (ref, ty_ref, KIND,
                 {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
                  locus},
                 specified_bounds, refs),
-    is_trait_self (is_trait_self), symbol (symbol), param (param)
+    is_trait_self (is_trait_self), symbol (symbol)
 {}
 
-HIR::GenericParam &
-ParamType::get_generic_param ()
-{
-  return param;
-}
-
 bool
 ParamType::can_resolve () const
 {
@@ -3489,7 +3489,7 @@ BaseType *
 ParamType::clone () const
 {
   return new ParamType (is_trait_self, get_symbol (), ident.locus, get_ref (),
-                       get_ty_ref (), param, get_specified_bounds (),
+                       get_ty_ref (), get_specified_bounds (),
                        get_combined_refs ());
 }
 
@@ -3592,12 +3592,14 @@ ConstType::ConstType (ConstKind kind, std::string 
symbol, TyTy::BaseType *ty,
                      tree value,
                      std::vector<TypeBoundPredicate> specified_bounds,
                      location_t locus, HirId ref, HirId ty_ref,
-                     HIR::GenericParam &param, std::set<HirId> refs)
+                     std::set<HirId> refs)
   : BaseGeneric (ref, ty_ref, KIND,
-                {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
+                {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID,
+                                                   symbol.empty () ? "<n/a>"
+                                                                   : symbol),
                  locus},
                 specified_bounds, refs),
-    const_kind (kind), ty (ty), value (value), symbol (symbol), param (param)
+    const_kind (kind), ty (ty), value (value), symbol (symbol)
 {}
 
 void
@@ -3612,6 +3614,13 @@ ConstType::accept_vis (TyConstVisitor &vis) const
   vis.visit (*this);
 }
 
+void
+ConstType::set_value (tree v)
+{
+  value = v;
+  const_kind = ConstType::ConstKind::Value;
+}
+
 std::string
 ConstType::as_string () const
 {
@@ -3629,7 +3638,7 @@ BaseType *
 ConstType::clone () const
 {
   return new ConstType (const_kind, symbol, ty, value, get_specified_bounds (),
-                       ident.locus, ref, ty_ref, param, get_combined_refs ());
+                       ident.locus, ref, ty_ref, get_combined_refs ());
 }
 
 std::string
@@ -3638,12 +3647,6 @@ ConstType::get_symbol () const
   return symbol;
 }
 
-HIR::GenericParam &
-ConstType::get_generic_param ()
-{
-  return param;
-}
-
 bool
 ConstType::can_resolve () const
 {
@@ -3657,10 +3660,48 @@ ConstType::resolve () const
   return nullptr;
 }
 
+static std::string
+generate_tree_str (tree value)
+{
+  char *buf = nullptr;
+  size_t size = 0;
+
+  FILE *stream = open_memstream (&buf, &size);
+  if (!stream)
+    return "<error>";
+
+  print_generic_stmt (stream, value, TDF_NONE);
+  fclose (stream);
+
+  std::string result = (buf ? std::string (buf, size) : "<error>");
+  free (buf);
+
+  if (!result.empty () && result.back () == '\n')
+    result.pop_back ();
+
+  return result;
+}
+
 std::string
 ConstType::get_name () const
 {
-  return "CONST_TYPE";
+  if (value == error_mark_node)
+    {
+      switch (get_const_kind ())
+       {
+       case Rust::TyTy::ConstType::Decl:
+         return "ConstType:<" + get_ty ()->get_name () + " " + get_symbol ()
+                + ">";
+
+       case Rust::TyTy::ConstType::Infer:
+         return "ConstType:<" + get_ty ()->get_name () + " ?" + ">";
+
+       default:
+         return "ConstType:<" + get_ty ()->get_name () + " - <error>" + ">";
+       }
+    }
+
+  return generate_tree_str (value);
 }
 
 bool
@@ -3679,8 +3720,16 @@ ConstType::is_equal (const BaseType &other) const
 ConstType *
 ConstType::handle_substitions (SubstitutionArgumentMappings &mappings)
 {
-  rust_unreachable ();
-  return nullptr;
+  SubstitutionArg arg = SubstitutionArg::error ();
+  bool found = mappings.get_argument_for_symbol (this, &arg);
+  if (found && !arg.is_error ())
+    {
+      TyTy::BaseType *subst = arg.get_tyty ();
+      rust_assert (subst->is<TyTy::ConstType> ());
+      return static_cast<TyTy::ConstType *> (subst);
+    }
+
+  return this;
 }
 
 // OpaqueType
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 7fd5c4695e65..585062b0cb79 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -19,6 +19,7 @@
 #ifndef RUST_TYTY
 #define RUST_TYTY
 
+#include "optional.h"
 #include "rust-hir-map.h"
 #include "rust-common.h"
 #include "rust-identifier.h"
@@ -371,8 +372,6 @@ class BaseGeneric : public BaseType
 public:
   virtual std::string get_symbol () const = 0;
 
-  virtual HIR::GenericParam &get_generic_param () = 0;
-
   virtual bool can_resolve () const = 0;
 
   virtual BaseType *resolve () const = 0;
@@ -391,12 +390,11 @@ public:
   static constexpr auto KIND = TypeKind::PARAM;
 
   ParamType (std::string symbol, location_t locus, HirId ref,
-            HIR::GenericParam &param,
             std::vector<TypeBoundPredicate> specified_bounds,
             std::set<HirId> refs = std::set<HirId> ());
 
   ParamType (bool is_trait_self, std::string symbol, location_t locus,
-            HirId ref, HirId ty_ref, HIR::GenericParam &param,
+            HirId ref, HirId ty_ref,
             std::vector<TypeBoundPredicate> specified_bounds,
             std::set<HirId> refs = std::set<HirId> ());
 
@@ -411,8 +409,6 @@ public:
 
   std::string get_symbol () const override final;
 
-  HIR::GenericParam &get_generic_param () override final;
-
   bool can_resolve () const override final;
 
   BaseType *resolve () const override final;
@@ -429,7 +425,6 @@ public:
 private:
   bool is_trait_self;
   std::string symbol;
-  HIR::GenericParam &param;
 };
 
 class ConstType : public BaseGeneric
@@ -447,7 +442,7 @@ public:
 
   ConstType (ConstKind kind, std::string symbol, TyTy::BaseType *ty, tree 
value,
             std::vector<TypeBoundPredicate> specified_bounds, location_t locus,
-            HirId ref, HirId ty_ref, HIR::GenericParam &param,
+            HirId ref, HirId ty_ref,
             std::set<HirId> refs = std::set<HirId> ());
 
   void accept_vis (TyVisitor &vis) override;
@@ -457,6 +452,8 @@ public:
   TyTy::BaseType *get_ty () const { return ty; }
   tree get_value () const { return value; }
 
+  void set_value (tree value);
+
   std::string as_string () const override;
 
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
@@ -465,8 +462,6 @@ public:
 
   std::string get_symbol () const override final;
 
-  HIR::GenericParam &get_generic_param () override final;
-
   bool can_resolve () const override final;
 
   BaseType *resolve () const override final;
@@ -482,7 +477,6 @@ private:
   TyTy::BaseType *ty;
   tree value;
   std::string symbol;
-  HIR::GenericParam &param;
 };
 
 class OpaqueType : public BaseType
@@ -1231,14 +1225,14 @@ class ArrayType : public BaseType
 public:
   static constexpr auto KIND = TypeKind::ARRAY;
 
-  ArrayType (HirId ref, location_t locus, tree capacity, TyVar base,
+  ArrayType (HirId ref, location_t locus, ConstType *capacity, TyVar base,
             std::set<HirId> refs = std::set<HirId> ())
     : BaseType (ref, ref, TypeKind::ARRAY,
                {Resolver::CanonicalPath::create_empty (), locus}, refs),
       element_type (base), capacity (capacity)
   {}
 
-  ArrayType (HirId ref, HirId ty_ref, location_t locus, tree capacity,
+  ArrayType (HirId ref, HirId ty_ref, location_t locus, ConstType *capacity,
             TyVar base, std::set<HirId> refs = std::set<HirId> ())
     : BaseType (ref, ty_ref, TypeKind::ARRAY,
                {Resolver::CanonicalPath::create_empty (), locus}, refs),
@@ -1261,13 +1255,13 @@ public:
 
   BaseType *clone () const final override;
 
-  tree get_capacity () const { return capacity; }
+  ConstType *get_capacity () const { return capacity; }
 
   ArrayType *handle_substitions (SubstitutionArgumentMappings &mappings);
 
 private:
   TyVar element_type;
-  tree capacity;
+  ConstType *capacity;
 };
 
 class SliceType : public BaseType
diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc
index 7780ae63f1ce..30ead5b4e0e9 100644
--- a/gcc/rust/typecheck/rust-unify.cc
+++ b/gcc/rust/typecheck/rust-unify.cc
@@ -17,6 +17,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-unify.h"
+#include "fold-const.h"
 #include "rust-tyty.h"
 #include "tree.h"
 
@@ -839,20 +840,21 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, 
TyTy::BaseType *rtype)
        if (element_unify->get_kind () == TyTy::TypeKind::ERROR)
          return new TyTy::ErrorType (0);
 
-       // TODO infer capacity?
-       tree lcap = ltype->get_capacity ();
-       tree rcap = type.get_capacity ();
-       if (error_operand_p (lcap) || error_operand_p (rcap))
-         return new TyTy::ErrorType (0);
+       bool save_emit_error = emit_error;
+       emit_error = false;
+       TyTy::BaseType *capacity_unify
+         = resolve_subtype (TyTy::TyWithLocation (ltype->get_capacity ()),
+                            TyTy::TyWithLocation (type.get_capacity ()));
+       emit_error = save_emit_error;
 
-       auto lc = wi::to_wide (lcap).to_uhwi ();
-       auto rc = wi::to_wide (rcap).to_uhwi ();
-       if (lc != rc)
+       if (capacity_unify->get_kind () != TyTy::TypeKind::CONST)
          return new TyTy::ErrorType (0);
 
+       TyTy::ConstType *capacity_type_unify
+         = static_cast<TyTy::ConstType *> (capacity_unify);
        return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (),
                                    type.get_ident ().locus,
-                                   type.get_capacity (),
+                                   capacity_type_unify,
                                    TyTy::TyVar (element_unify->get_ref ()));
       }
       break;
@@ -1941,9 +1943,63 @@ UnifyRules::expect_const (TyTy::ConstType *ltype, 
TyTy::BaseType *rtype)
   if (rtype->get_kind () != TyTy::TypeKind::CONST)
     return new TyTy::ErrorType (0);
 
-  // TODO
-  // TyTy::ConstType &lhs = *ltype;
-  // TyTy::ConstType &rhs = *static_cast<TyTy::ConstType *> (rtype);
+  TyTy::ConstType &lhs = *ltype;
+  TyTy::ConstType &rhs = *static_cast<TyTy::ConstType *> (rtype);
+
+  auto res = resolve_subtype (TyTy::TyWithLocation (lhs.get_ty ()),
+                             TyTy::TyWithLocation (rhs.get_ty ()));
+  if (res->get_kind () == TyTy::TypeKind::ERROR)
+    return new TyTy::ErrorType (0);
+
+  tree lv = lhs.get_value ();
+  tree rv = rhs.get_value ();
+
+  if (error_operand_p (lv) && error_operand_p (rv))
+    {
+      // this is only allowed for some silly senarios like:
+      // gcc/testsuite/rust/compile/issue-const_generics_5.rs
+      if (lhs.get_const_kind () == rhs.get_const_kind ())
+       {
+         return new TyTy::ConstType (lhs.get_const_kind (), lhs.get_symbol (),
+                                     res, error_mark_node,
+                                     lhs.get_specified_bounds (),
+                                     lhs.get_locus (), lhs.get_ref (),
+                                     lhs.get_ty_ref (),
+                                     lhs.get_combined_refs ());
+       }
+
+      return new TyTy::ErrorType (0);
+    }
+
+  bool equal = operand_equal_p (lv, rv, 0);
+  if (equal)
+    {
+      return new TyTy::ConstType (TyTy::ConstType::ConstKind::Value,
+                                 lhs.get_symbol (), res, lv,
+                                 lhs.get_specified_bounds (), lhs.get_locus (),
+                                 lhs.get_ref (), lhs.get_ty_ref (),
+                                 lhs.get_combined_refs ());
+    }
+
+  if (lhs.get_const_kind () == TyTy::ConstType::Infer && !error_operand_p (rv))
+    {
+      lhs.set_value (rv);
+      return new TyTy::ConstType (TyTy::ConstType::ConstKind::Value,
+                                 lhs.get_symbol (), res, rv,
+                                 lhs.get_specified_bounds (), lhs.get_locus (),
+                                 lhs.get_ref (), lhs.get_ty_ref (),
+                                 lhs.get_combined_refs ());
+    }
+  else if (rhs.get_const_kind () == TyTy::ConstType::Infer
+          && !error_operand_p (lv))
+    {
+      rhs.set_value (lv);
+      return new TyTy::ConstType (TyTy::ConstType::ConstKind::Value,
+                                 rhs.get_symbol (), res, lv,
+                                 rhs.get_specified_bounds (), rhs.get_locus (),
+                                 rhs.get_ref (), rhs.get_ty_ref (),
+                                 rhs.get_combined_refs ());
+    }
 
   return new TyTy::ErrorType (0);
 }
diff --git a/gcc/testsuite/rust/compile/const_generics_10.rs 
b/gcc/testsuite/rust/compile/const_generics_10.rs
new file mode 100644
index 000000000000..7e3bc86bd9fc
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const_generics_10.rs
@@ -0,0 +1,32 @@
+#[lang = "sized"]
+trait Sized {}
+
+const M: usize = 4;
+
+struct Foo<T, const N: usize = 1> {
+    value: [T; N],
+}
+
+fn main() {
+    let foo = Foo::<i32> { value: [15] };
+    let foo = Foo::<i32, 2> { value: [15, 13] };
+    let foo: Foo<i32, 2> = Foo { value: [15, 13] };
+    let foo: Foo<i32, 2> = Foo::<i32, 2> { value: [15, 13] };
+    let foo: Foo<i32, { 1 + 1 }> = Foo { value: [15, 13] };
+    let foo = Foo::<i32, { 1 + 1 }> { value: [15, 13] };
+    let foo: Foo<i32, { 1 + 1 }> = Foo::<i32, { 1 + 1 }> { value: [15, 13] };
+    let foo: Foo<i32, M> = Foo::<i32, 4> {
+        value: [15, 13, 11, 9],
+    };
+
+    let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, 3> { value: [15, 13] };
+    // { dg-error {mismatched types, expected ..T=i32; 3.. but got 
...integer.; 2.. .E0308.} "" { target *-*-* } .-1 }
+    // { dg-error {mismatched types, expected ..T=i32; 2.. but got ..T=i32; 
3.. .E0308.} "" { target *-*-* } .-2 }
+
+    let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, M> { value: [15, 13] };
+    // { dg-error {mismatched types, expected ..T=i32; 4.. but got 
...integer.; 2.. .E0308.} "" { target *-*-* } .-1 }
+    // { dg-error {mismatched types, expected ..T=i32; 2.. but got ..T=i32; 
4.. .E0308.} "" { target *-*-* } .-2 }
+
+    let invalid_foo: Foo<i32> = Foo::<i32, 2> { value: [15, 13] };
+    // { dg-error {mismatched types, expected ..T=i32; 1.. but got ..T=i32; 
2.. .E0308.} "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/rust/compile/const_generics_11.rs 
b/gcc/testsuite/rust/compile/const_generics_11.rs
new file mode 100644
index 000000000000..de902ee0d06e
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const_generics_11.rs
@@ -0,0 +1,14 @@
+// { dg-options "-w" }
+
+#[lang = "sized"]
+trait Sized {}
+
+struct Matrix<T, const ROWS: usize, const COLS: usize> {
+    data: [[T; COLS]; ROWS],
+}
+
+fn main() {
+    let _: Matrix<u8, 2, 3> = Matrix {
+        data: [[1, 2, 3], [4, 5, 6]],
+    };
+}
diff --git a/gcc/testsuite/rust/compile/const_generics_12.rs 
b/gcc/testsuite/rust/compile/const_generics_12.rs
new file mode 100644
index 000000000000..a17c52594b1f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const_generics_12.rs
@@ -0,0 +1,14 @@
+// { dg-options "-w" }
+
+#[lang = "sized"]
+trait Sized {}
+
+const BASE: usize = 2;
+
+struct Foo<T, const N: usize> {
+    data: [T; N],
+}
+
+fn main() {
+    let _ = Foo::<u8, { BASE + 1 * 2 }> { data: [0; 4] };
+}
diff --git a/gcc/testsuite/rust/compile/const_generics_13.rs 
b/gcc/testsuite/rust/compile/const_generics_13.rs
new file mode 100644
index 000000000000..20dd0b906ce3
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const_generics_13.rs
@@ -0,0 +1,11 @@
+#[lang = "sized"]
+trait Sized {}
+
+struct Foo<T, const N: usize> {
+    value: [T; N],
+}
+
+fn main() {
+    let foo: Foo<_, _>;
+    // { dg-error {type provided when a constant was expected .E0747.} "" { 
target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/rust/compile/const_generics_14.rs 
b/gcc/testsuite/rust/compile/const_generics_14.rs
new file mode 100644
index 000000000000..4d52efb16bb1
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const_generics_14.rs
@@ -0,0 +1,13 @@
+#[lang = "sized"]
+trait Sized {}
+
+type MyLen = usize;
+struct Foo<T, const N: usize> {
+    data: [T; N],
+}
+
+fn main() {
+    let _ = Foo::<u8, MyLen> { data: [1, 2, 3] };
+    // { dg-error {type provided when a constant was expected .E0747.} "" { 
target *-*-* } .-1 }
+    // { dg-error {expected an ADT type for constructor} "" { target *-*-* } 
.-2 }
+}
diff --git a/gcc/testsuite/rust/compile/const_generics_15.rs 
b/gcc/testsuite/rust/compile/const_generics_15.rs
new file mode 100644
index 000000000000..a160abf59f1c
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const_generics_15.rs
@@ -0,0 +1,16 @@
+#[lang = "sized"]
+trait Sized {}
+
+enum Foo<const N: usize> {
+    A([u8; N]),
+}
+
+union Bar<const N: usize> {
+    a: [i32; N],
+    b: [u8; N],
+}
+
+fn main() {
+    let _ = Foo::<4>::A([1, 2, 3, 4]);
+    let _ = Bar::<4> { a: [0; 4] };
+}
diff --git a/gcc/testsuite/rust/compile/const_generics_16.rs 
b/gcc/testsuite/rust/compile/const_generics_16.rs
new file mode 100644
index 000000000000..060dbda79de6
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const_generics_16.rs
@@ -0,0 +1,10 @@
+#[lang = "sized"]
+trait Sized {}
+
+struct Foo<T = u8, const N: usize = 4> {
+    data: [T; N], // { dg-warning "field is never read: .data." }
+}
+
+fn main() {
+    let _x = Foo { data: [1, 2, 3, 4] };
+}
diff --git a/gcc/testsuite/rust/compile/const_generics_3.rs 
b/gcc/testsuite/rust/compile/const_generics_3.rs
index d8b2ddfedaf0..3415f176b2f4 100644
--- a/gcc/testsuite/rust/compile/const_generics_3.rs
+++ b/gcc/testsuite/rust/compile/const_generics_3.rs
@@ -1,28 +1,21 @@
-// { dg-additional-options "-w -frust-compile-until=typecheck" }
-
 #[lang = "sized"]
 trait Sized {}
 
 const M: usize = 4;
 
 struct Foo<T, const N: usize = 1> {
-    value: [T; N],
+    value: [T; N], // { dg-warning "field is never read: .value." }
 }
 
 fn main() {
-    let foo = Foo::<i32> { value: [15] };
-    let foo = Foo::<i32, 2> { value: [15, 13] };
-    let foo: Foo<i32, 2> = Foo { value: [15, 13] };
-    let foo: Foo<i32, 2> = Foo::<i32, 2> { value: [15, 13] };
-    let foo: Foo<i32, { 1 + 1 }> = Foo { value: [15, 13] };
-    let foo = Foo::<i32, { 1 + 1 }> { value: [15, 13] };
-    let foo: Foo<i32, { 1 + 1 }> = Foo::<i32, { 1 + 1 }> { value: [15, 13] };
-    let foo: Foo<i32, M> = Foo::<i32, 4> {
+    let _foo = Foo::<i32> { value: [15] };
+    let _foo = Foo::<i32, 2> { value: [15, 13] };
+    let _foo: Foo<i32, 2> = Foo { value: [15, 13] };
+    let _foo: Foo<i32, 2> = Foo::<i32, 2> { value: [15, 13] };
+    let _foo: Foo<i32, { 1 + 1 }> = Foo { value: [15, 13] };
+    let _foo = Foo::<i32, { 1 + 1 }> { value: [15, 13] };
+    let _foo: Foo<i32, { 1 + 1 }> = Foo::<i32, { 1 + 1 }> { value: [15, 13] };
+    let _foo: Foo<i32, M> = Foo::<i32, 4> {
         value: [15, 13, 11, 9],
     };
-
-    // FIXME: Add proper const typecheck errors here
-    let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, 3> { value: [15, 13] };
-    let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, M> { value: [15, 13] };
-    let invalid_foo: Foo<i32> = Foo::<i32, 2> { value: [15, 13] };
 }
diff --git a/gcc/testsuite/rust/compile/const_generics_5.rs 
b/gcc/testsuite/rust/compile/const_generics_5.rs
index 685229eabd21..4d05569462bd 100644
--- a/gcc/testsuite/rust/compile/const_generics_5.rs
+++ b/gcc/testsuite/rust/compile/const_generics_5.rs
@@ -1,4 +1,3 @@
-// { dg-options "-w" }
 struct Foo<const N: usize = { 14 }>;
 
 const M: usize = 15;
@@ -8,5 +7,6 @@ fn main() {
     let _: Foo<15> = Foo;
     let _: Foo<{ M }> = Foo;
     let _: Foo<M> = Foo;
-    // let _: Foo<N> = Foo; this causes an ICE we need to do const generics
+    let _: Foo<N> = Foo;
+    // { dg-error {type provided when a constant was expected .E0747.} "" { 
target *-*-* } .-1 }
 }
diff --git a/gcc/testsuite/rust/compile/const_generics_8.rs 
b/gcc/testsuite/rust/compile/const_generics_8.rs
index bb34652b9a63..ce5e1b59bd71 100644
--- a/gcc/testsuite/rust/compile/const_generics_8.rs
+++ b/gcc/testsuite/rust/compile/const_generics_8.rs
@@ -9,12 +9,13 @@ type Bipboupe<const N: i32 = 15> = Bidule;
 trait Fooable<const N: i32 = 15> {}
 
 union Bidoulepe<const N: i32 = 15> {
-    // { dg-error "default values for const generic parameters are not allowed 
in .union. items"  "" {target *-*-* } .-1 }
     int: i32,
     float: f32,
 }
 
-fn const_default<const N: i32 = 15>() {} // { dg-error "default values for 
const generic parameters are not allowed in .function. items" }
+fn const_default<const N: i32 = 15>() {} // { dg-error "default values for 
const generic parameters are not allowed here" }
 
 // Note - missing generic parameter - needs name resolution on const generics
-impl<const N: i32 = 15> Bidule {} // { dg-error "default values for const 
generic parameters are not allowed in .impl. items" }
+impl<const N: i32 = 15> Bidule {}
+// { dg-error "default values for const generic parameters are not allowed 
here"   "" {target *-*-* } .-1 }
+// { dg-error "unconstrained type parameter"  "" {target *-*-* } .-2 }
diff --git a/gcc/testsuite/rust/compile/const_generics_9.rs 
b/gcc/testsuite/rust/compile/const_generics_9.rs
new file mode 100644
index 000000000000..98e2d3ff0683
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const_generics_9.rs
@@ -0,0 +1,13 @@
+// { dg-options "-w" }
+
+#[lang = "sized"]
+trait Sized {}
+
+struct ArrayWrapper<T, const N: usize> {
+    data: [T; N],
+}
+
+pub fn test() -> [u8; 4] {
+    let a = ArrayWrapper { data: [1u8; 4] };
+    a.data
+}

Reply via email to