Require target lra in gcc.dg/pr108095.c
[official-gcc.git] / gcc / rust / rust-diagnostics.cc
blob16665b058d191881f6610fd83163e00b19917ce2
1 // rust-diagnostics.cc -- GCC implementation of rust diagnostics interface.
2 // Copyright (C) 2016-2023 Free Software Foundation, Inc.
3 // Contributed by Than McIntosh, Google.
5 // This file is part of GCC.
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.
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.
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/>.
21 #include "rust-system.h"
22 #include "rust-diagnostics.h"
24 #include "options.h"
25 #include "diagnostic-metadata.h"
27 static std::string
28 mformat_value ()
30 return std::string (xstrerror (errno));
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.
37 static std::string
38 expand_format (const char *fmt)
40 std::stringstream ss;
41 for (const char *c = fmt; *c; ++c)
43 if (*c != '%')
45 ss << *c;
46 continue;
48 c++;
49 switch (*c)
51 case '\0': {
52 // malformed format string
53 rust_unreachable ();
55 case '%': {
56 ss << "%";
57 break;
59 case 'm': {
60 ss << mformat_value ();
61 break;
63 case '<': {
64 ss << rust_open_quote ();
65 break;
67 case '>': {
68 ss << rust_close_quote ();
69 break;
71 case 'q': {
72 ss << rust_open_quote ();
73 c++;
74 if (*c == 'm')
76 ss << mformat_value ();
78 else
80 ss << "%" << *c;
82 ss << rust_close_quote ();
83 break;
85 default: {
86 ss << "%" << *c;
90 return ss.str ();
93 // Expand message format specifiers, using a combination of
94 // expand_format above to handle extensions (ex: %m, %q) and vasprintf()
95 // to handle regular printf-style formatting. A pragma is being used here to
96 // suppress this warning:
98 // warning: function ‘std::__cxx11::string expand_message(const char*,
99 // __va_list_tag*)’ might be a candidate for ‘gnu_printf’ format attribute
100 // [-Wsuggest-attribute=format]
102 // What appears to be happening here is that the checker is deciding that
103 // because of the call to vasprintf() (which has attribute gnu_printf), the
104 // calling function must need to have attribute gnu_printf as well, even
105 // though there is already an attribute declaration for it.
107 static std::string
108 expand_message (const char *fmt, va_list ap) RUST_ATTRIBUTE_GCC_DIAG (1, 0);
110 #pragma GCC diagnostic push
111 #pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
113 static std::string
114 expand_message (const char *fmt, va_list ap)
116 char *mbuf = 0;
117 std::string expanded_fmt = expand_format (fmt);
118 int nwr = vasprintf (&mbuf, expanded_fmt.c_str (), ap);
119 if (nwr == -1)
121 // memory allocation failed
122 rust_be_error_at (Linemap::unknown_location (),
123 "memory allocation failed in vasprintf");
124 rust_assert (0);
126 std::string rval = std::string (mbuf);
127 free (mbuf);
128 return rval;
131 #pragma GCC diagnostic pop
133 static const char *cached_open_quote = NULL;
134 static const char *cached_close_quote = NULL;
136 void
137 rust_be_get_quotechars (const char **open_qu, const char **close_qu)
139 *open_qu = open_quote;
140 *close_qu = close_quote;
143 const char *
144 rust_open_quote ()
146 if (cached_open_quote == NULL)
147 rust_be_get_quotechars (&cached_open_quote, &cached_close_quote);
148 return cached_open_quote;
151 const char *
152 rust_close_quote ()
154 if (cached_close_quote == NULL)
155 rust_be_get_quotechars (&cached_open_quote, &cached_close_quote);
156 return cached_close_quote;
159 void
160 rust_be_internal_error_at (const Location location, const std::string &errmsg)
162 std::string loc_str = Linemap::location_to_string (location);
163 if (loc_str.empty ())
164 internal_error ("%s", errmsg.c_str ());
165 else
166 internal_error ("at %s, %s", loc_str.c_str (), errmsg.c_str ());
169 void
170 rust_internal_error_at (const Location location, const char *fmt, ...)
172 va_list ap;
174 va_start (ap, fmt);
175 rust_be_internal_error_at (location, expand_message (fmt, ap));
176 va_end (ap);
179 void
180 rust_be_error_at (const Location location, const std::string &errmsg)
182 location_t gcc_loc = location.gcc_location ();
183 error_at (gcc_loc, "%s", errmsg.c_str ());
186 void
187 rust_error_at (const Location location, const char *fmt, ...)
189 va_list ap;
191 va_start (ap, fmt);
192 rust_be_error_at (location, expand_message (fmt, ap));
193 va_end (ap);
196 class rust_error_code_rule : public diagnostic_metadata::rule
198 public:
199 rust_error_code_rule (const ErrorCode code) : m_code (code) {}
201 char *make_description () const final override
203 return xstrdup (m_code.m_str);
206 char *make_url () const final override
208 return concat ("https://doc.rust-lang.org/error-index.html#", m_code.m_str,
209 NULL);
212 private:
213 const ErrorCode m_code;
216 void
217 rust_be_error_at (const RichLocation &location, const ErrorCode code,
218 const std::string &errmsg)
220 /* TODO: 'error_at' would like a non-'const' 'rich_location *'. */
221 rich_location &gcc_loc = const_cast<rich_location &> (location.get ());
222 diagnostic_metadata m;
223 rust_error_code_rule rule (code);
224 m.add_rule (rule);
225 error_meta (&gcc_loc, m, "%s", errmsg.c_str ());
228 void
229 rust_error_at (const RichLocation &location, const ErrorCode code,
230 const char *fmt, ...)
232 va_list ap;
234 va_start (ap, fmt);
235 rust_be_error_at (location, code, expand_message (fmt, ap));
236 va_end (ap);
239 void
240 rust_be_warning_at (const Location location, int opt,
241 const std::string &warningmsg)
243 location_t gcc_loc = location.gcc_location ();
244 warning_at (gcc_loc, opt, "%s", warningmsg.c_str ());
247 void
248 rust_warning_at (const Location location, int opt, const char *fmt, ...)
250 va_list ap;
252 va_start (ap, fmt);
253 rust_be_warning_at (location, opt, expand_message (fmt, ap));
254 va_end (ap);
257 void
258 rust_be_fatal_error (const Location location, const std::string &fatalmsg)
260 location_t gcc_loc = location.gcc_location ();
261 fatal_error (gcc_loc, "%s", fatalmsg.c_str ());
264 void
265 rust_fatal_error (const Location location, const char *fmt, ...)
267 va_list ap;
269 va_start (ap, fmt);
270 rust_be_fatal_error (location, expand_message (fmt, ap));
271 va_end (ap);
274 void
275 rust_be_inform (const Location location, const std::string &infomsg)
277 location_t gcc_loc = location.gcc_location ();
278 inform (gcc_loc, "%s", infomsg.c_str ());
281 void
282 rust_inform (const Location location, const char *fmt, ...)
284 va_list ap;
286 va_start (ap, fmt);
287 rust_be_inform (location, expand_message (fmt, ap));
288 va_end (ap);
291 // Rich Locations
292 void
293 rust_be_error_at (const RichLocation &location, const std::string &errmsg)
295 /* TODO: 'error_at' would like a non-'const' 'rich_location *'. */
296 rich_location &gcc_loc = const_cast<rich_location &> (location.get ());
297 error_at (&gcc_loc, "%s", errmsg.c_str ());
300 void
301 rust_error_at (const RichLocation &location, const char *fmt, ...)
303 va_list ap;
305 va_start (ap, fmt);
306 rust_be_error_at (location, expand_message (fmt, ap));
307 va_end (ap);
310 bool
311 rust_be_debug_p (void)
313 return !!flag_rust_debug;
316 void
317 rust_debug_loc (const Location location, const char *fmt, ...)
319 if (!rust_be_debug_p ())
320 return;
322 va_list ap;
324 va_start (ap, fmt);
325 char *mbuf = NULL;
326 int nwr = vasprintf (&mbuf, fmt, ap);
327 va_end (ap);
328 if (nwr == -1)
330 rust_be_error_at (Linemap::unknown_location (),
331 "memory allocation failed in vasprintf");
332 rust_assert (0);
334 std::string rval = std::string (mbuf);
335 free (mbuf);
336 rust_be_inform (location, rval);
339 namespace Rust {
342 * This function takes ownership of `args` and calls `va_end` on it
344 static Error
345 va_constructor (Error::Kind kind, Location locus, const char *fmt, va_list args)
346 RUST_ATTRIBUTE_GCC_DIAG (3, 0);
348 static Error
349 va_constructor (Error::Kind kind, Location locus, const char *fmt, va_list args)
351 std::string message = expand_message (fmt, args);
352 message.shrink_to_fit ();
353 va_end (args);
355 return Error (kind, locus, message);
358 Error::Error (const Location location, const char *fmt, ...)
359 : kind (Kind::Err), locus (location)
361 va_list ap;
362 va_start (ap, fmt);
364 *this = va_constructor (Kind::Err, location, fmt, ap);
367 Error
368 Error::Hint (const Location location, const char *fmt, ...)
370 va_list ap;
371 va_start (ap, fmt);
373 return va_constructor (Kind::Hint, location, fmt, ap);
376 Error
377 Error::Fatal (const Location location, const char *fmt, ...)
379 va_list ap;
380 va_start (ap, fmt);
382 return va_constructor (Kind::FatalErr, location, fmt, ap);
385 } // namespace Rust