Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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 : 13097 : 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 : 6853 : Error (Kind kind, location_t locus, std::string message)
184 : 11268 : : kind (kind), locus (locus), message (std::move (message))
185 : : {
186 : 6853 : this->message.shrink_to_fit ();
187 : : }
188 : : // simple location + error code
189 : 49 : Error (Kind kind, location_t locus, ErrorCode code, std::string message)
190 : 49 : : kind (kind), locus (locus), errorcode (std::move (code)),
191 : 49 : message (std::move (message))
192 : : {
193 : 49 : is_errorcode = true;
194 : 49 : 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 : 4415 : Error (location_t locus, std::string message)
213 : 4415 : {
214 : 8830 : Error (Kind::Err, locus, std::move (message));
215 : 4415 : }
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 : 265 : void emit () const
272 : : {
273 : 265 : switch (kind)
274 : : {
275 : 6 : case Kind::Hint:
276 : 6 : rust_inform (locus, "%s", message.c_str ());
277 : 6 : break;
278 : 259 : case Kind::Err:
279 : 259 : if (is_errorcode)
280 : : {
281 : 32 : if (richlocus == nullptr)
282 : 32 : 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 : 227 : if (richlocus == nullptr)
289 : 227 : 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 : 265 : break;
297 : : }
298 : 265 : }
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)
|