LCOV - code coverage report
Current view: top level - gcc/rust/expand - rust-expand-format-args.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.6 % 68 63
Test Date: 2026-08-22 16:33:35 Functions: 100.0 % 3 3
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2024-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              : #include "rust-expand-format-args.h"
      20              : #include "rust-ast-fragment.h"
      21              : #include "rust-ast.h"
      22              : #include "rust-builtin-ast-nodes.h"
      23              : #include "rust-ast-builder.h"
      24              : #include "rust-diagnostics.h"
      25              : #include "rust-expr.h"
      26              : #include "rust-fmt.h"
      27              : #include "rust-path.h"
      28              : #include "rust-system.h"
      29              : #include "rust-token.h"
      30              : 
      31              : namespace Rust {
      32              : namespace Fmt {
      33              : 
      34              : static std::unique_ptr<AST::Expr>
      35          119 : format_arg (const AST::Builder &builder, std::unique_ptr<AST::Expr> &&to_format,
      36              :             const std::string &trait)
      37              : {
      38          119 :   auto formatter_fn = std::unique_ptr<AST::Expr> (
      39          833 :     new AST::PathInExpression (builder.path_in_expression (
      40          238 :       {builder.get_path_start (), "fmt", trait, "fmt"})));
      41              : 
      42          119 :   auto path = std::unique_ptr<AST::Expr> (
      43          714 :     new AST::PathInExpression (builder.path_in_expression (
      44          238 :       {builder.get_path_start (), "fmt", "ArgumentV1", "new"})));
      45              : 
      46          119 :   auto args = std::vector<std::unique_ptr<AST::Expr>> ();
      47          119 :   args.emplace_back (std::move (to_format));
      48          119 :   args.emplace_back (std::move (formatter_fn));
      49              : 
      50          119 :   return builder.call (std::move (path), std::move (args));
      51          119 : }
      52              : 
      53              : const std::string &
      54          119 : get_trait_name (ffi::FormatSpec format_specifier)
      55              : {
      56          119 :   static const std::unordered_map<std::string, std::string> spec_map = {
      57              :     {"", "Display"},   {"?", "Debug"},    {"e", "LowerExp"},
      58              :     {"E", "UpperExp"}, {"o", "Octal"},    {"p", "Pointer"},
      59              :     {"b", "Binary"},   {"x", "LowerHex"}, {"X", "UpperHex"},
      60          155 :   };
      61              : 
      62          119 :   auto it = spec_map.find (format_specifier.ty.to_string ());
      63              : 
      64          119 :   if (it == spec_map.end ())
      65            0 :     rust_unreachable ();
      66              : 
      67          119 :   return it->second;
      68              : }
      69              : 
      70              : tl::optional<AST::Fragment>
      71           76 : expand_format_args (AST::FormatArgs &fmt,
      72              :                     std::vector<std::unique_ptr<AST::Token>> &&tokens)
      73              : {
      74           76 :   auto loc = fmt.get_locus ();
      75              :   // FIXME: This needs to be aware of the crate in which we are expanding it.
      76              :   // Expanding format_args!() within core needs to use paths that start with
      77              :   // `crate::`, not `core::`
      78           76 :   auto builder = AST::Builder (loc, AST::Builder::Source::InCore);
      79           76 :   auto &arguments = fmt.get_arguments ();
      80              : 
      81           76 :   auto static_pieces = std::vector<std::unique_ptr<AST::Expr>> ();
      82           76 :   auto args
      83              :     = std::vector<std::pair<std::unique_ptr<AST::Expr>, ffi::FormatSpec>> ();
      84              : 
      85          346 :   for (const auto &node : fmt.get_template ().get_pieces ())
      86              :     {
      87          270 :       switch (node.tag)
      88              :         {
      89          151 :         case ffi::Piece::Tag::String:
      90          151 :           static_pieces.emplace_back (
      91          302 :             builder.literal_string (node.string._0.to_string ()));
      92          151 :           break;
      93          119 :         case ffi::Piece::Tag::NextArgument:
      94          119 :           {
      95          119 :             auto next_argument = node.next_argument._0;
      96          119 :             switch (node.next_argument._0.position.tag)
      97              :               {
      98          119 :               case ffi::Position::Tag::ArgumentImplicitlyIs:
      99          119 :                 {
     100          119 :                   auto idx = next_argument.position.argument_implicitly_is._0;
     101          119 :                   auto trait = next_argument.format;
     102          119 :                   auto arg = arguments.at (idx);
     103              : 
     104              :                   // FIXME(Arthur): This API sucks
     105          119 :                   rust_assert (arg.get_kind ().kind
     106              :                                == AST::FormatArgumentKind::Kind::Normal);
     107              : 
     108          119 :                   args.push_back ({arg.get_expr ().clone_expr (), trait});
     109          119 :                 }
     110          119 :                 break;
     111            0 :               case ffi::Position::Tag::ArgumentIs:
     112            0 :               case ffi::Position::Tag::ArgumentNamed:
     113            0 :                 rust_sorry_at (loc, "unhandled argument position specifier");
     114            0 :                 break;
     115              :               }
     116          119 :           }
     117          119 :           break;
     118              :         }
     119              :     }
     120              : 
     121           76 :   auto args_array = std::vector<std::unique_ptr<AST::Expr>> ();
     122          195 :   for (auto &&arg : args)
     123          238 :     args_array.emplace_back (format_arg (builder,
     124          238 :                                          builder.ref (std::move (arg.first)),
     125          238 :                                          get_trait_name (arg.second)));
     126              : 
     127           76 :   auto pieces = builder.ref (builder.array (std::move (static_pieces)));
     128           76 :   auto args_slice = builder.ref (builder.array (std::move (args_array)));
     129              : 
     130           76 :   auto final_path
     131          456 :     = std::make_unique<AST::PathInExpression> (builder.path_in_expression (
     132           76 :       {builder.get_path_start (), "fmt", "Arguments", "new_v1"}));
     133           76 :   auto final_args = std::vector<std::unique_ptr<AST::Expr>> ();
     134           76 :   final_args.emplace_back (std::move (pieces));
     135           76 :   final_args.emplace_back (std::move (args_slice));
     136              : 
     137           76 :   auto final_call
     138           76 :     = builder.call (std::move (final_path), std::move (final_args));
     139              : 
     140           76 :   auto node = AST::SingleASTNode (std::move (final_call));
     141              : 
     142          228 :   return AST::Fragment ({node}, std::move (tokens));
     143           76 : }
     144              : 
     145              : } // namespace Fmt
     146              : } // namespace Rust
        

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.