diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index a062694f706..82a4d6bf3c6 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -111,6 +111,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
+// .
+
+#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 (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 ())
{
- tree variant_accessor
- = ctx->get_backend ()->struct_field_expression (
- match_scrutinee_expr, variant_index, pattern->get_locus ());
+ // 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 ());
+ 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);
+ }
+ }
+ else
+ {
+ 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 ());
+
+ 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 (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 (*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 52c866cb40d..db055053e63 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 (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 (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
+}