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 +}