xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/fortran/error.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1627f7eb2Smrg /* Handle errors.
2*4c3eb207Smrg    Copyright (C) 2000-2020 Free Software Foundation, Inc.
3627f7eb2Smrg    Contributed by Andy Vaught & Niels Kristian Bech Jensen
4627f7eb2Smrg 
5627f7eb2Smrg This file is part of GCC.
6627f7eb2Smrg 
7627f7eb2Smrg GCC is free software; you can redistribute it and/or modify it under
8627f7eb2Smrg the terms of the GNU General Public License as published by the Free
9627f7eb2Smrg Software Foundation; either version 3, or (at your option) any later
10627f7eb2Smrg version.
11627f7eb2Smrg 
12627f7eb2Smrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13627f7eb2Smrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
14627f7eb2Smrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15627f7eb2Smrg for more details.
16627f7eb2Smrg 
17627f7eb2Smrg You should have received a copy of the GNU General Public License
18627f7eb2Smrg along with GCC; see the file COPYING3.  If not see
19627f7eb2Smrg <http://www.gnu.org/licenses/>.  */
20627f7eb2Smrg 
21627f7eb2Smrg /* Handle the inevitable errors.  A major catch here is that things
22627f7eb2Smrg    flagged as errors in one match subroutine can conceivably be legal
23627f7eb2Smrg    elsewhere.  This means that error messages are recorded and saved
24627f7eb2Smrg    for possible use later.  If a line does not match a legal
25627f7eb2Smrg    construction, then the saved error message is reported.  */
26627f7eb2Smrg 
27627f7eb2Smrg #include "config.h"
28627f7eb2Smrg #include "system.h"
29627f7eb2Smrg #include "coretypes.h"
30627f7eb2Smrg #include "options.h"
31627f7eb2Smrg #include "gfortran.h"
32627f7eb2Smrg 
33627f7eb2Smrg #include "diagnostic.h"
34627f7eb2Smrg #include "diagnostic-color.h"
35627f7eb2Smrg #include "tree-diagnostic.h" /* tree_diagnostics_defaults */
36627f7eb2Smrg 
37627f7eb2Smrg static int suppress_errors = 0;
38627f7eb2Smrg 
39627f7eb2Smrg static bool warnings_not_errors = false;
40627f7eb2Smrg 
41627f7eb2Smrg static int terminal_width;
42627f7eb2Smrg 
43627f7eb2Smrg /* True if the error/warnings should be buffered.  */
44627f7eb2Smrg static bool buffered_p;
45627f7eb2Smrg 
46627f7eb2Smrg static gfc_error_buffer error_buffer;
47627f7eb2Smrg /* These are always buffered buffers (.flush_p == false) to be used by
48627f7eb2Smrg    the pretty-printer.  */
49627f7eb2Smrg static output_buffer *pp_error_buffer, *pp_warning_buffer;
50627f7eb2Smrg static int warningcount_buffered, werrorcount_buffered;
51627f7eb2Smrg 
52627f7eb2Smrg /* Return true if there output_buffer is empty.  */
53627f7eb2Smrg 
54627f7eb2Smrg static bool
gfc_output_buffer_empty_p(const output_buffer * buf)55627f7eb2Smrg gfc_output_buffer_empty_p (const output_buffer * buf)
56627f7eb2Smrg {
57627f7eb2Smrg   return output_buffer_last_position_in_text (buf) == NULL;
58627f7eb2Smrg }
59627f7eb2Smrg 
60627f7eb2Smrg /* Go one level deeper suppressing errors.  */
61627f7eb2Smrg 
62627f7eb2Smrg void
gfc_push_suppress_errors(void)63627f7eb2Smrg gfc_push_suppress_errors (void)
64627f7eb2Smrg {
65627f7eb2Smrg   gcc_assert (suppress_errors >= 0);
66627f7eb2Smrg   ++suppress_errors;
67627f7eb2Smrg }
68627f7eb2Smrg 
69627f7eb2Smrg static void
70627f7eb2Smrg gfc_error_opt (int opt, const char *gmsgid, va_list ap)  ATTRIBUTE_GCC_GFC(2,0);
71627f7eb2Smrg 
72627f7eb2Smrg static bool
73627f7eb2Smrg gfc_warning (int opt, const char *gmsgid, va_list ap) ATTRIBUTE_GCC_GFC(2,0);
74627f7eb2Smrg 
75627f7eb2Smrg 
76627f7eb2Smrg /* Leave one level of error suppressing.  */
77627f7eb2Smrg 
78627f7eb2Smrg void
gfc_pop_suppress_errors(void)79627f7eb2Smrg gfc_pop_suppress_errors (void)
80627f7eb2Smrg {
81627f7eb2Smrg   gcc_assert (suppress_errors > 0);
82627f7eb2Smrg   --suppress_errors;
83627f7eb2Smrg }
84627f7eb2Smrg 
85627f7eb2Smrg 
86627f7eb2Smrg /* Determine terminal width (for trimming source lines in output).  */
87627f7eb2Smrg 
88627f7eb2Smrg static int
gfc_get_terminal_width(void)89627f7eb2Smrg gfc_get_terminal_width (void)
90627f7eb2Smrg {
91627f7eb2Smrg   return isatty (STDERR_FILENO) ? get_terminal_width () : INT_MAX;
92627f7eb2Smrg }
93627f7eb2Smrg 
94627f7eb2Smrg 
95627f7eb2Smrg /* Per-file error initialization.  */
96627f7eb2Smrg 
97627f7eb2Smrg void
gfc_error_init_1(void)98627f7eb2Smrg gfc_error_init_1 (void)
99627f7eb2Smrg {
100627f7eb2Smrg   terminal_width = gfc_get_terminal_width ();
101627f7eb2Smrg   gfc_buffer_error (false);
102627f7eb2Smrg }
103627f7eb2Smrg 
104627f7eb2Smrg 
105627f7eb2Smrg /* Set the flag for buffering errors or not.  */
106627f7eb2Smrg 
107627f7eb2Smrg void
gfc_buffer_error(bool flag)108627f7eb2Smrg gfc_buffer_error (bool flag)
109627f7eb2Smrg {
110627f7eb2Smrg   buffered_p = flag;
111627f7eb2Smrg }
112627f7eb2Smrg 
113627f7eb2Smrg 
114627f7eb2Smrg /* Add a single character to the error buffer or output depending on
115627f7eb2Smrg    buffered_p.  */
116627f7eb2Smrg 
117627f7eb2Smrg static void
error_char(char)118627f7eb2Smrg error_char (char)
119627f7eb2Smrg {
120627f7eb2Smrg   /* FIXME: Unused function to be removed in a subsequent patch.  */
121627f7eb2Smrg }
122627f7eb2Smrg 
123627f7eb2Smrg 
124627f7eb2Smrg /* Copy a string to wherever it needs to go.  */
125627f7eb2Smrg 
126627f7eb2Smrg static void
error_string(const char * p)127627f7eb2Smrg error_string (const char *p)
128627f7eb2Smrg {
129627f7eb2Smrg   while (*p)
130627f7eb2Smrg     error_char (*p++);
131627f7eb2Smrg }
132627f7eb2Smrg 
133627f7eb2Smrg 
134627f7eb2Smrg /* Print a formatted integer to the error buffer or output.  */
135627f7eb2Smrg 
136627f7eb2Smrg #define IBUF_LEN 60
137627f7eb2Smrg 
138627f7eb2Smrg static void
error_uinteger(unsigned long int i)139627f7eb2Smrg error_uinteger (unsigned long int i)
140627f7eb2Smrg {
141627f7eb2Smrg   char *p, int_buf[IBUF_LEN];
142627f7eb2Smrg 
143627f7eb2Smrg   p = int_buf + IBUF_LEN - 1;
144627f7eb2Smrg   *p-- = '\0';
145627f7eb2Smrg 
146627f7eb2Smrg   if (i == 0)
147627f7eb2Smrg     *p-- = '0';
148627f7eb2Smrg 
149627f7eb2Smrg   while (i > 0)
150627f7eb2Smrg     {
151627f7eb2Smrg       *p-- = i % 10 + '0';
152627f7eb2Smrg       i = i / 10;
153627f7eb2Smrg     }
154627f7eb2Smrg 
155627f7eb2Smrg   error_string (p + 1);
156627f7eb2Smrg }
157627f7eb2Smrg 
158627f7eb2Smrg static void
error_integer(long int i)159627f7eb2Smrg error_integer (long int i)
160627f7eb2Smrg {
161627f7eb2Smrg   unsigned long int u;
162627f7eb2Smrg 
163627f7eb2Smrg   if (i < 0)
164627f7eb2Smrg     {
165627f7eb2Smrg       u = (unsigned long int) -i;
166627f7eb2Smrg       error_char ('-');
167627f7eb2Smrg     }
168627f7eb2Smrg   else
169627f7eb2Smrg     u = i;
170627f7eb2Smrg 
171627f7eb2Smrg   error_uinteger (u);
172627f7eb2Smrg }
173627f7eb2Smrg 
174627f7eb2Smrg 
175627f7eb2Smrg static size_t
gfc_widechar_display_length(gfc_char_t c)176627f7eb2Smrg gfc_widechar_display_length (gfc_char_t c)
177627f7eb2Smrg {
178627f7eb2Smrg   if (gfc_wide_is_printable (c) || c == '\t')
179627f7eb2Smrg     /* Printable ASCII character, or tabulation (output as a space).  */
180627f7eb2Smrg     return 1;
181627f7eb2Smrg   else if (c < ((gfc_char_t) 1 << 8))
182627f7eb2Smrg     /* Displayed as \x??  */
183627f7eb2Smrg     return 4;
184627f7eb2Smrg   else if (c < ((gfc_char_t) 1 << 16))
185627f7eb2Smrg     /* Displayed as \u????  */
186627f7eb2Smrg     return 6;
187627f7eb2Smrg   else
188627f7eb2Smrg     /* Displayed as \U????????  */
189627f7eb2Smrg     return 10;
190627f7eb2Smrg }
191627f7eb2Smrg 
192627f7eb2Smrg 
193627f7eb2Smrg /* Length of the ASCII representation of the wide string, escaping wide
194627f7eb2Smrg    characters as print_wide_char_into_buffer() does.  */
195627f7eb2Smrg 
196627f7eb2Smrg static size_t
gfc_wide_display_length(const gfc_char_t * str)197627f7eb2Smrg gfc_wide_display_length (const gfc_char_t *str)
198627f7eb2Smrg {
199627f7eb2Smrg   size_t i, len;
200627f7eb2Smrg 
201627f7eb2Smrg   for (i = 0, len = 0; str[i]; i++)
202627f7eb2Smrg     len += gfc_widechar_display_length (str[i]);
203627f7eb2Smrg 
204627f7eb2Smrg   return len;
205627f7eb2Smrg }
206627f7eb2Smrg 
207627f7eb2Smrg static int
print_wide_char_into_buffer(gfc_char_t c,char * buf)208627f7eb2Smrg print_wide_char_into_buffer (gfc_char_t c, char *buf)
209627f7eb2Smrg {
210627f7eb2Smrg   static const char xdigit[16] = { '0', '1', '2', '3', '4', '5', '6',
211627f7eb2Smrg     '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
212627f7eb2Smrg 
213627f7eb2Smrg   if (gfc_wide_is_printable (c) || c == '\t')
214627f7eb2Smrg     {
215627f7eb2Smrg       buf[1] = '\0';
216627f7eb2Smrg       /* Tabulation is output as a space.  */
217627f7eb2Smrg       buf[0] = (unsigned char) (c == '\t' ? ' ' : c);
218627f7eb2Smrg       return 1;
219627f7eb2Smrg     }
220627f7eb2Smrg   else if (c < ((gfc_char_t) 1 << 8))
221627f7eb2Smrg     {
222627f7eb2Smrg       buf[4] = '\0';
223627f7eb2Smrg       buf[3] = xdigit[c & 0x0F];
224627f7eb2Smrg       c = c >> 4;
225627f7eb2Smrg       buf[2] = xdigit[c & 0x0F];
226627f7eb2Smrg 
227627f7eb2Smrg       buf[1] = 'x';
228627f7eb2Smrg       buf[0] = '\\';
229627f7eb2Smrg       return 4;
230627f7eb2Smrg     }
231627f7eb2Smrg   else if (c < ((gfc_char_t) 1 << 16))
232627f7eb2Smrg     {
233627f7eb2Smrg       buf[6] = '\0';
234627f7eb2Smrg       buf[5] = xdigit[c & 0x0F];
235627f7eb2Smrg       c = c >> 4;
236627f7eb2Smrg       buf[4] = xdigit[c & 0x0F];
237627f7eb2Smrg       c = c >> 4;
238627f7eb2Smrg       buf[3] = xdigit[c & 0x0F];
239627f7eb2Smrg       c = c >> 4;
240627f7eb2Smrg       buf[2] = xdigit[c & 0x0F];
241627f7eb2Smrg 
242627f7eb2Smrg       buf[1] = 'u';
243627f7eb2Smrg       buf[0] = '\\';
244627f7eb2Smrg       return 6;
245627f7eb2Smrg     }
246627f7eb2Smrg   else
247627f7eb2Smrg     {
248627f7eb2Smrg       buf[10] = '\0';
249627f7eb2Smrg       buf[9] = xdigit[c & 0x0F];
250627f7eb2Smrg       c = c >> 4;
251627f7eb2Smrg       buf[8] = xdigit[c & 0x0F];
252627f7eb2Smrg       c = c >> 4;
253627f7eb2Smrg       buf[7] = xdigit[c & 0x0F];
254627f7eb2Smrg       c = c >> 4;
255627f7eb2Smrg       buf[6] = xdigit[c & 0x0F];
256627f7eb2Smrg       c = c >> 4;
257627f7eb2Smrg       buf[5] = xdigit[c & 0x0F];
258627f7eb2Smrg       c = c >> 4;
259627f7eb2Smrg       buf[4] = xdigit[c & 0x0F];
260627f7eb2Smrg       c = c >> 4;
261627f7eb2Smrg       buf[3] = xdigit[c & 0x0F];
262627f7eb2Smrg       c = c >> 4;
263627f7eb2Smrg       buf[2] = xdigit[c & 0x0F];
264627f7eb2Smrg 
265627f7eb2Smrg       buf[1] = 'U';
266627f7eb2Smrg       buf[0] = '\\';
267627f7eb2Smrg       return 10;
268627f7eb2Smrg     }
269627f7eb2Smrg }
270627f7eb2Smrg 
271627f7eb2Smrg static char wide_char_print_buffer[11];
272627f7eb2Smrg 
273627f7eb2Smrg const char *
gfc_print_wide_char(gfc_char_t c)274627f7eb2Smrg gfc_print_wide_char (gfc_char_t c)
275627f7eb2Smrg {
276627f7eb2Smrg   print_wide_char_into_buffer (c, wide_char_print_buffer);
277627f7eb2Smrg   return wide_char_print_buffer;
278627f7eb2Smrg }
279627f7eb2Smrg 
280627f7eb2Smrg 
281627f7eb2Smrg /* Show the file, where it was included, and the source line, give a
282627f7eb2Smrg    locus.  Calls error_printf() recursively, but the recursion is at
283627f7eb2Smrg    most one level deep.  */
284627f7eb2Smrg 
285627f7eb2Smrg static void error_printf (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
286627f7eb2Smrg 
287627f7eb2Smrg static void
show_locus(locus * loc,int c1,int c2)288627f7eb2Smrg show_locus (locus *loc, int c1, int c2)
289627f7eb2Smrg {
290627f7eb2Smrg   gfc_linebuf *lb;
291627f7eb2Smrg   gfc_file *f;
292627f7eb2Smrg   gfc_char_t *p;
293627f7eb2Smrg   int i, offset, cmax;
294627f7eb2Smrg 
295627f7eb2Smrg   /* TODO: Either limit the total length and number of included files
296627f7eb2Smrg      displayed or add buffering of arbitrary number of characters in
297627f7eb2Smrg      error messages.  */
298627f7eb2Smrg 
299627f7eb2Smrg   /* Write out the error header line, giving the source file and error
300627f7eb2Smrg      location (in GNU standard "[file]:[line].[column]:" format),
301627f7eb2Smrg      followed by an "included by" stack and a blank line.  This header
302627f7eb2Smrg      format is matched by a testsuite parser defined in
303627f7eb2Smrg      lib/gfortran-dg.exp.  */
304627f7eb2Smrg 
305627f7eb2Smrg   lb = loc->lb;
306627f7eb2Smrg   f = lb->file;
307627f7eb2Smrg 
308627f7eb2Smrg   error_string (f->filename);
309627f7eb2Smrg   error_char (':');
310627f7eb2Smrg 
311627f7eb2Smrg   error_integer (LOCATION_LINE (lb->location));
312627f7eb2Smrg 
313627f7eb2Smrg   if ((c1 > 0) || (c2 > 0))
314627f7eb2Smrg     error_char ('.');
315627f7eb2Smrg 
316627f7eb2Smrg   if (c1 > 0)
317627f7eb2Smrg     error_integer (c1);
318627f7eb2Smrg 
319627f7eb2Smrg   if ((c1 > 0) && (c2 > 0))
320627f7eb2Smrg     error_char ('-');
321627f7eb2Smrg 
322627f7eb2Smrg   if (c2 > 0)
323627f7eb2Smrg     error_integer (c2);
324627f7eb2Smrg 
325627f7eb2Smrg   error_char (':');
326627f7eb2Smrg   error_char ('\n');
327627f7eb2Smrg 
328627f7eb2Smrg   for (;;)
329627f7eb2Smrg     {
330627f7eb2Smrg       i = f->inclusion_line;
331627f7eb2Smrg 
332627f7eb2Smrg       f = f->up;
333627f7eb2Smrg       if (f == NULL) break;
334627f7eb2Smrg 
335627f7eb2Smrg       error_printf ("    Included at %s:%d:", f->filename, i);
336627f7eb2Smrg     }
337627f7eb2Smrg 
338627f7eb2Smrg   error_char ('\n');
339627f7eb2Smrg 
340627f7eb2Smrg   /* Calculate an appropriate horizontal offset of the source line in
341627f7eb2Smrg      order to get the error locus within the visible portion of the
342627f7eb2Smrg      line.  Note that if the margin of 5 here is changed, the
343627f7eb2Smrg      corresponding margin of 10 in show_loci should be changed.  */
344627f7eb2Smrg 
345627f7eb2Smrg   offset = 0;
346627f7eb2Smrg 
347627f7eb2Smrg   /* If the two loci would appear in the same column, we shift
348627f7eb2Smrg      '2' one column to the right, so as to print '12' rather than
349627f7eb2Smrg      just '1'.  We do this here so it will be accounted for in the
350627f7eb2Smrg      margin calculations.  */
351627f7eb2Smrg 
352627f7eb2Smrg   if (c1 == c2)
353627f7eb2Smrg     c2 += 1;
354627f7eb2Smrg 
355627f7eb2Smrg   cmax = (c1 < c2) ? c2 : c1;
356627f7eb2Smrg   if (cmax > terminal_width - 5)
357627f7eb2Smrg     offset = cmax - terminal_width + 5;
358627f7eb2Smrg 
359627f7eb2Smrg   /* Show the line itself, taking care not to print more than what can
360627f7eb2Smrg      show up on the terminal.  Tabs are converted to spaces, and
361627f7eb2Smrg      nonprintable characters are converted to a "\xNN" sequence.  */
362627f7eb2Smrg 
363627f7eb2Smrg   p = &(lb->line[offset]);
364627f7eb2Smrg   i = gfc_wide_display_length (p);
365627f7eb2Smrg   if (i > terminal_width)
366627f7eb2Smrg     i = terminal_width - 1;
367627f7eb2Smrg 
368627f7eb2Smrg   while (i > 0)
369627f7eb2Smrg     {
370627f7eb2Smrg       static char buffer[11];
371627f7eb2Smrg       i -= print_wide_char_into_buffer (*p++, buffer);
372627f7eb2Smrg       error_string (buffer);
373627f7eb2Smrg     }
374627f7eb2Smrg 
375627f7eb2Smrg   error_char ('\n');
376627f7eb2Smrg 
377627f7eb2Smrg   /* Show the '1' and/or '2' corresponding to the column of the error
378627f7eb2Smrg      locus.  Note that a value of -1 for c1 or c2 will simply cause
379627f7eb2Smrg      the relevant number not to be printed.  */
380627f7eb2Smrg 
381627f7eb2Smrg   c1 -= offset;
382627f7eb2Smrg   c2 -= offset;
383627f7eb2Smrg   cmax -= offset;
384627f7eb2Smrg 
385627f7eb2Smrg   p = &(lb->line[offset]);
386627f7eb2Smrg   for (i = 0; i < cmax; i++)
387627f7eb2Smrg     {
388627f7eb2Smrg       int spaces, j;
389627f7eb2Smrg       spaces = gfc_widechar_display_length (*p++);
390627f7eb2Smrg 
391627f7eb2Smrg       if (i == c1)
392627f7eb2Smrg 	error_char ('1'), spaces--;
393627f7eb2Smrg       else if (i == c2)
394627f7eb2Smrg 	error_char ('2'), spaces--;
395627f7eb2Smrg 
396627f7eb2Smrg       for (j = 0; j < spaces; j++)
397627f7eb2Smrg 	error_char (' ');
398627f7eb2Smrg     }
399627f7eb2Smrg 
400627f7eb2Smrg   if (i == c1)
401627f7eb2Smrg     error_char ('1');
402627f7eb2Smrg   else if (i == c2)
403627f7eb2Smrg     error_char ('2');
404627f7eb2Smrg 
405627f7eb2Smrg   error_char ('\n');
406627f7eb2Smrg 
407627f7eb2Smrg }
408627f7eb2Smrg 
409627f7eb2Smrg 
410627f7eb2Smrg /* As part of printing an error, we show the source lines that caused
411627f7eb2Smrg    the problem.  We show at least one, and possibly two loci; the two
412627f7eb2Smrg    loci may or may not be on the same source line.  */
413627f7eb2Smrg 
414627f7eb2Smrg static void
show_loci(locus * l1,locus * l2)415627f7eb2Smrg show_loci (locus *l1, locus *l2)
416627f7eb2Smrg {
417627f7eb2Smrg   int m, c1, c2;
418627f7eb2Smrg 
419627f7eb2Smrg   if (l1 == NULL || l1->lb == NULL)
420627f7eb2Smrg     {
421627f7eb2Smrg       error_printf ("<During initialization>\n");
422627f7eb2Smrg       return;
423627f7eb2Smrg     }
424627f7eb2Smrg 
425627f7eb2Smrg   /* While calculating parameters for printing the loci, we consider possible
426627f7eb2Smrg      reasons for printing one per line.  If appropriate, print the loci
427627f7eb2Smrg      individually; otherwise we print them both on the same line.  */
428627f7eb2Smrg 
429627f7eb2Smrg   c1 = l1->nextc - l1->lb->line;
430627f7eb2Smrg   if (l2 == NULL)
431627f7eb2Smrg     {
432627f7eb2Smrg       show_locus (l1, c1, -1);
433627f7eb2Smrg       return;
434627f7eb2Smrg     }
435627f7eb2Smrg 
436627f7eb2Smrg   c2 = l2->nextc - l2->lb->line;
437627f7eb2Smrg 
438627f7eb2Smrg   if (c1 < c2)
439627f7eb2Smrg     m = c2 - c1;
440627f7eb2Smrg   else
441627f7eb2Smrg     m = c1 - c2;
442627f7eb2Smrg 
443627f7eb2Smrg   /* Note that the margin value of 10 here needs to be less than the
444627f7eb2Smrg      margin of 5 used in the calculation of offset in show_locus.  */
445627f7eb2Smrg 
446627f7eb2Smrg   if (l1->lb != l2->lb || m > terminal_width - 10)
447627f7eb2Smrg     {
448627f7eb2Smrg       show_locus (l1, c1, -1);
449627f7eb2Smrg       show_locus (l2, -1, c2);
450627f7eb2Smrg       return;
451627f7eb2Smrg     }
452627f7eb2Smrg 
453627f7eb2Smrg   show_locus (l1, c1, c2);
454627f7eb2Smrg 
455627f7eb2Smrg   return;
456627f7eb2Smrg }
457627f7eb2Smrg 
458627f7eb2Smrg 
459627f7eb2Smrg /* Workhorse for the error printing subroutines.  This subroutine is
460627f7eb2Smrg    inspired by g77's error handling and is similar to printf() with
461627f7eb2Smrg    the following %-codes:
462627f7eb2Smrg 
463627f7eb2Smrg    %c Character, %d or %i Integer, %s String, %% Percent
464627f7eb2Smrg    %L  Takes locus argument
465627f7eb2Smrg    %C  Current locus (no argument)
466627f7eb2Smrg 
467627f7eb2Smrg    If a locus pointer is given, the actual source line is printed out
468627f7eb2Smrg    and the column is indicated.  Since we want the error message at
469627f7eb2Smrg    the bottom of any source file information, we must scan the
470627f7eb2Smrg    argument list twice -- once to determine whether the loci are
471627f7eb2Smrg    present and record this for printing, and once to print the error
472627f7eb2Smrg    message after and loci have been printed.  A maximum of two locus
473627f7eb2Smrg    arguments are permitted.
474627f7eb2Smrg 
475627f7eb2Smrg    This function is also called (recursively) by show_locus in the
476627f7eb2Smrg    case of included files; however, as show_locus does not resupply
477627f7eb2Smrg    any loci, the recursion is at most one level deep.  */
478627f7eb2Smrg 
479627f7eb2Smrg #define MAX_ARGS 10
480627f7eb2Smrg 
481627f7eb2Smrg static void ATTRIBUTE_GCC_GFC(2,0)
error_print(const char * type,const char * format0,va_list argp)482627f7eb2Smrg error_print (const char *type, const char *format0, va_list argp)
483627f7eb2Smrg {
484627f7eb2Smrg   enum { TYPE_CURRENTLOC, TYPE_LOCUS, TYPE_INTEGER, TYPE_UINTEGER,
485627f7eb2Smrg          TYPE_LONGINT, TYPE_ULONGINT, TYPE_CHAR, TYPE_STRING,
486627f7eb2Smrg 	 NOTYPE };
487627f7eb2Smrg   struct
488627f7eb2Smrg   {
489627f7eb2Smrg     int type;
490627f7eb2Smrg     int pos;
491627f7eb2Smrg     union
492627f7eb2Smrg     {
493627f7eb2Smrg       int intval;
494627f7eb2Smrg       unsigned int uintval;
495627f7eb2Smrg       long int longintval;
496627f7eb2Smrg       unsigned long int ulongintval;
497627f7eb2Smrg       char charval;
498627f7eb2Smrg       const char * stringval;
499627f7eb2Smrg     } u;
500627f7eb2Smrg   } arg[MAX_ARGS], spec[MAX_ARGS];
501627f7eb2Smrg   /* spec is the array of specifiers, in the same order as they
502627f7eb2Smrg      appear in the format string.  arg is the array of arguments,
503627f7eb2Smrg      in the same order as they appear in the va_list.  */
504627f7eb2Smrg 
505627f7eb2Smrg   char c;
506627f7eb2Smrg   int i, n, have_l1, pos, maxpos;
507627f7eb2Smrg   locus *l1, *l2, *loc;
508627f7eb2Smrg   const char *format;
509627f7eb2Smrg 
510627f7eb2Smrg   loc = l1 = l2 = NULL;
511627f7eb2Smrg 
512627f7eb2Smrg   have_l1 = 0;
513627f7eb2Smrg   pos = -1;
514627f7eb2Smrg   maxpos = -1;
515627f7eb2Smrg 
516627f7eb2Smrg   n = 0;
517627f7eb2Smrg   format = format0;
518627f7eb2Smrg 
519627f7eb2Smrg   for (i = 0; i < MAX_ARGS; i++)
520627f7eb2Smrg     {
521627f7eb2Smrg       arg[i].type = NOTYPE;
522627f7eb2Smrg       spec[i].pos = -1;
523627f7eb2Smrg     }
524627f7eb2Smrg 
525627f7eb2Smrg   /* First parse the format string for position specifiers.  */
526627f7eb2Smrg   while (*format)
527627f7eb2Smrg     {
528627f7eb2Smrg       c = *format++;
529627f7eb2Smrg       if (c != '%')
530627f7eb2Smrg 	continue;
531627f7eb2Smrg 
532627f7eb2Smrg       if (*format == '%')
533627f7eb2Smrg 	{
534627f7eb2Smrg 	  format++;
535627f7eb2Smrg 	  continue;
536627f7eb2Smrg 	}
537627f7eb2Smrg 
538627f7eb2Smrg       if (ISDIGIT (*format))
539627f7eb2Smrg 	{
540627f7eb2Smrg 	  /* This is a position specifier.  For example, the number
541627f7eb2Smrg 	     12 in the format string "%12$d", which specifies the third
542627f7eb2Smrg 	     argument of the va_list, formatted in %d format.
543627f7eb2Smrg 	     For details, see "man 3 printf".  */
544627f7eb2Smrg 	  pos = atoi(format) - 1;
545627f7eb2Smrg 	  gcc_assert (pos >= 0);
546627f7eb2Smrg 	  while (ISDIGIT(*format))
547627f7eb2Smrg 	    format++;
548627f7eb2Smrg 	  gcc_assert (*format == '$');
549627f7eb2Smrg 	  format++;
550627f7eb2Smrg 	}
551627f7eb2Smrg       else
552627f7eb2Smrg 	pos++;
553627f7eb2Smrg 
554627f7eb2Smrg       c = *format++;
555627f7eb2Smrg 
556627f7eb2Smrg       if (pos > maxpos)
557627f7eb2Smrg 	maxpos = pos;
558627f7eb2Smrg 
559627f7eb2Smrg       switch (c)
560627f7eb2Smrg 	{
561627f7eb2Smrg 	  case 'C':
562627f7eb2Smrg 	    arg[pos].type = TYPE_CURRENTLOC;
563627f7eb2Smrg 	    break;
564627f7eb2Smrg 
565627f7eb2Smrg 	  case 'L':
566627f7eb2Smrg 	    arg[pos].type = TYPE_LOCUS;
567627f7eb2Smrg 	    break;
568627f7eb2Smrg 
569627f7eb2Smrg 	  case 'd':
570627f7eb2Smrg 	  case 'i':
571627f7eb2Smrg 	    arg[pos].type = TYPE_INTEGER;
572627f7eb2Smrg 	    break;
573627f7eb2Smrg 
574627f7eb2Smrg 	  case 'u':
575627f7eb2Smrg 	    arg[pos].type = TYPE_UINTEGER;
576627f7eb2Smrg 	    break;
577627f7eb2Smrg 
578627f7eb2Smrg 	  case 'l':
579627f7eb2Smrg 	    c = *format++;
580627f7eb2Smrg 	    if (c == 'u')
581627f7eb2Smrg 	      arg[pos].type = TYPE_ULONGINT;
582627f7eb2Smrg 	    else if (c == 'i' || c == 'd')
583627f7eb2Smrg 	      arg[pos].type = TYPE_LONGINT;
584627f7eb2Smrg 	    else
585627f7eb2Smrg 	      gcc_unreachable ();
586627f7eb2Smrg 	    break;
587627f7eb2Smrg 
588627f7eb2Smrg 	  case 'c':
589627f7eb2Smrg 	    arg[pos].type = TYPE_CHAR;
590627f7eb2Smrg 	    break;
591627f7eb2Smrg 
592627f7eb2Smrg 	  case 's':
593627f7eb2Smrg 	    arg[pos].type = TYPE_STRING;
594627f7eb2Smrg 	    break;
595627f7eb2Smrg 
596627f7eb2Smrg 	  default:
597627f7eb2Smrg 	    gcc_unreachable ();
598627f7eb2Smrg 	}
599627f7eb2Smrg 
600627f7eb2Smrg       spec[n++].pos = pos;
601627f7eb2Smrg     }
602627f7eb2Smrg 
603627f7eb2Smrg   /* Then convert the values for each %-style argument.  */
604627f7eb2Smrg   for (pos = 0; pos <= maxpos; pos++)
605627f7eb2Smrg     {
606627f7eb2Smrg       gcc_assert (arg[pos].type != NOTYPE);
607627f7eb2Smrg       switch (arg[pos].type)
608627f7eb2Smrg 	{
609627f7eb2Smrg 	  case TYPE_CURRENTLOC:
610627f7eb2Smrg 	    loc = &gfc_current_locus;
611627f7eb2Smrg 	    /* Fall through.  */
612627f7eb2Smrg 
613627f7eb2Smrg 	  case TYPE_LOCUS:
614627f7eb2Smrg 	    if (arg[pos].type == TYPE_LOCUS)
615627f7eb2Smrg 	      loc = va_arg (argp, locus *);
616627f7eb2Smrg 
617627f7eb2Smrg 	    if (have_l1)
618627f7eb2Smrg 	      {
619627f7eb2Smrg 		l2 = loc;
620627f7eb2Smrg 		arg[pos].u.stringval = "(2)";
621*4c3eb207Smrg 		/* Point %C first offending character not the last good one. */
622*4c3eb207Smrg 		if (arg[pos].type == TYPE_CURRENTLOC && *l2->nextc != '\0')
623*4c3eb207Smrg 		  l2->nextc++;
624627f7eb2Smrg 	      }
625627f7eb2Smrg 	    else
626627f7eb2Smrg 	      {
627627f7eb2Smrg 		l1 = loc;
628627f7eb2Smrg 		have_l1 = 1;
629627f7eb2Smrg 		arg[pos].u.stringval = "(1)";
630*4c3eb207Smrg 		/* Point %C first offending character not the last good one. */
631*4c3eb207Smrg 		if (arg[pos].type == TYPE_CURRENTLOC && *l1->nextc != '\0')
632*4c3eb207Smrg 		  l1->nextc++;
633627f7eb2Smrg 	      }
634627f7eb2Smrg 	    break;
635627f7eb2Smrg 
636627f7eb2Smrg 	  case TYPE_INTEGER:
637627f7eb2Smrg 	    arg[pos].u.intval = va_arg (argp, int);
638627f7eb2Smrg 	    break;
639627f7eb2Smrg 
640627f7eb2Smrg 	  case TYPE_UINTEGER:
641627f7eb2Smrg 	    arg[pos].u.uintval = va_arg (argp, unsigned int);
642627f7eb2Smrg 	    break;
643627f7eb2Smrg 
644627f7eb2Smrg 	  case TYPE_LONGINT:
645627f7eb2Smrg 	    arg[pos].u.longintval = va_arg (argp, long int);
646627f7eb2Smrg 	    break;
647627f7eb2Smrg 
648627f7eb2Smrg 	  case TYPE_ULONGINT:
649627f7eb2Smrg 	    arg[pos].u.ulongintval = va_arg (argp, unsigned long int);
650627f7eb2Smrg 	    break;
651627f7eb2Smrg 
652627f7eb2Smrg 	  case TYPE_CHAR:
653627f7eb2Smrg 	    arg[pos].u.charval = (char) va_arg (argp, int);
654627f7eb2Smrg 	    break;
655627f7eb2Smrg 
656627f7eb2Smrg 	  case TYPE_STRING:
657627f7eb2Smrg 	    arg[pos].u.stringval = (const char *) va_arg (argp, char *);
658627f7eb2Smrg 	    break;
659627f7eb2Smrg 
660627f7eb2Smrg 	  default:
661627f7eb2Smrg 	    gcc_unreachable ();
662627f7eb2Smrg 	}
663627f7eb2Smrg     }
664627f7eb2Smrg 
665627f7eb2Smrg   for (n = 0; spec[n].pos >= 0; n++)
666627f7eb2Smrg     spec[n].u = arg[spec[n].pos].u;
667627f7eb2Smrg 
668627f7eb2Smrg   /* Show the current loci if we have to.  */
669627f7eb2Smrg   if (have_l1)
670627f7eb2Smrg     show_loci (l1, l2);
671627f7eb2Smrg 
672627f7eb2Smrg   if (*type)
673627f7eb2Smrg     {
674627f7eb2Smrg       error_string (type);
675627f7eb2Smrg       error_char (' ');
676627f7eb2Smrg     }
677627f7eb2Smrg 
678627f7eb2Smrg   have_l1 = 0;
679627f7eb2Smrg   format = format0;
680627f7eb2Smrg   n = 0;
681627f7eb2Smrg 
682627f7eb2Smrg   for (; *format; format++)
683627f7eb2Smrg     {
684627f7eb2Smrg       if (*format != '%')
685627f7eb2Smrg 	{
686627f7eb2Smrg 	  error_char (*format);
687627f7eb2Smrg 	  continue;
688627f7eb2Smrg 	}
689627f7eb2Smrg 
690627f7eb2Smrg       format++;
691627f7eb2Smrg       if (ISDIGIT (*format))
692627f7eb2Smrg 	{
693627f7eb2Smrg 	  /* This is a position specifier.  See comment above.  */
694627f7eb2Smrg 	  while (ISDIGIT (*format))
695627f7eb2Smrg 	    format++;
696627f7eb2Smrg 
697627f7eb2Smrg 	  /* Skip over the dollar sign.  */
698627f7eb2Smrg 	  format++;
699627f7eb2Smrg 	}
700627f7eb2Smrg 
701627f7eb2Smrg       switch (*format)
702627f7eb2Smrg 	{
703627f7eb2Smrg 	case '%':
704627f7eb2Smrg 	  error_char ('%');
705627f7eb2Smrg 	  break;
706627f7eb2Smrg 
707627f7eb2Smrg 	case 'c':
708627f7eb2Smrg 	  error_char (spec[n++].u.charval);
709627f7eb2Smrg 	  break;
710627f7eb2Smrg 
711627f7eb2Smrg 	case 's':
712627f7eb2Smrg 	case 'C':		/* Current locus */
713627f7eb2Smrg 	case 'L':		/* Specified locus */
714627f7eb2Smrg 	  error_string (spec[n++].u.stringval);
715627f7eb2Smrg 	  break;
716627f7eb2Smrg 
717627f7eb2Smrg 	case 'd':
718627f7eb2Smrg 	case 'i':
719627f7eb2Smrg 	  error_integer (spec[n++].u.intval);
720627f7eb2Smrg 	  break;
721627f7eb2Smrg 
722627f7eb2Smrg 	case 'u':
723627f7eb2Smrg 	  error_uinteger (spec[n++].u.uintval);
724627f7eb2Smrg 	  break;
725627f7eb2Smrg 
726627f7eb2Smrg 	case 'l':
727627f7eb2Smrg 	  format++;
728627f7eb2Smrg 	  if (*format == 'u')
729627f7eb2Smrg 	    error_uinteger (spec[n++].u.ulongintval);
730627f7eb2Smrg 	  else
731627f7eb2Smrg 	    error_integer (spec[n++].u.longintval);
732627f7eb2Smrg 	  break;
733627f7eb2Smrg 
734627f7eb2Smrg 	}
735627f7eb2Smrg     }
736627f7eb2Smrg 
737627f7eb2Smrg   error_char ('\n');
738627f7eb2Smrg }
739627f7eb2Smrg 
740627f7eb2Smrg 
741627f7eb2Smrg /* Wrapper for error_print().  */
742627f7eb2Smrg 
743627f7eb2Smrg static void
error_printf(const char * gmsgid,...)744627f7eb2Smrg error_printf (const char *gmsgid, ...)
745627f7eb2Smrg {
746627f7eb2Smrg   va_list argp;
747627f7eb2Smrg 
748627f7eb2Smrg   va_start (argp, gmsgid);
749627f7eb2Smrg   error_print ("", _(gmsgid), argp);
750627f7eb2Smrg   va_end (argp);
751627f7eb2Smrg }
752627f7eb2Smrg 
753627f7eb2Smrg 
754627f7eb2Smrg /* Clear any output buffered in a pretty-print output_buffer.  */
755627f7eb2Smrg 
756627f7eb2Smrg static void
gfc_clear_pp_buffer(output_buffer * this_buffer)757627f7eb2Smrg gfc_clear_pp_buffer (output_buffer *this_buffer)
758627f7eb2Smrg {
759627f7eb2Smrg   pretty_printer *pp = global_dc->printer;
760627f7eb2Smrg   output_buffer *tmp_buffer = pp->buffer;
761627f7eb2Smrg   pp->buffer = this_buffer;
762627f7eb2Smrg   pp_clear_output_area (pp);
763627f7eb2Smrg   pp->buffer = tmp_buffer;
764627f7eb2Smrg   /* We need to reset last_location, otherwise we may skip caret lines
765627f7eb2Smrg      when we actually give a diagnostic.  */
766627f7eb2Smrg   global_dc->last_location = UNKNOWN_LOCATION;
767627f7eb2Smrg }
768627f7eb2Smrg 
769*4c3eb207Smrg /* The currently-printing diagnostic, for use by gfc_format_decoder,
770*4c3eb207Smrg    for colorizing %C and %L.  */
771*4c3eb207Smrg 
772*4c3eb207Smrg static diagnostic_info *curr_diagnostic;
773*4c3eb207Smrg 
774*4c3eb207Smrg /* A helper function to call diagnostic_report_diagnostic, while setting
775*4c3eb207Smrg    curr_diagnostic for the duration of the call.  */
776*4c3eb207Smrg 
777*4c3eb207Smrg static bool
gfc_report_diagnostic(diagnostic_info * diagnostic)778*4c3eb207Smrg gfc_report_diagnostic (diagnostic_info *diagnostic)
779*4c3eb207Smrg {
780*4c3eb207Smrg   gcc_assert (diagnostic != NULL);
781*4c3eb207Smrg   curr_diagnostic = diagnostic;
782*4c3eb207Smrg   bool ret = diagnostic_report_diagnostic (global_dc, diagnostic);
783*4c3eb207Smrg   curr_diagnostic = NULL;
784*4c3eb207Smrg   return ret;
785*4c3eb207Smrg }
786627f7eb2Smrg 
787627f7eb2Smrg /* This is just a helper function to avoid duplicating the logic of
788627f7eb2Smrg    gfc_warning.  */
789627f7eb2Smrg 
790627f7eb2Smrg static bool
gfc_warning(int opt,const char * gmsgid,va_list ap)791627f7eb2Smrg gfc_warning (int opt, const char *gmsgid, va_list ap)
792627f7eb2Smrg {
793627f7eb2Smrg   va_list argp;
794627f7eb2Smrg   va_copy (argp, ap);
795627f7eb2Smrg 
796627f7eb2Smrg   diagnostic_info diagnostic;
797627f7eb2Smrg   rich_location rich_loc (line_table, UNKNOWN_LOCATION);
798627f7eb2Smrg   bool fatal_errors = global_dc->fatal_errors;
799627f7eb2Smrg   pretty_printer *pp = global_dc->printer;
800627f7eb2Smrg   output_buffer *tmp_buffer = pp->buffer;
801627f7eb2Smrg 
802627f7eb2Smrg   gfc_clear_pp_buffer (pp_warning_buffer);
803627f7eb2Smrg 
804627f7eb2Smrg   if (buffered_p)
805627f7eb2Smrg     {
806627f7eb2Smrg       pp->buffer = pp_warning_buffer;
807627f7eb2Smrg       global_dc->fatal_errors = false;
808627f7eb2Smrg       /* To prevent -fmax-errors= triggering.  */
809627f7eb2Smrg       --werrorcount;
810627f7eb2Smrg     }
811627f7eb2Smrg 
812627f7eb2Smrg   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
813627f7eb2Smrg 		       DK_WARNING);
814627f7eb2Smrg   diagnostic.option_index = opt;
815*4c3eb207Smrg   bool ret = gfc_report_diagnostic (&diagnostic);
816627f7eb2Smrg 
817627f7eb2Smrg   if (buffered_p)
818627f7eb2Smrg     {
819627f7eb2Smrg       pp->buffer = tmp_buffer;
820627f7eb2Smrg       global_dc->fatal_errors = fatal_errors;
821627f7eb2Smrg 
822627f7eb2Smrg       warningcount_buffered = 0;
823627f7eb2Smrg       werrorcount_buffered = 0;
824627f7eb2Smrg       /* Undo the above --werrorcount if not Werror, otherwise
825627f7eb2Smrg 	 werrorcount is correct already.  */
826627f7eb2Smrg       if (!ret)
827627f7eb2Smrg 	++werrorcount;
828627f7eb2Smrg       else if (diagnostic.kind == DK_ERROR)
829627f7eb2Smrg 	++werrorcount_buffered;
830627f7eb2Smrg       else
831627f7eb2Smrg 	++werrorcount, --warningcount, ++warningcount_buffered;
832627f7eb2Smrg     }
833627f7eb2Smrg 
834627f7eb2Smrg   va_end (argp);
835627f7eb2Smrg   return ret;
836627f7eb2Smrg }
837627f7eb2Smrg 
838627f7eb2Smrg /* Issue a warning.  */
839627f7eb2Smrg 
840627f7eb2Smrg bool
gfc_warning(int opt,const char * gmsgid,...)841627f7eb2Smrg gfc_warning (int opt, const char *gmsgid, ...)
842627f7eb2Smrg {
843627f7eb2Smrg   va_list argp;
844627f7eb2Smrg 
845627f7eb2Smrg   va_start (argp, gmsgid);
846627f7eb2Smrg   bool ret = gfc_warning (opt, gmsgid, argp);
847627f7eb2Smrg   va_end (argp);
848627f7eb2Smrg   return ret;
849627f7eb2Smrg }
850627f7eb2Smrg 
851627f7eb2Smrg 
852627f7eb2Smrg /* Whether, for a feature included in a given standard set (GFC_STD_*),
853627f7eb2Smrg    we should issue an error or a warning, or be quiet.  */
854627f7eb2Smrg 
855627f7eb2Smrg notification
gfc_notification_std(int std)856627f7eb2Smrg gfc_notification_std (int std)
857627f7eb2Smrg {
858627f7eb2Smrg   bool warning;
859627f7eb2Smrg 
860627f7eb2Smrg   warning = ((gfc_option.warn_std & std) != 0) && !inhibit_warnings;
861627f7eb2Smrg   if ((gfc_option.allow_std & std) != 0 && !warning)
862627f7eb2Smrg     return SILENT;
863627f7eb2Smrg 
864627f7eb2Smrg   return warning ? WARNING : ERROR;
865627f7eb2Smrg }
866627f7eb2Smrg 
867627f7eb2Smrg 
868627f7eb2Smrg /* Return a string describing the nature of a standard violation
869627f7eb2Smrg  * and/or the relevant version of the standard.  */
870627f7eb2Smrg 
871627f7eb2Smrg char const*
notify_std_msg(int std)872627f7eb2Smrg notify_std_msg(int std)
873627f7eb2Smrg {
874627f7eb2Smrg 
875627f7eb2Smrg   if (std & GFC_STD_F2018_DEL)
876627f7eb2Smrg     return _("Fortran 2018 deleted feature:");
877627f7eb2Smrg   else if (std & GFC_STD_F2018_OBS)
878627f7eb2Smrg     return _("Fortran 2018 obsolescent feature:");
879627f7eb2Smrg   else if (std & GFC_STD_F2018)
880627f7eb2Smrg     return _("Fortran 2018:");
881627f7eb2Smrg   else if (std & GFC_STD_F2008_OBS)
882627f7eb2Smrg     return _("Fortran 2008 obsolescent feature:");
883627f7eb2Smrg   else if (std & GFC_STD_F2008)
884627f7eb2Smrg     return "Fortran 2008:";
885627f7eb2Smrg   else if (std & GFC_STD_F2003)
886627f7eb2Smrg     return "Fortran 2003:";
887627f7eb2Smrg   else if (std & GFC_STD_GNU)
888627f7eb2Smrg     return _("GNU Extension:");
889627f7eb2Smrg   else if (std & GFC_STD_LEGACY)
890627f7eb2Smrg     return _("Legacy Extension:");
891627f7eb2Smrg   else if (std & GFC_STD_F95_OBS)
892627f7eb2Smrg     return _("Obsolescent feature:");
893627f7eb2Smrg   else if (std & GFC_STD_F95_DEL)
894627f7eb2Smrg     return _("Deleted feature:");
895627f7eb2Smrg   else
896627f7eb2Smrg     gcc_unreachable ();
897627f7eb2Smrg }
898627f7eb2Smrg 
899627f7eb2Smrg 
900627f7eb2Smrg /* Possibly issue a warning/error about use of a nonstandard (or deleted)
901627f7eb2Smrg    feature.  An error/warning will be issued if the currently selected
902627f7eb2Smrg    standard does not contain the requested bits.  Return false if
903627f7eb2Smrg    an error is generated.  */
904627f7eb2Smrg 
905627f7eb2Smrg bool
gfc_notify_std(int std,const char * gmsgid,...)906627f7eb2Smrg gfc_notify_std (int std, const char *gmsgid, ...)
907627f7eb2Smrg {
908627f7eb2Smrg   va_list argp;
909627f7eb2Smrg   const char *msg, *msg2;
910627f7eb2Smrg   char *buffer;
911627f7eb2Smrg 
912627f7eb2Smrg   /* Determine whether an error or a warning is needed.  */
913627f7eb2Smrg   const int wstd = std & gfc_option.warn_std;    /* Standard to warn about.  */
914627f7eb2Smrg   const int estd = std & ~gfc_option.allow_std;  /* Standard to error about.  */
915627f7eb2Smrg   const bool warning = (wstd != 0) && !inhibit_warnings;
916627f7eb2Smrg   const bool error = (estd != 0);
917627f7eb2Smrg 
918627f7eb2Smrg   if (!error && !warning)
919627f7eb2Smrg     return true;
920627f7eb2Smrg   if (suppress_errors)
921627f7eb2Smrg     return !error;
922627f7eb2Smrg 
923627f7eb2Smrg   if (error)
924627f7eb2Smrg     msg = notify_std_msg (estd);
925627f7eb2Smrg   else
926627f7eb2Smrg     msg = notify_std_msg (wstd);
927627f7eb2Smrg 
928627f7eb2Smrg   msg2 = _(gmsgid);
929627f7eb2Smrg   buffer = (char *) alloca (strlen (msg) + strlen (msg2) + 2);
930627f7eb2Smrg   strcpy (buffer, msg);
931627f7eb2Smrg   strcat (buffer, " ");
932627f7eb2Smrg   strcat (buffer, msg2);
933627f7eb2Smrg 
934627f7eb2Smrg   va_start (argp, gmsgid);
935627f7eb2Smrg   if (error)
936627f7eb2Smrg     gfc_error_opt (0, buffer, argp);
937627f7eb2Smrg   else
938627f7eb2Smrg     gfc_warning (0, buffer, argp);
939627f7eb2Smrg   va_end (argp);
940627f7eb2Smrg 
941627f7eb2Smrg   if (error)
942627f7eb2Smrg     return false;
943627f7eb2Smrg   else
944627f7eb2Smrg     return (warning && !warnings_are_errors);
945627f7eb2Smrg }
946627f7eb2Smrg 
947627f7eb2Smrg 
948627f7eb2Smrg /* Called from output_format -- during diagnostic message processing
949627f7eb2Smrg    to handle Fortran specific format specifiers with the following meanings:
950627f7eb2Smrg 
951627f7eb2Smrg    %C  Current locus (no argument)
952627f7eb2Smrg    %L  Takes locus argument
953627f7eb2Smrg */
954627f7eb2Smrg static bool
gfc_format_decoder(pretty_printer * pp,text_info * text,const char * spec,int precision,bool wide,bool set_locus,bool hash,bool * quoted,const char ** buffer_ptr)955627f7eb2Smrg gfc_format_decoder (pretty_printer *pp, text_info *text, const char *spec,
956627f7eb2Smrg 		    int precision, bool wide, bool set_locus, bool hash,
957627f7eb2Smrg 		    bool *quoted, const char **buffer_ptr)
958627f7eb2Smrg {
959627f7eb2Smrg   switch (*spec)
960627f7eb2Smrg     {
961627f7eb2Smrg     case 'C':
962627f7eb2Smrg     case 'L':
963627f7eb2Smrg       {
964627f7eb2Smrg 	static const char *result[2] = { "(1)", "(2)" };
965627f7eb2Smrg 	locus *loc;
966627f7eb2Smrg 	if (*spec == 'C')
967627f7eb2Smrg 	  loc = &gfc_current_locus;
968627f7eb2Smrg 	else
969627f7eb2Smrg 	  loc = va_arg (*text->args_ptr, locus *);
970627f7eb2Smrg 	gcc_assert (loc->nextc - loc->lb->line >= 0);
971627f7eb2Smrg 	unsigned int offset = loc->nextc - loc->lb->line;
972*4c3eb207Smrg 	if (*spec == 'C' && *loc->nextc != '\0')
973*4c3eb207Smrg 	  /* Point %C first offending character not the last good one. */
974*4c3eb207Smrg 	  offset++;
975627f7eb2Smrg 	/* If location[0] != UNKNOWN_LOCATION means that we already
976627f7eb2Smrg 	   processed one of %C/%L.  */
977627f7eb2Smrg 	int loc_num = text->get_location (0) == UNKNOWN_LOCATION ? 0 : 1;
978627f7eb2Smrg 	location_t src_loc
979627f7eb2Smrg 	  = linemap_position_for_loc_and_offset (line_table,
980627f7eb2Smrg 						 loc->lb->location,
981627f7eb2Smrg 						 offset);
982627f7eb2Smrg 	text->set_location (loc_num, src_loc, SHOW_RANGE_WITH_CARET);
983*4c3eb207Smrg 	/* Colorize the markers to match the color choices of
984*4c3eb207Smrg 	   diagnostic_show_locus (the initial location has a color given
985*4c3eb207Smrg 	   by the "kind" of the diagnostic, the secondary location has
986*4c3eb207Smrg 	   color "range1").  */
987*4c3eb207Smrg 	gcc_assert (curr_diagnostic != NULL);
988*4c3eb207Smrg 	const char *color
989*4c3eb207Smrg 	  = (loc_num
990*4c3eb207Smrg 	     ? "range1"
991*4c3eb207Smrg 	     : diagnostic_get_color_for_kind (curr_diagnostic->kind));
992*4c3eb207Smrg 	pp_string (pp, colorize_start (pp_show_color (pp), color));
993627f7eb2Smrg 	pp_string (pp, result[loc_num]);
994*4c3eb207Smrg 	pp_string (pp, colorize_stop (pp_show_color (pp)));
995627f7eb2Smrg 	return true;
996627f7eb2Smrg       }
997627f7eb2Smrg     default:
998627f7eb2Smrg       /* Fall through info the middle-end decoder, as e.g. stor-layout.c
999627f7eb2Smrg 	 etc. diagnostics can use the FE printer while the FE is still
1000627f7eb2Smrg 	 active.  */
1001627f7eb2Smrg       return default_tree_printer (pp, text, spec, precision, wide,
1002627f7eb2Smrg 				   set_locus, hash, quoted, buffer_ptr);
1003627f7eb2Smrg     }
1004627f7eb2Smrg }
1005627f7eb2Smrg 
1006627f7eb2Smrg /* Return a malloc'd string describing the kind of diagnostic.  The
1007627f7eb2Smrg    caller is responsible for freeing the memory.  */
1008627f7eb2Smrg static char *
gfc_diagnostic_build_kind_prefix(diagnostic_context * context,const diagnostic_info * diagnostic)1009627f7eb2Smrg gfc_diagnostic_build_kind_prefix (diagnostic_context *context,
1010627f7eb2Smrg 				  const diagnostic_info *diagnostic)
1011627f7eb2Smrg {
1012627f7eb2Smrg   static const char *const diagnostic_kind_text[] = {
1013627f7eb2Smrg #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
1014627f7eb2Smrg #include "gfc-diagnostic.def"
1015627f7eb2Smrg #undef DEFINE_DIAGNOSTIC_KIND
1016627f7eb2Smrg     "must-not-happen"
1017627f7eb2Smrg   };
1018627f7eb2Smrg   static const char *const diagnostic_kind_color[] = {
1019627f7eb2Smrg #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (C),
1020627f7eb2Smrg #include "gfc-diagnostic.def"
1021627f7eb2Smrg #undef DEFINE_DIAGNOSTIC_KIND
1022627f7eb2Smrg     NULL
1023627f7eb2Smrg   };
1024627f7eb2Smrg   gcc_assert (diagnostic->kind < DK_LAST_DIAGNOSTIC_KIND);
1025627f7eb2Smrg   const char *text = _(diagnostic_kind_text[diagnostic->kind]);
1026627f7eb2Smrg   const char *text_cs = "", *text_ce = "";
1027627f7eb2Smrg   pretty_printer *pp = context->printer;
1028627f7eb2Smrg 
1029627f7eb2Smrg   if (diagnostic_kind_color[diagnostic->kind])
1030627f7eb2Smrg     {
1031627f7eb2Smrg       text_cs = colorize_start (pp_show_color (pp),
1032627f7eb2Smrg 				diagnostic_kind_color[diagnostic->kind]);
1033627f7eb2Smrg       text_ce = colorize_stop (pp_show_color (pp));
1034627f7eb2Smrg     }
1035627f7eb2Smrg   return build_message_string ("%s%s:%s ", text_cs, text, text_ce);
1036627f7eb2Smrg }
1037627f7eb2Smrg 
1038627f7eb2Smrg /* Return a malloc'd string describing a location.  The caller is
1039627f7eb2Smrg    responsible for freeing the memory.  */
1040627f7eb2Smrg static char *
gfc_diagnostic_build_locus_prefix(diagnostic_context * context,expanded_location s)1041627f7eb2Smrg gfc_diagnostic_build_locus_prefix (diagnostic_context *context,
1042627f7eb2Smrg 				   expanded_location s)
1043627f7eb2Smrg {
1044627f7eb2Smrg   pretty_printer *pp = context->printer;
1045627f7eb2Smrg   const char *locus_cs = colorize_start (pp_show_color (pp), "locus");
1046627f7eb2Smrg   const char *locus_ce = colorize_stop (pp_show_color (pp));
1047627f7eb2Smrg   return (s.file == NULL
1048627f7eb2Smrg 	  ? build_message_string ("%s%s:%s", locus_cs, progname, locus_ce )
1049627f7eb2Smrg 	  : !strcmp (s.file, N_("<built-in>"))
1050627f7eb2Smrg 	  ? build_message_string ("%s%s:%s", locus_cs, s.file, locus_ce)
1051627f7eb2Smrg 	  : context->show_column
1052627f7eb2Smrg 	  ? build_message_string ("%s%s:%d:%d:%s", locus_cs, s.file, s.line,
1053627f7eb2Smrg 				  s.column, locus_ce)
1054627f7eb2Smrg 	  : build_message_string ("%s%s:%d:%s", locus_cs, s.file, s.line, locus_ce));
1055627f7eb2Smrg }
1056627f7eb2Smrg 
1057627f7eb2Smrg /* Return a malloc'd string describing two locations.  The caller is
1058627f7eb2Smrg    responsible for freeing the memory.  */
1059627f7eb2Smrg static char *
gfc_diagnostic_build_locus_prefix(diagnostic_context * context,expanded_location s,expanded_location s2)1060627f7eb2Smrg gfc_diagnostic_build_locus_prefix (diagnostic_context *context,
1061627f7eb2Smrg 				   expanded_location s, expanded_location s2)
1062627f7eb2Smrg {
1063627f7eb2Smrg   pretty_printer *pp = context->printer;
1064627f7eb2Smrg   const char *locus_cs = colorize_start (pp_show_color (pp), "locus");
1065627f7eb2Smrg   const char *locus_ce = colorize_stop (pp_show_color (pp));
1066627f7eb2Smrg 
1067627f7eb2Smrg   return (s.file == NULL
1068627f7eb2Smrg 	  ? build_message_string ("%s%s:%s", locus_cs, progname, locus_ce )
1069627f7eb2Smrg 	  : !strcmp (s.file, N_("<built-in>"))
1070627f7eb2Smrg 	  ? build_message_string ("%s%s:%s", locus_cs, s.file, locus_ce)
1071627f7eb2Smrg 	  : context->show_column
1072627f7eb2Smrg 	  ? build_message_string ("%s%s:%d:%d-%d:%s", locus_cs, s.file, s.line,
1073627f7eb2Smrg 				  MIN (s.column, s2.column),
1074627f7eb2Smrg 				  MAX (s.column, s2.column), locus_ce)
1075627f7eb2Smrg 	  : build_message_string ("%s%s:%d:%s", locus_cs, s.file, s.line,
1076627f7eb2Smrg 				  locus_ce));
1077627f7eb2Smrg }
1078627f7eb2Smrg 
1079627f7eb2Smrg /* This function prints the locus (file:line:column), the diagnostic kind
1080627f7eb2Smrg    (Error, Warning) and (optionally) the relevant lines of code with
1081627f7eb2Smrg    annotation lines with '1' and/or '2' below them.
1082627f7eb2Smrg 
1083627f7eb2Smrg    With -fdiagnostic-show-caret (the default) it prints:
1084627f7eb2Smrg 
1085627f7eb2Smrg        [locus of primary range]:
1086627f7eb2Smrg 
1087627f7eb2Smrg           some code
1088627f7eb2Smrg                  1
1089627f7eb2Smrg        Error: Some error at (1)
1090627f7eb2Smrg 
1091627f7eb2Smrg   With -fno-diagnostic-show-caret or if the primary range is not
1092627f7eb2Smrg   valid, it prints:
1093627f7eb2Smrg 
1094627f7eb2Smrg        [locus of primary range]: Error: Some error at (1) and (2)
1095627f7eb2Smrg */
1096627f7eb2Smrg static void
gfc_diagnostic_starter(diagnostic_context * context,diagnostic_info * diagnostic)1097627f7eb2Smrg gfc_diagnostic_starter (diagnostic_context *context,
1098627f7eb2Smrg 			diagnostic_info *diagnostic)
1099627f7eb2Smrg {
1100627f7eb2Smrg   char * kind_prefix = gfc_diagnostic_build_kind_prefix (context, diagnostic);
1101627f7eb2Smrg 
1102627f7eb2Smrg   expanded_location s1 = diagnostic_expand_location (diagnostic);
1103627f7eb2Smrg   expanded_location s2;
1104627f7eb2Smrg   bool one_locus = diagnostic->richloc->get_num_locations () < 2;
1105627f7eb2Smrg   bool same_locus = false;
1106627f7eb2Smrg 
1107627f7eb2Smrg   if (!one_locus)
1108627f7eb2Smrg     {
1109627f7eb2Smrg       s2 = diagnostic_expand_location (diagnostic, 1);
1110627f7eb2Smrg       same_locus = diagnostic_same_line (context, s1, s2);
1111627f7eb2Smrg     }
1112627f7eb2Smrg 
1113627f7eb2Smrg   char * locus_prefix = (one_locus || !same_locus)
1114627f7eb2Smrg     ? gfc_diagnostic_build_locus_prefix (context, s1)
1115627f7eb2Smrg     : gfc_diagnostic_build_locus_prefix (context, s1, s2);
1116627f7eb2Smrg 
1117627f7eb2Smrg   if (!context->show_caret
1118627f7eb2Smrg       || diagnostic_location (diagnostic, 0) <= BUILTINS_LOCATION
1119627f7eb2Smrg       || diagnostic_location (diagnostic, 0) == context->last_location)
1120627f7eb2Smrg     {
1121627f7eb2Smrg       pp_set_prefix (context->printer,
1122627f7eb2Smrg 		     concat (locus_prefix, " ", kind_prefix, NULL));
1123627f7eb2Smrg       free (locus_prefix);
1124627f7eb2Smrg 
1125627f7eb2Smrg       if (one_locus || same_locus)
1126627f7eb2Smrg 	{
1127627f7eb2Smrg 	  free (kind_prefix);
1128627f7eb2Smrg 	  return;
1129627f7eb2Smrg 	}
1130627f7eb2Smrg       /* In this case, we print the previous locus and prefix as:
1131627f7eb2Smrg 
1132627f7eb2Smrg 	  [locus]:[prefix]: (1)
1133627f7eb2Smrg 
1134627f7eb2Smrg 	 and we flush with a new line before setting the new prefix.  */
1135627f7eb2Smrg       pp_string (context->printer, "(1)");
1136627f7eb2Smrg       pp_newline (context->printer);
1137627f7eb2Smrg       locus_prefix = gfc_diagnostic_build_locus_prefix (context, s2);
1138627f7eb2Smrg       pp_set_prefix (context->printer,
1139627f7eb2Smrg 		     concat (locus_prefix, " ", kind_prefix, NULL));
1140627f7eb2Smrg       free (kind_prefix);
1141627f7eb2Smrg       free (locus_prefix);
1142627f7eb2Smrg     }
1143627f7eb2Smrg   else
1144627f7eb2Smrg     {
1145627f7eb2Smrg       pp_verbatim (context->printer, "%s", locus_prefix);
1146627f7eb2Smrg       free (locus_prefix);
1147627f7eb2Smrg       /* Fortran uses an empty line between locus and caret line.  */
1148627f7eb2Smrg       pp_newline (context->printer);
1149*4c3eb207Smrg       pp_set_prefix (context->printer, NULL);
1150*4c3eb207Smrg       pp_newline (context->printer);
1151627f7eb2Smrg       diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind);
1152627f7eb2Smrg       /* If the caret line was shown, the prefix does not contain the
1153627f7eb2Smrg 	 locus.  */
1154627f7eb2Smrg       pp_set_prefix (context->printer, kind_prefix);
1155627f7eb2Smrg     }
1156627f7eb2Smrg }
1157627f7eb2Smrg 
1158627f7eb2Smrg static void
gfc_diagnostic_start_span(diagnostic_context * context,expanded_location exploc)1159627f7eb2Smrg gfc_diagnostic_start_span (diagnostic_context *context,
1160627f7eb2Smrg 			   expanded_location exploc)
1161627f7eb2Smrg {
1162627f7eb2Smrg   char *locus_prefix;
1163627f7eb2Smrg   locus_prefix = gfc_diagnostic_build_locus_prefix (context, exploc);
1164627f7eb2Smrg   pp_verbatim (context->printer, "%s", locus_prefix);
1165627f7eb2Smrg   free (locus_prefix);
1166627f7eb2Smrg   pp_newline (context->printer);
1167627f7eb2Smrg   /* Fortran uses an empty line between locus and caret line.  */
1168627f7eb2Smrg   pp_newline (context->printer);
1169627f7eb2Smrg }
1170627f7eb2Smrg 
1171627f7eb2Smrg 
1172627f7eb2Smrg static void
gfc_diagnostic_finalizer(diagnostic_context * context,diagnostic_info * diagnostic ATTRIBUTE_UNUSED,diagnostic_t orig_diag_kind ATTRIBUTE_UNUSED)1173627f7eb2Smrg gfc_diagnostic_finalizer (diagnostic_context *context,
1174627f7eb2Smrg 			  diagnostic_info *diagnostic ATTRIBUTE_UNUSED,
1175627f7eb2Smrg 			  diagnostic_t orig_diag_kind ATTRIBUTE_UNUSED)
1176627f7eb2Smrg {
1177627f7eb2Smrg   pp_destroy_prefix (context->printer);
1178627f7eb2Smrg   pp_newline_and_flush (context->printer);
1179627f7eb2Smrg }
1180627f7eb2Smrg 
1181627f7eb2Smrg /* Immediate warning (i.e. do not buffer the warning) with an explicit
1182627f7eb2Smrg    location.  */
1183627f7eb2Smrg 
1184627f7eb2Smrg bool
gfc_warning_now_at(location_t loc,int opt,const char * gmsgid,...)1185627f7eb2Smrg gfc_warning_now_at (location_t loc, int opt, const char *gmsgid, ...)
1186627f7eb2Smrg {
1187627f7eb2Smrg   va_list argp;
1188627f7eb2Smrg   diagnostic_info diagnostic;
1189627f7eb2Smrg   rich_location rich_loc (line_table, loc);
1190627f7eb2Smrg   bool ret;
1191627f7eb2Smrg 
1192627f7eb2Smrg   va_start (argp, gmsgid);
1193627f7eb2Smrg   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING);
1194627f7eb2Smrg   diagnostic.option_index = opt;
1195*4c3eb207Smrg   ret = gfc_report_diagnostic (&diagnostic);
1196627f7eb2Smrg   va_end (argp);
1197627f7eb2Smrg   return ret;
1198627f7eb2Smrg }
1199627f7eb2Smrg 
1200627f7eb2Smrg /* Immediate warning (i.e. do not buffer the warning).  */
1201627f7eb2Smrg 
1202627f7eb2Smrg bool
gfc_warning_now(int opt,const char * gmsgid,...)1203627f7eb2Smrg gfc_warning_now (int opt, const char *gmsgid, ...)
1204627f7eb2Smrg {
1205627f7eb2Smrg   va_list argp;
1206627f7eb2Smrg   diagnostic_info diagnostic;
1207627f7eb2Smrg   rich_location rich_loc (line_table, UNKNOWN_LOCATION);
1208627f7eb2Smrg   bool ret;
1209627f7eb2Smrg 
1210627f7eb2Smrg   va_start (argp, gmsgid);
1211627f7eb2Smrg   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
1212627f7eb2Smrg 		       DK_WARNING);
1213627f7eb2Smrg   diagnostic.option_index = opt;
1214*4c3eb207Smrg   ret = gfc_report_diagnostic (&diagnostic);
1215627f7eb2Smrg   va_end (argp);
1216627f7eb2Smrg   return ret;
1217627f7eb2Smrg }
1218627f7eb2Smrg 
1219627f7eb2Smrg /* Internal warning, do not buffer.  */
1220627f7eb2Smrg 
1221627f7eb2Smrg bool
gfc_warning_internal(int opt,const char * gmsgid,...)1222627f7eb2Smrg gfc_warning_internal (int opt, const char *gmsgid, ...)
1223627f7eb2Smrg {
1224627f7eb2Smrg   va_list argp;
1225627f7eb2Smrg   diagnostic_info diagnostic;
1226627f7eb2Smrg   rich_location rich_loc (line_table, UNKNOWN_LOCATION);
1227627f7eb2Smrg   bool ret;
1228627f7eb2Smrg 
1229627f7eb2Smrg   va_start (argp, gmsgid);
1230627f7eb2Smrg   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
1231627f7eb2Smrg 		       DK_WARNING);
1232627f7eb2Smrg   diagnostic.option_index = opt;
1233*4c3eb207Smrg   ret = gfc_report_diagnostic (&diagnostic);
1234627f7eb2Smrg   va_end (argp);
1235627f7eb2Smrg   return ret;
1236627f7eb2Smrg }
1237627f7eb2Smrg 
1238627f7eb2Smrg /* Immediate error (i.e. do not buffer).  */
1239627f7eb2Smrg 
1240627f7eb2Smrg void
gfc_error_now(const char * gmsgid,...)1241627f7eb2Smrg gfc_error_now (const char *gmsgid, ...)
1242627f7eb2Smrg {
1243627f7eb2Smrg   va_list argp;
1244627f7eb2Smrg   diagnostic_info diagnostic;
1245627f7eb2Smrg   rich_location rich_loc (line_table, UNKNOWN_LOCATION);
1246627f7eb2Smrg 
1247627f7eb2Smrg   error_buffer.flag = true;
1248627f7eb2Smrg 
1249627f7eb2Smrg   va_start (argp, gmsgid);
1250627f7eb2Smrg   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR);
1251*4c3eb207Smrg   gfc_report_diagnostic (&diagnostic);
1252627f7eb2Smrg   va_end (argp);
1253627f7eb2Smrg }
1254627f7eb2Smrg 
1255627f7eb2Smrg 
1256627f7eb2Smrg /* Fatal error, never returns.  */
1257627f7eb2Smrg 
1258627f7eb2Smrg void
gfc_fatal_error(const char * gmsgid,...)1259627f7eb2Smrg gfc_fatal_error (const char *gmsgid, ...)
1260627f7eb2Smrg {
1261627f7eb2Smrg   va_list argp;
1262627f7eb2Smrg   diagnostic_info diagnostic;
1263627f7eb2Smrg   rich_location rich_loc (line_table, UNKNOWN_LOCATION);
1264627f7eb2Smrg 
1265627f7eb2Smrg   va_start (argp, gmsgid);
1266627f7eb2Smrg   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_FATAL);
1267*4c3eb207Smrg   gfc_report_diagnostic (&diagnostic);
1268627f7eb2Smrg   va_end (argp);
1269627f7eb2Smrg 
1270627f7eb2Smrg   gcc_unreachable ();
1271627f7eb2Smrg }
1272627f7eb2Smrg 
1273627f7eb2Smrg /* Clear the warning flag.  */
1274627f7eb2Smrg 
1275627f7eb2Smrg void
gfc_clear_warning(void)1276627f7eb2Smrg gfc_clear_warning (void)
1277627f7eb2Smrg {
1278627f7eb2Smrg   gfc_clear_pp_buffer (pp_warning_buffer);
1279627f7eb2Smrg   warningcount_buffered = 0;
1280627f7eb2Smrg   werrorcount_buffered = 0;
1281627f7eb2Smrg }
1282627f7eb2Smrg 
1283627f7eb2Smrg 
1284627f7eb2Smrg /* Check to see if any warnings have been saved.
1285627f7eb2Smrg    If so, print the warning.  */
1286627f7eb2Smrg 
1287627f7eb2Smrg void
gfc_warning_check(void)1288627f7eb2Smrg gfc_warning_check (void)
1289627f7eb2Smrg {
1290627f7eb2Smrg   if (! gfc_output_buffer_empty_p (pp_warning_buffer))
1291627f7eb2Smrg     {
1292627f7eb2Smrg       pretty_printer *pp = global_dc->printer;
1293627f7eb2Smrg       output_buffer *tmp_buffer = pp->buffer;
1294627f7eb2Smrg       pp->buffer = pp_warning_buffer;
1295627f7eb2Smrg       pp_really_flush (pp);
1296627f7eb2Smrg       warningcount += warningcount_buffered;
1297627f7eb2Smrg       werrorcount += werrorcount_buffered;
1298627f7eb2Smrg       gcc_assert (warningcount_buffered + werrorcount_buffered == 1);
1299627f7eb2Smrg       pp->buffer = tmp_buffer;
1300627f7eb2Smrg       diagnostic_action_after_output (global_dc,
1301627f7eb2Smrg 				      warningcount_buffered
1302627f7eb2Smrg 				      ? DK_WARNING : DK_ERROR);
1303627f7eb2Smrg       diagnostic_check_max_errors (global_dc, true);
1304627f7eb2Smrg     }
1305627f7eb2Smrg }
1306627f7eb2Smrg 
1307627f7eb2Smrg 
1308627f7eb2Smrg /* Issue an error.  */
1309627f7eb2Smrg 
1310627f7eb2Smrg static void
gfc_error_opt(int opt,const char * gmsgid,va_list ap)1311627f7eb2Smrg gfc_error_opt (int opt, const char *gmsgid, va_list ap)
1312627f7eb2Smrg {
1313627f7eb2Smrg   va_list argp;
1314627f7eb2Smrg   va_copy (argp, ap);
1315627f7eb2Smrg   bool saved_abort_on_error = false;
1316627f7eb2Smrg 
1317627f7eb2Smrg   if (warnings_not_errors)
1318627f7eb2Smrg     {
1319627f7eb2Smrg       gfc_warning (opt, gmsgid, argp);
1320627f7eb2Smrg       va_end (argp);
1321627f7eb2Smrg       return;
1322627f7eb2Smrg     }
1323627f7eb2Smrg 
1324627f7eb2Smrg   if (suppress_errors)
1325627f7eb2Smrg     {
1326627f7eb2Smrg       va_end (argp);
1327627f7eb2Smrg       return;
1328627f7eb2Smrg     }
1329627f7eb2Smrg 
1330627f7eb2Smrg   diagnostic_info diagnostic;
1331627f7eb2Smrg   rich_location richloc (line_table, UNKNOWN_LOCATION);
1332627f7eb2Smrg   bool fatal_errors = global_dc->fatal_errors;
1333627f7eb2Smrg   pretty_printer *pp = global_dc->printer;
1334627f7eb2Smrg   output_buffer *tmp_buffer = pp->buffer;
1335627f7eb2Smrg 
1336627f7eb2Smrg   gfc_clear_pp_buffer (pp_error_buffer);
1337627f7eb2Smrg 
1338627f7eb2Smrg   if (buffered_p)
1339627f7eb2Smrg     {
1340627f7eb2Smrg       /* To prevent -dH from triggering an abort on a buffered error,
1341627f7eb2Smrg 	 save abort_on_error and restore it below.  */
1342627f7eb2Smrg       saved_abort_on_error = global_dc->abort_on_error;
1343627f7eb2Smrg       global_dc->abort_on_error = false;
1344627f7eb2Smrg       pp->buffer = pp_error_buffer;
1345627f7eb2Smrg       global_dc->fatal_errors = false;
1346627f7eb2Smrg       /* To prevent -fmax-errors= triggering, we decrease it before
1347627f7eb2Smrg 	 report_diagnostic increases it.  */
1348627f7eb2Smrg       --errorcount;
1349627f7eb2Smrg     }
1350627f7eb2Smrg 
1351627f7eb2Smrg   diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc, DK_ERROR);
1352*4c3eb207Smrg   gfc_report_diagnostic (&diagnostic);
1353627f7eb2Smrg 
1354627f7eb2Smrg   if (buffered_p)
1355627f7eb2Smrg     {
1356627f7eb2Smrg       pp->buffer = tmp_buffer;
1357627f7eb2Smrg       global_dc->fatal_errors = fatal_errors;
1358627f7eb2Smrg       global_dc->abort_on_error = saved_abort_on_error;
1359627f7eb2Smrg 
1360627f7eb2Smrg     }
1361627f7eb2Smrg 
1362627f7eb2Smrg   va_end (argp);
1363627f7eb2Smrg }
1364627f7eb2Smrg 
1365627f7eb2Smrg 
1366627f7eb2Smrg void
gfc_error_opt(int opt,const char * gmsgid,...)1367627f7eb2Smrg gfc_error_opt (int opt, const char *gmsgid, ...)
1368627f7eb2Smrg {
1369627f7eb2Smrg   va_list argp;
1370627f7eb2Smrg   va_start (argp, gmsgid);
1371627f7eb2Smrg   gfc_error_opt (opt, gmsgid, argp);
1372627f7eb2Smrg   va_end (argp);
1373627f7eb2Smrg }
1374627f7eb2Smrg 
1375627f7eb2Smrg 
1376627f7eb2Smrg void
gfc_error(const char * gmsgid,...)1377627f7eb2Smrg gfc_error (const char *gmsgid, ...)
1378627f7eb2Smrg {
1379627f7eb2Smrg   va_list argp;
1380627f7eb2Smrg   va_start (argp, gmsgid);
1381627f7eb2Smrg   gfc_error_opt (0, gmsgid, argp);
1382627f7eb2Smrg   va_end (argp);
1383627f7eb2Smrg }
1384627f7eb2Smrg 
1385627f7eb2Smrg 
1386627f7eb2Smrg /* This shouldn't happen... but sometimes does.  */
1387627f7eb2Smrg 
1388627f7eb2Smrg void
gfc_internal_error(const char * gmsgid,...)1389627f7eb2Smrg gfc_internal_error (const char *gmsgid, ...)
1390627f7eb2Smrg {
1391627f7eb2Smrg   int e, w;
1392627f7eb2Smrg   va_list argp;
1393627f7eb2Smrg   diagnostic_info diagnostic;
1394627f7eb2Smrg   rich_location rich_loc (line_table, UNKNOWN_LOCATION);
1395627f7eb2Smrg 
1396627f7eb2Smrg   gfc_get_errors (&w, &e);
1397627f7eb2Smrg   if (e > 0)
1398627f7eb2Smrg     exit(EXIT_FAILURE);
1399627f7eb2Smrg 
1400627f7eb2Smrg   va_start (argp, gmsgid);
1401627f7eb2Smrg   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ICE);
1402*4c3eb207Smrg   gfc_report_diagnostic (&diagnostic);
1403627f7eb2Smrg   va_end (argp);
1404627f7eb2Smrg 
1405627f7eb2Smrg   gcc_unreachable ();
1406627f7eb2Smrg }
1407627f7eb2Smrg 
1408627f7eb2Smrg 
1409627f7eb2Smrg /* Clear the error flag when we start to compile a source line.  */
1410627f7eb2Smrg 
1411627f7eb2Smrg void
gfc_clear_error(void)1412627f7eb2Smrg gfc_clear_error (void)
1413627f7eb2Smrg {
1414*4c3eb207Smrg   error_buffer.flag = false;
1415627f7eb2Smrg   warnings_not_errors = false;
1416627f7eb2Smrg   gfc_clear_pp_buffer (pp_error_buffer);
1417627f7eb2Smrg }
1418627f7eb2Smrg 
1419627f7eb2Smrg 
1420627f7eb2Smrg /* Tests the state of error_flag.  */
1421627f7eb2Smrg 
1422627f7eb2Smrg bool
gfc_error_flag_test(void)1423627f7eb2Smrg gfc_error_flag_test (void)
1424627f7eb2Smrg {
1425627f7eb2Smrg   return error_buffer.flag
1426627f7eb2Smrg     || !gfc_output_buffer_empty_p (pp_error_buffer);
1427627f7eb2Smrg }
1428627f7eb2Smrg 
1429627f7eb2Smrg 
1430627f7eb2Smrg /* Check to see if any errors have been saved.
1431627f7eb2Smrg    If so, print the error.  Returns the state of error_flag.  */
1432627f7eb2Smrg 
1433627f7eb2Smrg bool
gfc_error_check(void)1434627f7eb2Smrg gfc_error_check (void)
1435627f7eb2Smrg {
1436627f7eb2Smrg   if (error_buffer.flag
1437627f7eb2Smrg       || ! gfc_output_buffer_empty_p (pp_error_buffer))
1438627f7eb2Smrg     {
1439627f7eb2Smrg       error_buffer.flag = false;
1440627f7eb2Smrg       pretty_printer *pp = global_dc->printer;
1441627f7eb2Smrg       output_buffer *tmp_buffer = pp->buffer;
1442627f7eb2Smrg       pp->buffer = pp_error_buffer;
1443627f7eb2Smrg       pp_really_flush (pp);
1444627f7eb2Smrg       ++errorcount;
1445627f7eb2Smrg       gcc_assert (gfc_output_buffer_empty_p (pp_error_buffer));
1446627f7eb2Smrg       pp->buffer = tmp_buffer;
1447627f7eb2Smrg       diagnostic_action_after_output (global_dc, DK_ERROR);
1448627f7eb2Smrg       diagnostic_check_max_errors (global_dc, true);
1449627f7eb2Smrg       return true;
1450627f7eb2Smrg     }
1451627f7eb2Smrg 
1452627f7eb2Smrg   return false;
1453627f7eb2Smrg }
1454627f7eb2Smrg 
1455627f7eb2Smrg /* Move the text buffered from FROM to TO, then clear
1456627f7eb2Smrg    FROM. Independently if there was text in FROM, TO is also
1457627f7eb2Smrg    cleared. */
1458627f7eb2Smrg 
1459627f7eb2Smrg static void
gfc_move_error_buffer_from_to(gfc_error_buffer * buffer_from,gfc_error_buffer * buffer_to)1460627f7eb2Smrg gfc_move_error_buffer_from_to (gfc_error_buffer * buffer_from,
1461627f7eb2Smrg 			       gfc_error_buffer * buffer_to)
1462627f7eb2Smrg {
1463627f7eb2Smrg   output_buffer * from = &(buffer_from->buffer);
1464627f7eb2Smrg   output_buffer * to =  &(buffer_to->buffer);
1465627f7eb2Smrg 
1466627f7eb2Smrg   buffer_to->flag = buffer_from->flag;
1467627f7eb2Smrg   buffer_from->flag = false;
1468627f7eb2Smrg 
1469627f7eb2Smrg   gfc_clear_pp_buffer (to);
1470627f7eb2Smrg   /* We make sure this is always buffered.  */
1471627f7eb2Smrg   to->flush_p = false;
1472627f7eb2Smrg 
1473627f7eb2Smrg   if (! gfc_output_buffer_empty_p (from))
1474627f7eb2Smrg     {
1475627f7eb2Smrg       const char *str = output_buffer_formatted_text (from);
1476627f7eb2Smrg       output_buffer_append_r (to, str, strlen (str));
1477627f7eb2Smrg       gfc_clear_pp_buffer (from);
1478627f7eb2Smrg     }
1479627f7eb2Smrg }
1480627f7eb2Smrg 
1481627f7eb2Smrg /* Save the existing error state.  */
1482627f7eb2Smrg 
1483627f7eb2Smrg void
gfc_push_error(gfc_error_buffer * err)1484627f7eb2Smrg gfc_push_error (gfc_error_buffer *err)
1485627f7eb2Smrg {
1486627f7eb2Smrg   gfc_move_error_buffer_from_to (&error_buffer, err);
1487627f7eb2Smrg }
1488627f7eb2Smrg 
1489627f7eb2Smrg 
1490627f7eb2Smrg /* Restore a previous pushed error state.  */
1491627f7eb2Smrg 
1492627f7eb2Smrg void
gfc_pop_error(gfc_error_buffer * err)1493627f7eb2Smrg gfc_pop_error (gfc_error_buffer *err)
1494627f7eb2Smrg {
1495627f7eb2Smrg   gfc_move_error_buffer_from_to (err, &error_buffer);
1496627f7eb2Smrg }
1497627f7eb2Smrg 
1498627f7eb2Smrg 
1499627f7eb2Smrg /* Free a pushed error state, but keep the current error state.  */
1500627f7eb2Smrg 
1501627f7eb2Smrg void
gfc_free_error(gfc_error_buffer * err)1502627f7eb2Smrg gfc_free_error (gfc_error_buffer *err)
1503627f7eb2Smrg {
1504627f7eb2Smrg   gfc_clear_pp_buffer (&(err->buffer));
1505627f7eb2Smrg }
1506627f7eb2Smrg 
1507627f7eb2Smrg 
1508627f7eb2Smrg /* Report the number of warnings and errors that occurred to the caller.  */
1509627f7eb2Smrg 
1510627f7eb2Smrg void
gfc_get_errors(int * w,int * e)1511627f7eb2Smrg gfc_get_errors (int *w, int *e)
1512627f7eb2Smrg {
1513627f7eb2Smrg   if (w != NULL)
1514627f7eb2Smrg     *w = warningcount + werrorcount;
1515627f7eb2Smrg   if (e != NULL)
1516627f7eb2Smrg     *e = errorcount + sorrycount + werrorcount;
1517627f7eb2Smrg }
1518627f7eb2Smrg 
1519627f7eb2Smrg 
1520627f7eb2Smrg /* Switch errors into warnings.  */
1521627f7eb2Smrg 
1522627f7eb2Smrg void
gfc_errors_to_warnings(bool f)1523627f7eb2Smrg gfc_errors_to_warnings (bool f)
1524627f7eb2Smrg {
1525627f7eb2Smrg   warnings_not_errors = f;
1526627f7eb2Smrg }
1527627f7eb2Smrg 
1528627f7eb2Smrg void
gfc_diagnostics_init(void)1529627f7eb2Smrg gfc_diagnostics_init (void)
1530627f7eb2Smrg {
1531627f7eb2Smrg   diagnostic_starter (global_dc) = gfc_diagnostic_starter;
1532627f7eb2Smrg   global_dc->start_span = gfc_diagnostic_start_span;
1533627f7eb2Smrg   diagnostic_finalizer (global_dc) = gfc_diagnostic_finalizer;
1534627f7eb2Smrg   diagnostic_format_decoder (global_dc) = gfc_format_decoder;
1535627f7eb2Smrg   global_dc->caret_chars[0] = '1';
1536627f7eb2Smrg   global_dc->caret_chars[1] = '2';
1537627f7eb2Smrg   pp_warning_buffer = new (XNEW (output_buffer)) output_buffer ();
1538627f7eb2Smrg   pp_warning_buffer->flush_p = false;
1539627f7eb2Smrg   /* pp_error_buffer is statically allocated.  This simplifies memory
1540627f7eb2Smrg      management when using gfc_push/pop_error. */
1541627f7eb2Smrg   pp_error_buffer = &(error_buffer.buffer);
1542627f7eb2Smrg   pp_error_buffer->flush_p = false;
1543627f7eb2Smrg }
1544627f7eb2Smrg 
1545627f7eb2Smrg void
gfc_diagnostics_finish(void)1546627f7eb2Smrg gfc_diagnostics_finish (void)
1547627f7eb2Smrg {
1548627f7eb2Smrg   tree_diagnostics_defaults (global_dc);
1549627f7eb2Smrg   /* We still want to use the gfc starter and finalizer, not the tree
1550627f7eb2Smrg      defaults.  */
1551627f7eb2Smrg   diagnostic_starter (global_dc) = gfc_diagnostic_starter;
1552627f7eb2Smrg   diagnostic_finalizer (global_dc) = gfc_diagnostic_finalizer;
1553627f7eb2Smrg   global_dc->caret_chars[0] = '^';
1554627f7eb2Smrg   global_dc->caret_chars[1] = '^';
1555627f7eb2Smrg }
1556