LCOV - code coverage report
Current view: top level - gcc/rust - rust-diagnostics.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 69.4 % 255 177
Test Date: 2026-02-28 14:20:25 Functions: 70.0 % 40 28
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // rust-diagnostics.cc -- GCC implementation of rust diagnostics interface.
       2              : // Copyright (C) 2016-2026 Free Software Foundation, Inc.
       3              : // Contributed by Than McIntosh, Google.
       4              : 
       5              : // This file is part of GCC.
       6              : 
       7              : // GCC is free software; you can redistribute it and/or modify it under
       8              : // the terms of the GNU General Public License as published by the Free
       9              : // Software Foundation; either version 3, or (at your option) any later
      10              : // version.
      11              : 
      12              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15              : // for more details.
      16              : 
      17              : // You should have received a copy of the GNU General Public License
      18              : // along with GCC; see the file COPYING3.  If not see
      19              : // <http://www.gnu.org/licenses/>.
      20              : 
      21              : #include "rust-system.h"
      22              : #include "rust-diagnostics.h"
      23              : 
      24              : #include "options.h"
      25              : #include "diagnostics/metadata.h"
      26              : 
      27              : static std::string
      28           15 : mformat_value ()
      29              : {
      30           15 :   return std::string (xstrerror (errno));
      31              : }
      32              : 
      33              : // Rewrite a format string to expand any extensions not
      34              : // supported by sprintf(). See comments in rust-diagnostics.h
      35              : // for list of supported format specifiers.
      36              : 
      37              : static std::string
      38         4682 : expand_format (const char *fmt)
      39              : {
      40         4682 :   std::stringstream ss;
      41       138480 :   for (const char *c = fmt; *c; ++c)
      42              :     {
      43       133798 :       if (*c != '%')
      44              :         {
      45       127183 :           ss << *c;
      46       127183 :           continue;
      47              :         }
      48         6615 :       c++;
      49         6615 :       switch (*c)
      50              :         {
      51            0 :         case '\0':
      52            0 :           {
      53              :             // malformed format string
      54            0 :             rust_unreachable ();
      55              :           }
      56            0 :         case '%':
      57            0 :           {
      58            0 :             ss << "%";
      59            0 :             break;
      60              :           }
      61           15 :         case 'm':
      62           15 :           {
      63           30 :             ss << mformat_value ();
      64           15 :             break;
      65              :           }
      66          306 :         case '<':
      67          306 :           {
      68          306 :             ss << rust_open_quote ();
      69          306 :             break;
      70              :           }
      71          306 :         case '>':
      72          306 :           {
      73          306 :             ss << rust_close_quote ();
      74          306 :             break;
      75              :           }
      76         5355 :         case 'q':
      77         5355 :           {
      78         5355 :             ss << rust_open_quote ();
      79         5355 :             c++;
      80         5355 :             if (*c == 'm')
      81              :               {
      82            0 :                 ss << mformat_value ();
      83              :               }
      84              :             else
      85              :               {
      86         5355 :                 ss << "%" << *c;
      87              :               }
      88         5355 :             ss << rust_close_quote ();
      89         5355 :             break;
      90              :           }
      91          633 :         default:
      92          633 :           {
      93          633 :             ss << "%" << *c;
      94              :           }
      95              :         }
      96              :     }
      97         4682 :   return ss.str ();
      98         4682 : }
      99              : 
     100              : // Expand message format specifiers, using a combination of
     101              : // expand_format above to handle extensions (ex: %m, %q) and vasprintf()
     102              : // to handle regular printf-style formatting. A pragma is being used here to
     103              : // suppress this warning:
     104              : //
     105              : //   warning: function ‘std::__cxx11::string expand_message(const char*,
     106              : //   __va_list_tag*)’ might be a candidate for ‘gnu_printf’ format attribute
     107              : //   [-Wsuggest-attribute=format]
     108              : //
     109              : // What appears to be happening here is that the checker is deciding that
     110              : // because of the call to vasprintf() (which has attribute gnu_printf), the
     111              : // calling function must need to have attribute gnu_printf as well, even
     112              : // though there is already an attribute declaration for it.
     113              : 
     114              : static std::string expand_message (const char *fmt, va_list ap)
     115              :   RUST_ATTRIBUTE_GCC_DIAG (1, 0);
     116              : 
     117              : #pragma GCC diagnostic push
     118              : #pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
     119              : 
     120              : static std::string
     121         4682 : expand_message (const char *fmt, va_list ap)
     122              : {
     123         4682 :   char *mbuf = 0;
     124         4682 :   std::string expanded_fmt = expand_format (fmt);
     125         4682 :   int nwr = vasprintf (&mbuf, expanded_fmt.c_str (), ap);
     126         4682 :   if (nwr == -1)
     127              :     {
     128              :       // memory allocation failed
     129            0 :       rust_be_error_at (UNKNOWN_LOCATION,
     130            0 :                         "memory allocation failed in vasprintf");
     131            0 :       rust_assert (0);
     132              :     }
     133         4682 :   std::string rval = std::string (mbuf);
     134         4682 :   free (mbuf);
     135         4682 :   return rval;
     136         4682 : }
     137              : 
     138              : #pragma GCC diagnostic pop
     139              : 
     140              : static const char *cached_open_quote = NULL;
     141              : static const char *cached_close_quote = NULL;
     142              : 
     143              : void
     144         1264 : rust_be_get_quotechars (const char **open_qu, const char **close_qu)
     145              : {
     146         1264 :   *open_qu = open_quote;
     147         1264 :   *close_qu = close_quote;
     148         1264 : }
     149              : 
     150              : const char *
     151         5666 : rust_open_quote ()
     152              : {
     153         5666 :   if (cached_open_quote == NULL)
     154         1264 :     rust_be_get_quotechars (&cached_open_quote, &cached_close_quote);
     155         5666 :   return cached_open_quote;
     156              : }
     157              : 
     158              : const char *
     159         5666 : rust_close_quote ()
     160              : {
     161         5666 :   if (cached_close_quote == NULL)
     162            0 :     rust_be_get_quotechars (&cached_open_quote, &cached_close_quote);
     163         5666 :   return cached_close_quote;
     164              : }
     165              : 
     166              : void
     167            0 : rust_be_internal_error_at (const location_t location, const std::string &errmsg)
     168              : {
     169            0 :   std::string loc_str = Linemap::location_to_string (location);
     170            0 :   if (loc_str.empty ())
     171            0 :     internal_error ("%s", errmsg.c_str ());
     172              :   else
     173            0 :     internal_error ("at %s, %s", loc_str.c_str (), errmsg.c_str ());
     174              : }
     175              : 
     176              : void
     177            0 : rust_internal_error_at (const location_t location, const char *fmt, ...)
     178              : {
     179            0 :   va_list ap;
     180              : 
     181            0 :   va_start (ap, fmt);
     182            0 :   rust_be_internal_error_at (location, expand_message (fmt, ap));
     183              :   va_end (ap);
     184              : }
     185              : 
     186              : void
     187          631 : rust_be_error_at (const location_t location, const std::string &errmsg)
     188              : {
     189          631 :   error_at (location, "%s", errmsg.c_str ());
     190          631 : }
     191              : 
     192              : void
     193          631 : rust_error_at (const location_t location, const char *fmt, ...)
     194              : {
     195          631 :   va_list ap;
     196              : 
     197          631 :   va_start (ap, fmt);
     198          631 :   rust_be_error_at (location, expand_message (fmt, ap));
     199          631 :   va_end (ap);
     200          631 : }
     201              : 
     202              : class rust_error_code_rule : public diagnostics::metadata::rule
     203              : {
     204              : public:
     205          443 :   rust_error_code_rule (const ErrorCode code) : m_code (code) {}
     206              : 
     207          443 :   void format_error_code (char *buffer) const
     208              :   {
     209              :     // we can use the `u` format specifier because the `ErrorCode` enum class
     210              :     // "inherits" from `unsigned int` - add a static assertion to make sure
     211              :     // that's the case before we do the formatting
     212          443 :     static_assert (
     213              :       std::is_same<std::underlying_type<ErrorCode>::type, unsigned int>::value,
     214              :       "invalid format specifier for ErrorCode's underlying type");
     215              : 
     216          443 :     snprintf (buffer, 6, "E%04u",
     217          443 :               (std::underlying_type<ErrorCode>::type) m_code);
     218              :   }
     219              : 
     220          443 :   char *make_description () const final override
     221              :   {
     222              :     // 'E' + 4 characters + \0
     223          443 :     char *buffer = static_cast<char *> (xcalloc (6, sizeof (char)));
     224              : 
     225          443 :     format_error_code (buffer);
     226              : 
     227          443 :     return buffer;
     228              :   }
     229              : 
     230            0 :   char *make_url () const final override
     231              :   {
     232            0 :     char buffer[6] = {0};
     233            0 :     format_error_code (buffer);
     234              : 
     235            0 :     return concat ("https://doc.rust-lang.org/error-index.html#", buffer, NULL);
     236              :   }
     237              : 
     238              : private:
     239              :   const ErrorCode m_code;
     240              : };
     241              : 
     242              : void
     243          227 : rust_be_error_at (const location_t location, const ErrorCode code,
     244              :                   const std::string &errmsg)
     245              : {
     246          227 :   rich_location gcc_loc (line_table, location);
     247          227 :   diagnostics::metadata m;
     248          227 :   rust_error_code_rule rule (code);
     249          227 :   m.add_rule (rule);
     250          227 :   error_meta (&gcc_loc, m, "%s", errmsg.c_str ());
     251          227 : }
     252              : 
     253              : void
     254          227 : rust_error_at (const location_t location, const ErrorCode code, const char *fmt,
     255              :                ...)
     256              : {
     257          227 :   va_list ap;
     258              : 
     259          227 :   va_start (ap, fmt);
     260          227 :   rust_be_error_at (location, code, expand_message (fmt, ap));
     261          227 :   va_end (ap);
     262          227 : }
     263              : 
     264              : void
     265          216 : rust_be_error_at (const rich_location &location, const ErrorCode code,
     266              :                   const std::string &errmsg)
     267              : {
     268              :   /* TODO: 'error_at' would like a non-'const' 'rich_location *'.  */
     269          216 :   rich_location &gcc_loc = const_cast<rich_location &> (location);
     270          216 :   diagnostics::metadata m;
     271          216 :   rust_error_code_rule rule (code);
     272          216 :   m.add_rule (rule);
     273          216 :   error_meta (&gcc_loc, m, "%s", errmsg.c_str ());
     274          216 : }
     275              : 
     276              : void
     277          216 : rust_error_at (const rich_location &location, const ErrorCode code,
     278              :                const char *fmt, ...)
     279              : {
     280          216 :   va_list ap;
     281              : 
     282          216 :   va_start (ap, fmt);
     283          216 :   rust_be_error_at (location, code, expand_message (fmt, ap));
     284          216 :   va_end (ap);
     285          216 : }
     286              : 
     287              : void
     288            0 : rust_be_error_at (rich_location *richloc, const ErrorCode code,
     289              :                   const std::string &errmsg)
     290              : {
     291            0 :   diagnostics::metadata m;
     292            0 :   rust_error_code_rule rule (code);
     293            0 :   m.add_rule (rule);
     294            0 :   error_meta (richloc, m, "%s", errmsg.c_str ());
     295            0 : }
     296              : 
     297              : void
     298            0 : rust_error_at (rich_location *richloc, const ErrorCode code, const char *fmt,
     299              :                ...)
     300              : {
     301              :   /* TODO: Refactoring diagnostics to this overload */
     302            0 :   va_list ap;
     303              : 
     304            0 :   va_start (ap, fmt);
     305            0 :   rust_be_error_at (richloc, code, expand_message (fmt, ap));
     306            0 :   va_end (ap);
     307            0 : }
     308              : 
     309              : void
     310         1038 : rust_be_warning_at (const location_t location, int opt,
     311              :                     const std::string &warningmsg)
     312              : {
     313         1038 :   warning_at (location, opt, "%s", warningmsg.c_str ());
     314         1038 : }
     315              : 
     316              : void
     317         1038 : rust_warning_at (const location_t location, int opt, const char *fmt, ...)
     318              : {
     319         1038 :   va_list ap;
     320              : 
     321         1038 :   va_start (ap, fmt);
     322         1038 :   rust_be_warning_at (location, opt, expand_message (fmt, ap));
     323         1038 :   va_end (ap);
     324         1038 : }
     325              : 
     326              : void
     327            1 : rust_be_fatal_error (const location_t location, const std::string &fatalmsg)
     328              : {
     329            1 :   fatal_error (location, "%s", fatalmsg.c_str ());
     330              : }
     331              : 
     332              : void
     333            1 : rust_fatal_error (const location_t location, const char *fmt, ...)
     334              : {
     335            1 :   va_list ap;
     336              : 
     337            1 :   va_start (ap, fmt);
     338            1 :   rust_be_fatal_error (location, expand_message (fmt, ap));
     339              :   va_end (ap);
     340              : }
     341              : 
     342              : void
     343          178 : rust_be_inform (const location_t location, const std::string &infomsg)
     344              : {
     345          178 :   inform (location, "%s", infomsg.c_str ());
     346          178 : }
     347              : 
     348              : void
     349           52 : rust_inform (const location_t location, const char *fmt, ...)
     350              : {
     351           52 :   va_list ap;
     352              : 
     353           52 :   va_start (ap, fmt);
     354           52 :   rust_be_inform (location, expand_message (fmt, ap));
     355           52 :   va_end (ap);
     356           52 : }
     357              : 
     358              : // Rich Locations
     359              : void
     360           51 : rust_be_error_at (const rich_location &location, const std::string &errmsg)
     361              : {
     362              :   /* TODO: 'error_at' would like a non-'const' 'rich_location *'.  */
     363           51 :   rich_location &gcc_loc = const_cast<rich_location &> (location);
     364           51 :   error_at (&gcc_loc, "%s", errmsg.c_str ());
     365           51 : }
     366              : 
     367              : void
     368           51 : rust_error_at (const rich_location &location, const char *fmt, ...)
     369              : {
     370           51 :   va_list ap;
     371              : 
     372           51 :   va_start (ap, fmt);
     373           51 :   rust_be_error_at (location, expand_message (fmt, ap));
     374           51 :   va_end (ap);
     375           51 : }
     376              : 
     377              : void
     378            0 : rust_be_error_at (rich_location *richloc, const std::string &errmsg)
     379              : {
     380            0 :   error_at (richloc, "%s", errmsg.c_str ());
     381            0 : }
     382              : 
     383              : void
     384            0 : rust_error_at (rich_location *richloc, const char *fmt, ...)
     385              : {
     386              :   /* TODO: Refactoring diagnostics to this overload */
     387            0 :   va_list ap;
     388              : 
     389            0 :   va_start (ap, fmt);
     390            0 :   rust_be_error_at (richloc, expand_message (fmt, ap));
     391            0 :   va_end (ap);
     392            0 : }
     393              : 
     394              : bool
     395     11946070 : rust_be_debug_p (void)
     396              : {
     397     11946070 :   return !!flag_rust_debug;
     398              : }
     399              : 
     400              : void
     401     11946034 : rust_debug_loc (const location_t location, const char *fmt, ...)
     402              : {
     403     11946034 :   if (!rust_be_debug_p ())
     404     11945908 :     return;
     405              : 
     406          126 :   va_list ap;
     407              : 
     408          126 :   va_start (ap, fmt);
     409          126 :   char *mbuf = NULL;
     410          126 :   int nwr = vasprintf (&mbuf, fmt, ap);
     411          126 :   va_end (ap);
     412          126 :   if (nwr == -1)
     413              :     {
     414            0 :       rust_be_error_at (UNKNOWN_LOCATION,
     415            0 :                         "memory allocation failed in vasprintf");
     416            0 :       rust_assert (0);
     417              :     }
     418          126 :   std::string rval = std::string (mbuf);
     419          126 :   free (mbuf);
     420          126 :   rust_be_inform (location, rval);
     421          126 : }
     422              : 
     423              : namespace Rust {
     424              : 
     425              : /**
     426              :  * This function takes ownership of `args` and calls `va_end` on it
     427              :  */
     428              : 
     429              : // simple location
     430              : static Error va_constructor (Error::Kind kind, location_t locus,
     431              :                              const char *fmt, va_list args)
     432              :   RUST_ATTRIBUTE_GCC_DIAG (3, 0);
     433              : 
     434              : // simple location + error code
     435              : static Error va_constructor (Error::Kind kind, location_t locus,
     436              :                              const ErrorCode code, const char *fmt,
     437              :                              va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0);
     438              : 
     439              : // rich location
     440              : static Error va_constructor (Error::Kind kind, rich_location *r_locus,
     441              :                              const char *fmt, va_list args)
     442              :   RUST_ATTRIBUTE_GCC_DIAG (3, 0);
     443              : 
     444              : // rich location + error code
     445              : static Error va_constructor (Error::Kind kind, rich_location *r_locus,
     446              :                              const ErrorCode code, const char *fmt,
     447              :                              va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0);
     448              : 
     449              : // simple location
     450              : static Error
     451         2410 : va_constructor (Error::Kind kind, location_t locus, const char *fmt,
     452              :                 va_list args)
     453              : {
     454         2410 :   std::string message = expand_message (fmt, args);
     455         2410 :   message.shrink_to_fit ();
     456         2410 :   va_end (args);
     457              : 
     458         7230 :   return Error (kind, locus, message);
     459         2410 : }
     460              : 
     461              : // simple location + error code
     462              : static Error
     463           56 : va_constructor (Error::Kind kind, location_t locus, const ErrorCode code,
     464              :                 const char *fmt, va_list args)
     465              : {
     466           56 :   std::string message = expand_message (fmt, args);
     467           56 :   message.shrink_to_fit ();
     468           56 :   va_end (args);
     469              : 
     470          168 :   return Error (kind, locus, code, message);
     471           56 : }
     472              : 
     473              : // rich location
     474              : static Error
     475            0 : va_constructor (Error::Kind kind, rich_location *r_locus, const char *fmt,
     476              :                 va_list args)
     477              : {
     478            0 :   std::string message = expand_message (fmt, args);
     479            0 :   message.shrink_to_fit ();
     480            0 :   va_end (args);
     481              : 
     482            0 :   return Error (kind, r_locus, message);
     483            0 : }
     484              : 
     485              : // rich location + error code
     486              : static Error
     487            0 : va_constructor (Error::Kind kind, rich_location *r_locus, const ErrorCode code,
     488              :                 const char *fmt, va_list args)
     489              : {
     490            0 :   std::string message = expand_message (fmt, args);
     491            0 :   message.shrink_to_fit ();
     492            0 :   va_end (args);
     493              : 
     494            0 :   return Error (kind, r_locus, code, message);
     495            0 : }
     496              : 
     497              : // simple location
     498         2404 : Error::Error (const location_t location, const char *fmt, ...)
     499         2404 :   : kind (Kind::Err), locus (location)
     500              : {
     501         2404 :   va_list ap;
     502         2404 :   va_start (ap, fmt);
     503              : 
     504         2404 :   *this = va_constructor (Kind::Err, location, fmt, ap);
     505         2404 : }
     506              : 
     507              : // simple location + error code
     508           56 : Error::Error (const location_t location, const ErrorCode code, const char *fmt,
     509           56 :               ...)
     510           56 :   : kind (Kind::Err), locus (location), errorcode (code)
     511              : {
     512           56 :   va_list ap;
     513           56 :   va_start (ap, fmt);
     514              : 
     515           56 :   *this = va_constructor (Kind::Err, location, code, fmt, ap);
     516           56 : }
     517              : 
     518              : // rich location
     519            0 : Error::Error (rich_location *r_locus, const char *fmt, ...)
     520            0 :   : kind (Kind::Err), richlocus (r_locus)
     521              : {
     522            0 :   va_list ap;
     523            0 :   va_start (ap, fmt);
     524              : 
     525            0 :   *this = va_constructor (Kind::Err, r_locus, fmt, ap);
     526            0 : }
     527              : 
     528              : // rich location + error code
     529            0 : Error::Error (rich_location *r_locus, const ErrorCode code, const char *fmt,
     530            0 :               ...)
     531            0 :   : kind (Kind::Err), richlocus (r_locus), errorcode (code)
     532              : {
     533            0 :   va_list ap;
     534            0 :   va_start (ap, fmt);
     535              : 
     536            0 :   *this = va_constructor (Kind::Err, r_locus, code, fmt, ap);
     537            0 : }
     538              : 
     539              : Error
     540            6 : Error::Hint (const location_t location, const char *fmt, ...)
     541              : {
     542            6 :   va_list ap;
     543            6 :   va_start (ap, fmt);
     544              : 
     545            6 :   return va_constructor (Kind::Hint, location, fmt, ap);
     546              : }
     547              : 
     548              : Error
     549            0 : Error::Fatal (const location_t location, const char *fmt, ...)
     550              : {
     551            0 :   va_list ap;
     552            0 :   va_start (ap, fmt);
     553              : 
     554            0 :   return va_constructor (Kind::FatalErr, location, fmt, ap);
     555              : }
     556              : 
     557              : } // 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.