public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] Add support for enums on the match expression
@ 2022-06-08 11:57 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-06-08 11:57 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:52ee02f4012d0d5d4363ebb4e71e57b053acf072

commit 52ee02f4012d0d5d4363ebb4e71e57b053acf072
Author: Philip Herron <philip.herron@embecosm.com>
Date:   Tue Dec 14 21:11:04 2021 +0000

    Add support for enums on the match expression
    
    This is our initial first pass of adding support for the MatchExpr though
    two things stand out here. We need to switch over to using a GCC enumeral
    type for the union qualifier so we get advantage of the GCC code to ensure
    all variants are being addressed. We also need to fix out enum type to
    get better gdb support which might be simply chaning over to the
    qual_union_type.
    
    Fixes #190

Diff:
---
 gcc/rust/Make-lang.in                        |   1 +
 gcc/rust/backend/rust-compile-context.h      |  16 ++
 gcc/rust/backend/rust-compile-expr.cc        | 172 +++++++++++++++++++++
 gcc/rust/backend/rust-compile-expr.h         |   6 +
 gcc/rust/backend/rust-compile-pattern.cc     | 218 +++++++++++++++++++++++++++
 gcc/rust/backend/rust-compile-pattern.h      |  78 ++++++++++
 gcc/testsuite/rust/execute/torture/match1.rs |  58 +++++++
 gcc/testsuite/rust/execute/torture/match2.rs |  42 ++++++
 8 files changed, 591 insertions(+)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 391151f1af0..3554982ed4b 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -94,6 +94,7 @@ GRS_OBJS = \
     rust/rust-lint-marklive.o \
     rust/rust-hir-type-check-path.o \
     rust/rust-compile-intrinsic.o \
+    rust/rust-compile-pattern.o \
     rust/rust-base62.o \
     rust/rust-compile-expr.o \
     rust/rust-compile-type.o \
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index 6347e766f97..896d42e403b 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -233,6 +233,21 @@ public:
     return true;
   }
 
+  void insert_pattern_binding (HirId id, tree binding)
+  {
+    implicit_pattern_bindings[id] = binding;
+  }
+
+  bool lookup_pattern_binding (HirId id, tree *binding)
+  {
+    auto it = implicit_pattern_bindings.find (id);
+    if (it == implicit_pattern_bindings.end ())
+      return false;
+
+    *binding = it->second;
+    return true;
+  }
+
   void push_fn (tree fn, ::Bvariable *ret_addr)
   {
     fn_stack.push_back (fncontext{fn, ret_addr});
@@ -326,6 +341,7 @@ private:
   std::map<const TyTy::BaseType *, std::pair<HirId, tree>> mono;
   std::map<DefId, std::vector<std::pair<const TyTy::BaseType *, tree>>>
     mono_fns;
+  std::map<HirId, tree> implicit_pattern_bindings;
 
   // To GCC middle-end
   std::vector<tree> type_decls;
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index fa88e48c177..b77a4d5d57c 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -24,6 +24,9 @@
 #include "rust-hir-path-probe.h"
 #include "rust-hir-type-bounds.h"
 #include "rust-hir-dot-operator.h"
+#include "rust-compile-pattern.h"
+
+#include "fold-const.h"
 
 namespace Rust {
 namespace Compile {
@@ -154,6 +157,175 @@ CompileExpr::visit (HIR::DereferenceExpr &expr)
 						known_valid, expr.get_locus ());
 }
 
+void
+CompileExpr::visit (HIR::MatchExpr &expr)
+{
+  // https://gcc.gnu.org/onlinedocs/gccint/Basic-Statements.html#Basic-Statements
+  // TODO
+  // SWITCH_ALL_CASES_P is true if the switch includes a default label or the
+  // case label ranges cover all possible values of the condition expression
+
+  /* Switch expression.
+
+     TREE_TYPE is the original type of the condition, before any
+     language required type conversions.  It may be NULL, in which case
+     the original type and final types are assumed to be the same.
+
+     Operand 0 is the expression used to perform the branch,
+     Operand 1 is the body of the switch, which probably contains
+       CASE_LABEL_EXPRs.  It may also be NULL, in which case operand 2
+       must not be NULL.  */
+  // DEFTREECODE (SWITCH_EXPR, "switch_expr", tcc_statement, 2)
+
+  /* Used to represent a case label.
+
+     Operand 0 is CASE_LOW.  It may be NULL_TREE, in which case the label
+       is a 'default' label.
+     Operand 1 is CASE_HIGH.  If it is NULL_TREE, the label is a simple
+       (one-value) case label.  If it is non-NULL_TREE, the case is a range.
+     Operand 2 is CASE_LABEL, which has the corresponding LABEL_DECL.
+     Operand 3 is CASE_CHAIN.  This operand is only used in tree-cfg.c to
+       speed up the lookup of case labels which use a particular edge in
+       the control flow graph.  */
+  // DEFTREECODE (CASE_LABEL_EXPR, "case_label_expr", tcc_statement, 4)
+
+  TyTy::BaseType *scrutinee_expr_tyty = nullptr;
+  if (!ctx->get_tyctx ()->lookup_type (
+	expr.get_scrutinee_expr ()->get_mappings ().get_hirid (),
+	&scrutinee_expr_tyty))
+    {
+      translated = ctx->get_backend ()->error_expression ();
+      return;
+    }
+
+  rust_assert (scrutinee_expr_tyty->get_kind () == TyTy::TypeKind::ADT);
+
+  // this will need to change but for now the first pass implementation, lets
+  // assert this is the case
+  TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_expr_tyty);
+  rust_assert (adt->is_enum ());
+  rust_assert (adt->number_of_variants () > 0);
+
+  TyTy::BaseType *expr_tyty = nullptr;
+  if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
+				       &expr_tyty))
+    {
+      translated = ctx->get_backend ()->error_expression ();
+      return;
+    }
+
+  fncontext fnctx = ctx->peek_fn ();
+  Bvariable *tmp = NULL;
+  bool needs_temp = !expr_tyty->is_unit ();
+  if (needs_temp)
+    {
+      tree enclosing_scope = ctx->peek_enclosing_scope ();
+      tree block_type = TyTyResolveCompile::compile (ctx, expr_tyty);
+
+      bool is_address_taken = false;
+      tree ret_var_stmt = nullptr;
+      tmp = ctx->get_backend ()->temporary_variable (
+	fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
+	expr.get_locus (), &ret_var_stmt);
+      ctx->add_statement (ret_var_stmt);
+    }
+
+  // lets compile the scrutinee expression
+  tree match_scrutinee_expr
+    = CompileExpr::Compile (expr.get_scrutinee_expr ().get (), ctx);
+
+  // need to access the qualifier field, if we use QUAL_UNION_TYPE this would be
+  // DECL_QUALIFIER i think. For now this will just access the first record
+  // field and its respective qualifier because it will always be set because
+  // this is all a big special union
+  tree scrutinee_first_record_expr
+    = ctx->get_backend ()->struct_field_expression (
+      match_scrutinee_expr, 0, expr.get_scrutinee_expr ()->get_locus ());
+  tree match_scrutinee_expr_qualifier_expr
+    = ctx->get_backend ()->struct_field_expression (
+      scrutinee_first_record_expr, 0, expr.get_scrutinee_expr ()->get_locus ());
+
+  // setup the end label so the cases can exit properly
+  tree fndecl = fnctx.fndecl;
+  Location end_label_locus = expr.get_locus (); // FIXME
+  tree end_label
+    = ctx->get_backend ()->label (fndecl,
+				  "" /* empty creates an artificial label */,
+				  end_label_locus);
+  tree end_label_decl_statement
+    = ctx->get_backend ()->label_definition_statement (end_label);
+
+  // setup the switch-body-block
+  Location start_location; // FIXME
+  Location end_location;   // FIXME
+  tree enclosing_scope = ctx->peek_enclosing_scope ();
+  tree switch_body_block
+    = ctx->get_backend ()->block (fndecl, enclosing_scope, {}, start_location,
+				  end_location);
+  ctx->push_block (switch_body_block);
+
+  for (auto &kase : expr.get_match_cases ())
+    {
+      // for now lets just get single pattern's working
+      HIR::MatchArm &kase_arm = kase.get_arm ();
+      rust_assert (kase_arm.get_patterns ().size () > 0);
+
+      // generate implicit label
+      Location arm_locus = kase_arm.get_patterns ().at (0)->get_locus ();
+      tree case_label = ctx->get_backend ()->label (
+	fndecl, "" /* empty creates an artificial label */, arm_locus);
+
+      // not sure if we need to add this to the block or if the CASE_LABEL_EXPR
+      // does this implicitly
+      //
+      // tree case_label_decl_statement
+      //   = ctx->get_backend ()->label_definition_statement (case_label);
+
+      // setup the bindings for the block
+      for (auto &kase_pattern : kase_arm.get_patterns ())
+	{
+	  tree switch_kase_expr
+	    = CompilePatternCaseLabelExpr::Compile (kase_pattern.get (),
+						    case_label, ctx);
+	  // ctx->add_statement (case_label_decl_statement);
+	  ctx->add_statement (switch_kase_expr);
+
+	  CompilePatternBindings::Compile (kase_pattern.get (),
+					   match_scrutinee_expr, ctx);
+	}
+
+      // compile the expr and setup the assignment if required when tmp != NULL
+      tree kase_expr_tree = CompileExpr::Compile (kase.get_expr ().get (), ctx);
+      if (tmp != NULL)
+	{
+	  tree result_reference
+	    = ctx->get_backend ()->var_expression (tmp, arm_locus);
+	  tree assignment = ctx->get_backend ()->assignment_statement (
+	    fnctx.fndecl, result_reference, kase_expr_tree, arm_locus);
+	  ctx->add_statement (assignment);
+	}
+
+      // go to end label
+      tree goto_end_label = build1_loc (arm_locus.gcc_location (), GOTO_EXPR,
+					void_type_node, end_label);
+      ctx->add_statement (goto_end_label);
+    }
+
+  // setup the switch expression
+  tree match_body = ctx->pop_block ();
+  tree match_expr_stmt
+    = build2_loc (expr.get_locus ().gcc_location (), SWITCH_EXPR,
+		  TREE_TYPE (match_scrutinee_expr_qualifier_expr),
+		  match_scrutinee_expr_qualifier_expr, match_body);
+  ctx->add_statement (match_expr_stmt);
+  ctx->add_statement (end_label_decl_statement);
+
+  if (tmp != NULL)
+    {
+      translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
+    }
+}
+
 void
 CompileExpr::visit (HIR::CallExpr &expr)
 {
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h
index 9895540fecf..dc4f90937c2 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -221,6 +221,10 @@ public:
 	translated
 	  = ctx->get_backend ()->var_expression (var, expr.get_locus ());
       }
+    else if (ctx->lookup_pattern_binding (ref, &translated))
+      {
+	return;
+      }
     else
       {
 	rust_fatal_error (expr.get_locus (),
@@ -1043,6 +1047,8 @@ public:
 
   void visit (HIR::DereferenceExpr &expr) override;
 
+  void visit (HIR::MatchExpr &expr) override;
+
 protected:
   tree compile_dyn_dispatch_call (const TyTy::DynamicObjectType *dyn,
 				  TyTy::BaseType *receiver,
diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc
new file mode 100644
index 00000000000..e634dbd03c3
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-pattern.cc
@@ -0,0 +1,218 @@
+// Copyright (C) 2020-2021 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-pattern.h"
+
+namespace Rust {
+namespace Compile {
+
+void
+CompilePatternCaseLabelExpr::visit (HIR::PathInExpression &pattern)
+{
+  // lookup the type
+  TyTy::BaseType *lookup = nullptr;
+  bool ok
+    = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
+				      &lookup);
+  rust_assert (ok);
+
+  // 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 ());
+
+  // lookup the variant
+  HirId variant_id;
+  ok = ctx->get_tyctx ()->lookup_variant_definition (
+    pattern.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);
+
+  mpz_t disciminantl;
+  if (variant->get_variant_type () == TyTy::VariantDef::VariantType::NUM)
+    {
+      mpz_init_set_ui (disciminantl, variant->get_discriminant ());
+    }
+  else
+    {
+      HirId variant_id = variant->get_id ();
+      mpz_init_set_ui (disciminantl, variant_id);
+    }
+
+  tree t = TyTyResolveCompile::get_implicit_enumeral_node_type (ctx);
+  tree case_low
+    = double_int_to_tree (t, mpz_get_double_int (t, disciminantl, true));
+
+  case_label_expr
+    = build_case_label (case_low, NULL_TREE, associated_case_label);
+}
+
+void
+CompilePatternCaseLabelExpr::visit (HIR::StructPattern &pattern)
+{
+  CompilePatternCaseLabelExpr::visit (pattern.get_path ());
+}
+
+void
+CompilePatternCaseLabelExpr::visit (HIR::TupleStructPattern &pattern)
+{
+  CompilePatternCaseLabelExpr::visit (pattern.get_path ());
+}
+
+// setup the bindings
+
+void
+CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
+{
+  // lookup the type
+  TyTy::BaseType *lookup = nullptr;
+  bool ok = ctx->get_tyctx ()->lookup_type (
+    pattern.get_path ().get_mappings ().get_hirid (), &lookup);
+  rust_assert (ok);
+
+  // 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 ());
+
+  // 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 = -1;
+  TyTy::VariantDef *variant = nullptr;
+  ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
+  rust_assert (ok);
+
+  rust_assert (variant->get_variant_type ()
+	       == TyTy::VariantDef::VariantType::TUPLE);
+
+  std::unique_ptr<HIR::TupleStructItems> &items = pattern.get_items ();
+  switch (items->get_item_type ())
+    {
+      case HIR::TupleStructItems::RANGE: {
+	// TODO
+	gcc_unreachable ();
+      }
+      break;
+
+      case HIR::TupleStructItems::NO_RANGE: {
+	HIR::TupleStructItemsNoRange &items_no_range
+	  = static_cast<HIR::TupleStructItemsNoRange &> (*items.get ());
+
+	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 ())
+	  {
+	    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);
+	  }
+      }
+      break;
+    }
+}
+
+void
+CompilePatternBindings::visit (HIR::StructPattern &pattern)
+{
+  // lookup the type
+  TyTy::BaseType *lookup = nullptr;
+  bool ok = ctx->get_tyctx ()->lookup_type (
+    pattern.get_path ().get_mappings ().get_hirid (), &lookup);
+  rust_assert (ok);
+
+  // 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 ());
+
+  // 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 = -1;
+  TyTy::VariantDef *variant = nullptr;
+  ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
+  rust_assert (ok);
+
+  rust_assert (variant->get_variant_type ()
+	       == TyTy::VariantDef::VariantType::STRUCT);
+
+  auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
+  for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
+    {
+      switch (field->get_item_type ())
+	{
+	  case HIR::StructPatternField::ItemType::TUPLE_PAT: {
+	    // TODO
+	    gcc_unreachable ();
+	  }
+	  break;
+
+	  case HIR::StructPatternField::ItemType::IDENT_PAT: {
+	    // TODO
+	    gcc_unreachable ();
+	  }
+	  break;
+
+	  case HIR::StructPatternField::ItemType::IDENT: {
+	    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 ());
+
+	    ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (),
+					 binding);
+	  }
+	  break;
+	}
+    }
+}
+
+} // namespace Compile
+} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/rust-compile-pattern.h
new file mode 100644
index 00000000000..e49f75c70c7
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-pattern.h
@@ -0,0 +1,78 @@
+// Copyright (C) 2020-2021 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-base.h"
+
+namespace Rust {
+namespace Compile {
+
+class CompilePatternCaseLabelExpr : public HIRCompileBase
+{
+  using Rust::Compile::HIRCompileBase::visit;
+
+public:
+  static tree Compile (HIR::Pattern *pattern, tree associated_case_label,
+		       Context *ctx)
+  {
+    CompilePatternCaseLabelExpr compiler (ctx, associated_case_label);
+    pattern->accept_vis (compiler);
+    return compiler.case_label_expr;
+  }
+
+  void visit (HIR::PathInExpression &pattern) override;
+
+  void visit (HIR::StructPattern &pattern) override;
+
+  void visit (HIR::TupleStructPattern &pattern) override;
+
+private:
+  CompilePatternCaseLabelExpr (Context *ctx, tree associated_case_label)
+    : HIRCompileBase (ctx), case_label_expr (error_mark_node),
+      associated_case_label (associated_case_label)
+  {}
+
+  tree case_label_expr;
+  tree associated_case_label;
+};
+
+class CompilePatternBindings : public HIRCompileBase
+{
+  using Rust::Compile::HIRCompileBase::visit;
+
+public:
+  static void Compile (HIR::Pattern *pattern, tree match_scrutinee_expr,
+		       Context *ctx)
+  {
+    CompilePatternBindings compiler (ctx, match_scrutinee_expr);
+    pattern->accept_vis (compiler);
+  }
+
+  void visit (HIR::StructPattern &pattern) override;
+
+  void visit (HIR::TupleStructPattern &pattern) override;
+
+private:
+  CompilePatternBindings (Context *ctx, tree match_scrutinee_expr)
+    : HIRCompileBase (ctx), match_scrutinee_expr (match_scrutinee_expr)
+  {}
+
+  tree match_scrutinee_expr;
+};
+
+} // namespace Compile
+} // namespace Rust
diff --git a/gcc/testsuite/rust/execute/torture/match1.rs b/gcc/testsuite/rust/execute/torture/match1.rs
new file mode 100644
index 00000000000..2393b157324
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/match1.rs
@@ -0,0 +1,58 @@
+// { dg-output "Foo::A\nFoo::B\nFoo::C x\nFoo::D 20 80\n" }
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+enum Foo {
+    A,
+    B,
+    C(char),
+    D { x: i64, y: i64 },
+}
+
+fn inspect(f: Foo) {
+    match f {
+        Foo::A => unsafe {
+            let a = "Foo::A\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        },
+        Foo::B => unsafe {
+            let a = "Foo::B\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        },
+        Foo::C(x) => unsafe {
+            let a = "Foo::C %c\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c, x);
+        },
+        Foo::D { x, y } => unsafe {
+            let a = "Foo::D %i %i\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c, x, y);
+        },
+    }
+}
+
+fn main() -> i32 {
+    let a = Foo::A;
+    let b = Foo::B;
+    let c = Foo::C('x');
+    let d = Foo::D { x: 20, y: 80 };
+
+    inspect(a);
+    inspect(b);
+    inspect(c);
+    inspect(d);
+
+    0
+}
diff --git a/gcc/testsuite/rust/execute/torture/match2.rs b/gcc/testsuite/rust/execute/torture/match2.rs
new file mode 100644
index 00000000000..4a018c13cd2
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/match2.rs
@@ -0,0 +1,42 @@
+// { dg-output "123\n80\n" }
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+enum Foo {
+    C(i32),
+    D { x: i32, y: i32 },
+}
+
+fn inspect(f: Foo) -> i32 {
+    match f {
+        Foo::C(x) => x,
+        Foo::D { x, y } => y,
+        // { dg-warning "unused name .x." "" { target *-*-* } .-1 }
+    }
+}
+
+fn main() -> i32 {
+    let a = Foo::C(123);
+    let b = Foo::D { x: 20, y: 80 };
+
+    let result = inspect(a);
+    unsafe {
+        let a = "%i\n\0";
+        let b = a as *const str;
+        let c = b as *const i8;
+
+        printf(c, result);
+    }
+
+    let result = inspect(b);
+    unsafe {
+        let a = "%i\n\0";
+        let b = a as *const str;
+        let c = b as *const i8;
+
+        printf(c, result);
+    }
+
+    0
+}


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

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

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 11:57 [gcc/devel/rust/master] Add support for enums on the match expression 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).