LCOV - code coverage report
Current view: top level - gcc/rust - rust-diagnostics.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 72.7 % 253 184
Test Date: 2026-08-22 16:33:35 Functions: 75.0 % 40 30
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        20482 : expand_format (const char *fmt)
      39              : {
      40        20482 :   std::stringstream ss;
      41       704108 :   for (const char *c = fmt; *c; ++c)
      42              :     {
      43       663144 :       if (*c != '%')
      44              :         {
      45       643199 :           ss << *c;
      46       643199 :           continue;
      47              :         }
      48        19945 :       c++;
      49        19945 :       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          342 :         case '<':
      67          342 :           {
      68          342 :             ss << rust_open_quote ();
      69          342 :             break;
      70              :           }
      71          342 :         case '>':
      72          342 :           {
      73          342 :             ss << rust_close_quote ();
      74          342 :             break;
      75              :           }
      76        18518 :         case 'q':
      77        18518 :           {
      78        18518 :             ss << rust_open_quote ();
      79        18518 :             c++;
      80        18518 :             if (*c == 'm')
      81              :               {
      82            0 :                 ss << mformat_value ();
      83              :               }
      84              :             else
      85              :               {
      86        18518 :                 ss << "%" << *c;
      87              :               }
      88        18518 :             ss << rust_close_quote ();
      89        18518 :             break;
      90              :           }
      91          728 :         default:
      92          728 :           {
      93          728 :             ss << "%" << *c;
      94              :           }
      95              :         }
      96              :     }
      97        20482 :   return ss.str ();
      98        20482 : }
      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        20482 : expand_message (const char *fmt, va_list ap)
     122              : {
     123        20482 :   char *mbuf = 0;
     124        20482 :   std::string expanded_fmt = expand_format (fmt);
     125        20482 :   int nwr = vasprintf (&mbuf, expanded_fmt.c_str (), ap);
     126        20482 :   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        20482 :   std::string rval = std::string (mbuf);
     134        20482 :   free (mbuf);
     135        20482 :   return rval;
     136        20482 : }
     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         1368 : rust_be_get_quotechars (const char **open_qu, const char **close_qu)
     145              : {
     146         1368 :   *open_qu = open_quote;
     147         1368 :   *close_qu = close_quote;
     148         1368 : }
     149              : 
     150              : const char *
     151        18865 : rust_open_quote ()
     152              : {
     153        18865 :   if (cached_open_quote == NULL)
     154         1368 :     rust_be_get_quotechars (&cached_open_quote, &cached_close_quote);
     155        18865 :   return cached_open_quote;
     156              : }
     157              : 
     158              : const char *
     159        18865 : rust_close_quote ()
     160              : {
     161        18865 :   if (cached_close_quote == NULL)
     162            0 :     rust_be_get_quotechars (&cached_open_quote, &cached_close_quote);
     163        18865 :   return cached_close_quote;
     164              : }
     165              : 
     166              : void
     167            2 : rust_be_internal_error_at (const location_t location, const std::string &errmsg)
     168              : {
     169            2 :   std::string loc_str = Linemap::location_to_string (location);
     170            2 :   if (loc_str.empty ())
     171            0 :     internal_error ("%s", errmsg.c_str ());
     172              :   else
     173            2 :     internal_error ("at %s, %s", loc_str.c_str (), errmsg.c_str ());
     174              : }
     175              : 
     176              : void
     177            2 : rust_internal_error_at (const location_t location, const char *fmt, ...)
     178              : {
     179            2 :   va_list ap;
     180              : 
     181            2 :   va_start (ap, fmt);
     182            2 :   rust_be_internal_error_at (location, expand_message (fmt, ap));
     183              :   va_end (ap);
     184              : }
     185              : 
     186              : void
     187          689 : rust_be_error_at (const location_t location, const std::string &errmsg)
     188              : {
     189          689 :   error_at (location, "%s", errmsg.c_str ());
     190          689 : }
     191              : 
     192              : void
     193          689 : rust_error_at (const location_t location, const char *fmt, ...)
     194              : {
     195          689 :   va_list ap;
     196              : 
     197          689 :   va_start (ap, fmt);
     198          689 :   rust_be_error_at (location, expand_message (fmt, ap));
     199          689 :   va_end (ap);
     200          689 : }
     201              : 
     202              : class rust_error_code_rule : public diagnostics::metadata::rule
     203              : {
     204              : public:
     205          512 :   rust_error_code_rule (const ErrorCode code) : m_code (code) {}
     206              : 
     207          512 :   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          512 :     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          512 :     snprintf (buffer, 6, "E%04u",
     217          512 :               (std::underlying_type<ErrorCode>::type) m_code);
     218              :   }
     219              : 
     220          512 :   char *make_description () const final override
     221              :   {
     222              :     // 'E' + 4 characters + \0
     223          512 :     char *buffer = static_cast<char *> (xcalloc (6, sizeof (char)));
     224              : 
     225          512 :     format_error_code (buffer);
     226              : 
     227          512 :     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          286 : rust_be_error_at (const location_t location, const ErrorCode code,
     244              :                   const std::string &errmsg)
     245              : {
     246          286 :   rich_location gcc_loc (line_table, location);
     247          286 :   diagnostics::metadata m;
     248          286 :   rust_error_code_rule rule (code);
     249          286 :   m.add_rule (rule);
     250          286 :   error_meta (&gcc_loc, m, "%s", errmsg.c_str ());
     251          286 : }
     252              : 
     253              : void
     254          286 : rust_error_at (const location_t location, const ErrorCode code, const char *fmt,
     255              :                ...)
     256              : {
     257          286 :   va_list ap;
     258              : 
     259          286 :   va_start (ap, fmt);
     260          286 :   rust_be_error_at (location, code, expand_message (fmt, ap));
     261          286 :   va_end (ap);
     262          286 : }
     263              : 
     264              : void
     265          226 : 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          226 :   rich_location &gcc_loc = const_cast<rich_location &> (location);
     270          226 :   diagnostics::metadata m;
     271          226 :   rust_error_code_rule rule (code);
     272          226 :   m.add_rule (rule);
     273          226 :   error_meta (&gcc_loc, m, "%s", errmsg.c_str ());
     274          226 : }
     275              : 
     276              : void
     277          226 : rust_error_at (const rich_location &location, const ErrorCode code,
     278              :                const char *fmt, ...)
     279              : {
     280          226 :   va_list ap;
     281              : 
     282          226 :   va_start (ap, fmt);
     283          226 :   rust_be_error_at (location, code, expand_message (fmt, ap));
     284          226 :   va_end (ap);
     285          226 : }
     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         1246 : rust_be_warning_at (const location_t location, int opt,
     311              :                     const std::string &warningmsg)
     312              : {
     313         1246 :   warning_at (location, opt, "%s", warningmsg.c_str ());
     314         1246 : }
     315              : 
     316              : void
     317         1246 : rust_warning_at (const location_t location, int opt, const char *fmt, ...)
     318              : {
     319         1246 :   va_list ap;
     320              : 
     321         1246 :   va_start (ap, fmt);
     322         1246 :   rust_be_warning_at (location, opt, expand_message (fmt, ap));
     323         1246 :   va_end (ap);
     324         1246 : }
     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          216 : rust_be_inform (const location_t location, const std::string &infomsg)
     344              : {
     345          216 :   inform (location, "%s", infomsg.c_str ());
     346          216 : }
     347              : 
     348              : void
     349           65 : rust_inform (const location_t location, const char *fmt, ...)
     350              : {
     351           65 :   va_list ap;
     352              : 
     353           65 :   va_start (ap, fmt);
     354           65 :   rust_be_inform (location, expand_message (fmt, ap));
     355           65 :   va_end (ap);
     356           65 : }
     357              : 
     358              : // Rich Locations
     359              : void
     360           55 : 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           55 :   rich_location &gcc_loc = const_cast<rich_location &> (location);
     364           55 :   error_at (&gcc_loc, "%s", errmsg.c_str ());
     365           55 : }
     366              : 
     367              : void
     368           55 : rust_error_at (const rich_location &location, const char *fmt, ...)
     369              : {
     370           55 :   va_list ap;
     371              : 
     372           55 :   va_start (ap, fmt);
     373           55 :   rust_be_error_at (location, expand_message (fmt, ap));
     374           55 :   va_end (ap);
     375           55 : }
     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    661834918 : rust_be_debug_p (void)
     396              : {
     397    661834918 :   return !!flag_rust_debug;
     398              : }
     399              : 
     400              : void
     401    661834882 : rust_debug_loc (const location_t location, const char *fmt, ...)
     402              : {
     403    661834882 :   if (!rust_be_debug_p ())
     404    661834731 :     return;
     405              : 
     406          151 :   va_list ap;
     407              : 
     408          151 :   va_start (ap, fmt);
     409          151 :   char *mbuf = NULL;
     410          151 :   int nwr = vasprintf (&mbuf, fmt, ap);
     411          151 :   va_end (ap);
     412          151 :   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          151 :   std::string rval = std::string (mbuf);
     419          151 :   free (mbuf);
     420          151 :   rust_be_inform (location, rval);
     421          151 : }
     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        17517 : va_constructor (Error::Kind kind, location_t locus, const char *fmt,
     452              :                 va_list args)
     453              : {
     454        17517 :   std::string message = expand_message (fmt, args);
     455        17517 :   message.shrink_to_fit ();
     456        17517 :   va_end (args);
     457              : 
     458        52551 :   return Error (kind, locus, message);
     459        17517 : }
     460              : 
     461              : // simple location + error code
     462              : static Error
     463          395 : va_constructor (Error::Kind kind, location_t locus, const ErrorCode code,
     464              :                 const char *fmt, va_list args)
     465              : {
     466          395 :   std::string message = expand_message (fmt, args);
     467          395 :   message.shrink_to_fit ();
     468          395 :   va_end (args);
     469              : 
     470         1185 :   return Error (kind, locus, code, message);
     471          395 : }
     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        17511 : Error::Error (const location_t location, const char *fmt, ...)
     499        17511 :   : kind (Kind::Err), locus (location)
     500              : {
     501        17511 :   va_list ap;
     502        17511 :   va_start (ap, fmt);
     503              : 
     504        17511 :   *this = va_constructor (Kind::Err, location, fmt, ap);
     505        17511 : }
     506              : 
     507              : // simple location + error code
     508          395 : Error::Error (const location_t location, const ErrorCode code, const char *fmt,
     509              :               ...)
     510          395 :   : kind (Kind::Err), locus (location), errorcode (code)
     511              : {
     512          395 :   va_list ap;
     513          395 :   va_start (ap, fmt);
     514              : 
     515          395 :   *this = va_constructor (Kind::Err, location, code, fmt, ap);
     516          395 : }
     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              :               ...)
     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.