From: Philip Herron <herron.phi...@googlemail.com>

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.phi...@googlemail.com>
---
 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<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
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<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 }
+}
-- 
2.49.0

Reply via email to