From: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com> Enum variants shouldn't be accessed directly even from within an enum. This commit keeps the provenance for enum variants definition so we can skip them when resolving a value within an enum definition.
gcc/rust/ChangeLog: * resolve/rust-forever-stack.h: Add new function to insert enum variants and add argument to resolver's get function to explicitely skip enum variants. * resolve/rust-forever-stack.hxx: Update function definitions. * resolve/rust-name-resolution-context.cc (NameResolutionContext::insert_variant): Add function to insert enum variants. * resolve/rust-name-resolution-context.h: Add function's prototype. * resolve/rust-rib.cc (Rib::Definition::Definition): Add new boolean to hint at enum variant provenance. (Rib::Definition::is_variant): New getter for variant status. (Rib::Definition::Shadowable): Update constructor to opt out of enum variants. (Rib::Definition::Globbed): Likewise. (Rib::Definition::NonShadowable): Change constructor to forward enum variant provenance status. * resolve/rust-rib.h: Update function prototypes. * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::insert_enum_variant_or_error_out): Add function to insert enum variants in the name resolver. (TopLevel::visit): Update several enum variant's visitor function with the new enum variant name resolving code. * resolve/rust-toplevel-name-resolver-2.0.h: Update function prototypes. Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com> --- gcc/rust/resolve/rust-forever-stack.h | 3 ++ gcc/rust/resolve/rust-forever-stack.hxx | 18 +++++-- .../resolve/rust-name-resolution-context.cc | 6 +++ .../resolve/rust-name-resolution-context.h | 3 ++ gcc/rust/resolve/rust-rib.cc | 17 ++++-- gcc/rust/resolve/rust-rib.h | 14 ++++- .../rust-toplevel-name-resolver-2.0.cc | 54 ++++++++++++++----- .../resolve/rust-toplevel-name-resolver-2.0.h | 17 +++++- 8 files changed, 106 insertions(+), 26 deletions(-) diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index 64e8a0f0f2c..22efc973197 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -591,6 +591,9 @@ public: */ tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id); + tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name, + NodeId id); + /** * Insert a new shadowable definition in the innermost `Rib` in this stack * diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 9e66c802d5f..628b8c5b6fe 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -173,6 +173,14 @@ ForeverStack<Namespace::Labels>::insert (Identifier name, NodeId node) Rib::Definition::Shadowable (node)); } +template <> +inline tl::expected<NodeId, DuplicateNameError> +ForeverStack<Namespace::Types>::insert_variant (Identifier name, NodeId node) +{ + return insert_inner (peek (), name.as_string (), + Rib::Definition::NonShadowable (node, true)); +} + template <Namespace N> Rib & ForeverStack<N>::peek () @@ -275,10 +283,12 @@ ForeverStack<N>::get (const Identifier &name) return candidate.map_or ( [&resolved_definition] (Rib::Definition found) { - // for most namespaces, we do not need to care about various ribs - they - // are available from all contexts if defined in the current scope, or - // an outermore one. so if we do have a candidate, we can return it - // directly and stop iterating + if (found.is_variant ()) + return KeepGoing::Yes; + // for most namespaces, we do not need to care about various ribs - + // they are available from all contexts if defined in the current + // scope, or an outermore one. so if we do have a candidate, we can + // return it directly and stop iterating resolved_definition = found; return KeepGoing::No; diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index 1b375213878..517a4836aaf 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -45,6 +45,12 @@ NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns) } } +tl::expected<NodeId, DuplicateNameError> +NameResolutionContext::insert_variant (Identifier name, NodeId id) +{ + return types.insert_variant (name, id); +} + tl::expected<NodeId, DuplicateNameError> NameResolutionContext::insert_shadowable (Identifier name, NodeId id, Namespace ns) diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index a381411514d..ea81bdeed54 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -172,6 +172,9 @@ public: tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id, Namespace ns); + tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name, + NodeId id); + tl::expected<NodeId, DuplicateNameError> insert_shadowable (Identifier name, NodeId id, Namespace ns); diff --git a/gcc/rust/resolve/rust-rib.cc b/gcc/rust/resolve/rust-rib.cc index b0380bb0b78..1d53a741858 100644 --- a/gcc/rust/resolve/rust-rib.cc +++ b/gcc/rust/resolve/rust-rib.cc @@ -22,7 +22,8 @@ namespace Rust { namespace Resolver2_0 { -Rib::Definition::Definition (NodeId id, Mode mode) +Rib::Definition::Definition (NodeId id, Mode mode, bool enum_variant) + : enum_variant (enum_variant) { switch (mode) { @@ -51,6 +52,12 @@ Rib::Definition::is_ambiguous () const return ids_globbed.size () > 1; } +bool +Rib::Definition::is_variant () const +{ + return enum_variant; +} + std::string Rib::Definition::to_string () const { @@ -75,19 +82,19 @@ Rib::Definition::to_string () const Rib::Definition Rib::Definition::Shadowable (NodeId id) { - return Definition (id, Mode::SHADOWABLE); + return Definition (id, Mode::SHADOWABLE, false); } Rib::Definition -Rib::Definition::NonShadowable (NodeId id) +Rib::Definition::NonShadowable (NodeId id, bool enum_variant) { - return Definition (id, Mode::NON_SHADOWABLE); + return Definition (id, Mode::NON_SHADOWABLE, enum_variant); } Rib::Definition Rib::Definition::Globbed (NodeId id) { - return Definition (id, Mode::GLOBBED); + return Definition (id, Mode::GLOBBED, false); } DuplicateNameError::DuplicateNameError (std::string name, NodeId existing) diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h index 767547f985f..ccc4c277b12 100644 --- a/gcc/rust/resolve/rust-rib.h +++ b/gcc/rust/resolve/rust-rib.h @@ -111,7 +111,7 @@ public: class Definition { public: - static Definition NonShadowable (NodeId id); + static Definition NonShadowable (NodeId id, bool enum_variant = false); static Definition Shadowable (NodeId id); static Definition Globbed (NodeId id); @@ -124,11 +124,21 @@ public: std::vector<NodeId> ids_non_shadowable; std::vector<NodeId> ids_globbed; + // Enum variant should be skipped when dealing with inner definition. + // struct E2; + // + // enum MyEnum<T> /* <-- Should be kept */{ + // E2 /* <-- Should be skipped */ (E2); + // } + bool enum_variant; + Definition () = default; Definition &operator= (const Definition &) = default; Definition (Definition const &) = default; + bool is_variant () const; + bool is_ambiguous () const; NodeId get_node_id () const @@ -155,7 +165,7 @@ public: GLOBBED }; - Definition (NodeId id, Mode mode); + Definition (NodeId id, Mode mode, bool enum_variant); }; enum class Kind diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc index 572d5956c0a..8863be768a1 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -32,21 +32,18 @@ TopLevel::TopLevel (NameResolutionContext &resolver) template <typename T> void -TopLevel::insert_or_error_out (const Identifier &identifier, const T &node, - Namespace ns) +TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier, + const T &node) { - insert_or_error_out (identifier, node.get_locus (), node.get_node_id (), ns); + insert_enum_variant_or_error_out (identifier, node.get_locus (), + node.get_node_id ()); } void -TopLevel::insert_or_error_out (const Identifier &identifier, - const location_t &locus, const NodeId &node_id, - Namespace ns) +TopLevel::check_multiple_insertion_error ( + tl::expected<NodeId, DuplicateNameError> result, const Identifier &identifier, + const location_t &locus, const NodeId node_id) { - // keep track of each node's location to provide useful errors - node_locations.emplace (node_id, locus); - - auto result = ctx.insert (identifier, node_id, ns); if (result) dirty = true; else if (result.error ().existing != node_id) @@ -58,6 +55,37 @@ TopLevel::insert_or_error_out (const Identifier &identifier, identifier.as_string ().c_str ()); } } +void +TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier, + const location_t &locus, + const NodeId node_id) +{ + // keep track of each node's location to provide useful errors + node_locations.emplace (node_id, locus); + + auto result = ctx.insert_variant (identifier, node_id); + check_multiple_insertion_error (result, identifier, locus, node_id); +} + +template <typename T> +void +TopLevel::insert_or_error_out (const Identifier &identifier, const T &node, + Namespace ns) +{ + insert_or_error_out (identifier, node.get_locus (), node.get_node_id (), ns); +} + +void +TopLevel::insert_or_error_out (const Identifier &identifier, + const location_t &locus, const NodeId &node_id, + Namespace ns) +{ + // keep track of each node's location to provide useful errors + node_locations.emplace (node_id, locus); + + auto result = ctx.insert (identifier, node_id, ns); + check_multiple_insertion_error (result, identifier, locus, node_id); +} void TopLevel::go (AST::Crate &crate) @@ -336,19 +364,19 @@ TopLevel::visit (AST::TupleStruct &tuple_struct) void TopLevel::visit (AST::EnumItem &variant) { - insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + insert_enum_variant_or_error_out (variant.get_identifier (), variant); } void TopLevel::visit (AST::EnumItemTuple &variant) { - insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + insert_enum_variant_or_error_out (variant.get_identifier (), variant); } void TopLevel::visit (AST::EnumItemStruct &variant) { - insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + insert_enum_variant_or_error_out (variant.get_identifier (), variant); } void diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h index fabcb5bf707..559c0d8757f 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -114,9 +114,14 @@ public: return std::move (imports_to_resolve); } + void check_multiple_insertion_error ( + tl::expected<NodeId, DuplicateNameError> result, + const Identifier &identifier, const location_t &locus, + const NodeId node_id); + /** - * Insert a new definition or error out if a definition with the same name was - * already present in the same namespace in the same scope. + * Insert a new definition or error out if a definition with the same name + * was already present in the same namespace in the same scope. * * @param identifier The identifier of the definition to add. * @param node A reference to the node, so we can get its `NodeId` and @@ -130,6 +135,14 @@ public: const location_t &locus, const NodeId &id, Namespace ns); + template <typename T> + void insert_enum_variant_or_error_out (const Identifier &identifier, + const T &node); + + void insert_enum_variant_or_error_out (const Identifier &identifier, + const location_t &locus, + const NodeId node_id); + private: // If a new export has been defined whilst visiting the visitor is considered // dirty -- 2.45.2