--- /dev/null
+// Copyright (C) 2020-2023 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/>.
+
+#include "rust-rib.h"
+
+namespace Rust {
+namespace Resolver2_0 {
+
+DuplicateNameError::DuplicateNameError (std::string name, NodeId existing)
+ : name (name), existing (existing)
+{}
+
+Rib::Rib (Kind kind) : kind (kind) {}
+
+Rib::Rib (Kind kind, std::string identifier, NodeId id)
+ : Rib (kind, {{identifier, id}})
+{}
+
+Rib::Rib (Kind kind, std::unordered_map<std::string, NodeId> values)
+ : kind (kind), values (std::move (values))
+{}
+
+tl::expected<NodeId, DuplicateNameError>
+Rib::insert (std::string name, NodeId id)
+{
+ auto res = values.insert ({name, id});
+ auto inserted_id = res.first->second;
+
+ // if we couldn't insert, the element already exists - exit with an error
+ if (!res.second)
+ return tl::make_unexpected (DuplicateNameError (name, inserted_id));
+
+ // return the NodeId
+ return inserted_id;
+}
+
+tl::optional<NodeId>
+Rib::get (const std::string &name)
+{
+ auto it = values.find (name);
+
+ if (it == values.end ())
+ return {};
+
+ return it->second;
+}
+
+const std::unordered_map<std::string, NodeId> &
+Rib::get_values () const
+{
+ return values;
+}
+
+} // namespace Resolver2_0
+} // namespace Rust
--- /dev/null
+// Copyright (C) 2020-2023 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_RIB_H
+#define RUST_RIB_H
+
+#include "rust-system.h"
+#include "rust-ast.h"
+#include "optional.h"
+#include "expected.h"
+
+namespace Rust {
+namespace Resolver2_0 {
+
+/**
+ * All namespaces that Rust's name resolution needs to handle
+ */
+// TODO: Move to `rust-forever-stack.h`?
+enum class Namespace
+{
+ Values,
+ Types,
+ Labels,
+ Macros,
+ // TODO: Which namespaces are we missing?
+};
+
+/**
+ * Error returned by `Rib::insert` when the key was already present in the Rib's
+ * map. The class contains the previously-inserted NodeId as well as the name of
+ * the node.
+ */
+struct DuplicateNameError
+{
+ // TODO: We might need multiple kinds of errors later down the line
+ DuplicateNameError (std::string name, NodeId existing);
+
+ std::string name;
+ NodeId existing;
+};
+
+/**
+ * A rib is a container of nodes, either declaration or usages, as well as the
+ * identifier each node uses. They are used to delimit lexical scopes, and have
+ * an impact on name resolution - they restrict certain name accesses and serve
+ * as boundaries between scopes.
+
+ * For example, if we are resolving the following *variable* use:
+ *
+ * ```rust
+ * fn outer() {
+ * let a = 15; // decl
+ * fn inner() -> i32 {
+ * a // use
+ * }
+ * }
+ * ```
+ *
+ * The `Function` rib we will have pushed will restrict the access to `outer`'s
+ * `a` declaration: Variable uses cannot cross function boundaries. On the other
+ * hand, if we were resolving a type usage, this would be perfectly allowed.
+ */
+class Rib
+{
+public:
+ enum class Kind
+ {
+ Normal,
+ Module,
+ Function,
+ ConstantItem, // -> this variant has a boolean
+ TraitOrImpl,
+ /* Any item other than a Module, Function, Constant, Trait or Impl block */
+ Item,
+ Closure,
+ MacroDefinition,
+ /* Ban the use of forward-declared generic parameters in defaults */
+ ForwardTypeParamBan,
+ /* Const generic, as in the following example: fn foo<T, const X: T>() {} */
+ ConstParamType,
+ };
+
+ Rib (Kind kind);
+ Rib (Kind kind, std::string identifier, NodeId id);
+ Rib (Kind kind, std::unordered_map<std::string, NodeId> values);
+
+ // TODO: What's the correctbehavior if the key already exists? What if a decl
+ // and use are in the same rib? Is that possible? Okay based on RibKind?
+
+ /**
+ * Insert a new node in the rib
+ *
+ * @param name The name associated with the AST node
+ * @param id Its NodeId
+ *
+ * @return `DuplicateNameError` if the node is already present in the rib. The
+ * `DuplicateNameError` class contains the NodeId of the existing
+ * node. Returns the new NodeId on success.
+ */
+ tl::expected<NodeId, DuplicateNameError> insert (std::string name, NodeId id);
+
+ /**
+ * Access an inserted NodeId.
+ *
+ * @return tl::nullopt if the key does not exist, the NodeId otherwise
+ */
+ tl::optional<NodeId> get (const std::string &name);
+
+ /* View all the values stored in the rib */
+ const std::unordered_map<std::string, NodeId> &get_values () const;
+
+private:
+ Kind kind;
+ std::unordered_map<std::string, NodeId> values;
+};
+
+} // namespace Resolver2_0
+} // namespace Rust
+
+#endif // !RUST_RIB_H