public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] Support pattern bindings within function signitures
@ 2022-06-08 12:33 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-06-08 12:33 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:c3a3e1053f41819d1f6ff8fa68bcd4aca9fc5f80

commit c3a3e1053f41819d1f6ff8fa68bcd4aca9fc5f80
Author: Philip Herron <philip.herron@embecosm.com>
Date:   Tue Apr 19 16:32:50 2022 +0100

    Support pattern bindings within function signitures
    
    This reuses our code to handle match-arams within MatchExpressions, we
    resolve the pattern's type's and implicitly create types for that binding.
    For code-generation we create a tmp var name for the name of the parameter
    which is the base type and for the destructuring we reuse the same match
    arm code to generate the implicit bindings to the parts of the structure
    
    ```c
    __attribute__((cdecl))
    i32 test::pattern_as_arg (const struct test::Pattern RSTPRM.0)
    {
        i32 RUSTTMP.1;
      return RSTPRM.0.0;
    }
    ```
    
    Fixes #995

Diff:
---
 gcc/rust/Make-lang.in                             |   1 +
 gcc/rust/backend/rust-compile-fnparam.cc          |  62 ++++++++++++
 gcc/rust/backend/rust-compile-fnparam.h           |   5 +-
 gcc/rust/backend/rust-compile-pattern.cc          | 111 ++++++++++++++--------
 gcc/rust/backend/rust-compile-pattern.h           |   2 +-
 gcc/rust/typecheck/rust-hir-type-check-implitem.h |   4 +
 gcc/rust/typecheck/rust-hir-type-check-pattern.cc |  40 ++++----
 gcc/rust/typecheck/rust-hir-type-check-stmt.h     |   1 +
 gcc/rust/typecheck/rust-hir-type-check-toplevel.h |   1 +
 gcc/rust/typecheck/rust-hir-type-check.cc         |   1 +
 gcc/testsuite/rust/execute/torture/issue-995.rs   |   9 ++
 11 files changed, 177 insertions(+), 60 deletions(-)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 840a2452f96..10326acd8ac 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -110,6 +110,7 @@ GRS_OBJS = \
     rust/rust-hir-type-check-path.o \
     rust/rust-compile-intrinsic.o \
     rust/rust-compile-pattern.o \
+    rust/rust-compile-fnparam.o \
     rust/rust-base62.o \
     rust/rust-compile-item.o \
     rust/rust-compile-implitem.o \
diff --git a/gcc/rust/backend/rust-compile-fnparam.cc b/gcc/rust/backend/rust-compile-fnparam.cc
new file mode 100644
index 00000000000..b1b55232850
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-fnparam.cc
@@ -0,0 +1,62 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-compile-fnparam.h"
+#include "rust-compile-pattern.h"
+
+#include "gimple-expr.h"
+
+namespace Rust {
+namespace Compile {
+
+void
+CompileFnParam::visit (HIR::StructPattern &pattern)
+{
+  // generate the anon param
+  tree tmp_ident = create_tmp_var_name ("RSTPRM");
+  std::string cpp_str_identifier = std::string (IDENTIFIER_POINTER (tmp_ident));
+
+  decl_type = ctx->get_backend ()->immutable_type (decl_type);
+  compiled_param
+    = ctx->get_backend ()->parameter_variable (fndecl, cpp_str_identifier,
+					       decl_type, locus);
+
+  // setup the pattern bindings
+  tree anon_param = ctx->get_backend ()->var_expression (compiled_param, locus);
+  CompilePatternBindings::Compile (&pattern, anon_param, ctx);
+}
+
+void
+CompileFnParam::visit (HIR::TupleStructPattern &pattern)
+{
+  // generate the anon param
+  tree tmp_ident = create_tmp_var_name ("RSTPRM");
+  std::string cpp_str_identifier = std::string (IDENTIFIER_POINTER (tmp_ident));
+
+  decl_type = ctx->get_backend ()->immutable_type (decl_type);
+  compiled_param
+    = ctx->get_backend ()->parameter_variable (fndecl, cpp_str_identifier,
+					       decl_type, locus);
+
+  // setup the pattern bindings
+  tree anon_param = ctx->get_backend ()->var_expression (compiled_param, locus);
+  CompilePatternBindings::Compile (&pattern, anon_param, ctx);
+}
+
+} // namespace Compile
+} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-fnparam.h b/gcc/rust/backend/rust-compile-fnparam.h
index 5e3cfaa2f3d..7c4a43a973c 100644
--- a/gcc/rust/backend/rust-compile-fnparam.h
+++ b/gcc/rust/backend/rust-compile-fnparam.h
@@ -63,6 +63,9 @@ public:
       = ctx->get_backend ()->parameter_variable (fndecl, "_", decl_type, locus);
   }
 
+  void visit (HIR::StructPattern &) override;
+  void visit (HIR::TupleStructPattern &) override;
+
   // Empty visit for unused Pattern HIR nodes.
   void visit (HIR::GroupedPattern &) override {}
   void visit (HIR::LiteralPattern &) override {}
@@ -71,9 +74,7 @@ public:
   void visit (HIR::RangePattern &) override {}
   void visit (HIR::ReferencePattern &) override {}
   void visit (HIR::SlicePattern &) override {}
-  void visit (HIR::StructPattern &) override {}
   void visit (HIR::TuplePattern &) override {}
-  void visit (HIR::TupleStructPattern &) override {}
 
 private:
   CompileFnParam (Context *ctx, tree fndecl, tree decl_type, Location locus)
diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc
index d715c7c4f20..393fbd5d517 100644
--- a/gcc/rust/backend/rust-compile-pattern.cc
+++ b/gcc/rust/backend/rust-compile-pattern.cc
@@ -20,6 +20,8 @@
 #include "rust-compile-expr.h"
 #include "rust-constexpr.h"
 
+#include "print-tree.h"
+
 namespace Rust {
 namespace Compile {
 
@@ -92,18 +94,20 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
   // this must be an enum
   rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
-  rust_assert (adt->is_enum ());
+  rust_assert (adt->number_of_variants () > 0);
 
-  // lookup the variant
-  HirId variant_id;
-  ok = ctx->get_tyctx ()->lookup_variant_definition (
-    pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
-  rust_assert (ok);
+  int variant_index = 0;
+  TyTy::VariantDef *variant = adt->get_variants ().at (0);
+  if (adt->is_enum ())
+    {
+      HirId variant_id = UNKNOWN_HIRID;
+      bool ok = ctx->get_tyctx ()->lookup_variant_definition (
+	pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
+      rust_assert (ok);
 
-  int variant_index = -1;
-  TyTy::VariantDef *variant = nullptr;
-  ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
-  rust_assert (ok);
+      ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
+      rust_assert (ok);
+    }
 
   rust_assert (variant->get_variant_type ()
 	       == TyTy::VariantDef::VariantType::TUPLE);
@@ -124,20 +128,37 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
 	rust_assert (items_no_range.get_patterns ().size ()
 		     == variant->num_fields ());
 
-	// we are offsetting by + 1 here since the first field in the record
-	// is always the discriminator
-	size_t tuple_field_index = 1;
-	for (auto &pattern : items_no_range.get_patterns ())
+	if (adt->is_enum ())
+	  {
+	    // we are offsetting by + 1 here since the first field in the record
+	    // is always the discriminator
+	    size_t tuple_field_index = 1;
+	    for (auto &pattern : items_no_range.get_patterns ())
+	      {
+		tree variant_accessor
+		  = ctx->get_backend ()->struct_field_expression (
+		    match_scrutinee_expr, variant_index, pattern->get_locus ());
+
+		tree binding = ctx->get_backend ()->struct_field_expression (
+		  variant_accessor, tuple_field_index++, pattern->get_locus ());
+
+		ctx->insert_pattern_binding (
+		  pattern->get_pattern_mappings ().get_hirid (), binding);
+	      }
+	  }
+	else
 	  {
-	    tree variant_accessor
-	      = ctx->get_backend ()->struct_field_expression (
-		match_scrutinee_expr, variant_index, pattern->get_locus ());
+	    size_t tuple_field_index = 0;
+	    for (auto &pattern : items_no_range.get_patterns ())
+	      {
+		tree variant_accessor = match_scrutinee_expr;
 
-	    tree binding = ctx->get_backend ()->struct_field_expression (
-	      variant_accessor, tuple_field_index++, pattern->get_locus ());
+		tree binding = ctx->get_backend ()->struct_field_expression (
+		  variant_accessor, tuple_field_index++, pattern->get_locus ());
 
-	    ctx->insert_pattern_binding (
-	      pattern->get_pattern_mappings ().get_hirid (), binding);
+		ctx->insert_pattern_binding (
+		  pattern->get_pattern_mappings ().get_hirid (), binding);
+	      }
 	  }
       }
       break;
@@ -156,18 +177,20 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern)
   // this must be an enum
   rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
-  rust_assert (adt->is_enum ());
+  rust_assert (adt->number_of_variants () > 0);
 
-  // lookup the variant
-  HirId variant_id;
-  ok = ctx->get_tyctx ()->lookup_variant_definition (
-    pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
-  rust_assert (ok);
+  int variant_index = 0;
+  TyTy::VariantDef *variant = adt->get_variants ().at (0);
+  if (adt->is_enum ())
+    {
+      HirId variant_id = UNKNOWN_HIRID;
+      bool ok = ctx->get_tyctx ()->lookup_variant_definition (
+	pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
+      rust_assert (ok);
 
-  int variant_index = -1;
-  TyTy::VariantDef *variant = nullptr;
-  ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
-  rust_assert (ok);
+      ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
+      rust_assert (ok);
+    }
 
   rust_assert (variant->get_variant_type ()
 	       == TyTy::VariantDef::VariantType::STRUCT);
@@ -193,19 +216,29 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern)
 	    HIR::StructPatternFieldIdent &ident
 	      = static_cast<HIR::StructPatternFieldIdent &> (*field.get ());
 
-	    tree variant_accessor
-	      = ctx->get_backend ()->struct_field_expression (
-		match_scrutinee_expr, variant_index, ident.get_locus ());
-
 	    size_t offs = 0;
 	    ok
 	      = variant->lookup_field (ident.get_identifier (), nullptr, &offs);
 	    rust_assert (ok);
 
-	    // we are offsetting by + 1 here since the first field in the record
-	    // is always the discriminator
-	    tree binding = ctx->get_backend ()->struct_field_expression (
-	      variant_accessor, offs + 1, ident.get_locus ());
+	    tree binding = error_mark_node;
+	    if (adt->is_enum ())
+	      {
+		tree variant_accessor
+		  = ctx->get_backend ()->struct_field_expression (
+		    match_scrutinee_expr, variant_index, ident.get_locus ());
+
+		// we are offsetting by + 1 here since the first field in the
+		// record is always the discriminator
+		binding = ctx->get_backend ()->struct_field_expression (
+		  variant_accessor, offs + 1, ident.get_locus ());
+	      }
+	    else
+	      {
+		tree variant_accessor = match_scrutinee_expr;
+		binding = ctx->get_backend ()->struct_field_expression (
+		  variant_accessor, offs, ident.get_locus ());
+	      }
 
 	    ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (),
 					 binding);
diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/rust-compile-pattern.h
index 36e4ef3a5ae..5bff317fe98 100644
--- a/gcc/rust/backend/rust-compile-pattern.h
+++ b/gcc/rust/backend/rust-compile-pattern.h
@@ -83,7 +83,7 @@ public:
   void visit (HIR::TuplePattern &) override {}
   void visit (HIR::WildcardPattern &) override {}
 
-private:
+protected:
   CompilePatternBindings (Context *ctx, tree match_scrutinee_expr)
     : HIRCompileBase (ctx), match_scrutinee_expr (match_scrutinee_expr)
   {}
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
index f1b5e35450e..0a350458f31 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
@@ -116,6 +116,9 @@ public:
 						       param_tyty));
 
 	context->insert_type (param.get_mappings (), param_tyty);
+
+	// FIXME do we need error checking for patterns here?
+	// see https://github.com/Rust-GCC/gccrs/issues/995
       }
 
     uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG;
@@ -297,6 +300,7 @@ public:
 						       param_tyty));
 
 	context->insert_type (param.get_mappings (), param_tyty);
+	TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
       }
 
     const CanonicalPath *canonical_path = nullptr;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
index e4ec49bc5c1..feedbc5b899 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
@@ -37,17 +37,19 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
 
   rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
-  rust_assert (adt->is_enum ());
+  rust_assert (adt->number_of_variants () > 0);
 
-  // what variant is this?
-  HirId variant_id;
-  bool ok = context->lookup_variant_definition (
-    pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
-  rust_assert (ok);
+  TyTy::VariantDef *variant = adt->get_variants ().at (0);
+  if (adt->is_enum ())
+    {
+      HirId variant_id = UNKNOWN_HIRID;
+      bool ok = context->lookup_variant_definition (
+	pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
+      rust_assert (ok);
 
-  TyTy::VariantDef *variant = nullptr;
-  ok = adt->lookup_variant_by_id (variant_id, &variant);
-  rust_assert (ok);
+      ok = adt->lookup_variant_by_id (variant_id, &variant);
+      rust_assert (ok);
+    }
 
   // error[E0532]: expected tuple struct or tuple variant, found struct variant
   // `Foo::D`
@@ -121,17 +123,19 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
 
   rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
-  rust_assert (adt->is_enum ());
+  rust_assert (adt->number_of_variants () > 0);
 
-  // what variant is this?
-  HirId variant_id;
-  bool ok = context->lookup_variant_definition (
-    pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
-  rust_assert (ok);
+  TyTy::VariantDef *variant = adt->get_variants ().at (0);
+  if (adt->is_enum ())
+    {
+      HirId variant_id = UNKNOWN_HIRID;
+      bool ok = context->lookup_variant_definition (
+	pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
+      rust_assert (ok);
 
-  TyTy::VariantDef *variant = nullptr;
-  ok = adt->lookup_variant_by_id (variant_id, &variant);
-  rust_assert (ok);
+      ok = adt->lookup_variant_by_id (variant_id, &variant);
+      rust_assert (ok);
+    }
 
   // error[E0532]: expected tuple struct or tuple variant, found struct variant
   // `Foo::D`
diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
index f2196b7908f..42987716f4f 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
@@ -448,6 +448,7 @@ public:
 						       param_tyty));
 
 	context->insert_type (param.get_mappings (), param_tyty);
+	TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
       }
 
     // get the path
diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
index 5e124663fe7..40aaa872d84 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
@@ -416,6 +416,7 @@ public:
 						       param_tyty));
 
 	context->insert_type (param.get_mappings (), param_tyty);
+	TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
       }
 
     const CanonicalPath *canonical_path = nullptr;
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
index 6666603f562..b09ffc76481 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -320,6 +320,7 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const
 						     param_tyty));
 
       context->insert_type (param.get_mappings (), param_tyty);
+      TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
     }
 
   auto mappings = Analysis::Mappings::get ();
diff --git a/gcc/testsuite/rust/execute/torture/issue-995.rs b/gcc/testsuite/rust/execute/torture/issue-995.rs
new file mode 100644
index 00000000000..42570e33f74
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/issue-995.rs
@@ -0,0 +1,9 @@
+struct Pattern(i32);
+
+fn pattern_as_arg(Pattern(value): Pattern) -> i32 {
+    value
+}
+
+fn main() -> i32 {
+    pattern_as_arg(Pattern(15)) - 15
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-08 12:33 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 12:33 [gcc/devel/rust/master] Support pattern bindings within function signitures Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).