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.patry@embecosm.com>
*/
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
*
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 ()
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;
}
}
+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)
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);
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)
{
return ids_globbed.size () > 1;
}
+bool
+Rib::Definition::is_variant () const
+{
+ return enum_variant;
+}
+
std::string
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)
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);
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
GLOBBED
};
- Definition (NodeId id, Mode mode);
+ Definition (NodeId id, Mode mode, bool enum_variant);
};
enum class Kind
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)
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)
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
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
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