Line data Source code
1 : /* m2linemap.cc provides an interface to GCC linemaps.
2 :
3 : Copyright (C) 2012-2026 Free Software Foundation, Inc.
4 : Contributed by Gaius Mulley <gaius@glam.ac.uk>.
5 :
6 : This file is part of GNU Modula-2.
7 :
8 : GNU Modula-2 is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3, or (at your option)
11 : any later version.
12 :
13 : GNU Modula-2 is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with GNU Modula-2; see the file COPYING3. If not see
20 : <http://www.gnu.org/licenses/>. */
21 :
22 : #define INCLUDE_STRING
23 : #include "gcc-consolidation.h"
24 :
25 : /* Utilize some of the C build routines */
26 :
27 : #include "../gm2-lang.h"
28 : #include "../m2-tree.h"
29 :
30 : #include "m2assert.h"
31 : #include "m2block.h"
32 : #include "m2decl.h"
33 : #include "m2expr.h"
34 : #include "m2options.h"
35 : #include "m2tree.h"
36 : #include "m2type.h"
37 : #define m2linemap_c
38 : #include "m2linemap.h"
39 : #include "m2color.h"
40 :
41 : static int inFile = FALSE;
42 :
43 : #if defined(__cplusplus)
44 : #define EXTERN extern "C"
45 : #else
46 : #define EXTERN
47 : #endif
48 :
49 : /* Start getting locations from a new file. */
50 :
51 : EXTERN
52 : void
53 292144 : m2linemap_StartFile (void *filename, unsigned int linebegin)
54 : {
55 292144 : if (inFile)
56 277193 : m2linemap_EndFile ();
57 292144 : linemap_add (line_table, LC_ENTER, false,
58 292144 : xstrdup (reinterpret_cast<char *> (filename)), linebegin);
59 292144 : inFile = TRUE;
60 292144 : }
61 :
62 : /* Tell the line table the file has ended. */
63 :
64 : EXTERN
65 : void
66 277193 : m2linemap_EndFile (void)
67 : {
68 277193 : linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
69 277193 : inFile = FALSE;
70 277193 : }
71 :
72 : /* Indicate that there is a new source file line number with a
73 : maximum width. */
74 :
75 : EXTERN
76 : void
77 65921892 : m2linemap_StartLine (unsigned int linenumber, unsigned int linesize)
78 : {
79 65921892 : linemap_line_start (line_table, linenumber, linesize);
80 65921892 : }
81 :
82 : /* GetLocationColumn, returns a location_t based on the current line
83 : number and column. */
84 :
85 : EXTERN
86 : location_t
87 1878223628 : m2linemap_GetLocationColumn (unsigned int column)
88 : {
89 1878223628 : return linemap_position_for_column (line_table, column);
90 : }
91 :
92 : /* GetLocationRange, returns a location based on the start column
93 : and end column. */
94 :
95 : EXTERN
96 : location_t
97 1878223628 : m2linemap_GetLocationRange (unsigned int start, unsigned int end)
98 : {
99 1878223628 : location_t caret = m2linemap_GetLocationColumn (start);
100 :
101 1878223628 : source_range where;
102 1878223628 : where.m_start = linemap_position_for_column (line_table, start);
103 1878223628 : where.m_finish = linemap_position_for_column (line_table, end);
104 1878223628 : return make_location (caret, where);
105 : }
106 :
107 :
108 : static
109 : int
110 0 : isSrcLocation (location_t location)
111 : {
112 0 : return (location != BUILTINS_LOCATION) && (location != UNKNOWN_LOCATION);
113 : }
114 :
115 :
116 : /* GetLocationBinary, returns a location based on the expression
117 : start caret finish locations. */
118 :
119 : EXTERN
120 : location_t
121 12291885 : m2linemap_GetLocationBinary (location_t caret, location_t start, location_t finish)
122 : {
123 12291885 : if (isSrcLocation (start) && isSrcLocation (finish) && isSrcLocation (caret)
124 24583770 : && (m2linemap_GetFilenameFromLocation (start) != NULL))
125 : {
126 12147093 : linemap_add (line_table, LC_ENTER, false, xstrdup (m2linemap_GetFilenameFromLocation (start)), 1);
127 12147093 : gcc_assert (inFile);
128 12147093 : location_t location = make_location (caret, start, finish);
129 12147093 : linemap_add (line_table, LC_LEAVE, false, NULL, 0);
130 12147093 : return location;
131 : }
132 : return caret;
133 : }
134 :
135 : /* GetLineNoFromLocation - returns the lineno given a location. */
136 :
137 : EXTERN
138 : int
139 3868 : m2linemap_GetLineNoFromLocation (location_t location)
140 : {
141 3868 : if (isSrcLocation (location) && (!M2Options_GetCpp ()))
142 : {
143 3256 : expanded_location xl = expand_location (location);
144 3256 : return xl.line;
145 : }
146 : return 0;
147 : }
148 :
149 : /* GetColumnNoFromLocation - returns the columnno given a location. */
150 :
151 : EXTERN
152 : int
153 3868 : m2linemap_GetColumnNoFromLocation (location_t location)
154 : {
155 3868 : if (isSrcLocation (location) && (!M2Options_GetCpp ()))
156 : {
157 3256 : expanded_location xl = expand_location (location);
158 3256 : return xl.column;
159 : }
160 : return 0;
161 : }
162 :
163 : /* GetFilenameFromLocation - returns the filename given a location. */
164 :
165 : EXTERN
166 : const char *
167 24442846 : m2linemap_GetFilenameFromLocation (location_t location)
168 : {
169 24442846 : if (isSrcLocation (location) && (!M2Options_GetCpp ()))
170 : {
171 24297442 : expanded_location xl = expand_location (location);
172 24297442 : return xl.file;
173 : }
174 : return NULL;
175 : }
176 :
177 : /* ErrorAt - issue an error message. */
178 :
179 : EXTERN
180 : void
181 0 : m2linemap_ErrorAt (location_t location, char *message)
182 : {
183 0 : error_at (location, "%s", message);
184 0 : }
185 :
186 : /* m2linemap_ErrorAtf - wraps up an error message. */
187 :
188 : static void
189 3196 : m2linemap_ErrorAtf_1 (location_t location, const char *message, ...)
190 : {
191 3196 : diagnostics::diagnostic_info diagnostic;
192 3196 : va_list ap;
193 3196 : rich_location richloc (line_table, location);
194 :
195 3196 : va_start (ap, message);
196 3196 : diagnostic_set_info (&diagnostic, message, &ap, &richloc,
197 : diagnostics::kind::error);
198 3196 : diagnostic_report_diagnostic (global_dc, &diagnostic);
199 3196 : va_end (ap);
200 3196 : }
201 :
202 : void
203 3196 : m2linemap_ErrorAtf (location_t location, const char *message)
204 : {
205 3196 : m2linemap_ErrorAtf_1 (location, "%s", message);
206 3196 : }
207 :
208 : /* m2linemap_WarningAtf - wraps up a warning message. */
209 :
210 : static void
211 600 : m2linemap_WarningAtf_1 (location_t location, const char *message, ...)
212 : {
213 600 : diagnostics::diagnostic_info diagnostic;
214 600 : va_list ap;
215 600 : rich_location richloc (line_table, location);
216 :
217 600 : va_start (ap, message);
218 600 : diagnostic_set_info (&diagnostic, message, &ap, &richloc,
219 : diagnostics::kind::warning);
220 600 : diagnostic_report_diagnostic (global_dc, &diagnostic);
221 600 : va_end (ap);
222 600 : }
223 :
224 : void
225 600 : m2linemap_WarningAtf (location_t location, const char *message)
226 : {
227 600 : m2linemap_WarningAtf_1 (location, "%s", message);
228 600 : }
229 :
230 : /* m2linemap_NoteAtf - wraps up a note message. */
231 :
232 : static void
233 31 : m2linemap_NoteAtf_1 (location_t location, const char *message, ...)
234 : {
235 31 : diagnostics::diagnostic_info diagnostic;
236 31 : va_list ap;
237 31 : rich_location richloc (line_table, location);
238 :
239 31 : va_start (ap, message);
240 31 : diagnostic_set_info (&diagnostic, message, &ap, &richloc,
241 : diagnostics::kind::note);
242 31 : diagnostic_report_diagnostic (global_dc, &diagnostic);
243 31 : va_end (ap);
244 31 : }
245 :
246 : void
247 31 : m2linemap_NoteAtf (location_t location, const char *message)
248 : {
249 31 : m2linemap_NoteAtf_1 (location, "%s", message);
250 31 : }
251 :
252 : /* m2linemap_internal_error - allow Modula-2 to use the GCC internal error. */
253 :
254 : void
255 0 : m2linemap_internal_error (const char *message)
256 : {
257 0 : internal_error ("%s", message);
258 : }
259 :
260 :
261 : /* Code derived from rust. */
262 :
263 : static std::string
264 0 : mformat_value ()
265 : {
266 0 : return std::string (xstrerror (errno));
267 : }
268 :
269 :
270 : static std::string
271 0 : expand_format (const char *fmt)
272 : {
273 0 : std::string result;
274 0 : for (const char *c = fmt; *c; ++c)
275 : {
276 0 : if (*c != '%')
277 : {
278 0 : result += *c;
279 0 : continue;
280 : }
281 0 : c++;
282 0 : switch (*c)
283 : {
284 0 : case '\0': {
285 : // malformed format string
286 0 : gcc_unreachable ();
287 : }
288 0 : case '%': {
289 0 : result += '%';
290 0 : break;
291 : }
292 0 : case 'm': {
293 0 : result += mformat_value ();
294 0 : break;
295 : }
296 0 : case '<': {
297 0 : result += m2color_open_quote ();
298 0 : break;
299 : }
300 0 : case '>': {
301 0 : result += m2color_close_quote ();
302 0 : break;
303 : }
304 0 : case 'q': {
305 0 : result += m2color_open_quote ();
306 0 : c++;
307 0 : if (*c == 'm')
308 0 : result += mformat_value ();
309 : else
310 : {
311 0 : result += '%';
312 0 : result += *c;
313 : }
314 0 : result += m2color_close_quote ();
315 0 : break;
316 : }
317 0 : default: {
318 0 : result += '%';
319 0 : result += *c;
320 : }
321 : }
322 : }
323 0 : return result;
324 : }
325 :
326 : static std::string
327 0 : expand_message (const char *fmt, va_list ap)
328 : {
329 0 : char *mbuf = 0;
330 0 : std::string expanded_fmt = expand_format (fmt);
331 0 : int nwr = vasprintf (&mbuf, expanded_fmt.c_str (), ap);
332 0 : if (nwr == -1)
333 : {
334 : // memory allocation failed
335 0 : error_at (UNKNOWN_LOCATION,
336 : "memory allocation failed in vasprintf");
337 0 : gcc_assert (0);
338 : }
339 0 : std::string rval = std::string (mbuf);
340 0 : free (mbuf);
341 0 : return rval;
342 0 : }
343 :
344 :
345 : static void
346 0 : gm2_internal_error_at (location_t location, const std::string &errmsg)
347 : {
348 0 : expanded_location exp_loc = expand_location (location);
349 0 : std::string loc_str;
350 0 : std::string file_str;
351 :
352 0 : if (exp_loc.file == NULL)
353 : file_str.clear ();
354 : else
355 0 : file_str = std::string (exp_loc.file);
356 :
357 0 : if (! file_str.empty ())
358 : {
359 0 : loc_str += file_str;
360 0 : loc_str += ':';
361 0 : loc_str += std::to_string (exp_loc.line);
362 0 : loc_str += ':';
363 0 : loc_str += std::to_string (exp_loc.column);
364 : }
365 0 : if (loc_str.empty ())
366 0 : internal_error ("%s", errmsg.c_str ());
367 : else
368 0 : internal_error ("at %s, %s", loc_str.c_str (), errmsg.c_str ());
369 : }
370 :
371 :
372 : void
373 0 : m2linemap_internal_error_at (location_t location, const char *fmt, ...)
374 : {
375 0 : va_list ap;
376 :
377 0 : va_start (ap, fmt);
378 0 : gm2_internal_error_at (location, expand_message (fmt, ap));
379 : va_end (ap);
380 : }
381 :
382 : /* UnknownLocation - return the predefined location representing an
383 : unknown location. */
384 :
385 : EXTERN
386 : location_t
387 158405477 : m2linemap_UnknownLocation (void)
388 : {
389 158405477 : return UNKNOWN_LOCATION;
390 : }
391 :
392 : /* BuiltinsLocation - return the predefined location representing a
393 : builtin. */
394 :
395 : EXTERN
396 : location_t
397 3748375 : m2linemap_BuiltinsLocation (void)
398 : {
399 3748375 : return BUILTINS_LOCATION;
400 : }
|