xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/runtime/error.c (revision 4724848cf0da353df257f730694b7882798e5daf)
1 /* Copyright (C) 2002-2020 Free Software Foundation, Inc.
2    Contributed by Andy Vaught
3 
4 This file is part of the GNU Fortran runtime library (libgfortran).
5 
6 Libgfortran is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10 
11 Libgfortran is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19 
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 <http://www.gnu.org/licenses/>.  */
24 
25 
26 #include "libgfortran.h"
27 #include "io.h"
28 #include "async.h"
29 
30 #include <assert.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <signal.h>
34 
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 
39 #ifdef HAVE_SYS_TIME_H
40 #include <sys/time.h>
41 #endif
42 
43 /* <sys/time.h> has to be included before <sys/resource.h> to work
44    around PR 30518; otherwise, MacOS 10.3.9 headers are just broken.  */
45 #ifdef HAVE_SYS_RESOURCE_H
46 #include <sys/resource.h>
47 #endif
48 
49 
50 #include <locale.h>
51 
52 #ifdef HAVE_XLOCALE_H
53 #include <xlocale.h>
54 #endif
55 
56 
57 #ifdef __MINGW32__
58 #define HAVE_GETPID 1
59 #include <process.h>
60 #endif
61 
62 
63 /* Termination of a program: F2008 2.3.5 talks about "normal
64    termination" and "error termination". Normal termination occurs as
65    a result of e.g. executing the end program statement, and executing
66    the STOP statement. It includes the effect of the C exit()
67    function.
68 
69    Error termination is initiated when the ERROR STOP statement is
70    executed, when ALLOCATE/DEALLOCATE fails without STAT= being
71    specified, when some of the co-array synchronization statements
72    fail without STAT= being specified, and some I/O errors if
73    ERR/IOSTAT/END/EOR is not present, and finally EXECUTE_COMMAND_LINE
74    failure without CMDSTAT=.
75 
76    2.3.5 also explains how co-images synchronize during termination.
77 
78    In libgfortran we have three ways of ending a program. exit(code)
79    is a normal exit; calling exit() also causes open units to be
80    closed. No backtrace or core dump is needed here.  For error
81    termination, we have exit_error(status), which prints a backtrace
82    if backtracing is enabled, then exits.  Finally, when something
83    goes terribly wrong, we have sys_abort() which tries to print the
84    backtrace if -fbacktrace is enabled, and then dumps core; whether a
85    core file is generated is system dependent. When aborting, we don't
86    flush and close open units, as program memory might be corrupted
87    and we'd rather risk losing dirty data in the buffers rather than
88    corrupting files on disk.
89 
90 */
91 
92 /* Error conditions.  The tricky part here is printing a message when
93  * it is the I/O subsystem that is severely wounded.  Our goal is to
94  * try and print something making the fewest assumptions possible,
95  * then try to clean up before actually exiting.
96  *
97  * The following exit conditions are defined:
98  * 0    Normal program exit.
99  * 1    Terminated because of operating system error.
100  * 2    Error in the runtime library
101  * 3    Internal error in runtime library
102  *
103  * Other error returns are reserved for the STOP statement with a numeric code.
104  */
105 
106 
107 /* Write a null-terminated C string to standard error. This function
108    is async-signal-safe.  */
109 
110 ssize_t
111 estr_write (const char *str)
112 {
113   return write (STDERR_FILENO, str, strlen (str));
114 }
115 
116 
117 /* Write a vector of strings to standard error.  This function is
118    async-signal-safe.  */
119 
120 ssize_t
121 estr_writev (const struct iovec *iov, int iovcnt)
122 {
123 #ifdef HAVE_WRITEV
124   return writev (STDERR_FILENO, iov, iovcnt);
125 #else
126   ssize_t w = 0;
127   for (int i = 0; i < iovcnt; i++)
128     {
129       ssize_t r = write (STDERR_FILENO, iov[i].iov_base, iov[i].iov_len);
130       if (r == -1)
131 	return r;
132       w += r;
133     }
134   return w;
135 #endif
136 }
137 
138 
139 #ifndef HAVE_VSNPRINTF
140 static int
141 gf_vsnprintf (char *str, size_t size, const char *format, va_list ap)
142 {
143   int written;
144 
145   written = vsprintf(buffer, format, ap);
146 
147   if (written >= size - 1)
148     {
149       /* The error message was longer than our buffer.  Ouch.  Because
150 	 we may have messed up things badly, report the error and
151 	 quit.  */
152 #define ERROR_MESSAGE "Internal error: buffer overrun in gf_vsnprintf()\n"
153       write (STDERR_FILENO, buffer, size - 1);
154       write (STDERR_FILENO, ERROR_MESSAGE, strlen (ERROR_MESSAGE));
155       sys_abort ();
156 #undef ERROR_MESSAGE
157 
158     }
159   return written;
160 }
161 
162 #define vsnprintf gf_vsnprintf
163 #endif
164 
165 
166 /* printf() like function for for printing to stderr.  Uses a stack
167    allocated buffer and doesn't lock stderr, so it should be safe to
168    use from within a signal handler.  */
169 
170 #define ST_ERRBUF_SIZE 512
171 
172 int
173 st_printf (const char * format, ...)
174 {
175   char buffer[ST_ERRBUF_SIZE];
176   int written;
177   va_list ap;
178   va_start (ap, format);
179   written = vsnprintf (buffer, ST_ERRBUF_SIZE, format, ap);
180   va_end (ap);
181   written = write (STDERR_FILENO, buffer, written);
182   return written;
183 }
184 
185 
186 /* sys_abort()-- Terminate the program showing backtrace and dumping
187    core.  */
188 
189 void
190 sys_abort (void)
191 {
192   /* If backtracing is enabled, print backtrace and disable signal
193      handler for ABRT.  */
194   if (options.backtrace == 1
195       || (options.backtrace == -1 && compile_options.backtrace == 1))
196     {
197       estr_write ("\nProgram aborted. Backtrace:\n");
198       show_backtrace (false);
199       signal (SIGABRT, SIG_DFL);
200     }
201 
202   abort();
203 }
204 
205 
206 /* Exit in case of error termination. If backtracing is enabled, print
207    backtrace, then exit.  */
208 
209 void
210 exit_error (int status)
211 {
212   if (options.backtrace == 1
213       || (options.backtrace == -1 && compile_options.backtrace == 1))
214     {
215       estr_write ("\nError termination. Backtrace:\n");
216       show_backtrace (false);
217     }
218   exit (status);
219 }
220 
221 
222 
223 /* gfc_xtoa()-- Integer to hexadecimal conversion.  */
224 
225 const char *
226 gfc_xtoa (GFC_UINTEGER_LARGEST n, char *buffer, size_t len)
227 {
228   int digit;
229   char *p;
230 
231   assert (len >= GFC_XTOA_BUF_SIZE);
232 
233   if (n == 0)
234     return "0";
235 
236   p = buffer + GFC_XTOA_BUF_SIZE - 1;
237   *p = '\0';
238 
239   while (n != 0)
240     {
241       digit = n & 0xF;
242       if (digit > 9)
243 	digit += 'A' - '0' - 10;
244 
245       *--p = '0' + digit;
246       n >>= 4;
247     }
248 
249   return p;
250 }
251 
252 
253 /* Hopefully thread-safe wrapper for a strerror() style function.  */
254 
255 char *
256 gf_strerror (int errnum,
257              char * buf __attribute__((unused)),
258 	     size_t buflen __attribute__((unused)))
259 {
260 #ifdef HAVE_STRERROR_L
261   locale_t myloc = newlocale (LC_CTYPE_MASK | LC_MESSAGES_MASK, "",
262 			      (locale_t) 0);
263   char *p;
264   if (myloc)
265     {
266       p = strerror_l (errnum, myloc);
267       freelocale (myloc);
268     }
269   else
270     /* newlocale might fail e.g. due to running out of memory, fall
271        back to the simpler strerror.  */
272     p = strerror (errnum);
273   return p;
274 #elif defined(HAVE_STRERROR_R)
275 #ifdef HAVE_USELOCALE
276   /* Some targets (Darwin at least) have the POSIX 2008 extended
277      locale functions, but not strerror_l.  So reset the per-thread
278      locale here.  */
279   uselocale (LC_GLOBAL_LOCALE);
280 #endif
281   /* POSIX returns an "int", GNU a "char*".  */
282   return
283     __builtin_choose_expr (__builtin_classify_type (strerror_r (0, buf, 0))
284 			   == 5,
285 			   /* GNU strerror_r()  */
286 			   strerror_r (errnum, buf, buflen),
287 			   /* POSIX strerror_r ()  */
288 			   (strerror_r (errnum, buf, buflen), buf));
289 #elif defined(HAVE_STRERROR_R_2ARGS)
290   strerror_r (errnum, buf);
291   return buf;
292 #else
293   /* strerror () is not necessarily thread-safe, but should at least
294      be available everywhere.  */
295   return strerror (errnum);
296 #endif
297 }
298 
299 
300 /* show_locus()-- Print a line number and filename describing where
301  * something went wrong */
302 
303 void
304 show_locus (st_parameter_common *cmp)
305 {
306   char *filename;
307 
308   if (!options.locus || cmp == NULL || cmp->filename == NULL)
309     return;
310 
311   if (cmp->unit > 0)
312     {
313       filename = filename_from_unit (cmp->unit);
314 
315       if (filename != NULL)
316 	{
317 	  st_printf ("At line %d of file %s (unit = %d, file = '%s')\n",
318 		   (int) cmp->line, cmp->filename, (int) cmp->unit, filename);
319 	  free (filename);
320 	}
321       else
322 	{
323 	  st_printf ("At line %d of file %s (unit = %d)\n",
324 		   (int) cmp->line, cmp->filename, (int) cmp->unit);
325 	}
326       return;
327     }
328 
329   st_printf ("At line %d of file %s\n", (int) cmp->line, cmp->filename);
330 }
331 
332 
333 /* recursion_check()-- It's possible for additional errors to occur
334  * during fatal error processing.  We detect this condition here and
335  * abort immediately. */
336 
337 static __gthread_key_t recursion_key;
338 
339 static void
340 recursion_check (void)
341 {
342   if (__gthread_active_p ())
343     {
344       bool* p = __gthread_getspecific (recursion_key);
345       if (!p)
346         {
347           p = xcalloc (1, sizeof (bool));
348           __gthread_setspecific (recursion_key, p);
349         }
350       if (*p)
351 	sys_abort ();
352       *p = true;
353     }
354   else
355     {
356       static bool recur;
357       if (recur)
358 	sys_abort ();
359       recur = true;
360     }
361 }
362 
363 #ifdef __GTHREADS
364 static void __attribute__((constructor))
365 constructor_recursion_check (void)
366 {
367   if (__gthread_active_p ())
368     __gthread_key_create (&recursion_key, &free);
369 }
370 
371 static void __attribute__((destructor))
372 destructor_recursion_check (void)
373 {
374   if (__gthread_active_p ())
375     __gthread_key_delete (recursion_key);
376 }
377 #endif
378 
379 
380 
381 #define STRERR_MAXSZ 256
382 
383 /* os_error()-- Operating system error.  We get a message from the
384  * operating system, show it and leave.  Some operating system errors
385  * are caught and processed by the library.  If not, we come here. */
386 
387 void
388 os_error (const char *message)
389 {
390   char errmsg[STRERR_MAXSZ];
391   struct iovec iov[5];
392   recursion_check ();
393   iov[0].iov_base = (char*) "Operating system error: ";
394   iov[0].iov_len = strlen (iov[0].iov_base);
395   iov[1].iov_base = gf_strerror (errno, errmsg, STRERR_MAXSZ);
396   iov[1].iov_len = strlen (iov[1].iov_base);
397   iov[2].iov_base = (char*) "\n";
398   iov[2].iov_len = 1;
399   iov[3].iov_base = (char*) message;
400   iov[3].iov_len = strlen (message);
401   iov[4].iov_base = (char*) "\n";
402   iov[4].iov_len = 1;
403   estr_writev (iov, 5);
404   exit_error (1);
405 }
406 iexport(os_error); /* TODO, DEPRECATED, ABI: Should not be exported
407 		      anymore when bumping so version.  */
408 
409 
410 /* Improved version of os_error with a printf style format string and
411    a locus.  */
412 
413 void
414 os_error_at (const char *where, const char *message, ...)
415 {
416   char errmsg[STRERR_MAXSZ];
417   char buffer[STRERR_MAXSZ];
418   struct iovec iov[6];
419   va_list ap;
420   recursion_check ();
421   int written;
422 
423   iov[0].iov_base = (char*) where;
424   iov[0].iov_len = strlen (where);
425 
426   iov[1].iov_base = (char*) ": ";
427   iov[1].iov_len = strlen (iov[1].iov_base);
428 
429   va_start (ap, message);
430   written = vsnprintf (buffer, STRERR_MAXSZ, message, ap);
431   va_end (ap);
432   iov[2].iov_base = buffer;
433   if (written >= 0)
434     iov[2].iov_len = written;
435   else
436     iov[2].iov_len = 0;
437 
438   iov[3].iov_base = (char*) ": ";
439   iov[3].iov_len = strlen (iov[3].iov_base);
440 
441   iov[4].iov_base = gf_strerror (errno, errmsg, STRERR_MAXSZ);
442   iov[4].iov_len = strlen (iov[4].iov_base);
443 
444   iov[5].iov_base = (char*) "\n";
445   iov[5].iov_len = 1;
446 
447   estr_writev (iov, 6);
448   exit_error (1);
449 }
450 iexport(os_error_at);
451 
452 
453 /* void runtime_error()-- These are errors associated with an
454  * invalid fortran program. */
455 
456 void
457 runtime_error (const char *message, ...)
458 {
459   char buffer[ST_ERRBUF_SIZE];
460   struct iovec iov[3];
461   va_list ap;
462   int written;
463 
464   recursion_check ();
465   iov[0].iov_base = (char*) "Fortran runtime error: ";
466   iov[0].iov_len = strlen (iov[0].iov_base);
467   va_start (ap, message);
468   written = vsnprintf (buffer, ST_ERRBUF_SIZE, message, ap);
469   va_end (ap);
470   if (written >= 0)
471     {
472       iov[1].iov_base = buffer;
473       iov[1].iov_len = written;
474       iov[2].iov_base = (char*) "\n";
475       iov[2].iov_len = 1;
476       estr_writev (iov, 3);
477     }
478   exit_error (2);
479 }
480 iexport(runtime_error);
481 
482 /* void runtime_error_at()-- These are errors associated with a
483  * run time error generated by the front end compiler.  */
484 
485 void
486 runtime_error_at (const char *where, const char *message, ...)
487 {
488   char buffer[ST_ERRBUF_SIZE];
489   va_list ap;
490   struct iovec iov[4];
491   int written;
492 
493   recursion_check ();
494   iov[0].iov_base = (char*) where;
495   iov[0].iov_len = strlen (where);
496   iov[1].iov_base = (char*) "\nFortran runtime error: ";
497   iov[1].iov_len = strlen (iov[1].iov_base);
498   va_start (ap, message);
499   written = vsnprintf (buffer, ST_ERRBUF_SIZE, message, ap);
500   va_end (ap);
501   if (written >= 0)
502     {
503       iov[2].iov_base = buffer;
504       iov[2].iov_len = written;
505       iov[3].iov_base = (char*) "\n";
506       iov[3].iov_len = 1;
507       estr_writev (iov, 4);
508     }
509   exit_error (2);
510 }
511 iexport(runtime_error_at);
512 
513 
514 void
515 runtime_warning_at (const char *where, const char *message, ...)
516 {
517   char buffer[ST_ERRBUF_SIZE];
518   va_list ap;
519   struct iovec iov[4];
520   int written;
521 
522   iov[0].iov_base = (char*) where;
523   iov[0].iov_len = strlen (where);
524   iov[1].iov_base = (char*) "\nFortran runtime warning: ";
525   iov[1].iov_len = strlen (iov[1].iov_base);
526   va_start (ap, message);
527   written = vsnprintf (buffer, ST_ERRBUF_SIZE, message, ap);
528   va_end (ap);
529   if (written >= 0)
530     {
531       iov[2].iov_base = buffer;
532       iov[2].iov_len = written;
533       iov[3].iov_base = (char*) "\n";
534       iov[3].iov_len = 1;
535       estr_writev (iov, 4);
536     }
537 }
538 iexport(runtime_warning_at);
539 
540 
541 /* void internal_error()-- These are this-can't-happen errors
542  * that indicate something deeply wrong. */
543 
544 void
545 internal_error (st_parameter_common *cmp, const char *message)
546 {
547   struct iovec iov[3];
548 
549   recursion_check ();
550   show_locus (cmp);
551   iov[0].iov_base = (char*) "Internal Error: ";
552   iov[0].iov_len = strlen (iov[0].iov_base);
553   iov[1].iov_base = (char*) message;
554   iov[1].iov_len = strlen (message);
555   iov[2].iov_base = (char*) "\n";
556   iov[2].iov_len = 1;
557   estr_writev (iov, 3);
558 
559   /* This function call is here to get the main.o object file included
560      when linking statically. This works because error.o is supposed to
561      be always linked in (and the function call is in internal_error
562      because hopefully it doesn't happen too often).  */
563   stupid_function_name_for_static_linking();
564 
565  exit_error (3);
566 }
567 
568 
569 /* translate_error()-- Given an integer error code, return a string
570  * describing the error. */
571 
572 const char *
573 translate_error (int code)
574 {
575   const char *p;
576 
577   switch (code)
578     {
579     case LIBERROR_EOR:
580       p = "End of record";
581       break;
582 
583     case LIBERROR_END:
584       p = "End of file";
585       break;
586 
587     case LIBERROR_OK:
588       p = "Successful return";
589       break;
590 
591     case LIBERROR_OS:
592       p = "Operating system error";
593       break;
594 
595     case LIBERROR_BAD_OPTION:
596       p = "Bad statement option";
597       break;
598 
599     case LIBERROR_MISSING_OPTION:
600       p = "Missing statement option";
601       break;
602 
603     case LIBERROR_OPTION_CONFLICT:
604       p = "Conflicting statement options";
605       break;
606 
607     case LIBERROR_ALREADY_OPEN:
608       p = "File already opened in another unit";
609       break;
610 
611     case LIBERROR_BAD_UNIT:
612       p = "Unattached unit";
613       break;
614 
615     case LIBERROR_FORMAT:
616       p = "FORMAT error";
617       break;
618 
619     case LIBERROR_BAD_ACTION:
620       p = "Incorrect ACTION specified";
621       break;
622 
623     case LIBERROR_ENDFILE:
624       p = "Read past ENDFILE record";
625       break;
626 
627     case LIBERROR_BAD_US:
628       p = "Corrupt unformatted sequential file";
629       break;
630 
631     case LIBERROR_READ_VALUE:
632       p = "Bad value during read";
633       break;
634 
635     case LIBERROR_READ_OVERFLOW:
636       p = "Numeric overflow on read";
637       break;
638 
639     case LIBERROR_INTERNAL:
640       p = "Internal error in run-time library";
641       break;
642 
643     case LIBERROR_INTERNAL_UNIT:
644       p = "Internal unit I/O error";
645       break;
646 
647     case LIBERROR_DIRECT_EOR:
648       p = "Write exceeds length of DIRECT access record";
649       break;
650 
651     case LIBERROR_SHORT_RECORD:
652       p = "I/O past end of record on unformatted file";
653       break;
654 
655     case LIBERROR_CORRUPT_FILE:
656       p = "Unformatted file structure has been corrupted";
657       break;
658 
659     case LIBERROR_INQUIRE_INTERNAL_UNIT:
660       p = "Inquire statement identifies an internal file";
661       break;
662 
663     case LIBERROR_BAD_WAIT_ID:
664       p = "Bad ID in WAIT statement";
665       break;
666 
667     default:
668       p = "Unknown error code";
669       break;
670     }
671 
672   return p;
673 }
674 
675 
676 /* Worker function for generate_error and generate_error_async.  Return true
677    if a straight return is to be done, zero if the program should abort. */
678 
679 bool
680 generate_error_common (st_parameter_common *cmp, int family, const char *message)
681 {
682   char errmsg[STRERR_MAXSZ];
683 
684 #if ASYNC_IO
685   gfc_unit *u;
686 
687   NOTE ("Entering generate_error_common");
688 
689   u = thread_unit;
690   if (u && u->au)
691     {
692       if (u->au->error.has_error)
693 	return true;
694 
695       if (__gthread_equal (u->au->thread, __gthread_self ()))
696 	{
697 	  u->au->error.has_error = 1;
698 	  u->au->error.cmp = cmp;
699 	  u->au->error.family = family;
700 	  u->au->error.message = message;
701 	  return true;
702 	}
703     }
704 #endif
705 
706   /* If there was a previous error, don't mask it with another
707      error message, EOF or EOR condition.  */
708 
709   if ((cmp->flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_ERROR)
710     return true;
711 
712   /* Set the error status.  */
713   if ((cmp->flags & IOPARM_HAS_IOSTAT))
714     *cmp->iostat = (family == LIBERROR_OS) ? errno : family;
715 
716   if (message == NULL)
717     message =
718       (family == LIBERROR_OS) ? gf_strerror (errno, errmsg, STRERR_MAXSZ) :
719       translate_error (family);
720 
721   if (cmp->flags & IOPARM_HAS_IOMSG)
722     cf_strcpy (cmp->iomsg, cmp->iomsg_len, message);
723 
724   /* Report status back to the compiler.  */
725   cmp->flags &= ~IOPARM_LIBRETURN_MASK;
726   switch (family)
727     {
728     case LIBERROR_EOR:
729       cmp->flags |= IOPARM_LIBRETURN_EOR;  NOTE("EOR");
730       if ((cmp->flags & IOPARM_EOR))
731 	return true;
732       break;
733 
734     case LIBERROR_END:
735       cmp->flags |= IOPARM_LIBRETURN_END; NOTE("END");
736       if ((cmp->flags & IOPARM_END))
737 	return true;
738       break;
739 
740     default:
741       cmp->flags |= IOPARM_LIBRETURN_ERROR; NOTE("ERROR");
742       if ((cmp->flags & IOPARM_ERR))
743 	return true;
744       break;
745     }
746 
747   /* Return if the user supplied an iostat variable.  */
748   if ((cmp->flags & IOPARM_HAS_IOSTAT))
749     return true;
750 
751   /* Return code, caller is responsible for terminating
752    the program if necessary.  */
753 
754   recursion_check ();
755   show_locus (cmp);
756   struct iovec iov[3];
757   iov[0].iov_base = (char*) "Fortran runtime error: ";
758   iov[0].iov_len = strlen (iov[0].iov_base);
759   iov[1].iov_base = (char*) message;
760   iov[1].iov_len = strlen (message);
761   iov[2].iov_base = (char*) "\n";
762   iov[2].iov_len = 1;
763   estr_writev (iov, 3);
764   return false;
765 }
766 
767 /* generate_error()-- Come here when an error happens.  This
768  * subroutine is called if it is possible to continue on after the error.
769  * If an IOSTAT or IOMSG variable exists, we set it.  If IOSTAT or
770  * ERR labels are present, we return, otherwise we terminate the program
771  * after printing a message.  The error code is always required but the
772  * message parameter can be NULL, in which case a string describing
773  * the most recent operating system error is used.
774  * If the error is for an asynchronous unit and if the program is currently
775  * executing the asynchronous thread, just mark the error and return.  */
776 
777 void
778 generate_error (st_parameter_common *cmp, int family, const char *message)
779 {
780   if (generate_error_common (cmp, family, message))
781     return;
782 
783   exit_error(2);
784 }
785 iexport(generate_error);
786 
787 
788 /* generate_warning()-- Similar to generate_error but just give a warning.  */
789 
790 void
791 generate_warning (st_parameter_common *cmp, const char *message)
792 {
793   if (message == NULL)
794     message = " ";
795 
796   show_locus (cmp);
797   struct iovec iov[3];
798   iov[0].iov_base = (char*) "Fortran runtime warning: ";
799   iov[0].iov_len = strlen (iov[0].iov_base);
800   iov[1].iov_base = (char*) message;
801   iov[1].iov_len = strlen (message);
802   iov[2].iov_base = (char*) "\n";
803   iov[2].iov_len = 1;
804   estr_writev (iov, 3);
805 }
806 
807 
808 /* Whether, for a feature included in a given standard set (GFC_STD_*),
809    we should issue an error or a warning, or be quiet.  */
810 
811 notification
812 notification_std (int std)
813 {
814   int warning;
815 
816   if (!compile_options.pedantic)
817     return NOTIFICATION_SILENT;
818 
819   warning = compile_options.warn_std & std;
820   if ((compile_options.allow_std & std) != 0 && !warning)
821     return NOTIFICATION_SILENT;
822 
823   return warning ? NOTIFICATION_WARNING : NOTIFICATION_ERROR;
824 }
825 
826 
827 /* Possibly issue a warning/error about use of a nonstandard (or deleted)
828    feature.  An error/warning will be issued if the currently selected
829    standard does not contain the requested bits.  */
830 
831 bool
832 notify_std (st_parameter_common *cmp, int std, const char * message)
833 {
834   int warning;
835   struct iovec iov[3];
836 
837   if (!compile_options.pedantic)
838     return true;
839 
840   warning = compile_options.warn_std & std;
841   if ((compile_options.allow_std & std) != 0 && !warning)
842     return true;
843 
844   if (!warning)
845     {
846       recursion_check ();
847       show_locus (cmp);
848       iov[0].iov_base = (char*) "Fortran runtime error: ";
849       iov[0].iov_len = strlen (iov[0].iov_base);
850       iov[1].iov_base = (char*) message;
851       iov[1].iov_len = strlen (message);
852       iov[2].iov_base = (char*) "\n";
853       iov[2].iov_len = 1;
854       estr_writev (iov, 3);
855       exit_error (2);
856     }
857   else
858     {
859       show_locus (cmp);
860       iov[0].iov_base = (char*) "Fortran runtime warning: ";
861       iov[0].iov_len = strlen (iov[0].iov_base);
862       iov[1].iov_base = (char*) message;
863       iov[1].iov_len = strlen (message);
864       iov[2].iov_base = (char*) "\n";
865       iov[2].iov_len = 1;
866       estr_writev (iov, 3);
867     }
868   return false;
869 }
870