From dd4eabb87bff25a1a1ad5fc7b8f2da7cce8e0e47 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 23 Jun 2025 11:21:02 +0100 Subject: [PATCH] gccrs: check for invalid const calls during code-gen Closure calls are not const so this is invalid. This patch fixes two bugs 1. Make the look at the parent context optional for generics 2. Ensure we look for non const calls during call expr code-gen Fixes Rust-GCC#3551 gcc/rust/ChangeLog: * backend/rust-compile-expr.cc (CompileExpr::visit): add const call check * backend/rust-compile-item.cc (CompileItem::visit): ensure we upfront compile types where possible * backend/rust-compile-item.h: update header * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): make parent ctx optional gcc/testsuite/ChangeLog: * rust/compile/issue-3551.rs: New test. Signed-off-by: Philip Herron --- gcc/rust/backend/rust-compile-expr.cc | 22 +++++++ gcc/rust/backend/rust-compile-item.cc | 60 +++++++++++++++++++ gcc/rust/backend/rust-compile-item.h | 8 +-- .../typecheck/rust-hir-type-check-expr.cc | 20 ++++--- gcc/testsuite/rust/compile/issue-3551.rs | 15 +++++ 5 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/rust/compile/issue-3551.rs diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index d8ddab5bd9a..7a1e5a70ab6 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -1338,6 +1338,28 @@ CompileExpr::visit (HIR::CallExpr &expr) }; auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx); + if (ctx->const_context_p ()) + { + if (!FUNCTION_POINTER_TYPE_P (TREE_TYPE (fn_address))) + { + rust_error_at (expr.get_locus (), + "calls in constants are limited to constant " + "functions, tuple structs and tuple variants"); + return; + } + + if (TREE_CODE (fn_address) == ADDR_EXPR) + { + tree fndecl = TREE_OPERAND (fn_address, 0); + if (!DECL_DECLARED_CONSTEXPR_P (fndecl)) + { + rust_error_at (expr.get_locus (), + "calls in constants are limited to constant " + "functions, tuple structs and tuple variants"); + return; + } + } + } // is this a closure call? bool possible_trait_call diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index 3e7ea9a25e9..78f6f571e9c 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -297,5 +297,65 @@ CompileItem::visit (HIR::Module &module) CompileItem::compile (item.get (), ctx); } +void +CompileItem::visit (HIR::TupleStruct &tuple_struct_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type ( + tuple_struct_decl.get_mappings ().get_hirid (), &lookup)) + { + rust_error_at (tuple_struct_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + +void +CompileItem::visit (HIR::Enum &enum_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type (enum_decl.get_mappings ().get_hirid (), + &lookup)) + { + rust_error_at (enum_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + +void +CompileItem::visit (HIR::Union &union_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type (union_decl.get_mappings ().get_hirid (), + &lookup)) + { + rust_error_at (union_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + +void +CompileItem::visit (HIR::StructStruct &struct_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type (struct_decl.get_mappings ().get_hirid (), + &lookup)) + { + rust_error_at (struct_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h index d9d946d2514..56baaabce87 100644 --- a/gcc/rust/backend/rust-compile-item.h +++ b/gcc/rust/backend/rust-compile-item.h @@ -44,9 +44,12 @@ public: void visit (HIR::ImplBlock &impl_block) override; void visit (HIR::ExternBlock &extern_block) override; void visit (HIR::Module &module) override; + void visit (HIR::TupleStruct &tuple_struct) override; + void visit (HIR::Enum &enum_decl) override; + void visit (HIR::Union &union_decl) override; + void visit (HIR::StructStruct &struct_decl) override; // Empty visit for unused Stmt HIR nodes. - void visit (HIR::TupleStruct &) override {} void visit (HIR::EnumItem &) override {} void visit (HIR::EnumItemTuple &) override {} void visit (HIR::EnumItemStruct &) override {} @@ -57,9 +60,6 @@ public: void visit (HIR::ExternCrate &) override {} void visit (HIR::UseDeclaration &) override {} void visit (HIR::TypeAlias &) override {} - void visit (HIR::StructStruct &) override {} - void visit (HIR::Enum &) override {} - void visit (HIR::Union &) override {} void visit (HIR::Trait &) override {} void visit (HIR::EmptyStmt &) override {} void visit (HIR::LetStmt &) override {} diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 753d3915f69..eb50803814f 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -1726,16 +1726,22 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr) void TypeCheckExpr::visit (HIR::ClosureExpr &expr) { - TypeCheckContextItem current_context = context->peek_context (); - TyTy::FnType *current_context_fndecl = current_context.get_context_type (); - + std::vector subst_refs; HirId ref = expr.get_mappings ().get_hirid (); DefId id = expr.get_mappings ().get_defid (); - RustIdent ident{current_context_fndecl->get_ident ().path, expr.get_locus ()}; + RustIdent ident{CanonicalPath::create_empty (), expr.get_locus ()}; + + if (context->have_function_context ()) + { + TypeCheckContextItem current_context = context->peek_context (); + TyTy::FnType *current_context_fndecl + = current_context.get_context_type (); + + ident = RustIdent{current_context_fndecl->get_ident ().path, + expr.get_locus ()}; - // get from parent context - std::vector subst_refs - = current_context_fndecl->clone_substs (); + subst_refs = current_context_fndecl->clone_substs (); + } std::vector parameter_types; for (auto &p : expr.get_params ()) diff --git a/gcc/testsuite/rust/compile/issue-3551.rs b/gcc/testsuite/rust/compile/issue-3551.rs new file mode 100644 index 00000000000..6d6a8129885 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3551.rs @@ -0,0 +1,15 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +struct Bug { + a: [(); (|| 0)()], + // { dg-error "calls in constants are limited to constant functions, tuple structs and tuple variants" "" { target *-*-* } .-1 } +} -- 2.47.2