LCOV - code coverage report
Current view: top level - gcc/rust - rust-diagnostics.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 71.8 % 259 186
Test Date: 2026-09-12 16:25:28 Functions: 75.6 % 41 31
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        55874 : expand_format (const char *fmt)
      39              : {
      40        55874 :   std::stringstream ss;
      41      1932614 :   for (const char *c = fmt; *c; ++c)
      42              :     {
      43      1820866 :       if (*c != '%')
      44              :         {
      45      1779227 :           ss << *c;
      46      1779227 :           continue;
      47              :         }
      48        41639 :       c++;
      49        41639 :       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          349 :         case '<':
      67          349 :           {
      68          349 :             ss << rust_open_quote ();
      69          349 :             break;
      70              :           }
      71          349 :         case '>':
      72          349 :           {
      73          349 :             ss << rust_close_quote ();
      74          349 :             break;
      75              :           }
      76        40193 :         case 'q':
      77        40193 :           {
      78        40193 :             ss << rust_open_quote ();
      79        40193 :             c++;
      80        40193 :             if (*c == 'm')
      81              :               {
      82            0 :                 ss << mformat_value ();
      83              :               }
      84              :             else
      85              :               {
      86        40193 :                 ss << "%" << *c;
      87              :               }
      88        40193 :             ss << rust_close_quote ();
      89        40193 :             break;
      90              :           }
      91          733 :         default:
      92          733 :           {
      93          733 :             ss << "%" << *c;
      94              :           }
      95              :         }
      96              :     }
      97        55874 :   return ss.str ();
      98        55874 : }
      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        55874 : expand_message (const char *fmt, va_list ap)
     122              : {
     123        55874 :   char *mbuf = 0;
     124        55874 :   std::string expanded_fmt = expand_format (fmt);
     125        55874 :   int nwr = vasprintf (&mbuf, expanded_fmt.c_str (), ap);
     126        55874 :   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        55874 :   std::string rval = std::string (mbuf);
     134        55874 :   free (mbuf);
     135        55874 :   return rval;
     136        55874 : }
     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         1401 : rust_be_get_quotechars (const char **open_qu, const char **close_qu)
     145              : {
     146         1401 :   *open_qu = open_quote;
     147         1401 :   *close_qu = close_quote;
     148         1401 : }
     149              : 
     150              : const char *
     151        40547 : rust_open_quote ()
     152              : {
     153        40547 :   if (cached_open_quote == NULL)
     154         1401 :     rust_be_get_quotechars (&cached_open_quote, &cached_close_quote);
     155        40547 :   return cached_open_quote;
     156              : }
     157              : 
     158              : const char *
     159        40547 : rust_close_quote ()
     160              : {
     161        40547 :   if (cached_close_quote == NULL)
     162            0 :     rust_be_get_quotechars (&cached_open_quote, &cached_close_quote);
     163        40547 :   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          704 : rust_be_error_at (const location_t location, const std::string &errmsg)
     188              : {
     189          704 :   error_at (location, "%s", errmsg.c_str ());
     190          704 : }
     191              : 
     192              : void
     193          704 : rust_error_at (const location_t location, const char *fmt, ...)
     194              : {
     195          704 :   va_list ap;
     196              : 
     197          704 :   va_start (ap, fmt);
     198          704 :   rust_be_error_at (location, expand_message (fmt, ap));
     199          704 :   va_end (ap);
     200          704 : }
     201              : 
     202              : class rust_error_code_rule : public diagnostics::metadata::rule
     203              : {
     204              : public:
     205          534 :   rust_error_code_rule (const ErrorCode code) : m_code (code) {}
     206              : 
     207          534 :   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          534 :     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          534 :     snprintf (buffer, 6, "E%04u",
     217          534 :               (std::underlying_type<ErrorCode>::type) m_code);
     218              :   }
     219              : 
     220          534 :   char *make_description () const final override
     221              :   {
     222              :     // 'E' + 4 characters + \0
     223          534 :     char *buffer = static_cast<char *> (xcalloc (6, sizeof (char)));
     224              : 
     225          534 :     format_error_code (buffer);
     226              : 
     227          534 :     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          287 : rust_be_error_at (const location_t location, const ErrorCode code,
     244              :                   const std::string &errmsg)
     245              : {
     246          287 :   rich_location gcc_loc (line_table, location);
     247          287 :   diagnostics::metadata m;
     248          287 :   rust_error_code_rule rule (code);
     249          287 :   m.add_rule (rule);
     250          287 :   error_meta (&gcc_loc, m, "%s", errmsg.c_str ());
     251          287 : }
     252              : 
     253              : void
     254          287 : rust_error_at (const location_t location, const ErrorCode code, const char *fmt,
     255              :                ...)
     256              : {
     257          287 :   va_list ap;
     258              : 
     259          287 :   va_start (ap, fmt);
     260          287 :   rust_be_error_at (location, code, expand_message (fmt, ap));
     261          287 :   va_end (ap);
     262          287 : }
     263              : 
     264              : void
     265          247 : 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          247 :   rich_location &gcc_loc = const_cast<rich_location &> (location);
     270          247 :   diagnostics::metadata m;
     271          247 :   rust_error_code_rule rule (code);
     272          247 :   m.add_rule (rule);
     273          247 :   error_meta (&gcc_loc, m, "%s", errmsg.c_str ());
     274          247 : }
     275              : 
     276              : void
     277          247 : rust_error_at (const rich_location &location, const ErrorCode code,
     278              :                const char *fmt, ...)
     279              : {
     280          247 :   va_list ap;
     281              : 
     282          247 :   va_start (ap, fmt);
     283          247 :   rust_be_error_at (location, code, expand_message (fmt, ap));
     284          247 :   va_end (ap);
     285          247 : }
     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         1267 : rust_be_warning_at (const location_t location, int opt,
     311              :                     const std::string &warningmsg)
     312              : {
     313         1267 :   warning_at (location, opt, "%s", warningmsg.c_str ());
     314         1267 : }
     315              : 
     316              : void
     317         1267 : rust_warning_at (const location_t location, int opt, const char *fmt, ...)
     318              : {
     319         1267 :   va_list ap;
     320              : 
     321         1267 :   va_start (ap, fmt);
     322         1267 :   rust_be_warning_at (location, opt, expand_message (fmt, ap));
     323         1267 :   va_end (ap);
     324         1267 : }
     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           54 : 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           54 :   rich_location &gcc_loc = const_cast<rich_location &> (location);
     364           54 :   error_at (&gcc_loc, "%s", errmsg.c_str ());
     365           54 : }
     366              : 
     367              : void
     368           54 : rust_error_at (const rich_location &location, const char *fmt, ...)
     369              : {
     370           54 :   va_list ap;
     371              : 
     372           54 :   va_start (ap, fmt);
     373           54 :   rust_be_error_at (location, expand_message (fmt, ap));
     374           54 :   va_end (ap);
     375           54 : }
     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    665846556 : rust_be_debug_p (void)
     396              : {
     397    665846556 :   return !!flag_rust_debug;
     398              : }
     399              : 
     400              : void
     401    665846507 : rust_debug_loc (const location_t location, const char *fmt, ...)
     402              : {
     403    665846507 :   if (!rust_be_debug_p ())
     404    665846356 :     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              : void
     424            2 : rust_debug_fmt_at (const location_t location, const char *fmt, ...)
     425              : {
     426            2 :   if (!rust_be_debug_p ())
     427              :     return;
     428              : 
     429            0 :   va_list ap;
     430              : 
     431            0 :   va_start (ap, fmt);
     432            0 :   rust_be_inform (location, expand_message (fmt, ap));
     433            0 :   va_end (ap);
     434              : }
     435              : 
     436              : namespace Rust {
     437              : 
     438              : /**
     439              :  * This function takes ownership of `args` and calls `va_end` on it
     440              :  */
     441              : 
     442              : // simple location
     443              : static Error va_constructor (Error::Kind kind, location_t locus,
     444              :                              const char *fmt, va_list args)
     445              :   RUST_ATTRIBUTE_GCC_DIAG (3, 0);
     446              : 
     447              : // simple location + error code
     448              : static Error va_constructor (Error::Kind kind, location_t locus,
     449              :                              const ErrorCode code, const char *fmt,
     450              :                              va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0);
     451              : 
     452              : // rich location
     453              : static Error va_constructor (Error::Kind kind, rich_location *r_locus,
     454              :                              const char *fmt, va_list args)
     455              :   RUST_ATTRIBUTE_GCC_DIAG (3, 0);
     456              : 
     457              : // rich location + error code
     458              : static Error va_constructor (Error::Kind kind, rich_location *r_locus,
     459              :                              const ErrorCode code, const char *fmt,
     460              :                              va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0);
     461              : 
     462              : // simple location
     463              : static Error
     464        52852 : va_constructor (Error::Kind kind, location_t locus, const char *fmt,
     465              :                 va_list args)
     466              : {
     467        52852 :   std::string message = expand_message (fmt, args);
     468        52852 :   message.shrink_to_fit ();
     469        52852 :   va_end (args);
     470              : 
     471       158556 :   return Error (kind, locus, message);
     472        52852 : }
     473              : 
     474              : // simple location + error code
     475              : static Error
     476          395 : va_constructor (Error::Kind kind, location_t locus, const ErrorCode code,
     477              :                 const char *fmt, va_list args)
     478              : {
     479          395 :   std::string message = expand_message (fmt, args);
     480          395 :   message.shrink_to_fit ();
     481          395 :   va_end (args);
     482              : 
     483         1185 :   return Error (kind, locus, code, message);
     484          395 : }
     485              : 
     486              : // rich location
     487              : static Error
     488            0 : va_constructor (Error::Kind kind, rich_location *r_locus, const char *fmt,
     489              :                 va_list args)
     490              : {
     491            0 :   std::string message = expand_message (fmt, args);
     492            0 :   message.shrink_to_fit ();
     493            0 :   va_end (args);
     494              : 
     495            0 :   return Error (kind, r_locus, message);
     496            0 : }
     497              : 
     498              : // rich location + error code
     499              : static Error
     500            0 : va_constructor (Error::Kind kind, rich_location *r_locus, const ErrorCode code,
     501              :                 const char *fmt, va_list args)
     502              : {
     503            0 :   std::string message = expand_message (fmt, args);
     504            0 :   message.shrink_to_fit ();
     505            0 :   va_end (args);
     506              : 
     507            0 :   return Error (kind, r_locus, code, message);
     508            0 : }
     509              : 
     510              : // simple location
     511        52846 : Error::Error (const location_t location, const char *fmt, ...)
     512        52846 :   : kind (Kind::Err), locus (location)
     513              : {
     514        52846 :   va_list ap;
     515        52846 :   va_start (ap, fmt);
     516              : 
     517        52846 :   *this = va_constructor (Kind::Err, location, fmt, ap);
     518        52846 : }
     519              : 
     520              : // simple location + error code
     521          395 : Error::Error (const location_t location, const ErrorCode code, const char *fmt,
     522              :               ...)
     523          395 :   : kind (Kind::Err), locus (location), errorcode (code)
     524              : {
     525          395 :   va_list ap;
     526          395 :   va_start (ap, fmt);
     527              : 
     528          395 :   *this = va_constructor (Kind::Err, location, code, fmt, ap);
     529          395 : }
     530              : 
     531              : // rich location
     532            0 : Error::Error (rich_location *r_locus, const char *fmt, ...)
     533            0 :   : kind (Kind::Err), richlocus (r_locus)
     534              : {
     535            0 :   va_list ap;
     536            0 :   va_start (ap, fmt);
     537              : 
     538            0 :   *this = va_constructor (Kind::Err, r_locus, fmt, ap);
     539            0 : }
     540              : 
     541              : // rich location + error code
     542            0 : Error::Error (rich_location *r_locus, const ErrorCode code, const char *fmt,
     543              :               ...)
     544            0 :   : kind (Kind::Err), richlocus (r_locus), errorcode (code)
     545              : {
     546            0 :   va_list ap;
     547            0 :   va_start (ap, fmt);
     548              : 
     549            0 :   *this = va_constructor (Kind::Err, r_locus, code, fmt, ap);
     550            0 : }
     551              : 
     552              : Error
     553            6 : Error::Hint (const location_t location, const char *fmt, ...)
     554              : {
     555            6 :   va_list ap;
     556            6 :   va_start (ap, fmt);
     557              : 
     558            6 :   return va_constructor (Kind::Hint, location, fmt, ap);
     559              : }
     560              : 
     561              : Error
     562            0 : Error::Fatal (const location_t location, const char *fmt, ...)
     563              : {
     564            0 :   va_list ap;
     565            0 :   va_start (ap, fmt);
     566              : 
     567            0 :   return va_constructor (Kind::FatalErr, location, fmt, ap);
     568              : }
     569              : 
     570              : } // 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.