]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: check for invalid const calls during code-gen
authorPhilip Herron <herron.philip@googlemail.com>
Mon, 23 Jun 2025 10:21:02 +0000 (11:21 +0100)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 5 Aug 2025 14:36:51 +0000 (16:36 +0200)
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 <herron.philip@googlemail.com>
gcc/rust/backend/rust-compile-expr.cc
gcc/rust/backend/rust-compile-item.cc
gcc/rust/backend/rust-compile-item.h
gcc/rust/typecheck/rust-hir-type-check-expr.cc
gcc/testsuite/rust/compile/issue-3551.rs [new file with mode: 0644]

index d8ddab5bd9aa13c041fa3a6909bfc287a84bc3ae..7a1e5a70ab69e7ef94ceae38a7220226ac44a3e6 100644 (file)
@@ -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
index 3e7ea9a25e9347155f0e26fc288d3041f758c569..78f6f571e9ce7b0066f6505871ced986570ae260 100644 (file)
@@ -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
index d9d946d251401ebc79af58de43482aa682b2a5d4..56baaabce8771c8479b6f116efaddf9fefedd345 100644 (file)
@@ -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 {}
index 753d3915f69fa2a2dabbbb03c49d227d88942e0f..eb50803814f42c155c126401ad6fd4558f2f5d90 100644 (file)
@@ -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<TyTy::SubstitutionParamMapping> 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<TyTy::SubstitutionParamMapping> subst_refs
-    = current_context_fndecl->clone_substs ();
+      subst_refs = current_context_fndecl->clone_substs ();
+    }
 
   std::vector<TyTy::TyVar> 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 (file)
index 0000000..6d6a812
--- /dev/null
@@ -0,0 +1,15 @@
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "fn_once"]
+pub trait FnOnce<Args> {
+    #[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 }
+}