Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : // rust-diagnostics.h -- interface to diagnostic reporting -*- C++ -*-
20 :
21 : #ifndef RUST_DIAGNOSTICS_H
22 : #define RUST_DIAGNOSTICS_H
23 :
24 : #include "rust-linemap.h"
25 : #include "util/optional.h"
26 :
27 : // This macro is used to specify the position of format string & it's
28 : // arguments within the function's parameter list.
29 : // 'm' specifies the position of the format string parameter.
30 : // 'n' specifies the position of the first argument for the format string.
31 : #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
32 : #define RUST_ATTRIBUTE_GCC_DIAG(m, n) \
33 : __attribute__ ((__format__ (__gcc_tdiag__, m, n))) \
34 : __attribute__ ((__nonnull__ (m)))
35 : #else
36 : #define RUST_ATTRIBUTE_GCC_DIAG(m, n)
37 : #endif
38 :
39 : // These declarations define the interface through which the frontend
40 : // reports errors and warnings. These functions accept printf-like
41 : // format specifiers (e.g. %d, %f, %s, etc), with the following additional
42 : // extensions:
43 : //
44 : // 1. 'q' qualifier may be applied to a specifier to add quoting, e.g.
45 : // %qd produces a quoted decimal output, %qs a quoted string output.
46 : // [This extension is supported only with single-character format
47 : // specifiers].
48 : //
49 : // 2. %m specifier outputs value of "strerror(errno)" at time of call.
50 : //
51 : // 3. %< outputs an opening quote, %> a closing quote.
52 : //
53 : // All other format specifiers are as defined by 'sprintf'. The final resulting
54 : // message is then sent to the back end via rust_be_error_at/rust_be_warning_at.
55 :
56 : // simple location
57 :
58 : // https://gist.github.com/MahadMuhammad/8c9d5fc88ea18d8c520937a8071d4185
59 :
60 : // We want E0005 to be mapped to the value `5` - this way, we can easily format
61 : // it in `make_description`. We also want to keep the value "5" only once when
62 : // defining the error code in rust-error-codes.def, so not have ERROR(E0005, 5)
63 : // as that is error prone. If we just use `0005` as the discriminant for the
64 : // `E0005` enum variant, then we are actually creating octal values (!) as `0`
65 : // is the C/C++ octal prefix. So this does not work for `E0009` for example,
66 : // since 0009 is not a valid octal literal.
67 : // We can circumvent this by doing a little bit of constant folding in the
68 : // discriminant expression. So for ERROR(E0009), this macro expands to the
69 : // following variant:
70 : //
71 : // E0009 = (10009 - 10000)
72 : //
73 : // which gets folded to the result of the substraction... 9. A valid decimal
74 : // literal which corresponds to E0009.
75 : #define ERROR(N) E##N = (1##N - 10000)
76 : enum class ErrorCode : unsigned int
77 : {
78 : #include "rust-error-codes.def"
79 : };
80 : #undef ERROR
81 :
82 : // clang-format off
83 : extern void
84 : rust_internal_error_at (const location_t, const char *fmt, ...)
85 : RUST_ATTRIBUTE_GCC_DIAG (2, 3)
86 : RUST_ATTRIBUTE_NORETURN;
87 : extern void
88 : rust_error_at (const location_t, const char *fmt, ...)
89 : RUST_ATTRIBUTE_GCC_DIAG (2, 3);
90 : extern void
91 : rust_error_at (const location_t, const ErrorCode, const char *fmt, ...)
92 : RUST_ATTRIBUTE_GCC_DIAG (3, 4);
93 : extern void
94 : rust_warning_at (const location_t, int opt, const char *fmt, ...)
95 : RUST_ATTRIBUTE_GCC_DIAG (3, 4);
96 : extern void
97 : rust_fatal_error (const location_t, const char *fmt, ...)
98 : RUST_ATTRIBUTE_GCC_DIAG (2, 3)
99 : RUST_ATTRIBUTE_NORETURN;
100 : extern void
101 : rust_inform (const location_t, const char *fmt, ...)
102 : RUST_ATTRIBUTE_GCC_DIAG (2, 3);
103 :
104 : // rich locations
105 : extern void
106 : rust_error_at (const rich_location &, const char *fmt, ...)
107 : RUST_ATTRIBUTE_GCC_DIAG (2, 3);
108 : extern void
109 : rust_error_at (const rich_location &, const ErrorCode, const char *fmt, ...)
110 : RUST_ATTRIBUTE_GCC_DIAG (3, 4);
111 : extern void /* similiar to other frontends */
112 : rust_error_at(rich_location *richloc,const char *fmt, ...)
113 : RUST_ATTRIBUTE_GCC_DIAG (2, 3);
114 : extern void /* similiar to other frontends */
115 : rust_error_at(rich_location *richloc, const ErrorCode, const char *fmt, ...)
116 : RUST_ATTRIBUTE_GCC_DIAG (3, 4);
117 : // clang-format on
118 :
119 : // These interfaces provide a way for the front end to ask for
120 : // the open/close quote characters it should use when formatting
121 : // diagnostics (warnings, errors).
122 : extern const char *rust_open_quote ();
123 : extern const char *rust_close_quote ();
124 :
125 : // These interfaces are used by utilities above to pass warnings and
126 : // errors (once format specifiers have been expanded) to the back end,
127 : // and to determine quoting style. Avoid calling these routines directly;
128 : // instead use the equivalent routines above. The back end is required to
129 : // implement these routines.
130 :
131 : // clang-format off
132 : extern void
133 : rust_be_internal_error_at (const location_t, const std::string &errmsg)
134 : RUST_ATTRIBUTE_NORETURN;
135 : extern void
136 : rust_be_error_at (const location_t, const std::string &errmsg);
137 : extern void
138 : rust_be_error_at (const location_t, const ErrorCode,
139 : const std::string &errmsg);
140 : extern void
141 : rust_be_error_at (const rich_location &, const std::string &errmsg);
142 : extern void
143 : rust_be_error_at (const rich_location &, const ErrorCode,
144 : const std::string &errmsg);
145 : extern void /* similiar to other frontends */
146 : rust_be_error_at (rich_location *richloc, const std::string &errmsg);
147 : extern void /* similiar to other frontends */
148 : rust_be_error_at (rich_location *richloc, const ErrorCode,
149 : const std::string &errmsg);
150 : extern void
151 : rust_be_warning_at (const location_t, int opt, const std::string &warningmsg);
152 : extern void
153 : rust_be_fatal_error (const location_t, const std::string &errmsg)
154 : RUST_ATTRIBUTE_NORETURN;
155 : extern void
156 : rust_be_inform (const location_t, const std::string &infomsg);
157 : extern void
158 : rust_be_get_quotechars (const char **open_quote, const char **close_quote);
159 : extern bool
160 : rust_be_debug_p (void);
161 : // clang-format on
162 :
163 : namespace Rust {
164 : /* A structure used to represent an error. Useful for enabling
165 : * errors to be ignored, e.g. if backtracking. */
166 13148 : struct Error
167 : {
168 : enum class Kind
169 : {
170 : Hint,
171 : Err,
172 : FatalErr,
173 : };
174 :
175 : Kind kind;
176 : location_t locus;
177 : rich_location *richlocus = nullptr;
178 : ErrorCode errorcode;
179 : std::string message;
180 : bool is_errorcode = false;
181 :
182 : // simple location
183 7060 : Error (Kind kind, location_t locus, std::string message)
184 11708 : : kind (kind), locus (locus), message (std::move (message))
185 : {
186 7060 : this->message.shrink_to_fit ();
187 : }
188 : // simple location + error code
189 56 : Error (Kind kind, location_t locus, ErrorCode code, std::string message)
190 56 : : kind (kind), locus (locus), errorcode (std::move (code)),
191 56 : message (std::move (message))
192 : {
193 56 : is_errorcode = true;
194 56 : this->message.shrink_to_fit ();
195 : }
196 : // rich location
197 0 : Error (Kind kind, rich_location *richlocus, std::string message)
198 0 : : kind (kind), richlocus (richlocus), message (std::move (message))
199 : {
200 0 : this->message.shrink_to_fit ();
201 : }
202 : // rich location + error code
203 0 : Error (Kind kind, rich_location *richlocus, ErrorCode code,
204 : std::string message)
205 0 : : kind (kind), richlocus (richlocus), errorcode (std::move (code)),
206 0 : message (std::move (message))
207 : {
208 0 : is_errorcode = true;
209 0 : this->message.shrink_to_fit ();
210 : }
211 : // simple location
212 4648 : Error (location_t locus, std::string message)
213 4648 : {
214 9296 : Error (Kind::Err, locus, std::move (message));
215 4648 : }
216 : // simple location + error code
217 : Error (location_t locus, ErrorCode code, std::string message)
218 : {
219 : Error (Kind::Err, locus, std::move (code), std::move (message));
220 : }
221 : // rich location
222 : Error (rich_location *richlocus, std::string message)
223 : {
224 : Error (Kind::Err, richlocus, std::move (message));
225 : }
226 : // rich location + error code
227 : Error (rich_location *richlocus, ErrorCode code, std::string message)
228 : {
229 : Error (Kind::Err, richlocus, std::move (code), std::move (message));
230 : }
231 :
232 : static Error Hint (location_t locus, std::string message)
233 : {
234 : return Error (Kind::Hint, locus, std::move (message));
235 : }
236 :
237 : static Error Fatal (location_t locus, std::string message)
238 : {
239 : return Error (Kind::FatalErr, locus, std::move (message));
240 : }
241 :
242 : // TODO: the attribute part might be incorrect
243 : // simple location
244 : Error (location_t locus, const char *fmt,
245 : ...) /*RUST_ATTRIBUTE_GCC_DIAG (2, 3)*/ RUST_ATTRIBUTE_GCC_DIAG (3, 4);
246 :
247 : // simple location + error code
248 : Error (location_t locus, ErrorCode code, const char *fmt,
249 : ...) /*RUST_ATTRIBUTE_GCC_DIAG (3, 4)*/ RUST_ATTRIBUTE_GCC_DIAG (4, 5);
250 :
251 : // rich location
252 : Error (rich_location *richlocus, const char *fmt,
253 : ...) /*RUST_ATTRIBUTE_GCC_DIAG (2, 3)*/ RUST_ATTRIBUTE_GCC_DIAG (3, 4);
254 :
255 : // rich location + error code
256 : Error (rich_location *richlocus, ErrorCode code, const char *fmt,
257 : ...) /*RUST_ATTRIBUTE_GCC_DIAG (3, 4)*/ RUST_ATTRIBUTE_GCC_DIAG (4, 5);
258 :
259 : /**
260 : * printf-like overload of Error::Hint
261 : */
262 : static Error Hint (location_t locus, const char *fmt, ...)
263 : RUST_ATTRIBUTE_GCC_DIAG (2, 3);
264 :
265 : /**
266 : * printf-like overload of Error::Fatal
267 : */
268 : static Error Fatal (location_t locus, const char *fmt, ...)
269 : RUST_ATTRIBUTE_GCC_DIAG (2, 3);
270 :
271 219 : void emit () const
272 : {
273 219 : switch (kind)
274 : {
275 7 : case Kind::Hint:
276 7 : rust_inform (locus, "%s", message.c_str ());
277 7 : break;
278 212 : case Kind::Err:
279 212 : if (is_errorcode)
280 : {
281 36 : if (richlocus == nullptr)
282 36 : rust_error_at (locus, errorcode, "%s", message.c_str ());
283 : else
284 0 : rust_error_at (*richlocus, errorcode, "%s", message.c_str ());
285 : }
286 : else
287 : {
288 176 : if (richlocus == nullptr)
289 176 : rust_error_at (locus, "%s", message.c_str ());
290 : else
291 0 : rust_error_at (*richlocus, "%s", message.c_str ());
292 : }
293 : break;
294 0 : case Kind::FatalErr:
295 0 : rust_fatal_error (locus, "%s", message.c_str ());
296 219 : break;
297 : }
298 219 : }
299 : };
300 : } // namespace Rust
301 :
302 : // rust_debug uses normal printf formatting, not GCC diagnostic formatting.
303 : #define rust_debug(...) rust_debug_loc (UNDEF_LOCATION, __VA_ARGS__)
304 :
305 : #define rust_sorry_at(location, ...) sorry_at (location, __VA_ARGS__)
306 :
307 : void rust_debug_loc (const location_t location, const char *fmt,
308 : ...) ATTRIBUTE_PRINTF_2;
309 :
310 : #endif // !defined(RUST_DIAGNOSTICS_H)
|