LCOV - code coverage report
Current view: top level - gcc/rust/resolve - rust-rib.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 32.5 % 40 13
Test Date: 2026-02-28 14:20:25 Functions: 75.0 % 4 3
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #ifndef RUST_RIB_H
      20              : #define RUST_RIB_H
      21              : 
      22              : #include "rust-system.h"
      23              : #include "rust-ast.h"
      24              : #include "optional.h"
      25              : #include "expected.h"
      26              : 
      27              : namespace Rust {
      28              : namespace Resolver2_0 {
      29              : 
      30              : /**
      31              : 
      32              : pub enum Namespace {
      33              :    /// The type namespace includes `struct`s, `enum`s, `union`s, `trait`s, and
      34              : `mod`s
      35              :    /// (and, by extension, crates).
      36              :    ///
      37              :    /// Note that the type namespace includes other items; this is not an
      38              :    /// exhaustive list.
      39              :    TypeNS,
      40              :    /// The value namespace includes `fn`s, `const`s, `static`s, and local
      41              : variables (including function arguments). ValueNS,
      42              :    /// The macro namespace includes `macro_rules!` macros, declarative `macro`s,
      43              :    /// procedural macros, attribute macros, `derive` macros, and non-macro
      44              : attributes
      45              :    /// like `#[inline]` and `#[rustfmt::skip]`.
      46              :    MacroNS,
      47              : }
      48              : 
      49              : */
      50              : 
      51              : // FIXME: There's no `labels` namespace, not sure if we need one or how to keep
      52              : // one
      53              : // FIXME: And where are things like loop labels kept?
      54              : 
      55              : /**
      56              :  * All namespaces that Rust's name resolution needs to handle
      57              :  */
      58              : // TODO: Move to `rust-forever-stack.h`?
      59              : enum class Namespace
      60              : {
      61              :   Values,
      62              :   Types,
      63              :   Labels,
      64              :   Macros,
      65              :   // TODO: Which namespaces are we missing?
      66              : };
      67              : 
      68              : /**
      69              :  * Error returned by `Rib::insert` when the key was already present in the Rib's
      70              :  * map. The class contains the previously-inserted NodeId as well as the name of
      71              :  * the node.
      72              :  */
      73       322319 : struct DuplicateNameError
      74              : {
      75              :   // TODO: We might need multiple kinds of errors later down the line
      76              :   DuplicateNameError (std::string name, NodeId existing);
      77              : 
      78              :   std::string name;
      79              :   NodeId existing;
      80              : };
      81              : 
      82              : /**
      83              :  * A rib is a container of nodes, either declaration or usages, as well as the
      84              :  * identifier each node uses. They are used to delimit lexical scopes, and have
      85              :  * an impact on name resolution - they restrict certain name accesses and serve
      86              :  * as boundaries between scopes.
      87              : 
      88              :  * For example, if we are resolving the following *variable* use:
      89              :  *
      90              :  * ```rust
      91              :  * fn outer() {
      92              :  *     let a = 15; // decl
      93              :  *     fn inner() -> i32 {
      94              :  *         a // use
      95              :  *     }
      96              :  * }
      97              :  * ```
      98              :  *
      99              :  * The `Function` rib we will have pushed will restrict the access to `outer`'s
     100              :  * `a` declaration: Variable uses cannot cross function boundaries. On the other
     101              :  * hand, if we were resolving a type usage, this would be perfectly allowed.
     102              :  */
     103      4570399 : class Rib
     104              : {
     105              : public:
     106              :   // TODO: Rename the class? to what? Binding? Declaration?
     107              :   // This is useful for items which are in namespaces where shadowing is not
     108              :   // allowed, but which are still shadowable! for example, when you do a glob
     109              :   // import, if a later import has the same name as an item imported in the glob
     110              :   // import, that glob imported item will need to get shadowed
     111              :   class Definition
     112              :   {
     113              :   public:
     114              :     static Definition NonShadowable (NodeId id, bool enum_variant = false);
     115              :     static Definition Shadowable (NodeId id);
     116              :     static Definition Globbed (NodeId id);
     117              : 
     118              :     // checked shadowable -> non_shadowable -> globbed
     119              :     // we have shadowable *and* globbed in order to control
     120              :     // resolution priority
     121              :     // we *could* use a single vector with 2 indices here
     122              :     // but it's probably not worth it for now
     123              :     std::vector<NodeId> ids_shadowable;
     124              :     std::vector<NodeId> ids_non_shadowable;
     125              :     std::vector<NodeId> ids_globbed;
     126              : 
     127              :     // Enum variant should be skipped when dealing with inner definition.
     128              :     // struct E2;
     129              :     //
     130              :     // enum MyEnum<T> /* <-- Should be kept */{
     131              :     //     E2 /* <-- Should be skipped */ (E2);
     132              :     // }
     133              :     bool enum_variant;
     134              : 
     135       162062 :     Definition () = default;
     136              : 
     137       159021 :     Definition &operator= (const Definition &) = default;
     138       773166 :     Definition (Definition const &) = default;
     139              : 
     140              :     bool is_variant () const;
     141              : 
     142              :     bool is_ambiguous () const;
     143              : 
     144       248935 :     NodeId get_node_id () const
     145              :     {
     146       248935 :       if (!ids_shadowable.empty ())
     147        26616 :         return ids_shadowable.back ();
     148              : 
     149       222319 :       rust_assert (!is_ambiguous ());
     150              : 
     151       222319 :       if (!ids_non_shadowable.empty ())
     152       222303 :         return ids_non_shadowable.back ();
     153              : 
     154           16 :       rust_assert (!ids_globbed.empty ());
     155           16 :       return ids_globbed.back ();
     156              :     }
     157              : 
     158              :     std::string to_string () const;
     159              : 
     160              :   private:
     161              :     enum class Mode
     162              :     {
     163              :       SHADOWABLE,
     164              :       NON_SHADOWABLE,
     165              :       GLOBBED
     166              :     };
     167              : 
     168              :     Definition (NodeId id, Mode mode, bool enum_variant);
     169              :   };
     170              : 
     171              :   enum class Kind
     172              :   {
     173              :     Normal,
     174              :     Module,
     175              :     Function,
     176              :     ConstantItem, // -> this variant has a boolean
     177              :     TraitOrImpl,
     178              :     /* Any item other than a Module, Function, Constant, Trait or Impl block */
     179              :     Item,
     180              :     Closure,
     181              :     MacroDefinition,
     182              :     /* Ban the use of forward-declared generic parameters in defaults */
     183              :     ForwardTypeParamBan,
     184              :     /* Const generic, as in the following example: fn foo<T, const X: T>() {} */
     185              :     ConstParamType,
     186              :     /* Prelude rib, used for both the language prelude (i32,usize,etc) and the
     187              :      * (future) {std,core}::prelude::* import. A regular rib with the
     188              :      * restriction that you cannot `use` items from the Prelude
     189              :      */
     190              :     Prelude,
     191              :     /* Generic rib, used to store generics */
     192              :     Generics,
     193              :   } kind;
     194              : 
     195            0 :   static std::string kind_to_string (Rib::Kind kind)
     196              :   {
     197            0 :     switch (kind)
     198              :       {
     199            0 :       case Rib::Kind::Normal:
     200            0 :         return "Normal";
     201            0 :       case Rib::Kind::Module:
     202            0 :         return "Module";
     203            0 :       case Rib::Kind::Function:
     204            0 :         return "Function";
     205            0 :       case Rib::Kind::ConstantItem:
     206            0 :         return "ConstantItem";
     207            0 :       case Rib::Kind::TraitOrImpl:
     208            0 :         return "TraitOrImpl";
     209            0 :       case Rib::Kind::Item:
     210            0 :         return "Item";
     211            0 :       case Rib::Kind::Closure:
     212            0 :         return "Closure";
     213            0 :       case Rib::Kind::MacroDefinition:
     214            0 :         return "Macro definition";
     215            0 :       case Rib::Kind::ForwardTypeParamBan:
     216            0 :         return "Forward type param ban";
     217            0 :       case Rib::Kind::ConstParamType:
     218            0 :         return "Const Param Type";
     219            0 :       case Kind::Prelude:
     220            0 :         return "Prelude";
     221            0 :       case Kind::Generics:
     222            0 :         return "Generics";
     223              :       }
     224              : 
     225            0 :     rust_unreachable ();
     226              :   }
     227              : 
     228              :   Rib (Kind kind);
     229              :   Rib (Kind kind, std::string identifier, NodeId id);
     230              :   Rib (Kind kind, std::unordered_map<std::string, NodeId> values);
     231              : 
     232              :   // TODO: What's the correctbehavior if the key already exists? What if a decl
     233              :   // and use are in the same rib? Is that possible? Okay based on RibKind?
     234              : 
     235              :   /**
     236              :    * Insert a new node in the rib
     237              :    *
     238              :    * @param name The name associated with the AST node
     239              :    * @param def The `Definition` to insert
     240              :    *
     241              :    * @return `DuplicateNameError` if the node is already present in the rib. The
     242              :    *         `DuplicateNameError` class contains the NodeId of the existing
     243              :    * node. Returns the new NodeId on success.
     244              :    */
     245              :   tl::expected<NodeId, DuplicateNameError> insert (std::string name,
     246              :                                                    Definition def);
     247              : 
     248              :   /**
     249              :    * Access an inserted NodeId.
     250              :    *
     251              :    * @return tl::nullopt if the key does not exist, the NodeId otherwise
     252              :    */
     253              :   tl::optional<Rib::Definition> get (const std::string &name);
     254              : 
     255              :   /* View all the values stored in the rib */
     256              :   const std::unordered_map<std::string, Definition> &get_values () const;
     257              : 
     258              : private:
     259              :   // TODO: Switch this to (NodeId, shadowable = false);
     260              :   std::unordered_map<std::string, Definition> values;
     261              : };
     262              : 
     263              : } // namespace Resolver2_0
     264              : } // namespace Rust
     265              : 
     266              : #endif // !RUST_RIB_H
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.