Make HIT EnumItem class an Item, not VisItem like in the AST. At the HIR level EnumItems shouldn't have visibility anymore.
Move struct_field_name_exists to rust-ast-lower.cc with the declaration in rust-ast-lower.h to make it reusable in the different visitors. Add a new ASTLoweringEnumItem that can be used from ASTLoweringItem and ASTLoweringStmt. It checks the EnumItems don't have visibility and that EnumItemStruct fields are not duplicated. Add a new testcase 'bad_pub_enumitems.rs' to check the no-visibility and no-duplicates properties hold. --- gcc/rust/hir/rust-ast-lower-enumitem.h | 192 ++++++++++++++++++ gcc/rust/hir/rust-ast-lower-item.h | 59 ++++-- gcc/rust/hir/rust-ast-lower-stmt.h | 58 ++++-- gcc/rust/hir/rust-ast-lower.cc | 20 ++ gcc/rust/hir/rust-ast-lower.h | 5 + gcc/rust/hir/tree/rust-hir-full-test.cc | 19 +- gcc/rust/hir/tree/rust-hir-item.h | 58 +++--- .../rust/compile/bad_pub_enumitems.rs | 47 +++++ 8 files changed, 376 insertions(+), 82 deletions(-) create mode 100644 gcc/rust/hir/rust-ast-lower-enumitem.h create mode 100644 gcc/testsuite/rust/compile/bad_pub_enumitems.rs diff --git a/gcc/rust/hir/rust-ast-lower-enumitem.h b/gcc/rust/hir/rust-ast-lower-enumitem.h new file mode 100644 index 00000000000..333cb7ba3fb --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-enumitem.h @@ -0,0 +1,192 @@ +// Copyright (C) 2020 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/>. + +#ifndef RUST_AST_LOWER_ENUMITEM +#define RUST_AST_LOWER_ENUMITEM + +#include "rust-diagnostics.h" + +#include "rust-ast-lower-base.h" +#include "rust-ast-lower-type.h" +#include "rust-ast-lower-expr.h" +#include "rust-hir-full-decls.h" + +namespace Rust { +namespace HIR { + +class ASTLoweringEnumItem : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::EnumItem *translate (AST::EnumItem *item) + { + ASTLoweringEnumItem resolver; + item->accept_vis (resolver); + return resolver.translated; + } + + void visit (AST::EnumItem &item) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + if (item.has_visibility ()) + rust_error_at (item.get_locus (), + "visibility qualifier %qs not allowed on enum item", + item.get_vis ().as_string ().c_str ()); + + translated = new HIR::EnumItem (mapping, item.get_identifier (), + item.get_outer_attrs (), item.get_locus ()); + + mappings->insert_defid_mapping (mapping.get_defid (), translated); + mappings->insert_hir_item (mapping.get_crate_num (), mapping.get_hirid (), + translated); + mappings->insert_location (crate_num, mapping.get_hirid (), + item.get_locus ()); + } + + void visit (AST::EnumItemTuple &item) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + if (item.has_visibility ()) + rust_error_at (item.get_locus (), + "visibility qualifier %qs not allowed on enum item", + item.get_vis ().as_string ().c_str ()); + + std::vector<HIR::TupleField> fields; + for (auto &field : item.get_tuple_fields ()) + { + HIR::Visibility vis = HIR::Visibility::create_public (); + HIR::Type *type + = ASTLoweringType::translate (field.get_field_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping field_mapping ( + crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + HIR::TupleField translated_field (field_mapping, + std::unique_ptr<HIR::Type> (type), + vis, field.get_locus (), + field.get_outer_attrs ()); + fields.push_back (std::move (translated_field)); + } + + translated + = new HIR::EnumItemTuple (mapping, item.get_identifier (), + std::move (fields), item.get_outer_attrs (), + item.get_locus ()); + + mappings->insert_defid_mapping (mapping.get_defid (), translated); + mappings->insert_hir_item (mapping.get_crate_num (), mapping.get_hirid (), + translated); + mappings->insert_location (crate_num, mapping.get_hirid (), + item.get_locus ()); + } + + void visit (AST::EnumItemStruct &item) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + if (item.has_visibility ()) + rust_error_at (item.get_locus (), + "visibility qualifier %qs not allowed on enum item", + item.get_vis ().as_string ().c_str ()); + + std::vector<HIR::StructField> fields; + for (auto &field : item.get_struct_fields ()) + { + HIR::Visibility vis = HIR::Visibility::create_public (); + HIR::Type *type + = ASTLoweringType::translate (field.get_field_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping field_mapping ( + crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + HIR::StructField translated_field (field_mapping, + field.get_field_name (), + std::unique_ptr<HIR::Type> (type), + vis, field.get_locus (), + field.get_outer_attrs ()); + + if (struct_field_name_exists (fields, translated_field)) + break; + + fields.push_back (std::move (translated_field)); + } + + translated + = new HIR::EnumItemStruct (mapping, item.get_identifier (), + std::move (fields), item.get_outer_attrs (), + item.get_locus ()); + + mappings->insert_defid_mapping (mapping.get_defid (), translated); + mappings->insert_hir_item (mapping.get_crate_num (), mapping.get_hirid (), + translated); + mappings->insert_location (crate_num, mapping.get_hirid (), + item.get_locus ()); + } + void visit (AST::EnumItemDiscriminant &item) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + if (item.has_visibility ()) + rust_error_at (item.get_locus (), + "visibility qualifier %qs not allowed on enum item", + item.get_vis ().as_string ().c_str ()); + + HIR::Expr *expr = ASTLoweringExpr::translate (item.get_expr ().get ()); + translated + = new HIR::EnumItemDiscriminant (mapping, item.get_identifier (), + std::unique_ptr<HIR::Expr> (expr), + item.get_outer_attrs (), + item.get_locus ()); + + mappings->insert_defid_mapping (mapping.get_defid (), translated); + mappings->insert_hir_item (mapping.get_crate_num (), mapping.get_hirid (), + translated); + mappings->insert_location (crate_num, mapping.get_hirid (), + item.get_locus ()); + } + +private: + ASTLoweringEnumItem () : translated (nullptr) {} + HIR::EnumItem *translated; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_ENUMITEM diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h index 7efcffaf05b..2b56cbbf203 100644 --- a/gcc/rust/hir/rust-ast-lower-item.h +++ b/gcc/rust/hir/rust-ast-lower-item.h @@ -22,6 +22,7 @@ #include "rust-diagnostics.h" #include "rust-ast-lower-base.h" +#include "rust-ast-lower-enumitem.h" #include "rust-ast-lower-type.h" #include "rust-ast-lower-implitem.h" #include "rust-ast-lower-stmt.h" @@ -175,25 +176,6 @@ public: struct_decl.get_locus ()); } - /* Checks whether the name of a field already exists. Returns true - and produces an error if so. */ - static bool struct_field_name_exists (std::vector<HIR::StructField> &fields, - HIR::StructField &new_field) - { - for (auto &field : fields) - { - if (field.get_field_name ().compare (new_field.get_field_name ()) == 0) - { - RichLocation r (new_field.get_locus ()); - r.add_range (field.get_locus ()); - rust_error_at (r, "duplicate field name %qs", - field.get_field_name ().c_str ()); - return true; - } - } - return false; - } - void visit (AST::StructStruct &struct_decl) override { std::vector<std::unique_ptr<HIR::GenericParam> > generic_params; @@ -251,6 +233,45 @@ public: struct_decl.get_locus ()); } + void visit (AST::Enum &enum_decl) override + { + std::vector<std::unique_ptr<HIR::GenericParam>> generic_params; + if (enum_decl.has_generics ()) + { + generic_params = lower_generic_params (enum_decl.get_generic_params ()); + } + + std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = HIR::Visibility::create_public (); + + // bool is_unit = enum_decl.is_zero_variant (); + std::vector<std::unique_ptr<HIR::EnumItem>> items; + for (auto &variant : enum_decl.get_variants ()) + { + HIR::EnumItem *hir_item + = ASTLoweringEnumItem::translate (variant.get ()); + items.push_back (std::unique_ptr<HIR::EnumItem> (hir_item)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, enum_decl.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::Enum (mapping, enum_decl.get_identifier (), vis, + std::move (generic_params), + std::move (where_clause), /* is_unit, */ + std::move (items), enum_decl.get_outer_attrs (), + enum_decl.get_locus ()); + + mappings->insert_defid_mapping (mapping.get_defid (), translated); + mappings->insert_hir_item (mapping.get_crate_num (), mapping.get_hirid (), + translated); + mappings->insert_location (crate_num, mapping.get_hirid (), + enum_decl.get_locus ()); + } + void visit (AST::Union &union_decl) override { std::vector<std::unique_ptr<HIR::GenericParam> > generic_params; diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h index fdd5041d602..05c70e9c03b 100644 --- a/gcc/rust/hir/rust-ast-lower-stmt.h +++ b/gcc/rust/hir/rust-ast-lower-stmt.h @@ -22,6 +22,7 @@ #include "rust-diagnostics.h" #include "rust-ast-lower-base.h" +#include "rust-ast-lower-enumitem.h" #include "rust-ast-lower-type.h" #include "rust-ast-lower-block.h" #include "rust-ast-lower-expr.h" @@ -159,25 +160,6 @@ public: struct_decl.get_locus ()); } - /* Checks whether the name of a field already exists. Returns true - and produces an error if so. */ - static bool struct_field_name_exists (std::vector<HIR::StructField> &fields, - HIR::StructField &new_field) - { - for (auto &field : fields) - { - if (field.get_field_name ().compare (new_field.get_field_name ()) == 0) - { - RichLocation r (new_field.get_locus ()); - r.add_range (field.get_locus ()); - rust_error_at (r, "duplicate field name %qs", - field.get_field_name ().c_str ()); - return true; - } - } - return false; - } - void visit (AST::StructStruct &struct_decl) override { std::vector<std::unique_ptr<HIR::GenericParam> > generic_params; @@ -288,6 +270,44 @@ public: union_decl.get_locus ()); } + void visit (AST::Enum &enum_decl) override + { + std::vector<std::unique_ptr<HIR::GenericParam>> generic_params; + if (enum_decl.has_generics ()) + { + generic_params = lower_generic_params (enum_decl.get_generic_params ()); + } + + std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = HIR::Visibility::create_public (); + + // bool is_unit = enum_decl.is_zero_variant (); + std::vector<std::unique_ptr<HIR::EnumItem>> items; + for (auto &variant : enum_decl.get_variants ()) + { + HIR::EnumItem *hir_item + = ASTLoweringEnumItem::translate (variant.get ()); + items.push_back (std::unique_ptr<HIR::EnumItem> (hir_item)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, enum_decl.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::Enum (mapping, enum_decl.get_identifier (), vis, + std::move (generic_params), + std::move (where_clause), /* is_unit, */ + std::move (items), enum_decl.get_outer_attrs (), + enum_decl.get_locus ()); + + mappings->insert_hir_stmt (mapping.get_crate_num (), mapping.get_hirid (), + translated); + mappings->insert_location (crate_num, mapping.get_hirid (), + enum_decl.get_locus ()); + } + void visit (AST::EmptyStmt &empty) override { auto crate_num = mappings->get_current_crate (); diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc index e8784b61da5..b64e1a05438 100644 --- a/gcc/rust/hir/rust-ast-lower.cc +++ b/gcc/rust/hir/rust-ast-lower.cc @@ -520,5 +520,25 @@ ASTLoweringBase::lower_bound (AST::TypeParamBound *bound) return ASTLoweringTypeBounds::translate (bound); } +/* Checks whether the name of a field already exists. Returns true + and produces an error if so. */ +bool +struct_field_name_exists (std::vector<HIR::StructField> &fields, + HIR::StructField &new_field) +{ + for (auto &field : fields) + { + if (field.get_field_name ().compare (new_field.get_field_name ()) == 0) + { + RichLocation r (new_field.get_locus ()); + r.add_range (field.get_locus ()); + rust_error_at (r, "duplicate field name %qs", + field.get_field_name ().c_str ()); + return true; + } + } + return false; +} + } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower.h b/gcc/rust/hir/rust-ast-lower.h index bdc21ba486b..254f68649db 100644 --- a/gcc/rust/hir/rust-ast-lower.h +++ b/gcc/rust/hir/rust-ast-lower.h @@ -27,6 +27,11 @@ namespace Rust { namespace HIR { +/* Checks whether the name of a field already exists. Returns true + and produces an error if so. */ +bool +struct_field_name_exists (std::vector<HIR::StructField> &fields, + HIR::StructField &new_field); class ASTLowering { public: diff --git a/gcc/rust/hir/tree/rust-hir-full-test.cc b/gcc/rust/hir/tree/rust-hir-full-test.cc index f328ae67abe..b0e418c166b 100644 --- a/gcc/rust/hir/tree/rust-hir-full-test.cc +++ b/gcc/rust/hir/tree/rust-hir-full-test.cc @@ -3086,23 +3086,8 @@ StructExprStructFields::as_string () const std::string EnumItem::as_string () const { - // outer attributes - std::string str = "outer attributes: "; - if (outer_attrs.empty ()) - { - str += "none"; - } - else - { - /* note that this does not print them with "outer attribute" syntax - - * just the body */ - for (const auto &attr : outer_attrs) - { - str += "\n " + attr.as_string (); - } - } - - str += "\n" + variant_name; + std::string str = Item::as_string (); + str += variant_name; return str; } diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index 7a2c2676825..35b1c64e6d2 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -1636,12 +1636,11 @@ protected: }; /* An item used in an "enum" tagged union - not abstract: base represents a - * name-only enum */ -class EnumItem + name-only enum. Syntactically EnumItem's can have a Visibility. But not + Semantically. So check there is no Visibility when lowering and make this + an Item, not an VisItem. */ +class EnumItem : public Item { - // bool has_attrs; - AST::AttrVec outer_attrs; - Identifier variant_name; Location locus; @@ -1649,18 +1648,16 @@ class EnumItem public: virtual ~EnumItem () {} - // Returns whether enum item has outer attributes. - bool has_outer_attrs () const { return !outer_attrs.empty (); } - - EnumItem (Identifier variant_name, AST::AttrVec outer_attrs, Location locus) - : outer_attrs (std::move (outer_attrs)), + EnumItem (Analysis::NodeMapping mappings, Identifier variant_name, + AST::AttrVec outer_attrs, Location locus) + : Item (std::move (mappings), std::move (outer_attrs)), variant_name (std::move (variant_name)), locus (locus) {} // Unique pointer custom clone function std::unique_ptr<EnumItem> clone_enum_item () const { - return std::unique_ptr<EnumItem> (clone_enum_item_impl ()); + return std::unique_ptr<EnumItem> (clone_item_impl ()); } virtual std::string as_string () const; @@ -1668,12 +1665,12 @@ public: // not pure virtual as not abstract virtual void accept_vis (HIRVisitor &vis); + Location get_locus () const { return locus; } + + Identifier get_identifier () const { return variant_name; } + protected: - // Clone function implementation as (not pure) virtual method - virtual EnumItem *clone_enum_item_impl () const - { - return new EnumItem (*this); - } + EnumItem *clone_item_impl () const override { return new EnumItem (*this); } }; // A tuple item used in an "enum" tagged union @@ -1686,9 +1683,11 @@ public: // Returns whether tuple enum item has tuple fields. bool has_tuple_fields () const { return !tuple_fields.empty (); } - EnumItemTuple (Identifier variant_name, std::vector<TupleField> tuple_fields, - AST::AttrVec outer_attrs, Location locus) - : EnumItem (std::move (variant_name), std::move (outer_attrs), locus), + EnumItemTuple (Analysis::NodeMapping mappings, Identifier variant_name, + std::vector<TupleField> tuple_fields, AST::AttrVec outer_attrs, + Location locus) + : EnumItem (std::move (mappings), std::move (variant_name), + std::move (outer_attrs), locus), tuple_fields (std::move (tuple_fields)) {} @@ -1698,7 +1697,7 @@ public: protected: // Clone function implementation as (not pure) virtual method - EnumItemTuple *clone_enum_item_impl () const override + EnumItemTuple *clone_item_impl () const override { return new EnumItemTuple (*this); } @@ -1714,10 +1713,11 @@ public: // Returns whether struct enum item has struct fields. bool has_struct_fields () const { return !struct_fields.empty (); } - EnumItemStruct (Identifier variant_name, + EnumItemStruct (Analysis::NodeMapping mappings, Identifier variant_name, std::vector<StructField> struct_fields, AST::AttrVec outer_attrs, Location locus) - : EnumItem (std::move (variant_name), std::move (outer_attrs), locus), + : EnumItem (std::move (mappings), std::move (variant_name), + std::move (outer_attrs), locus), struct_fields (std::move (struct_fields)) {} @@ -1727,7 +1727,7 @@ public: protected: // Clone function implementation as (not pure) virtual method - EnumItemStruct *clone_enum_item_impl () const override + EnumItemStruct *clone_item_impl () const override { return new EnumItemStruct (*this); } @@ -1739,9 +1739,11 @@ class EnumItemDiscriminant : public EnumItem std::unique_ptr<Expr> expression; public: - EnumItemDiscriminant (Identifier variant_name, std::unique_ptr<Expr> expr, - AST::AttrVec outer_attrs, Location locus) - : EnumItem (std::move (variant_name), std::move (outer_attrs), locus), + EnumItemDiscriminant (Analysis::NodeMapping mappings, Identifier variant_name, + std::unique_ptr<Expr> expr, AST::AttrVec outer_attrs, + Location locus) + : EnumItem (std::move (mappings), std::move (variant_name), + std::move (outer_attrs), locus), expression (std::move (expr)) {} @@ -1771,7 +1773,7 @@ public: protected: // Clone function implementation as (not pure) virtual method - EnumItemDiscriminant *clone_enum_item_impl () const override + EnumItemDiscriminant *clone_item_impl () const override { return new EnumItemDiscriminant (*this); } @@ -1861,6 +1863,8 @@ public: void accept_vis (HIRVisitor &vis) override; + Identifier get_identifier () const { return enum_name; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ diff --git a/gcc/testsuite/rust/compile/bad_pub_enumitems.rs b/gcc/testsuite/rust/compile/bad_pub_enumitems.rs new file mode 100644 index 00000000000..e7fd5edb981 --- /dev/null +++ b/gcc/testsuite/rust/compile/bad_pub_enumitems.rs @@ -0,0 +1,47 @@ +pub enum E +{ + pub A { a: i32 }, // { dg-error "visibility qualifier" } + B (u8), + pub C, // { dg-error "visibility qualifier" } + D +} + +enum E1 +{ + A, + pub B = 42, // { dg-error "visibility qualifier" } + C = 3, + D, + pub E // { dg-error "visibility qualifier" } +} + +enum E2 +{ + pub A (u8, i32, u64), // { dg-error "visibility qualifier" } + B { a: u8, a: u8 } // { dg-error "duplicate field" }} +} + +fn main () +{ + enum EE + { + Alpha { alpha: i32 }, + pub Beta (u8), // { dg-error "visibility qualifier" } + pub Gamma, // { dg-error "visibility qualifier" } + Delta { delta: u32 } + } + + enum EE1 + { + pub Alpha, // { dg-error "visibility qualifier" } + Beta = 41, + pub Gamma = 3, // { dg-error "visibility qualifier" } + Delta, + } + + enum E2 + { + Alpha { a: u8, a: u8 }, // { dg-error "duplicate field" }} + pub Beta (u8, i32, u64) // { dg-error "visibility qualifier" } + } +} -- 2.32.0 -- Gcc-rust mailing list Gcc-rust@gcc.gnu.org https://gcc.gnu.org/mailman/listinfo/gcc-rust