* libgfortran.h (support_fpu_underflow_control,
[official-gcc.git] / gcc / ada / errutil.adb
blobf15eec9a7b17f4533eada444f81bbda32b232535
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- E R R U T I L --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1991-2014, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Atree; use Atree;
27 with Err_Vars; use Err_Vars;
28 with Erroutc; use Erroutc;
29 with Namet; use Namet;
30 with Opt; use Opt;
31 with Output; use Output;
32 with Scans; use Scans;
33 with Sinput; use Sinput;
34 with Stringt; use Stringt;
35 with Stylesw; use Stylesw;
37 package body Errutil is
39 Errors_Must_Be_Ignored : Boolean := False;
40 -- Set to True by procedure Set_Ignore_Errors (True), when calls to
41 -- error message procedures should be ignored (when parsing irrelevant
42 -- text in sources being preprocessed).
44 -----------------------
45 -- Local Subprograms --
46 -----------------------
48 procedure Error_Msg_AP (Msg : String);
49 -- Output a message just after the previous token
51 procedure Output_Source_Line
52 (L : Physical_Line_Number;
53 Sfile : Source_File_Index;
54 Errs : Boolean;
55 Source_Type : String);
56 -- Outputs text of source line L, in file S, together with preceding line
57 -- number, as described above for Output_Line_Number. The Errs parameter
58 -- indicates if there are errors attached to the line, which forces
59 -- listing on, even in the presence of pragma List (Off).
61 procedure Set_Msg_Insertion_Column;
62 -- Handle column number insertion (@ insertion character)
64 procedure Set_Msg_Text (Text : String; Flag : Source_Ptr);
65 -- Add a sequence of characters to the current message. The characters may
66 -- be one of the special insertion characters (see documentation in spec).
67 -- Flag is the location at which the error is to be posted, which is used
68 -- to determine whether or not the # insertion needs a file name. The
69 -- variables Msg_Buffer, Msglen, Is_Style_Msg, Is_Warning_Msg, and
70 -- Is_Unconditional_Msg are set on return.
72 ------------------
73 -- Error_Msg_AP --
74 ------------------
76 procedure Error_Msg_AP (Msg : String) is
77 S1 : Source_Ptr;
78 C : Character;
80 begin
81 -- If we had saved the Scan_Ptr value after scanning the previous
82 -- token, then we would have exactly the right place for putting
83 -- the flag immediately at hand. However, that would add at least
84 -- two instructions to a Scan call *just* to service the possibility
85 -- of an Error_Msg_AP call. So instead we reconstruct that value.
87 -- We have two possibilities, start with Prev_Token_Ptr and skip over
88 -- the current token, which is made harder by the possibility that this
89 -- token may be in error, or start with Token_Ptr and work backwards.
90 -- We used to take the second approach, but it's hard because of
91 -- comments, and harder still because things that look like comments
92 -- can appear inside strings. So now we take the first approach.
94 -- Note: in the case where there is no previous token, Prev_Token_Ptr
95 -- is set to Source_First, which is a reasonable position for the
96 -- error flag in this situation.
98 S1 := Prev_Token_Ptr;
99 C := Source (S1);
101 -- If the previous token is a string literal, we need a special approach
102 -- since there may be white space inside the literal and we don't want
103 -- to stop on that white space.
105 -- Note that it is not worth worrying about special UTF_32 line
106 -- terminator characters in this context, since this is only about
107 -- error recovery anyway.
109 if Prev_Token = Tok_String_Literal then
110 loop
111 S1 := S1 + 1;
113 if Source (S1) = C then
114 S1 := S1 + 1;
115 exit when Source (S1) /= C;
116 elsif Source (S1) in Line_Terminator then
117 exit;
118 end if;
119 end loop;
121 -- Character literal also needs special handling
123 elsif Prev_Token = Tok_Char_Literal then
124 S1 := S1 + 3;
126 -- Otherwise we search forward for the end of the current token, marked
127 -- by a line terminator, white space, a comment symbol or if we bump
128 -- into the following token (i.e. the current token)
130 -- Note that it is not worth worrying about special UTF_32 line
131 -- terminator characters in this context, since this is only about
132 -- error recovery anyway.
134 else
135 while Source (S1) not in Line_Terminator
136 and then Source (S1) /= ' '
137 and then Source (S1) /= ASCII.HT
138 and then (Source (S1) /= '-' or else Source (S1 + 1) /= '-')
139 and then S1 /= Token_Ptr
140 loop
141 S1 := S1 + 1;
142 end loop;
143 end if;
145 -- S1 is now set to the location for the flag
147 Error_Msg (Msg, S1);
149 end Error_Msg_AP;
151 ---------------
152 -- Error_Msg --
153 ---------------
155 procedure Error_Msg (Msg : String; Flag_Location : Source_Ptr) is
157 Next_Msg : Error_Msg_Id;
158 -- Pointer to next message at insertion point
160 Prev_Msg : Error_Msg_Id;
161 -- Pointer to previous message at insertion point
163 Sptr : Source_Ptr renames Flag_Location;
164 -- Corresponds to the Sptr value in the error message object
166 Optr : Source_Ptr renames Flag_Location;
167 -- Corresponds to the Optr value in the error message object. Note that
168 -- for this usage, Sptr and Optr always have the same value, since we do
169 -- not have to worry about generic instantiations.
171 begin
172 if Errors_Must_Be_Ignored then
173 return;
174 end if;
176 if Raise_Exception_On_Error /= 0 then
177 raise Error_Msg_Exception;
178 end if;
180 Prescan_Message (Msg);
181 Set_Msg_Text (Msg, Sptr);
183 -- Kill continuation if parent message killed
185 if Continuation and Last_Killed then
186 return;
187 end if;
189 -- Return without doing anything if message is killed and this is not
190 -- the first error message. The philosophy is that if we get a weird
191 -- error message and we already have had a message, then we hope the
192 -- weird message is a junk cascaded message
194 -- Immediate return if warning message and warnings are suppressed.
195 -- Note that style messages are not warnings for this purpose.
197 if Is_Warning_Msg and then Warnings_Suppressed (Sptr) /= No_String then
198 Cur_Msg := No_Error_Msg;
199 return;
200 end if;
202 -- Otherwise build error message object for new message
204 Errors.Increment_Last;
205 Cur_Msg := Errors.Last;
206 Errors.Table (Cur_Msg).Text := new String'(Msg_Buffer (1 .. Msglen));
207 Errors.Table (Cur_Msg).Next := No_Error_Msg;
208 Errors.Table (Cur_Msg).Sptr := Sptr;
209 Errors.Table (Cur_Msg).Optr := Optr;
210 Errors.Table (Cur_Msg).Sfile := Get_Source_File_Index (Sptr);
211 Errors.Table (Cur_Msg).Line := Get_Physical_Line_Number (Sptr);
212 Errors.Table (Cur_Msg).Col := Get_Column_Number (Sptr);
213 Errors.Table (Cur_Msg).Style := Is_Style_Msg;
214 Errors.Table (Cur_Msg).Warn := Is_Warning_Msg;
215 Errors.Table (Cur_Msg).Info := Is_Info_Msg;
216 Errors.Table (Cur_Msg).Warn_Chr := Warning_Msg_Char;
217 Errors.Table (Cur_Msg).Serious := Is_Serious_Error;
218 Errors.Table (Cur_Msg).Uncond := Is_Unconditional_Msg;
219 Errors.Table (Cur_Msg).Msg_Cont := Continuation;
220 Errors.Table (Cur_Msg).Deleted := False;
222 Prev_Msg := No_Error_Msg;
223 Next_Msg := First_Error_Msg;
225 while Next_Msg /= No_Error_Msg loop
226 exit when
227 Errors.Table (Cur_Msg).Sfile < Errors.Table (Next_Msg).Sfile;
229 if Errors.Table (Cur_Msg).Sfile = Errors.Table (Next_Msg).Sfile then
230 exit when Sptr < Errors.Table (Next_Msg).Sptr;
231 end if;
233 Prev_Msg := Next_Msg;
234 Next_Msg := Errors.Table (Next_Msg).Next;
235 end loop;
237 -- Now we insert the new message in the error chain. The insertion
238 -- point for the message is after Prev_Msg and before Next_Msg.
240 -- The possible insertion point for the new message is after Prev_Msg
241 -- and before Next_Msg. However, this is where we do a special check
242 -- for redundant parsing messages, defined as messages posted on the
243 -- same line. The idea here is that probably such messages are junk
244 -- from the parser recovering. In full errors mode, we don't do this
245 -- deletion, but otherwise such messages are discarded at this stage.
247 if Prev_Msg /= No_Error_Msg
248 and then Errors.Table (Prev_Msg).Line =
249 Errors.Table (Cur_Msg).Line
250 and then Errors.Table (Prev_Msg).Sfile =
251 Errors.Table (Cur_Msg).Sfile
252 then
253 -- Don't delete unconditional messages and at this stage, don't
254 -- delete continuation lines (we attempted to delete those earlier
255 -- if the parent message was deleted.
257 if not Errors.Table (Cur_Msg).Uncond
258 and then not Continuation
259 then
261 -- Don't delete if prev msg is warning and new msg is an error.
262 -- This is because we don't want a real error masked by a warning.
263 -- In all other cases (that is parse errors for the same line that
264 -- are not unconditional) we do delete the message. This helps to
265 -- avoid junk extra messages from cascaded parsing errors
267 if not (Errors.Table (Prev_Msg).Warn
268 or else
269 Errors.Table (Prev_Msg).Style)
270 or else
271 (Errors.Table (Cur_Msg).Warn
272 or else
273 Errors.Table (Cur_Msg).Style)
274 then
275 -- All tests passed, delete the message by simply returning
276 -- without any further processing.
278 if not Continuation then
279 Last_Killed := True;
280 end if;
282 return;
283 end if;
284 end if;
285 end if;
287 -- Come here if message is to be inserted in the error chain
289 if not Continuation then
290 Last_Killed := False;
291 end if;
293 if Prev_Msg = No_Error_Msg then
294 First_Error_Msg := Cur_Msg;
295 else
296 Errors.Table (Prev_Msg).Next := Cur_Msg;
297 end if;
299 Errors.Table (Cur_Msg).Next := Next_Msg;
301 -- Bump appropriate statistics count
303 if Errors.Table (Cur_Msg).Warn
304 or else
305 Errors.Table (Cur_Msg).Style
306 then
307 Warnings_Detected := Warnings_Detected + 1;
309 else
310 Total_Errors_Detected := Total_Errors_Detected + 1;
312 if Errors.Table (Cur_Msg).Serious then
313 Serious_Errors_Detected := Serious_Errors_Detected + 1;
314 end if;
315 end if;
317 end Error_Msg;
319 -----------------
320 -- Error_Msg_S --
321 -----------------
323 procedure Error_Msg_S (Msg : String) is
324 begin
325 Error_Msg (Msg, Scan_Ptr);
326 end Error_Msg_S;
328 ------------------
329 -- Error_Msg_SC --
330 ------------------
332 procedure Error_Msg_SC (Msg : String) is
333 begin
334 -- If we are at end of file, post the flag after the previous token
336 if Token = Tok_EOF then
337 Error_Msg_AP (Msg);
339 -- For all other cases the message is posted at the current token
340 -- pointer position
342 else
343 Error_Msg (Msg, Token_Ptr);
344 end if;
345 end Error_Msg_SC;
347 ------------------
348 -- Error_Msg_SP --
349 ------------------
351 procedure Error_Msg_SP (Msg : String) is
352 begin
353 -- Note: in the case where there is no previous token, Prev_Token_Ptr
354 -- is set to Source_First, which is a reasonable position for the
355 -- error flag in this situation
357 Error_Msg (Msg, Prev_Token_Ptr);
358 end Error_Msg_SP;
360 --------------
361 -- Finalize --
362 --------------
364 procedure Finalize (Source_Type : String := "project") is
365 Cur : Error_Msg_Id;
366 Nxt : Error_Msg_Id;
367 E, F : Error_Msg_Id;
368 Err_Flag : Boolean;
370 begin
371 -- Eliminate any duplicated error messages from the list. This is
372 -- done after the fact to avoid problems with Change_Error_Text.
374 Cur := First_Error_Msg;
375 while Cur /= No_Error_Msg loop
376 Nxt := Errors.Table (Cur).Next;
378 F := Nxt;
379 while F /= No_Error_Msg
380 and then Errors.Table (F).Sptr = Errors.Table (Cur).Sptr
381 loop
382 Check_Duplicate_Message (Cur, F);
383 F := Errors.Table (F).Next;
384 end loop;
386 Cur := Nxt;
387 end loop;
389 -- Brief Error mode
391 if Brief_Output or (not Full_List and not Verbose_Mode) then
392 E := First_Error_Msg;
393 Set_Standard_Error;
395 while E /= No_Error_Msg loop
396 if not Errors.Table (E).Deleted then
397 if Full_Path_Name_For_Brief_Errors then
398 Write_Name (Full_Ref_Name (Errors.Table (E).Sfile));
399 else
400 Write_Name (Reference_Name (Errors.Table (E).Sfile));
401 end if;
403 Write_Char (':');
404 Write_Int (Int (Physical_To_Logical
405 (Errors.Table (E).Line,
406 Errors.Table (E).Sfile)));
407 Write_Char (':');
409 if Errors.Table (E).Col < 10 then
410 Write_Char ('0');
411 end if;
413 Write_Int (Int (Errors.Table (E).Col));
414 Write_Str (": ");
415 Output_Msg_Text (E);
416 Write_Eol;
417 end if;
419 E := Errors.Table (E).Next;
420 end loop;
422 Set_Standard_Output;
423 end if;
425 -- Full source listing case
427 if Full_List then
428 List_Pragmas_Index := 1;
429 List_Pragmas_Mode := True;
430 E := First_Error_Msg;
431 Write_Eol;
433 -- First list initial main source file with its error messages
435 for N in 1 .. Last_Source_Line (Main_Source_File) loop
436 Err_Flag :=
437 E /= No_Error_Msg
438 and then Errors.Table (E).Line = N
439 and then Errors.Table (E).Sfile = Main_Source_File;
441 Output_Source_Line (N, Main_Source_File, Err_Flag, Source_Type);
443 if Err_Flag then
444 Output_Error_Msgs (E);
446 Write_Eol;
447 end if;
448 end loop;
450 -- Then output errors, if any, for subsidiary units
452 while E /= No_Error_Msg
453 and then Errors.Table (E).Sfile /= Main_Source_File
454 loop
455 Write_Eol;
456 Output_Source_Line
457 (Errors.Table (E).Line,
458 Errors.Table (E).Sfile,
459 True,
460 Source_Type);
461 Output_Error_Msgs (E);
462 end loop;
463 end if;
465 -- Verbose mode (error lines only with error flags)
467 if Verbose_Mode then
468 E := First_Error_Msg;
470 -- Loop through error lines
472 while E /= No_Error_Msg loop
473 Write_Eol;
474 Output_Source_Line
475 (Errors.Table (E).Line,
476 Errors.Table (E).Sfile,
477 True,
478 Source_Type);
479 Output_Error_Msgs (E);
480 end loop;
481 end if;
483 -- Output error summary if verbose or full list mode
485 if Verbose_Mode or else Full_List then
487 -- Extra blank line if error messages or source listing were output
489 if Total_Errors_Detected + Warnings_Detected > 0
490 or else Full_List
491 then
492 Write_Eol;
493 end if;
495 -- Message giving number of lines read and number of errors detected.
496 -- This normally goes to Standard_Output. The exception is when brief
497 -- mode is not set, verbose mode (or full list mode) is set, and
498 -- there are errors. In this case we send the message to standard
499 -- error to make sure that *something* appears on standard error in
500 -- an error situation.
502 -- Formerly, only the "# errors" suffix was sent to stderr, whereas
503 -- "# lines:" appeared on stdout. This caused problems on VMS when
504 -- the stdout buffer was flushed, giving an extra line feed after
505 -- the prefix.
507 if Total_Errors_Detected + Warnings_Detected /= 0
508 and then not Brief_Output
509 and then (Verbose_Mode or Full_List)
510 then
511 Set_Standard_Error;
512 end if;
514 -- Message giving total number of lines
516 Write_Str (" ");
517 Write_Int (Num_Source_Lines (Main_Source_File));
519 if Num_Source_Lines (Main_Source_File) = 1 then
520 Write_Str (" line: ");
521 else
522 Write_Str (" lines: ");
523 end if;
525 if Total_Errors_Detected = 0 then
526 Write_Str ("No errors");
528 elsif Total_Errors_Detected = 1 then
529 Write_Str ("1 error");
531 else
532 Write_Int (Total_Errors_Detected);
533 Write_Str (" errors");
534 end if;
536 if Warnings_Detected /= 0 then
537 Write_Str (", ");
538 Write_Int (Warnings_Detected);
539 Write_Str (" warning");
541 if Warnings_Detected /= 1 then
542 Write_Char ('s');
543 end if;
545 if Warning_Mode = Treat_As_Error then
546 Write_Str (" (treated as error");
548 if Warnings_Detected /= 1 then
549 Write_Char ('s');
550 end if;
552 Write_Char (')');
553 end if;
554 end if;
556 Write_Eol;
557 Set_Standard_Output;
558 end if;
560 if Maximum_Messages /= 0 then
561 if Warnings_Detected >= Maximum_Messages then
562 Set_Standard_Error;
563 Write_Line ("maximum number of warnings detected");
564 Warning_Mode := Suppress;
565 end if;
567 if Total_Errors_Detected >= Maximum_Messages then
568 Set_Standard_Error;
569 Write_Line ("fatal error: maximum errors reached");
570 Set_Standard_Output;
571 end if;
572 end if;
574 if Warning_Mode = Treat_As_Error then
575 Total_Errors_Detected := Total_Errors_Detected + Warnings_Detected;
576 Warnings_Detected := 0;
577 end if;
579 -- Prevent displaying the same messages again in the future
581 First_Error_Msg := No_Error_Msg;
582 end Finalize;
584 ----------------
585 -- Initialize --
586 ----------------
588 procedure Initialize is
589 begin
590 Errors.Init;
591 First_Error_Msg := No_Error_Msg;
592 Last_Error_Msg := No_Error_Msg;
593 Serious_Errors_Detected := 0;
594 Total_Errors_Detected := 0;
595 Warnings_Detected := 0;
596 Cur_Msg := No_Error_Msg;
598 -- Initialize warnings table, if all warnings are suppressed, supply
599 -- an initial dummy entry covering all possible source locations.
601 Warnings.Init;
603 if Warning_Mode = Suppress then
604 Warnings.Append
605 (New_Val =>
606 (Start => Source_Ptr'First,
607 Stop => Source_Ptr'Last,
608 Reason => Null_String_Id));
609 end if;
610 end Initialize;
612 ------------------------
613 -- Output_Source_Line --
614 ------------------------
616 procedure Output_Source_Line
617 (L : Physical_Line_Number;
618 Sfile : Source_File_Index;
619 Errs : Boolean;
620 Source_Type : String)
622 S : Source_Ptr;
623 C : Character;
625 Line_Number_Output : Boolean := False;
626 -- Set True once line number is output
628 begin
629 if Sfile /= Current_Error_Source_File then
630 Write_Str ("==============Error messages for ");
631 Write_Str (Source_Type);
632 Write_Str (" file: ");
633 Write_Name (Full_File_Name (Sfile));
634 Write_Eol;
635 Current_Error_Source_File := Sfile;
636 end if;
638 if Errs then
639 Output_Line_Number (Physical_To_Logical (L, Sfile));
640 Line_Number_Output := True;
641 end if;
643 S := Line_Start (L, Sfile);
645 loop
646 C := Source_Text (Sfile) (S);
647 exit when C = ASCII.LF or else C = ASCII.CR or else C = EOF;
649 if Errs then
650 Write_Char (C);
651 end if;
653 S := S + 1;
654 end loop;
656 if Line_Number_Output then
657 Write_Eol;
658 end if;
659 end Output_Source_Line;
661 -----------------------
662 -- Set_Ignore_Errors --
663 -----------------------
665 procedure Set_Ignore_Errors (To : Boolean) is
666 begin
667 Errors_Must_Be_Ignored := To;
668 end Set_Ignore_Errors;
670 ------------------------------
671 -- Set_Msg_Insertion_Column --
672 ------------------------------
674 procedure Set_Msg_Insertion_Column is
675 begin
676 if RM_Column_Check then
677 Set_Msg_Str (" in column ");
678 Set_Msg_Int (Int (Error_Msg_Col) + 1);
679 end if;
680 end Set_Msg_Insertion_Column;
682 ------------------
683 -- Set_Msg_Text --
684 ------------------
686 procedure Set_Msg_Text (Text : String; Flag : Source_Ptr) is
687 C : Character; -- Current character
688 P : Natural; -- Current index;
690 begin
691 Manual_Quote_Mode := False;
692 Msglen := 0;
693 Flag_Source := Get_Source_File_Index (Flag);
694 P := Text'First;
696 while P <= Text'Last loop
697 C := Text (P);
698 P := P + 1;
700 -- Check for insertion character
702 if C = '%' then
703 if P <= Text'Last and then Text (P) = '%' then
704 P := P + 1;
705 Set_Msg_Insertion_Name_Literal;
706 else
707 Set_Msg_Insertion_Name;
708 end if;
710 elsif C = '$' then
712 -- '$' is ignored
714 null;
716 elsif C = '{' then
717 Set_Msg_Insertion_File_Name;
719 elsif C = '}' then
721 -- '}' is ignored
723 null;
725 elsif C = '*' then
726 Set_Msg_Insertion_Reserved_Name;
728 elsif C = '&' then
730 -- '&' is ignored
732 null;
734 elsif C = '#' then
735 Set_Msg_Insertion_Line_Number (Error_Msg_Sloc, Flag);
737 elsif C = '\' then
738 Continuation := True;
740 elsif C = '@' then
741 Set_Msg_Insertion_Column;
743 elsif C = '^' then
744 Set_Msg_Insertion_Uint;
746 elsif C = '`' then
747 Manual_Quote_Mode := not Manual_Quote_Mode;
748 Set_Msg_Char ('"');
750 elsif C = '!' then
751 null;
753 elsif C = '?' then
754 null;
756 elsif C = '<' then
757 null;
759 elsif C = '|' then
760 null;
762 elsif C = ''' then
763 Set_Msg_Char (Text (P));
764 P := P + 1;
766 -- Upper case letter (start of reserved word if 2 or more)
768 elsif C in 'A' .. 'Z'
769 and then P <= Text'Last
770 and then Text (P) in 'A' .. 'Z'
771 then
772 P := P - 1;
773 Set_Msg_Insertion_Reserved_Word (Text, P);
775 -- Normal character with no special treatment
777 else
778 Set_Msg_Char (C);
779 end if;
781 end loop;
782 end Set_Msg_Text;
784 end Errutil;