1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1991-2012, Free Software Foundation, Inc. --
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. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
26 with Atree
; use Atree
;
27 with Err_Vars
; use Err_Vars
;
28 with Erroutc
; use Erroutc
;
29 with Namet
; use Namet
;
31 with Output
; use Output
;
32 with Scans
; use Scans
;
33 with Sinput
; use Sinput
;
34 with Stylesw
; use Stylesw
;
36 package body Errutil
is
38 Errors_Must_Be_Ignored
: Boolean := False;
39 -- Set to True by procedure Set_Ignore_Errors (True), when calls to
40 -- error message procedures should be ignored (when parsing irrelevant
41 -- text in sources being preprocessed).
43 -----------------------
44 -- Local Subprograms --
45 -----------------------
47 procedure Error_Msg_AP
(Msg
: String);
48 -- Output a message just after the previous token
50 procedure Output_Source_Line
51 (L
: Physical_Line_Number
;
52 Sfile
: Source_File_Index
;
54 Source_Type
: String);
55 -- Outputs text of source line L, in file S, together with preceding line
56 -- number, as described above for Output_Line_Number. The Errs parameter
57 -- indicates if there are errors attached to the line, which forces
58 -- listing on, even in the presence of pragma List (Off).
60 procedure Set_Msg_Insertion_Column
;
61 -- Handle column number insertion (@ insertion character)
63 procedure Set_Msg_Text
(Text
: String; Flag
: Source_Ptr
);
64 -- Add a sequence of characters to the current message. The characters may
65 -- be one of the special insertion characters (see documentation in spec).
66 -- Flag is the location at which the error is to be posted, which is used
67 -- to determine whether or not the # insertion needs a file name. The
68 -- variables Msg_Buffer, Msglen, Is_Style_Msg, Is_Warning_Msg, and
69 -- Is_Unconditional_Msg are set on return.
75 procedure Error_Msg_AP
(Msg
: String) is
80 -- If we had saved the Scan_Ptr value after scanning the previous
81 -- token, then we would have exactly the right place for putting
82 -- the flag immediately at hand. However, that would add at least
83 -- two instructions to a Scan call *just* to service the possibility
84 -- of an Error_Msg_AP call. So instead we reconstruct that value.
86 -- We have two possibilities, start with Prev_Token_Ptr and skip over
87 -- the current token, which is made harder by the possibility that this
88 -- token may be in error, or start with Token_Ptr and work backwards.
89 -- We used to take the second approach, but it's hard because of
90 -- comments, and harder still because things that look like comments
91 -- can appear inside strings. So now we take the first approach.
93 -- Note: in the case where there is no previous token, Prev_Token_Ptr
94 -- is set to Source_First, which is a reasonable position for the
95 -- error flag in this situation.
100 -- If the previous token is a string literal, we need a special approach
101 -- since there may be white space inside the literal and we don't want
102 -- to stop on that white space.
104 -- Note that it is not worth worrying about special UTF_32 line
105 -- terminator characters in this context, since this is only about
106 -- error recovery anyway.
108 if Prev_Token
= Tok_String_Literal
then
112 if Source
(S1
) = C
then
114 exit when Source
(S1
) /= C
;
115 elsif Source
(S1
) in Line_Terminator
then
120 -- Character literal also needs special handling
122 elsif Prev_Token
= Tok_Char_Literal
then
125 -- Otherwise we search forward for the end of the current token, marked
126 -- by a line terminator, white space, a comment symbol or if we bump
127 -- into the following token (i.e. the current token)
129 -- Note that it is not worth worrying about special UTF_32 line
130 -- terminator characters in this context, since this is only about
131 -- error recovery anyway.
134 while Source
(S1
) not in Line_Terminator
135 and then Source
(S1
) /= ' '
136 and then Source
(S1
) /= ASCII
.HT
137 and then (Source
(S1
) /= '-' or else Source
(S1
+ 1) /= '-')
138 and then S1
/= Token_Ptr
144 -- S1 is now set to the location for the flag
154 procedure Error_Msg
(Msg
: String; Flag_Location
: Source_Ptr
) is
156 Next_Msg
: Error_Msg_Id
;
157 -- Pointer to next message at insertion point
159 Prev_Msg
: Error_Msg_Id
;
160 -- Pointer to previous message at insertion point
162 Sptr
: Source_Ptr
renames Flag_Location
;
163 -- Corresponds to the Sptr value in the error message object
165 Optr
: Source_Ptr
renames Flag_Location
;
166 -- Corresponds to the Optr value in the error message object. Note
167 -- that for this usage, Sptr and Optr always have the same value,
168 -- since we do not have to worry about generic instantiations.
171 if Errors_Must_Be_Ignored
then
175 if Raise_Exception_On_Error
/= 0 then
176 raise Error_Msg_Exception
;
179 Test_Style_Warning_Serious_Msg
(Msg
);
180 Set_Msg_Text
(Msg
, Sptr
);
182 -- Kill continuation if parent message killed
184 if Continuation
and Last_Killed
then
188 -- Return without doing anything if message is killed and this is not
189 -- the first error message. The philosophy is that if we get a weird
190 -- error message and we already have had a message, then we hope the
191 -- weird message is a junk cascaded message
193 -- Immediate return if warning message and warnings are suppressed.
194 -- Note that style messages are not warnings for this purpose.
196 if Is_Warning_Msg
and then Warnings_Suppressed
(Sptr
) then
197 Cur_Msg
:= No_Error_Msg
;
201 -- Otherwise build error message object for new message
203 Errors
.Increment_Last
;
204 Cur_Msg
:= Errors
.Last
;
205 Errors
.Table
(Cur_Msg
).Text
:= new String'(Msg_Buffer (1 .. Msglen));
206 Errors.Table (Cur_Msg).Next := No_Error_Msg;
207 Errors.Table (Cur_Msg).Sptr := Sptr;
208 Errors.Table (Cur_Msg).Optr := Optr;
209 Errors.Table (Cur_Msg).Sfile := Get_Source_File_Index (Sptr);
210 Errors.Table (Cur_Msg).Line := Get_Physical_Line_Number (Sptr);
211 Errors.Table (Cur_Msg).Col := Get_Column_Number (Sptr);
212 Errors.Table (Cur_Msg).Style := Is_Style_Msg;
213 Errors.Table (Cur_Msg).Warn := Is_Warning_Msg;
214 Errors.Table (Cur_Msg).Warn_Chr := Warning_Msg_Char;
215 Errors.Table (Cur_Msg).Serious := Is_Serious_Error;
216 Errors.Table (Cur_Msg).Uncond := Is_Unconditional_Msg;
217 Errors.Table (Cur_Msg).Msg_Cont := Continuation;
218 Errors.Table (Cur_Msg).Deleted := False;
220 Prev_Msg := No_Error_Msg;
221 Next_Msg := First_Error_Msg;
223 while Next_Msg /= No_Error_Msg loop
225 Errors.Table (Cur_Msg).Sfile < Errors.Table (Next_Msg).Sfile;
227 if Errors.Table (Cur_Msg).Sfile = Errors.Table (Next_Msg).Sfile then
228 exit when Sptr < Errors.Table (Next_Msg).Sptr;
231 Prev_Msg := Next_Msg;
232 Next_Msg := Errors.Table (Next_Msg).Next;
235 -- Now we insert the new message in the error chain. The insertion
236 -- point for the message is after Prev_Msg and before Next_Msg.
238 -- The possible insertion point for the new message is after Prev_Msg
239 -- and before Next_Msg. However, this is where we do a special check
240 -- for redundant parsing messages, defined as messages posted on the
241 -- same line. The idea here is that probably such messages are junk
242 -- from the parser recovering. In full errors mode, we don't do this
243 -- deletion, but otherwise such messages are discarded at this stage.
245 if Prev_Msg /= No_Error_Msg
246 and then Errors.Table (Prev_Msg).Line =
247 Errors.Table (Cur_Msg).Line
248 and then Errors.Table (Prev_Msg).Sfile =
249 Errors.Table (Cur_Msg).Sfile
251 -- Don't delete unconditional messages and at this stage, don't
252 -- delete continuation lines (we attempted to delete those earlier
253 -- if the parent message was deleted.
255 if not Errors.Table (Cur_Msg).Uncond
256 and then not Continuation
259 -- Don't delete if prev msg is warning and new msg is an error.
260 -- This is because we don't want a real error masked by a warning.
261 -- In all other cases (that is parse errors for the same line that
262 -- are not unconditional) we do delete the message. This helps to
263 -- avoid junk extra messages from cascaded parsing errors
265 if not (Errors.Table (Prev_Msg).Warn
267 Errors.Table (Prev_Msg).Style)
269 (Errors.Table (Cur_Msg).Warn
271 Errors.Table (Cur_Msg).Style)
273 -- All tests passed, delete the message by simply returning
274 -- without any further processing.
276 if not Continuation then
285 -- Come here if message is to be inserted in the error chain
287 if not Continuation then
288 Last_Killed := False;
291 if Prev_Msg = No_Error_Msg then
292 First_Error_Msg := Cur_Msg;
294 Errors.Table (Prev_Msg).Next := Cur_Msg;
297 Errors.Table (Cur_Msg).Next := Next_Msg;
299 -- Bump appropriate statistics count
301 if Errors.Table (Cur_Msg).Warn
303 Errors.Table (Cur_Msg).Style
305 Warnings_Detected := Warnings_Detected + 1;
308 Total_Errors_Detected := Total_Errors_Detected + 1;
310 if Errors.Table (Cur_Msg).Serious then
311 Serious_Errors_Detected := Serious_Errors_Detected + 1;
321 procedure Error_Msg_S (Msg : String) is
323 Error_Msg (Msg, Scan_Ptr);
330 procedure Error_Msg_SC (Msg : String) is
332 -- If we are at end of file, post the flag after the previous token
334 if Token = Tok_EOF then
337 -- For all other cases the message is posted at the current token
341 Error_Msg (Msg, Token_Ptr);
349 procedure Error_Msg_SP (Msg : String) is
351 -- Note: in the case where there is no previous token, Prev_Token_Ptr
352 -- is set to Source_First, which is a reasonable position for the
353 -- error flag in this situation
355 Error_Msg (Msg, Prev_Token_Ptr);
362 procedure Finalize (Source_Type : String := "project") is
369 -- Eliminate any duplicated error messages from the list. This is
370 -- done after the fact to avoid problems with Change_Error_Text.
372 Cur := First_Error_Msg;
373 while Cur /= No_Error_Msg loop
374 Nxt := Errors.Table (Cur).Next;
377 while F /= No_Error_Msg
378 and then Errors.Table (F).Sptr = Errors.Table (Cur).Sptr
380 Check_Duplicate_Message (Cur, F);
381 F := Errors.Table (F).Next;
389 if Brief_Output or (not Full_List and not Verbose_Mode) then
390 E := First_Error_Msg;
393 while E /= No_Error_Msg loop
394 if not Errors.Table (E).Deleted then
395 if Full_Path_Name_For_Brief_Errors then
396 Write_Name (Full_Ref_Name (Errors.Table (E).Sfile));
398 Write_Name (Reference_Name (Errors.Table (E).Sfile));
402 Write_Int (Int (Physical_To_Logical
403 (Errors.Table (E).Line,
404 Errors.Table (E).Sfile)));
407 if Errors.Table (E).Col < 10 then
411 Write_Int (Int (Errors.Table (E).Col));
417 E := Errors.Table (E).Next;
423 -- Full source listing case
426 List_Pragmas_Index := 1;
427 List_Pragmas_Mode := True;
428 E := First_Error_Msg;
431 -- First list initial main source file with its error messages
433 for N in 1 .. Last_Source_Line (Main_Source_File) loop
436 and then Errors.Table (E).Line = N
437 and then Errors.Table (E).Sfile = Main_Source_File;
439 Output_Source_Line (N, Main_Source_File, Err_Flag, Source_Type);
442 Output_Error_Msgs (E);
448 -- Then output errors, if any, for subsidiary units
450 while E /= No_Error_Msg
451 and then Errors.Table (E).Sfile /= Main_Source_File
455 (Errors.Table (E).Line,
456 Errors.Table (E).Sfile,
459 Output_Error_Msgs (E);
463 -- Verbose mode (error lines only with error flags)
466 E := First_Error_Msg;
468 -- Loop through error lines
470 while E /= No_Error_Msg loop
473 (Errors.Table (E).Line,
474 Errors.Table (E).Sfile,
477 Output_Error_Msgs (E);
481 -- Output error summary if verbose or full list mode
483 if Verbose_Mode or else Full_List then
485 -- Extra blank line if error messages or source listing were output
487 if Total_Errors_Detected + Warnings_Detected > 0
493 -- Message giving number of lines read and number of errors detected.
494 -- This normally goes to Standard_Output. The exception is when brief
495 -- mode is not set, verbose mode (or full list mode) is set, and
496 -- there are errors. In this case we send the message to standard
497 -- error to make sure that *something* appears on standard error in
498 -- an error situation.
500 -- Formerly, only the "# errors" suffix was sent to stderr, whereas
501 -- "# lines:" appeared on stdout. This caused problems on VMS when
502 -- the stdout buffer was flushed, giving an extra line feed after
505 if Total_Errors_Detected + Warnings_Detected /= 0
506 and then not Brief_Output
507 and then (Verbose_Mode or Full_List)
512 -- Message giving total number of lines
515 Write_Int (Num_Source_Lines (Main_Source_File));
517 if Num_Source_Lines (Main_Source_File) = 1 then
518 Write_Str (" line: ");
520 Write_Str (" lines: ");
523 if Total_Errors_Detected = 0 then
524 Write_Str ("No errors");
526 elsif Total_Errors_Detected = 1 then
527 Write_Str ("1 error");
530 Write_Int (Total_Errors_Detected);
531 Write_Str (" errors");
534 if Warnings_Detected /= 0 then
536 Write_Int (Warnings_Detected);
537 Write_Str (" warning");
539 if Warnings_Detected /= 1 then
543 if Warning_Mode = Treat_As_Error then
544 Write_Str (" (treated as error");
546 if Warnings_Detected /= 1 then
558 if Maximum_Messages /= 0 then
559 if Warnings_Detected >= Maximum_Messages then
561 Write_Line ("maximum number of warnings detected");
562 Warning_Mode := Suppress;
565 if Total_Errors_Detected >= Maximum_Messages then
567 Write_Line ("fatal error: maximum errors reached");
572 if Warning_Mode = Treat_As_Error then
573 Total_Errors_Detected := Total_Errors_Detected + Warnings_Detected;
574 Warnings_Detected := 0;
577 -- Prevent displaying the same messages again in the future
579 First_Error_Msg := No_Error_Msg;
586 procedure Initialize is
589 First_Error_Msg := No_Error_Msg;
590 Last_Error_Msg := No_Error_Msg;
591 Serious_Errors_Detected := 0;
592 Total_Errors_Detected := 0;
593 Warnings_Detected := 0;
594 Cur_Msg := No_Error_Msg;
596 -- Initialize warnings table, if all warnings are suppressed, supply
597 -- an initial dummy entry covering all possible source locations.
601 if Warning_Mode = Suppress then
602 Warnings.Increment_Last;
603 Warnings.Table (Warnings.Last).Start := Source_Ptr'First;
604 Warnings.Table (Warnings.Last).Stop := Source_Ptr'Last;
608 ------------------------
609 -- Output_Source_Line --
610 ------------------------
612 procedure Output_Source_Line
613 (L : Physical_Line_Number;
614 Sfile : Source_File_Index;
616 Source_Type : String)
621 Line_Number_Output : Boolean := False;
622 -- Set True once line number is output
625 if Sfile /= Current_Error_Source_File then
626 Write_Str ("==============Error messages for ");
627 Write_Str (Source_Type);
628 Write_Str (" file: ");
629 Write_Name (Full_File_Name (Sfile));
631 Current_Error_Source_File := Sfile;
635 Output_Line_Number (Physical_To_Logical (L, Sfile));
636 Line_Number_Output := True;
639 S := Line_Start (L, Sfile);
642 C := Source_Text (Sfile) (S);
643 exit when C = ASCII.LF or else C = ASCII.CR or else C = EOF;
652 if Line_Number_Output then
655 end Output_Source_Line;
657 -----------------------
658 -- Set_Ignore_Errors --
659 -----------------------
661 procedure Set_Ignore_Errors (To : Boolean) is
663 Errors_Must_Be_Ignored := To;
664 end Set_Ignore_Errors;
666 ------------------------------
667 -- Set_Msg_Insertion_Column --
668 ------------------------------
670 procedure Set_Msg_Insertion_Column is
672 if RM_Column_Check then
673 Set_Msg_Str (" in column ");
674 Set_Msg_Int (Int (Error_Msg_Col) + 1);
676 end Set_Msg_Insertion_Column;
682 procedure Set_Msg_Text (Text : String; Flag : Source_Ptr) is
683 C : Character; -- Current character
684 P : Natural; -- Current index;
687 Manual_Quote_Mode := False;
689 Flag_Source := Get_Source_File_Index (Flag);
692 while P <= Text'Last loop
696 -- Check for insertion character
699 if P <= Text'Last and then Text (P) = '%' then
701 Set_Msg_Insertion_Name_Literal;
703 Set_Msg_Insertion_Name;
713 Set_Msg_Insertion_File_Name;
722 Set_Msg_Insertion_Reserved_Name;
731 Set_Msg_Insertion_Line_Number (Error_Msg_Sloc, Flag);
734 Continuation := True;
737 Set_Msg_Insertion_Column;
740 Set_Msg_Insertion_Uint;
743 Manual_Quote_Mode := not Manual_Quote_Mode;
747 Is_Unconditional_Msg := True;
759 Set_Msg_Char (Text (P));
762 -- Upper case letter (start of reserved word if 2 or more)
764 elsif C in 'A' .. 'Z'
765 and then P <= Text'Last
766 and then Text (P) in 'A' .. 'Z'
769 Set_Msg_Insertion_Reserved_Word (Text, P);
771 -- Normal character with no special treatment