https://gcc.gnu.org/g:b42c7041ae227f8e52dc085ca2ba46aac062414a
commit r16-2923-gb42c7041ae227f8e52dc085ca2ba46aac062414a Author: Philip Herron <herron.phi...@googlemail.com> Date: Tue Jul 8 21:13:48 2025 +0100 gccrs: Do proper const folding during typechecking for array capacities This patch adds proper folding to the const expression for array capacity we already have the const folding mechanics and the query system needed to handle cases where the capacity is a function call in a const context. This leverages and pulls the gcc tree capacity into the TyTy::ArrayType so it can be used for more typechecking and eventually doing more const generics work. Addresses Rust-GCC#3885 Fixes Rust-GCC#3882 gcc/rust/ChangeLog: * backend/rust-compile-base.cc (HIRCompileBase::query_compile_const_expr): new wrapper * backend/rust-compile-base.h: add prototype * backend/rust-compile-context.cc (Context::get): singleton helper * backend/rust-compile-context.h: likewise * backend/rust-compile-type.cc (TyTyResolveCompile::visit): handle infer's that can default * rust-session-manager.cc (Session::compile_crate): create the gcc context earlier for tychk * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::resolve_literal): const fold it * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): likewise * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): likewise * typecheck/rust-tyty.cc (BaseType::monomorphized_clone): fix constructor call (ArrayType::as_string): print capacity (ArrayType::clone): fix constructor call * typecheck/rust-tyty.h: track capacity * typecheck/rust-unify.cc (UnifyRules::expect_array): check the capacities gcc/testsuite/ChangeLog: * rust/compile/all-cast.rs: shows array capacity now * rust/compile/arrays2.rs: likewise * rust/compile/const3.rs: fix error message * rust/compile/const_generics_3.rs: disable until typecheck we get proper errors now! * rust/compile/usize1.rs: proper capacity error message Signed-off-by: Philip Herron <herron.phi...@googlemail.com> Diff: --- gcc/rust/backend/rust-compile-base.cc | 19 +++++++++++++++++ gcc/rust/backend/rust-compile-base.h | 3 +++ gcc/rust/backend/rust-compile-context.cc | 10 +++++++++ gcc/rust/backend/rust-compile-context.h | 4 +++- gcc/rust/backend/rust-compile-type.cc | 24 ++++++++-------------- gcc/rust/rust-session-manager.cc | 10 ++++----- gcc/rust/typecheck/rust-hir-type-check-base.cc | 7 +++++-- gcc/rust/typecheck/rust-hir-type-check-expr.cc | 28 +++++++++++++++++--------- gcc/rust/typecheck/rust-hir-type-check-type.cc | 12 ++++++++--- gcc/rust/typecheck/rust-tyty.cc | 17 +++++++++++++--- gcc/rust/typecheck/rust-tyty.h | 18 ++++++++--------- gcc/rust/typecheck/rust-unify.cc | 27 +++++++++++++++++-------- gcc/testsuite/rust/compile/all-cast.rs | 2 +- gcc/testsuite/rust/compile/arrays2.rs | 3 +-- gcc/testsuite/rust/compile/const3.rs | 2 +- gcc/testsuite/rust/compile/const_generics_3.rs | 2 +- gcc/testsuite/rust/compile/usize1.rs | 2 +- 17 files changed, 127 insertions(+), 63 deletions(-) diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc index c9f9fbe76bfd..b2913ad3c381 100644 --- a/gcc/rust/backend/rust-compile-base.cc +++ b/gcc/rust/backend/rust-compile-base.cc @@ -575,6 +575,25 @@ HIRCompileBase::compile_constant_expr ( expr_locus); } +tree +HIRCompileBase::query_compile_const_expr (Context *ctx, TyTy::BaseType *expr_ty, + HIR::Expr &const_value_expr) +{ + HIRCompileBase c (ctx); + + ctx->push_const_context (); + + HirId expr_id = const_value_expr.get_mappings ().get_hirid (); + location_t locus = const_value_expr.get_locus (); + tree capacity_expr = HIRCompileBase::compile_constant_expr ( + ctx, expr_id, expr_ty, expr_ty, Resolver::CanonicalPath::create_empty (), + const_value_expr, locus, locus); + + ctx->pop_const_context (); + + return fold_expr (capacity_expr); +} + tree HIRCompileBase::indirect_expression (tree expr, location_t locus) { diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h index 6814abcf9deb..e9b85968fac3 100644 --- a/gcc/rust/backend/rust-compile-base.h +++ b/gcc/rust/backend/rust-compile-base.h @@ -38,6 +38,9 @@ public: const Resolver::CanonicalPath &canonical_path, HIR::Expr &const_value_expr, location_t locus, location_t expr_locus); + static tree query_compile_const_expr (Context *ctx, TyTy::BaseType *expr_ty, + HIR::Expr &const_value_expr); + protected: HIRCompileBase (Context *ctx) : ctx (ctx) {} diff --git a/gcc/rust/backend/rust-compile-context.cc b/gcc/rust/backend/rust-compile-context.cc index 3f328d33e7fb..349d4927cb48 100644 --- a/gcc/rust/backend/rust-compile-context.cc +++ b/gcc/rust/backend/rust-compile-context.cc @@ -22,6 +22,16 @@ namespace Rust { namespace Compile { +Context * +Context::get () +{ + static Context *instance; + if (instance == nullptr) + instance = new Context (); + + return instance; +} + Context::Context () : tyctx (Resolver::TypeCheckContext::get ()), mappings (Analysis::Mappings::get ()), mangler (Mangler ()) diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index bb942816946d..d4a642b653ca 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -49,7 +49,7 @@ struct CustomDeriveInfo class Context { public: - Context (); + static Context *get (); void setup_builtins (); @@ -390,6 +390,8 @@ public: } private: + Context (); + Resolver::TypeCheckContext *tyctx; Analysis::Mappings &mappings; Mangler mangler; diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index c397b4beb4ca..8f13bba534b6 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -121,6 +121,13 @@ TyTyResolveCompile::visit (const TyTy::InferType &type) if (orig == lookup) { + TyTy::BaseType *def = nullptr; + if (type.default_type (&def)) + { + translated = TyTyResolveCompile::compile (ctx, def); + return; + } + translated = error_mark_node; return; } @@ -463,22 +470,7 @@ TyTyResolveCompile::visit (const TyTy::ArrayType &type) { tree element_type = TyTyResolveCompile::compile (ctx, type.get_element_type ()); - - ctx->push_const_context (); - - HIR::Expr &hir_capacity_expr = type.get_capacity_expr (); - TyTy::BaseType *capacity_expr_ty = nullptr; - bool ok = ctx->get_tyctx ()->lookup_type ( - hir_capacity_expr.get_mappings ().get_hirid (), &capacity_expr_ty); - rust_assert (ok); - tree capacity_expr = HIRCompileBase::compile_constant_expr ( - ctx, hir_capacity_expr.get_mappings ().get_hirid (), capacity_expr_ty, - capacity_expr_ty, Resolver::CanonicalPath::create_empty (), - hir_capacity_expr, type.get_locus (), hir_capacity_expr.get_locus ()); - - ctx->pop_const_context (); - - tree folded_capacity_expr = fold_expr (capacity_expr); + tree folded_capacity_expr = type.get_capacity (); // build_index_type takes the maximum index, which is one less than // the length. diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 3252fcdcc6c0..12cdc2e5dba9 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -681,6 +681,7 @@ Session::compile_crate (const char *filename) Resolver2_0::ImmutableNameResolutionContext::init (name_resolution_ctx); // type resolve + Compile::Context *ctx = Compile::Context::get (); Resolver::TypeResolution::Resolve (hir); Resolver::TypeCheckContext::get ()->get_variance_analysis_ctx ().solve (); @@ -728,16 +729,15 @@ Session::compile_crate (const char *filename) return; // do compile to gcc generic - Compile::Context ctx; - Compile::CompileCrate::Compile (hir, &ctx); + Compile::CompileCrate::Compile (hir, ctx); // we can't do static analysis if there are errors to worry about if (!saw_errors ()) { // lints Analysis::ScanDeadcode::Scan (hir); - Analysis::UnusedVariables::Lint (ctx); - Analysis::ReadonlyCheck::Lint (ctx); + Analysis::UnusedVariables::Lint (*ctx); + Analysis::ReadonlyCheck::Lint (*ctx); // metadata bool specified_emit_metadata @@ -758,7 +758,7 @@ Session::compile_crate (const char *filename) } // pass to GCC middle-end - ctx.write_to_backend (); + ctx->write_to_backend (); } void diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index 6d5806f967f8..4bbd52a29f45 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -17,6 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-hir-type-check-base.h" +#include "rust-compile-base.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-type.h" #include "rust-hir-trait-resolve.h" @@ -287,9 +288,11 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, crate_num), UNKNOWN_LOCAL_DEFID); + auto ctx = Compile::Context::get (); + tree capacity = Compile::HIRCompileBase::query_compile_const_expr ( + ctx, expected_ty, *literal_capacity); TyTy::ArrayType *array - = new TyTy::ArrayType (array_mapping.get_hirid (), locus, - *literal_capacity, + = new TyTy::ArrayType (array_mapping.get_hirid (), locus, capacity, TyTy::TyVar (u8->get_ref ())); context->insert_type (array_mapping, array); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index eb50803814f4..ccde4dd77bff 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -31,6 +31,7 @@ #include "rust-hir-type-check-item.h" #include "rust-type-util.h" #include "rust-immutable-name-resolution-context.h" +#include "rust-compile-base.h" // for flag_name_resolution_2_0 #include "options.h" @@ -1031,6 +1032,7 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) HIR::Expr *capacity_expr = nullptr; TyTy::BaseType *element_type = nullptr; + TyTy::BaseType *capacity_type = nullptr; switch (elements.get_array_expr_type ()) { case HIR::ArrayElems::ArrayExprType::COPIED: @@ -1039,7 +1041,7 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) = static_cast<HIR::ArrayElemsCopied &> (elements); element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ()); - auto capacity_type + auto capacity_expr_ty = TypeCheckExpr::Resolve (elems.get_num_copies_expr ()); TyTy::BaseType *expected_ty = nullptr; @@ -1048,13 +1050,14 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) context->insert_type (elems.get_num_copies_expr ().get_mappings (), expected_ty); - unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (expected_ty), - TyTy::TyWithLocation ( - capacity_type, elems.get_num_copies_expr ().get_locus ()), - expr.get_locus ()); + unify_site ( + expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty), + TyTy::TyWithLocation (capacity_expr_ty, + elems.get_num_copies_expr ().get_locus ()), + expr.get_locus ()); capacity_expr = &elems.get_num_copies_expr (); + capacity_type = expected_ty; } break; @@ -1096,13 +1099,20 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) bool ok = context->lookup_builtin ("usize", &expected_ty); rust_assert (ok); context->insert_type (mapping, expected_ty); + capacity_type = expected_ty; } break; } - infered = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), - expr.get_locus (), *capacity_expr, - TyTy::TyVar (element_type->get_ref ())); + rust_assert (capacity_expr); + rust_assert (capacity_type); + auto ctx = Compile::Context::get (); + tree capacity + = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type, + *capacity_expr); + infered + = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), expr.get_locus (), + capacity, TyTy::TyVar (element_type->get_ref ())); } // empty struct diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index f23352baacda..462b3d487673 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -29,6 +29,7 @@ #include "rust-substitution-mapper.h" #include "rust-type-util.h" #include "rust-system.h" +#include "rust-compile-base.h" namespace Rust { namespace Resolver { @@ -710,9 +711,14 @@ TypeCheckType::visit (HIR::ArrayType &type) type.get_size_expr ().get_locus ()); TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ()); - translated = new TyTy::ArrayType (type.get_mappings ().get_hirid (), - type.get_locus (), type.get_size_expr (), - TyTy::TyVar (base->get_ref ())); + + 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 ())); } void diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index e2dfa743b9aa..75370e96c662 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -30,9 +30,11 @@ #include "rust-tyty-cmp.h" #include "rust-type-util.h" #include "rust-hir-type-bounds.h" +#include "print-tree.h" #include "options.h" #include "rust-system.h" +#include "tree.h" namespace Rust { namespace TyTy { @@ -574,7 +576,7 @@ BaseType::monomorphized_clone () const { TyVar elm = arr->get_var_element_type ().monomorphized_clone (); return new ArrayType (arr->get_ref (), arr->get_ty_ref (), ident.locus, - arr->get_capacity_expr (), elm, + arr->get_capacity (), elm, arr->get_combined_refs ()); } else if (auto slice = x->try_as<const SliceType> ()) @@ -2486,7 +2488,16 @@ ArrayType::accept_vis (TyConstVisitor &vis) const std::string ArrayType::as_string () const { - return "[" + get_element_type ()->as_string () + ":" + "CAPACITY" + "]"; + 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 + "]"; } bool @@ -2525,7 +2536,7 @@ ArrayType::get_var_element_type () const BaseType * ArrayType::clone () const { - return new ArrayType (get_ref (), get_ty_ref (), ident.locus, capacity_expr, + return new ArrayType (get_ref (), get_ty_ref (), ident.locus, capacity, element_type, get_combined_refs ()); } diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index e8ddd3e1d91d..e0d0358e9e66 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -29,6 +29,7 @@ #include "rust-tyty-region.h" #include "rust-system.h" #include "rust-hir.h" +#include "tree.h" namespace Rust { @@ -1156,19 +1157,18 @@ class ArrayType : public BaseType public: static constexpr auto KIND = TypeKind::ARRAY; - ArrayType (HirId ref, location_t locus, HIR::Expr &capacity_expr, TyVar base, + ArrayType (HirId ref, location_t locus, tree 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_expr (capacity_expr) + element_type (base), capacity (capacity) {} - ArrayType (HirId ref, HirId ty_ref, location_t locus, - HIR::Expr &capacity_expr, TyVar base, - std::set<HirId> refs = std::set<HirId> ()) + ArrayType (HirId ref, HirId ty_ref, location_t locus, tree capacity, + TyVar base, std::set<HirId> refs = std::set<HirId> ()) : BaseType (ref, ty_ref, TypeKind::ARRAY, {Resolver::CanonicalPath::create_empty (), locus}, refs), - element_type (base), capacity_expr (capacity_expr) + element_type (base), capacity (capacity) {} void accept_vis (TyVisitor &vis) override; @@ -1187,15 +1187,13 @@ public: BaseType *clone () const final override; - HIR::Expr &get_capacity_expr () const { return capacity_expr; } + tree get_capacity () const { return capacity; } ArrayType *handle_substitions (SubstitutionArgumentMappings &mappings); private: TyVar element_type; - // FIXME: I dont think this should be in tyty - tyty should already be const - // evaluated - HIR::Expr &capacity_expr; + tree capacity; }; class SliceType : public BaseType diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc index 2a981acaf3a7..ac9019369826 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 "tree.h" namespace Rust { namespace Resolver { @@ -825,14 +826,24 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) = resolve_subtype (TyTy::TyWithLocation (ltype->get_element_type ()), TyTy::TyWithLocation (type.get_element_type ())); - if (element_unify->get_kind () != TyTy::TypeKind::ERROR) - { - return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (), - type.get_ident ().locus, - type.get_capacity_expr (), - TyTy::TyVar ( - element_unify->get_ref ())); - } + 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); + + auto lc = wi::to_wide (lcap).to_uhwi (); + auto rc = wi::to_wide (rcap).to_uhwi (); + if (lc != rc) + return new TyTy::ErrorType (0); + + return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (), + type.get_ident ().locus, + type.get_capacity (), + TyTy::TyVar (element_unify->get_ref ())); } break; diff --git a/gcc/testsuite/rust/compile/all-cast.rs b/gcc/testsuite/rust/compile/all-cast.rs index fa24373a6779..6d8576cc84f0 100644 --- a/gcc/testsuite/rust/compile/all-cast.rs +++ b/gcc/testsuite/rust/compile/all-cast.rs @@ -4,7 +4,7 @@ fn main() { 0u32 as char; // { dg-error "cannot cast .u32. as .char., only .u8. can be cast as .char." } - let x = &[1_usize, 2] as [usize]; // { dg-error "cast to unsized type: .& .usize:CAPACITY.. as ..usize.." } + let x = &[1_usize, 2] as [usize]; // { dg-error "cast to unsized type: .& .usize; 2.. as ..usize.." } let a = &0u8; // Here, `x` is a `&u8`. let y: u32 = a as u32; // { dg-error "casting .& u8. as .u32. is invalid" } diff --git a/gcc/testsuite/rust/compile/arrays2.rs b/gcc/testsuite/rust/compile/arrays2.rs index 668bcf0951b1..109005922c34 100644 --- a/gcc/testsuite/rust/compile/arrays2.rs +++ b/gcc/testsuite/rust/compile/arrays2.rs @@ -1,5 +1,4 @@ -// { dg-additional-options "-w" } fn main() { let array: [i32; 5] = [1, 2, 3]; - // { dg-error "mismatched types, expected an array with a fixed size of 5 elements, found one with 3 elements" "" { target *-*-* } .-1 } + // { dg-error "mismatched types, expected ..i32; 5.. but got ...integer.; 3.. .E0308." "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust/compile/const3.rs b/gcc/testsuite/rust/compile/const3.rs index 22dc3d356cac..c1d0f29ae199 100644 --- a/gcc/testsuite/rust/compile/const3.rs +++ b/gcc/testsuite/rust/compile/const3.rs @@ -3,5 +3,5 @@ fn size() -> usize { } fn main() { - let a = [15; size()]; // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" } + let a = [15; size()]; // { dg-error "calls in constants are limited to constant functions, tuple structs and tuple variants" } } diff --git a/gcc/testsuite/rust/compile/const_generics_3.rs b/gcc/testsuite/rust/compile/const_generics_3.rs index 09d5835074d1..d8b2ddfedaf0 100644 --- a/gcc/testsuite/rust/compile/const_generics_3.rs +++ b/gcc/testsuite/rust/compile/const_generics_3.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-w -frust-compile-until=compilation" } +// { dg-additional-options "-w -frust-compile-until=typecheck" } #[lang = "sized"] trait Sized {} diff --git a/gcc/testsuite/rust/compile/usize1.rs b/gcc/testsuite/rust/compile/usize1.rs index 36cb99b5574a..08f6c9cf5cb4 100644 --- a/gcc/testsuite/rust/compile/usize1.rs +++ b/gcc/testsuite/rust/compile/usize1.rs @@ -1,5 +1,5 @@ fn main() { let a = [1, 2, 3]; let b: u32 = 1; - let c = a[b]; // { dg-error "the type ...integer..CAPACITY.. cannot be indexed by .u32." } + let c = a[b]; // { dg-error "the type ...integer.; 3.. cannot be indexed by .u32." } }