Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 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 paramter 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 *
123 : : rust_open_quote ();
124 : : extern const char *
125 : : rust_close_quote ();
126 : :
127 : : // These interfaces are used by utilities above to pass warnings and
128 : : // errors (once format specifiers have been expanded) to the back end,
129 : : // and to determine quoting style. Avoid calling these routines directly;
130 : : // instead use the equivalent routines above. The back end is required to
131 : : // implement these routines.
132 : :
133 : : // clang-format off
134 : : extern void
135 : : rust_be_internal_error_at (const location_t, const std::string &errmsg)
136 : : RUST_ATTRIBUTE_NORETURN;
137 : : extern void
138 : : rust_be_error_at (const location_t, const std::string &errmsg);
139 : : extern void
140 : : rust_be_error_at (const location_t, const ErrorCode,
141 : : const std::string &errmsg);
142 : : extern void
143 : : rust_be_error_at (const rich_location &, const std::string &errmsg);
144 : : extern void
145 : : rust_be_error_at (const rich_location &, const ErrorCode,
146 : : const std::string &errmsg);
147 : : extern void /* similiar to other frontends */
148 : : rust_be_error_at (rich_location *richloc, const std::string &errmsg);
149 : : extern void /* similiar to other frontends */
150 : : rust_be_error_at (rich_location *richloc, const ErrorCode,
151 : : const std::string &errmsg);
152 : : extern void
153 : : rust_be_warning_at (const location_t, int opt, const std::string &warningmsg);
154 : : extern void
155 : : rust_be_fatal_error (const location_t, const std::string &errmsg)
156 : : RUST_ATTRIBUTE_NORETURN;
157 : : extern void
158 : : rust_be_inform (const location_t, const std::string &infomsg);
159 : : extern void
160 : : rust_be_get_quotechars (const char **open_quote, const char **close_quote);
161 : : extern bool
162 : : rust_be_debug_p (void);
163 : : // clang-format on
164 : :
165 : : namespace Rust {
166 : : /* A structure used to represent an error. Useful for enabling
167 : : * errors to be ignored, e.g. if backtracking. */
168 : 9330 : struct Error
169 : : {
170 : : enum class Kind
171 : : {
172 : : Hint,
173 : : Err,
174 : : FatalErr,
175 : : };
176 : :
177 : : Kind kind;
178 : : location_t locus;
179 : : rich_location *richlocus = nullptr;
180 : : ErrorCode errorcode;
181 : : std::string message;
182 : : bool is_errorcode = false;
183 : :
184 : : // simple location
185 : 5465 : Error (Kind kind, location_t locus, std::string message)
186 : 9194 : : kind (kind), locus (locus), message (std::move (message))
187 : : {
188 : 5465 : message.shrink_to_fit ();
189 : : }
190 : : // simple location + error code
191 : 12 : Error (Kind kind, location_t locus, ErrorCode code, std::string message)
192 : 12 : : kind (kind), locus (locus), errorcode (std::move (code)),
193 : 12 : message (std::move (message))
194 : : {
195 : 12 : is_errorcode = true;
196 : 12 : message.shrink_to_fit ();
197 : : }
198 : : // rich location
199 : 0 : Error (Kind kind, rich_location *richlocus, std::string message)
200 : 0 : : kind (kind), richlocus (richlocus), message (std::move (message))
201 : : {
202 : 0 : message.shrink_to_fit ();
203 : : }
204 : : // rich location + error code
205 : 0 : Error (Kind kind, rich_location *richlocus, ErrorCode code,
206 : : std::string message)
207 : 0 : : kind (kind), richlocus (richlocus), errorcode (std::move (code)),
208 : 0 : message (std::move (message))
209 : : {
210 : 0 : is_errorcode = true;
211 : 0 : message.shrink_to_fit ();
212 : : }
213 : : // simple location
214 : 3729 : Error (location_t locus, std::string message)
215 : 3729 : {
216 : 7458 : Error (Kind::Err, locus, std::move (message));
217 : 3729 : }
218 : : // simple location + error code
219 : : Error (location_t locus, ErrorCode code, std::string message)
220 : : {
221 : : Error (Kind::Err, locus, std::move (code), std::move (message));
222 : : }
223 : : // rich location
224 : : Error (rich_location *richlocus, std::string message)
225 : : {
226 : : Error (Kind::Err, richlocus, std::move (message));
227 : : }
228 : : // rich location + error code
229 : : Error (rich_location *richlocus, ErrorCode code, std::string message)
230 : : {
231 : : Error (Kind::Err, richlocus, std::move (code), std::move (message));
232 : : }
233 : :
234 : : static Error Hint (location_t locus, std::string message)
235 : : {
236 : : return Error (Kind::Hint, locus, std::move (message));
237 : : }
238 : :
239 : : static Error Fatal (location_t locus, std::string message)
240 : : {
241 : : return Error (Kind::FatalErr, locus, std::move (message));
242 : : }
243 : :
244 : : // TODO: the attribute part might be incorrect
245 : : // simple location
246 : : Error (location_t locus, const char *fmt,
247 : : ...) /*RUST_ATTRIBUTE_GCC_DIAG (2, 3)*/ RUST_ATTRIBUTE_GCC_DIAG (3, 4);
248 : :
249 : : // simple location + error code
250 : : Error (location_t locus, ErrorCode code, const char *fmt,
251 : : ...) /*RUST_ATTRIBUTE_GCC_DIAG (3, 4)*/ RUST_ATTRIBUTE_GCC_DIAG (4, 5);
252 : :
253 : : // rich location
254 : : Error (rich_location *richlocus, const char *fmt,
255 : : ...) /*RUST_ATTRIBUTE_GCC_DIAG (2, 3)*/ RUST_ATTRIBUTE_GCC_DIAG (3, 4);
256 : :
257 : : // rich location + error code
258 : : Error (rich_location *richlocus, ErrorCode code, const char *fmt,
259 : : ...) /*RUST_ATTRIBUTE_GCC_DIAG (3, 4)*/ RUST_ATTRIBUTE_GCC_DIAG (4, 5);
260 : :
261 : : /**
262 : : * printf-like overload of Error::Hint
263 : : */
264 : : static Error Hint (location_t locus, const char *fmt, ...)
265 : : RUST_ATTRIBUTE_GCC_DIAG (2, 3);
266 : :
267 : : /**
268 : : * printf-like overload of Error::Fatal
269 : : */
270 : : static Error Fatal (location_t locus, const char *fmt, ...)
271 : : RUST_ATTRIBUTE_GCC_DIAG (2, 3);
272 : :
273 : 237 : void emit () const
274 : : {
275 : 237 : switch (kind)
276 : : {
277 : 6 : case Kind::Hint:
278 : 6 : rust_inform (locus, "%s", message.c_str ());
279 : 6 : break;
280 : 231 : case Kind::Err:
281 : 231 : if (is_errorcode)
282 : : {
283 : 11 : if (richlocus == nullptr)
284 : 11 : rust_error_at (locus, errorcode, "%s", message.c_str ());
285 : : else
286 : 0 : rust_error_at (*richlocus, errorcode, "%s", message.c_str ());
287 : : }
288 : : else
289 : : {
290 : 220 : if (richlocus == nullptr)
291 : 220 : rust_error_at (locus, "%s", message.c_str ());
292 : : else
293 : 0 : rust_error_at (*richlocus, "%s", message.c_str ());
294 : : }
295 : : break;
296 : 0 : case Kind::FatalErr:
297 : 0 : rust_fatal_error (locus, "%s", message.c_str ());
298 : 237 : break;
299 : : }
300 : 237 : }
301 : : };
302 : : } // namespace Rust
303 : :
304 : : // rust_debug uses normal printf formatting, not GCC diagnostic formatting.
305 : : #define rust_debug(...) rust_debug_loc (UNDEF_LOCATION, __VA_ARGS__)
306 : :
307 : : #define rust_sorry_at(location, ...) sorry_at (location, __VA_ARGS__)
308 : :
309 : : void
310 : : rust_debug_loc (const location_t location, const char *fmt,
311 : : ...) ATTRIBUTE_PRINTF_2;
312 : :
313 : : #endif // !defined(RUST_DIAGNOSTICS_H)
|