[Ada] Fix spurious options being inserted in -fdiagnostics-format=json output
[official-gcc.git] / gcc / ada / erroutc.adb
blobcab7fecef5e381d453ed88de0c05d031cce72936
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- E R R O U T C --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2022, 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 -- Warning: Error messages can be generated during Gigi processing by direct
27 -- calls to error message routines, so it is essential that the processing
28 -- in this body be consistent with the requirements for the Gigi processing
29 -- environment, and that in particular, no disallowed table expansion is
30 -- allowed to occur.
32 with Atree; use Atree;
33 with Casing; use Casing;
34 with Csets; use Csets;
35 with Debug; use Debug;
36 with Err_Vars; use Err_Vars;
37 with Fname; use Fname;
38 with Namet; use Namet;
39 with Opt; use Opt;
40 with Output; use Output;
41 with Sinput; use Sinput;
42 with Snames; use Snames;
43 with Stringt; use Stringt;
44 with Targparm;
45 with Uintp; use Uintp;
46 with Widechar; use Widechar;
48 package body Erroutc is
50 -----------------------
51 -- Local Subprograms --
52 -----------------------
54 function Sloc_In_Range (Loc, Start, Stop : Source_Ptr) return Boolean;
55 -- Return whether Loc is in the range Start .. Stop, taking instantiation
56 -- locations of Loc into account. This is useful for suppressing warnings
57 -- from generic instantiations by using pragma Warnings around generic
58 -- instances, as needed in GNATprove.
60 ---------------
61 -- Add_Class --
62 ---------------
64 procedure Add_Class is
65 begin
66 if Class_Flag then
67 Class_Flag := False;
68 Set_Msg_Char (''');
69 Get_Name_String (Name_Class);
70 Set_Casing (Identifier_Casing (Flag_Source));
71 Set_Msg_Name_Buffer;
72 end if;
73 end Add_Class;
75 ----------------------
76 -- Buffer_Ends_With --
77 ----------------------
79 function Buffer_Ends_With (C : Character) return Boolean is
80 begin
81 return Msglen > 0 and then Msg_Buffer (Msglen) = C;
82 end Buffer_Ends_With;
84 function Buffer_Ends_With (S : String) return Boolean is
85 Len : constant Natural := S'Length;
86 begin
87 return Msglen > Len
88 and then Msg_Buffer (Msglen - Len) = ' '
89 and then Msg_Buffer (Msglen - Len + 1 .. Msglen) = S;
90 end Buffer_Ends_With;
92 -------------------
93 -- Buffer_Remove --
94 -------------------
96 procedure Buffer_Remove (C : Character) is
97 begin
98 if Buffer_Ends_With (C) then
99 Msglen := Msglen - 1;
100 end if;
101 end Buffer_Remove;
103 procedure Buffer_Remove (S : String) is
104 begin
105 if Buffer_Ends_With (S) then
106 Msglen := Msglen - S'Length;
107 end if;
108 end Buffer_Remove;
110 -----------------------------
111 -- Check_Duplicate_Message --
112 -----------------------------
114 procedure Check_Duplicate_Message (M1, M2 : Error_Msg_Id) is
115 L1, L2 : Error_Msg_Id;
116 N1, N2 : Error_Msg_Id;
118 procedure Delete_Msg (Delete, Keep : Error_Msg_Id);
119 -- Called to delete message Delete, keeping message Keep. Marks msg
120 -- Delete and all its continuations with deleted flag set to True.
121 -- Also makes sure that for the error messages that are retained the
122 -- preferred message is the one retained (we prefer the shorter one in
123 -- the case where one has an Instance tag). Note that we always know
124 -- that Keep has at least as many continuations as Delete (since we
125 -- always delete the shorter sequence).
127 ----------------
128 -- Delete_Msg --
129 ----------------
131 procedure Delete_Msg (Delete, Keep : Error_Msg_Id) is
132 D, K : Error_Msg_Id;
134 begin
135 D := Delete;
136 K := Keep;
138 loop
139 Errors.Table (D).Deleted := True;
141 -- Adjust error message count
143 if Errors.Table (D).Info then
145 if Errors.Table (D).Warn then
146 Warning_Info_Messages := Warning_Info_Messages - 1;
147 Warnings_Detected := Warnings_Detected - 1;
148 else
149 Report_Info_Messages := Report_Info_Messages - 1;
150 end if;
152 elsif Errors.Table (D).Warn or else Errors.Table (D).Style then
153 Warnings_Detected := Warnings_Detected - 1;
155 -- Note: we do not need to decrement Warnings_Treated_As_Errors
156 -- because this only gets incremented if we actually output the
157 -- message, which we won't do if we are deleting it here!
159 elsif Errors.Table (D).Check then
160 Check_Messages := Check_Messages - 1;
162 else
163 Total_Errors_Detected := Total_Errors_Detected - 1;
165 if Errors.Table (D).Serious then
166 Serious_Errors_Detected := Serious_Errors_Detected - 1;
167 end if;
168 end if;
170 -- Substitute shorter of the two error messages
172 if Errors.Table (K).Text'Length > Errors.Table (D).Text'Length then
173 Errors.Table (K).Text := Errors.Table (D).Text;
174 end if;
176 D := Errors.Table (D).Next;
177 K := Errors.Table (K).Next;
179 if D = No_Error_Msg or else not Errors.Table (D).Msg_Cont then
180 return;
181 end if;
182 end loop;
183 end Delete_Msg;
185 -- Start of processing for Check_Duplicate_Message
187 begin
188 -- Both messages must be non-continuation messages and not deleted
190 if Errors.Table (M1).Msg_Cont
191 or else Errors.Table (M2).Msg_Cont
192 or else Errors.Table (M1).Deleted
193 or else Errors.Table (M2).Deleted
194 then
195 return;
196 end if;
198 -- Definitely not equal if message text does not match
200 if not Same_Error (M1, M2) then
201 return;
202 end if;
204 -- Same text. See if all continuations are also identical
206 L1 := M1;
207 L2 := M2;
209 loop
210 N1 := Errors.Table (L1).Next;
211 N2 := Errors.Table (L2).Next;
213 -- If M1 continuations have run out, we delete M1, either the
214 -- messages have the same number of continuations, or M2 has
215 -- more and we prefer the one with more anyway.
217 if N1 = No_Error_Msg or else not Errors.Table (N1).Msg_Cont then
218 Delete_Msg (M1, M2);
219 return;
221 -- If M2 continuations have run out, we delete M2
223 elsif N2 = No_Error_Msg or else not Errors.Table (N2).Msg_Cont then
224 Delete_Msg (M2, M1);
225 return;
227 -- Otherwise see if continuations are the same, if not, keep both
228 -- sequences, a curious case, but better to keep everything.
230 elsif not Same_Error (N1, N2) then
231 return;
233 -- If continuations are the same, continue scan
235 else
236 L1 := N1;
237 L2 := N2;
238 end if;
239 end loop;
240 end Check_Duplicate_Message;
242 ------------------------
243 -- Compilation_Errors --
244 ------------------------
246 function Compilation_Errors return Boolean is
247 Warnings_Count : constant Int
248 := Warnings_Detected - Warning_Info_Messages;
249 begin
250 if Total_Errors_Detected /= 0 then
251 return True;
253 elsif Warnings_Treated_As_Errors /= 0 then
254 return True;
256 -- We should never treat warnings that originate from a
257 -- Compile_Time_Warning pragma as an error. Warnings_Count is the sum
258 -- of both "normal" and Compile_Time_Warning warnings. This means that
259 -- there are only one or more non-Compile_Time_Warning warnings when
260 -- Warnings_Count is greater than Count_Compile_Time_Pragma_Warnings.
262 elsif Warning_Mode = Treat_As_Error
263 and then Warnings_Count > Count_Compile_Time_Pragma_Warnings
264 then
265 return True;
266 end if;
268 return False;
269 end Compilation_Errors;
271 ----------------------------------------
272 -- Count_Compile_Time_Pragma_Warnings --
273 ----------------------------------------
275 function Count_Compile_Time_Pragma_Warnings return Int is
276 Result : Int := 0;
277 begin
278 for J in 1 .. Errors.Last loop
279 begin
280 if Errors.Table (J).Warn
281 and then Errors.Table (J).Compile_Time_Pragma
282 and then not Errors.Table (J).Deleted
283 then
284 Result := Result + 1;
285 end if;
286 end;
287 end loop;
288 return Result;
289 end Count_Compile_Time_Pragma_Warnings;
291 ------------------
292 -- Debug_Output --
293 ------------------
295 procedure Debug_Output (N : Node_Id) is
296 begin
297 if Debug_Flag_1 then
298 Write_Str ("*** following error message posted on node id = #");
299 Write_Int (Int (N));
300 Write_Str (" ***");
301 Write_Eol;
302 end if;
303 end Debug_Output;
305 ----------
306 -- dmsg --
307 ----------
309 procedure dmsg (Id : Error_Msg_Id) is
310 E : Error_Msg_Object renames Errors.Table (Id);
312 begin
313 w ("Dumping error message, Id = ", Int (Id));
314 w (" Text = ", E.Text.all);
315 w (" Next = ", Int (E.Next));
316 w (" Prev = ", Int (E.Prev));
317 w (" Sfile = ", Int (E.Sfile));
319 Write_Str
320 (" Sptr = ");
321 Write_Location (E.Sptr.Ptr); -- ??? Do not write the full span for now
322 Write_Eol;
324 Write_Str
325 (" Optr = ");
326 Write_Location (E.Optr);
327 Write_Eol;
329 w (" Line = ", Int (E.Line));
330 w (" Col = ", Int (E.Col));
331 w (" Warn = ", E.Warn);
332 w (" Warn_Err = ", E.Warn_Err);
333 w (" Warn_Chr = '" & E.Warn_Chr & ''');
334 w (" Style = ", E.Style);
335 w (" Serious = ", E.Serious);
336 w (" Uncond = ", E.Uncond);
337 w (" Msg_Cont = ", E.Msg_Cont);
338 w (" Deleted = ", E.Deleted);
339 w (" Node = ", Int (E.Node));
341 Write_Eol;
342 end dmsg;
344 ------------------
345 -- Get_Location --
346 ------------------
348 function Get_Location (E : Error_Msg_Id) return Source_Ptr is
349 begin
350 return Errors.Table (E).Sptr.Ptr;
351 end Get_Location;
353 ----------------
354 -- Get_Msg_Id --
355 ----------------
357 function Get_Msg_Id return Error_Msg_Id is
358 begin
359 return Cur_Msg;
360 end Get_Msg_Id;
362 ------------------------
363 -- Get_Warning_Option --
364 ------------------------
366 function Get_Warning_Option (Id : Error_Msg_Id) return String is
367 Warn : constant Boolean := Errors.Table (Id).Warn;
368 Warn_Chr : constant String (1 .. 2) := Errors.Table (Id).Warn_Chr;
369 begin
370 if Warn and then Warn_Chr /= " " and then Warn_Chr (1) /= '?' then
371 if Warn_Chr = "$ " then
372 return "-gnatel";
373 elsif Warn_Chr (2) = ' ' then
374 return "-gnatw" & Warn_Chr (1);
375 else
376 return "-gnatw" & Warn_Chr;
377 end if;
378 end if;
379 return "";
380 end Get_Warning_Option;
382 ---------------------
383 -- Get_Warning_Tag --
384 ---------------------
386 function Get_Warning_Tag (Id : Error_Msg_Id) return String is
387 Warn : constant Boolean := Errors.Table (Id).Warn;
388 Warn_Chr : constant String (1 .. 2) := Errors.Table (Id).Warn_Chr;
389 Option : constant String := Get_Warning_Option (Id);
390 begin
391 if Warn then
392 if Warn_Chr = "? " then
393 return "[enabled by default]";
394 elsif Warn_Chr = "* " then
395 return "[restriction warning]";
396 elsif Option /= "" then
397 return "[" & Option & "]";
398 end if;
399 end if;
401 return "";
402 end Get_Warning_Tag;
404 -------------
405 -- Matches --
406 -------------
408 function Matches (S : String; P : String) return Boolean is
409 Slast : constant Natural := S'Last;
410 PLast : constant Natural := P'Last;
412 SPtr : Natural := S'First;
413 PPtr : Natural := P'First;
415 begin
416 -- Loop advancing through characters of string and pattern
418 SPtr := S'First;
419 PPtr := P'First;
420 loop
421 -- Return True if pattern is a single asterisk
423 if PPtr = PLast and then P (PPtr) = '*' then
424 return True;
426 -- Return True if both pattern and string exhausted
428 elsif PPtr > PLast and then SPtr > Slast then
429 return True;
431 -- Return False, if one exhausted and not the other
433 elsif PPtr > PLast or else SPtr > Slast then
434 return False;
436 -- Case where pattern starts with asterisk
438 elsif P (PPtr) = '*' then
440 -- Try all possible starting positions in S for match with the
441 -- remaining characters of the pattern. This is the recursive
442 -- call that implements the scanner backup.
444 for J in SPtr .. Slast loop
445 if Matches (S (J .. Slast), P (PPtr + 1 .. PLast)) then
446 return True;
447 end if;
448 end loop;
450 return False;
452 -- Dealt with end of string and *, advance if we have a match
454 elsif Fold_Lower (S (SPtr)) = Fold_Lower (P (PPtr)) then
455 SPtr := SPtr + 1;
456 PPtr := PPtr + 1;
458 -- If first characters do not match, that's decisive
460 else
461 return False;
462 end if;
463 end loop;
464 end Matches;
466 -----------------------
467 -- Output_Error_Msgs --
468 -----------------------
470 procedure Output_Error_Msgs (E : in out Error_Msg_Id) is
471 P : Source_Ptr;
472 T : Error_Msg_Id;
473 S : Error_Msg_Id;
475 Flag_Num : Pos;
476 Mult_Flags : Boolean := False;
478 begin
479 S := E;
481 -- Skip deleted messages at start
483 if Errors.Table (S).Deleted then
484 Set_Next_Non_Deleted_Msg (S);
485 end if;
487 -- Figure out if we will place more than one error flag on this line
489 T := S;
490 while T /= No_Error_Msg
491 and then Errors.Table (T).Line = Errors.Table (E).Line
492 and then Errors.Table (T).Sfile = Errors.Table (E).Sfile
493 loop
494 if Errors.Table (T).Sptr.Ptr > Errors.Table (E).Sptr.Ptr then
495 Mult_Flags := True;
496 end if;
498 Set_Next_Non_Deleted_Msg (T);
499 end loop;
501 -- Output the error flags. The circuit here makes sure that the tab
502 -- characters in the original line are properly accounted for. The
503 -- eight blanks at the start are to match the line number.
505 if not Debug_Flag_2 then
506 Write_Str (" ");
507 P := Line_Start (Errors.Table (E).Sptr.Ptr);
508 Flag_Num := 1;
510 -- Loop through error messages for this line to place flags
512 T := S;
513 while T /= No_Error_Msg
514 and then Errors.Table (T).Line = Errors.Table (E).Line
515 and then Errors.Table (T).Sfile = Errors.Table (E).Sfile
516 loop
517 declare
518 Src : Source_Buffer_Ptr
519 renames Source_Text (Errors.Table (T).Sfile);
521 begin
522 -- Loop to output blanks till current flag position
524 while P < Errors.Table (T).Sptr.Ptr loop
526 -- Horizontal tab case, just echo the tab
528 if Src (P) = ASCII.HT then
529 Write_Char (ASCII.HT);
530 P := P + 1;
532 -- Deal with wide character case, but don't include brackets
533 -- notation in this circuit, since we know that this will
534 -- display unencoded (no one encodes brackets notation).
536 elsif Src (P) /= '['
537 and then Is_Start_Of_Wide_Char (Src, P)
538 then
539 Skip_Wide (Src, P);
540 Write_Char (' ');
542 -- Normal non-wide character case (or bracket)
544 else
545 P := P + 1;
546 Write_Char (' ');
547 end if;
548 end loop;
550 -- Output flag (unless already output, this happens if more
551 -- than one error message occurs at the same flag position).
553 if P = Errors.Table (T).Sptr.Ptr then
554 if (Flag_Num = 1 and then not Mult_Flags)
555 or else Flag_Num > 9
556 then
557 Write_Char ('|');
558 else
559 Write_Char
560 (Character'Val (Character'Pos ('0') + Flag_Num));
561 end if;
563 -- Skip past the corresponding source text character
565 -- Horizontal tab case, we output a flag at the tab position
566 -- so now we output a tab to match up with the text.
568 if Src (P) = ASCII.HT then
569 Write_Char (ASCII.HT);
570 P := P + 1;
572 -- Skip wide character other than left bracket
574 elsif Src (P) /= '['
575 and then Is_Start_Of_Wide_Char (Src, P)
576 then
577 Skip_Wide (Src, P);
579 -- Skip normal non-wide character case (or bracket)
581 else
582 P := P + 1;
583 end if;
584 end if;
585 end;
587 Set_Next_Non_Deleted_Msg (T);
588 Flag_Num := Flag_Num + 1;
589 end loop;
591 Write_Eol;
592 end if;
594 -- Now output the error messages
596 T := S;
597 while T /= No_Error_Msg
598 and then Errors.Table (T).Line = Errors.Table (E).Line
599 and then Errors.Table (T).Sfile = Errors.Table (E).Sfile
600 loop
601 Write_Str (" >>> ");
602 Output_Msg_Text (T);
604 if Debug_Flag_2 then
605 while Column < 74 loop
606 Write_Char (' ');
607 end loop;
609 Write_Str (" <<<");
610 end if;
612 Write_Eol;
613 Set_Next_Non_Deleted_Msg (T);
614 end loop;
616 E := T;
617 end Output_Error_Msgs;
619 ------------------------
620 -- Output_Line_Number --
621 ------------------------
623 procedure Output_Line_Number (L : Logical_Line_Number) is
624 D : Int; -- next digit
625 C : Character; -- next character
626 Z : Boolean; -- flag for zero suppress
627 N, M : Int; -- temporaries
629 begin
630 if L = No_Line_Number then
631 Write_Str (" ");
633 else
634 Z := False;
635 N := Int (L);
637 M := 100_000;
638 while M /= 0 loop
639 D := Int (N / M);
640 N := N rem M;
641 M := M / 10;
643 if D = 0 then
644 if Z then
645 C := '0';
646 else
647 C := ' ';
648 end if;
649 else
650 Z := True;
651 C := Character'Val (D + 48);
652 end if;
654 Write_Char (C);
655 end loop;
657 Write_Str (". ");
658 end if;
659 end Output_Line_Number;
661 ---------------------
662 -- Output_Msg_Text --
663 ---------------------
665 procedure Output_Msg_Text (E : Error_Msg_Id) is
666 Offs : constant Nat := Column - 1;
667 -- Offset to start of message, used for continuations
669 Max : Integer;
670 -- Maximum characters to output on next line
672 Length : Nat;
673 -- Maximum total length of lines
675 E_Msg : Error_Msg_Object renames Errors.Table (E);
676 Text : constant String_Ptr := E_Msg.Text;
677 Ptr : Natural;
678 Split : Natural;
679 Start : Natural;
680 Tag : constant String := Get_Warning_Tag (E);
681 Txt : String_Ptr;
682 Len : Natural;
684 begin
685 -- Postfix warning tag to message if needed
687 if Tag /= "" and then Warning_Doc_Switch then
688 if Include_Subprogram_In_Messages then
689 Txt :=
690 new String'
691 (Subprogram_Name_Ptr (E_Msg.Node) &
692 ": " & Text.all & ' ' & Tag);
693 else
694 Txt := new String'(Text.all & ' ' & Tag);
695 end if;
697 elsif Include_Subprogram_In_Messages
698 and then (E_Msg.Warn or else E_Msg.Style)
699 then
700 Txt :=
701 new String'(Subprogram_Name_Ptr (E_Msg.Node) & ": " & Text.all);
702 else
703 Txt := Text;
704 end if;
706 -- If -gnatdF is used, continuation messages follow the main message
707 -- with only an indentation of two space characters, without repeating
708 -- any prefix.
710 if Debug_Flag_FF and then E_Msg.Msg_Cont then
711 null;
713 -- For info messages, prefix message with "info: "
715 elsif E_Msg.Info then
716 Txt := new String'(SGR_Note & "info: " & SGR_Reset & Txt.all);
718 -- Warning treated as error
720 elsif E_Msg.Warn_Err then
722 -- We prefix with "error:" rather than warning: and postfix
723 -- [warning-as-error] at the end.
725 Warnings_Treated_As_Errors := Warnings_Treated_As_Errors + 1;
726 Txt := new String'(SGR_Error & "error: " & SGR_Reset
727 & Txt.all & " [warning-as-error]");
729 -- Normal warning, prefix with "warning: "
731 elsif E_Msg.Warn then
732 Txt := new String'(SGR_Warning & "warning: " & SGR_Reset & Txt.all);
734 -- No prefix needed for style message, "(style)" is there already,
735 -- although not necessarily in first position if -gnatdJ is used.
737 elsif E_Msg.Style then
738 if Txt (Txt'First .. Txt'First + 6) = "(style)" then
739 Txt := new String'(SGR_Warning & "(style)" & SGR_Reset
740 & Txt (Txt'First + 7 .. Txt'Last));
741 end if;
743 -- No prefix needed for check message, severity is there already
745 elsif E_Msg.Check then
747 -- The message format is "severity: ..."
749 -- Enclose the severity with an SGR control string if requested
751 if Use_SGR_Control then
752 declare
753 Msg : String renames Text.all;
754 Colon : Natural := 0;
755 begin
756 -- Find first colon
758 for J in Msg'Range loop
759 if Msg (J) = ':' then
760 Colon := J;
761 exit;
762 end if;
763 end loop;
765 pragma Assert (Colon > 0);
767 Txt := new String'(SGR_Error
768 & Msg (Msg'First .. Colon)
769 & SGR_Reset
770 & Msg (Colon + 1 .. Msg'Last));
771 end;
772 end if;
774 -- All other cases, add "error: " if unique error tag set
776 elsif Opt.Unique_Error_Tag then
777 Txt := new String'(SGR_Error & "error: " & SGR_Reset & Txt.all);
778 end if;
780 -- Set error message line length and length of message
782 if Error_Msg_Line_Length = 0 then
783 Length := Nat'Last;
784 else
785 Length := Error_Msg_Line_Length;
786 end if;
788 Max := Integer (Length - Column + 1);
789 Len := Txt'Length;
791 -- Here we have to split the message up into multiple lines
793 Ptr := 1;
794 loop
795 -- Make sure we do not have ludicrously small line
797 Max := Integer'Max (Max, 20);
799 -- If remaining text fits, output it respecting LF and we are done
801 if Len - Ptr < Max then
802 for J in Ptr .. Len loop
803 if Txt (J) = ASCII.LF then
804 Write_Eol;
805 Write_Spaces (Offs);
806 else
807 Write_Char (Txt (J));
808 end if;
809 end loop;
811 return;
813 -- Line does not fit
815 else
816 Start := Ptr;
818 -- First scan forward looking for a hard end of line
820 for Scan in Ptr .. Ptr + Max - 1 loop
821 if Txt (Scan) = ASCII.LF then
822 Split := Scan - 1;
823 Ptr := Scan + 1;
824 goto Continue;
825 end if;
826 end loop;
828 -- Otherwise scan backwards looking for a space
830 for Scan in reverse Ptr .. Ptr + Max - 1 loop
831 if Txt (Scan) = ' ' then
832 Split := Scan - 1;
833 Ptr := Scan + 1;
834 goto Continue;
835 end if;
836 end loop;
838 -- If we fall through, no space, so split line arbitrarily
840 Split := Ptr + Max - 1;
841 Ptr := Split + 1;
842 end if;
844 <<Continue>>
845 if Start <= Split then
846 Write_Line (Txt (Start .. Split));
847 Write_Spaces (Offs);
848 end if;
850 Max := Integer (Length - Column + 1);
851 end loop;
852 end Output_Msg_Text;
854 ---------------------
855 -- Prescan_Message --
856 ---------------------
858 procedure Prescan_Message (Msg : String) is
859 J : Natural;
861 function Parse_Message_Class return String;
862 -- Convert the warning insertion sequence to a warning class represented
863 -- as a length-two string padded, if necessary, with spaces.
864 -- Return the Message class and set the iterator J to the character
865 -- following the sequence.
866 -- Raise a Program_Error if the insertion sequence is not valid.
868 -------------------------
869 -- Parse_Message_Class --
870 -------------------------
872 function Parse_Message_Class return String is
873 C : constant Character := Msg (J - 1);
874 Message_Class : String (1 .. 2) := " ";
875 begin
876 if J <= Msg'Last and then Msg (J) = C then
877 Message_Class := "? ";
878 J := J + 1;
880 elsif J < Msg'Last and then Msg (J + 1) = C
881 and then Msg (J) in 'a' .. 'z' | '*' | '$'
882 then
883 Message_Class := Msg (J) & " ";
884 J := J + 2;
886 elsif J + 1 < Msg'Last and then Msg (J + 2) = C
887 and then Msg (J) in '.' | '_'
888 and then Msg (J + 1) in 'a' .. 'z'
889 then
890 Message_Class := Msg (J .. J + 1);
891 J := J + 3;
892 elsif (J < Msg'Last and then Msg (J + 1) = C) or else
893 (J + 1 < Msg'Last and then Msg (J + 2) = C)
894 then
895 raise Program_Error;
896 end if;
898 -- In any other cases, this is not a warning insertion sequence
899 -- and the default " " value is returned.
901 return Message_Class;
902 end Parse_Message_Class;
904 -- Start of processing for Prescan_Message
906 begin
907 -- Nothing to do for continuation line, unless -gnatdF is set
909 if not Debug_Flag_FF and then Msg (Msg'First) = '\' then
910 return;
912 -- Some global variables are not set for continuation messages, as they
913 -- only make sense for the initial message.
915 elsif Msg (Msg'First) /= '\' then
917 -- Set initial values of globals (may be changed during scan)
919 Is_Serious_Error := True;
920 Is_Unconditional_Msg := False;
921 Is_Warning_Msg := False;
922 Is_Runtime_Raise := False;
924 -- Check style message
926 Is_Style_Msg :=
927 Msg'Length > 7
928 and then Msg (Msg'First .. Msg'First + 6) = "(style)";
930 -- Check info message
932 Is_Info_Msg :=
933 Msg'Length > 6
934 and then Msg (Msg'First .. Msg'First + 5) = "info: ";
936 -- Check check message
938 Is_Check_Msg :=
939 (Msg'Length > 8
940 and then Msg (Msg'First .. Msg'First + 7) = "medium: ")
941 or else
942 (Msg'Length > 6
943 and then Msg (Msg'First .. Msg'First + 5) = "high: ")
944 or else
945 (Msg'Length > 5
946 and then Msg (Msg'First .. Msg'First + 4) = "low: ");
947 end if;
949 Has_Double_Exclam := False;
950 Has_Insertion_Line := False;
952 -- Loop through message looking for relevant insertion sequences
954 J := Msg'First;
955 while J <= Msg'Last loop
957 -- If we have a quote, don't look at following character
959 if Msg (J) = ''' then
960 J := J + 2;
962 -- Warning message (? or < insertion sequence)
964 elsif Msg (J) = '?' or else Msg (J) = '<' then
965 Is_Warning_Msg := Msg (J) = '?' or else Error_Msg_Warn;
966 J := J + 1;
968 if Is_Warning_Msg then
969 Warning_Msg_Char := Parse_Message_Class;
970 end if;
972 -- Bomb if untagged warning message. This code can be uncommented
973 -- for debugging when looking for untagged warning messages.
975 -- if Is_Warning_Msg and then Warning_Msg_Char = ' ' then
976 -- raise Program_Error;
977 -- end if;
979 -- Unconditional message (! insertion)
981 elsif Msg (J) = '!' then
982 Is_Unconditional_Msg := True;
983 J := J + 1;
985 if J <= Msg'Last and then Msg (J) = '!' then
986 Has_Double_Exclam := True;
987 J := J + 1;
988 end if;
990 -- Insertion line (# insertion)
992 elsif Msg (J) = '#' then
993 Has_Insertion_Line := True;
994 J := J + 1;
996 -- Non-serious error (| insertion)
998 elsif Msg (J) = '|' then
999 Is_Serious_Error := False;
1000 J := J + 1;
1002 else
1003 J := J + 1;
1004 end if;
1005 end loop;
1007 if Is_Info_Msg or Is_Warning_Msg or Is_Style_Msg or Is_Check_Msg then
1008 Is_Serious_Error := False;
1009 end if;
1010 end Prescan_Message;
1012 --------------------
1013 -- Purge_Messages --
1014 --------------------
1016 procedure Purge_Messages (From : Source_Ptr; To : Source_Ptr) is
1017 E : Error_Msg_Id;
1019 function To_Be_Purged (E : Error_Msg_Id) return Boolean;
1020 -- Returns True for a message that is to be purged. Also adjusts
1021 -- error counts appropriately.
1023 ------------------
1024 -- To_Be_Purged --
1025 ------------------
1027 function To_Be_Purged (E : Error_Msg_Id) return Boolean is
1028 begin
1029 if E /= No_Error_Msg
1030 and then Errors.Table (E).Sptr.Ptr > From
1031 and then Errors.Table (E).Sptr.Ptr < To
1032 then
1033 if Errors.Table (E).Warn or else Errors.Table (E).Style then
1034 Warnings_Detected := Warnings_Detected - 1;
1036 else
1037 Total_Errors_Detected := Total_Errors_Detected - 1;
1039 if Errors.Table (E).Serious then
1040 Serious_Errors_Detected := Serious_Errors_Detected - 1;
1041 end if;
1042 end if;
1044 return True;
1046 else
1047 return False;
1048 end if;
1049 end To_Be_Purged;
1051 -- Start of processing for Purge_Messages
1053 begin
1054 while To_Be_Purged (First_Error_Msg) loop
1055 First_Error_Msg := Errors.Table (First_Error_Msg).Next;
1056 end loop;
1058 E := First_Error_Msg;
1059 while E /= No_Error_Msg loop
1060 while To_Be_Purged (Errors.Table (E).Next) loop
1061 Errors.Table (E).Next :=
1062 Errors.Table (Errors.Table (E).Next).Next;
1063 end loop;
1065 E := Errors.Table (E).Next;
1066 end loop;
1067 end Purge_Messages;
1069 ----------------
1070 -- Same_Error --
1071 ----------------
1073 function Same_Error (M1, M2 : Error_Msg_Id) return Boolean is
1074 Msg1 : constant String_Ptr := Errors.Table (M1).Text;
1075 Msg2 : constant String_Ptr := Errors.Table (M2).Text;
1077 Msg2_Len : constant Integer := Msg2'Length;
1078 Msg1_Len : constant Integer := Msg1'Length;
1080 begin
1081 return
1082 Msg1.all = Msg2.all
1083 or else
1084 (Msg1_Len - 10 > Msg2_Len
1085 and then
1086 Msg2.all = Msg1.all (1 .. Msg2_Len)
1087 and then
1088 Msg1 (Msg2_Len + 1 .. Msg2_Len + 10) = ", instance")
1089 or else
1090 (Msg2_Len - 10 > Msg1_Len
1091 and then
1092 Msg1.all = Msg2.all (1 .. Msg1_Len)
1093 and then
1094 Msg2 (Msg1_Len + 1 .. Msg1_Len + 10) = ", instance");
1095 end Same_Error;
1097 -------------------
1098 -- Set_Msg_Blank --
1099 -------------------
1101 procedure Set_Msg_Blank is
1102 begin
1103 if Msglen > 0
1104 and then Msg_Buffer (Msglen) /= ' '
1105 and then Msg_Buffer (Msglen) /= '('
1106 and then Msg_Buffer (Msglen) /= '-'
1107 and then not Manual_Quote_Mode
1108 then
1109 Set_Msg_Char (' ');
1110 end if;
1111 end Set_Msg_Blank;
1113 -------------------------------
1114 -- Set_Msg_Blank_Conditional --
1115 -------------------------------
1117 procedure Set_Msg_Blank_Conditional is
1118 begin
1119 if Msglen > 0
1120 and then Msg_Buffer (Msglen) /= ' '
1121 and then Msg_Buffer (Msglen) /= '('
1122 and then Msg_Buffer (Msglen) /= '"'
1123 and then not Manual_Quote_Mode
1124 then
1125 Set_Msg_Char (' ');
1126 end if;
1127 end Set_Msg_Blank_Conditional;
1129 ------------------
1130 -- Set_Msg_Char --
1131 ------------------
1133 procedure Set_Msg_Char (C : Character) is
1134 begin
1136 -- The check for message buffer overflow is needed to deal with cases
1137 -- where insertions get too long (in particular a child unit name can
1138 -- be very long).
1140 if Msglen < Max_Msg_Length then
1141 Msglen := Msglen + 1;
1142 Msg_Buffer (Msglen) := C;
1143 end if;
1144 end Set_Msg_Char;
1146 ---------------------------------
1147 -- Set_Msg_Insertion_File_Name --
1148 ---------------------------------
1150 procedure Set_Msg_Insertion_File_Name is
1151 begin
1152 if Error_Msg_File_1 = No_File then
1153 null;
1155 elsif Error_Msg_File_1 = Error_File_Name then
1156 Set_Msg_Blank;
1157 Set_Msg_Str ("<error>");
1159 else
1160 Set_Msg_Blank;
1161 Get_Name_String (Error_Msg_File_1);
1162 Set_Msg_Quote;
1163 Set_Msg_Name_Buffer;
1164 Set_Msg_Quote;
1165 end if;
1167 -- The following assignments ensure that the second and third {
1168 -- insertion characters will correspond to the Error_Msg_File_2
1169 -- and Error_Msg_File_3 values.
1171 Error_Msg_File_1 := Error_Msg_File_2;
1172 Error_Msg_File_2 := Error_Msg_File_3;
1173 end Set_Msg_Insertion_File_Name;
1175 -----------------------------------
1176 -- Set_Msg_Insertion_Line_Number --
1177 -----------------------------------
1179 procedure Set_Msg_Insertion_Line_Number (Loc, Flag : Source_Ptr) is
1180 Sindex_Loc : Source_File_Index;
1181 Sindex_Flag : Source_File_Index;
1182 Fname : File_Name_Type;
1183 Int_File : Boolean;
1185 procedure Set_At;
1186 -- Outputs "at " unless last characters in buffer are " from ". Certain
1187 -- messages read better with from than at.
1189 ------------
1190 -- Set_At --
1191 ------------
1193 procedure Set_At is
1194 begin
1195 if Msglen < 6
1196 or else Msg_Buffer (Msglen - 5 .. Msglen) /= " from "
1197 then
1198 Set_Msg_Str ("at ");
1199 end if;
1200 end Set_At;
1202 -- Start of processing for Set_Msg_Insertion_Line_Number
1204 begin
1205 Set_Msg_Blank;
1207 if Loc = No_Location then
1208 Set_At;
1209 Set_Msg_Str ("unknown location");
1211 elsif Loc = System_Location then
1212 Set_Msg_Str ("in package System");
1213 Set_Msg_Insertion_Run_Time_Name;
1215 elsif Loc = Standard_Location then
1216 Set_Msg_Str ("in package Standard");
1218 elsif Loc = Standard_ASCII_Location then
1219 Set_Msg_Str ("in package Standard.ASCII");
1221 else
1222 -- Add "at file-name:" if reference is to other than the source
1223 -- file in which the error message is placed. Note that we check
1224 -- full file names, rather than just the source indexes, to
1225 -- deal with generic instantiations from the current file.
1227 Sindex_Loc := Get_Source_File_Index (Loc);
1228 Sindex_Flag := Get_Source_File_Index (Flag);
1230 if Full_File_Name (Sindex_Loc) /= Full_File_Name (Sindex_Flag) then
1231 Set_At;
1232 Fname := Reference_Name (Get_Source_File_Index (Loc));
1233 Int_File := Is_Internal_File_Name (Fname);
1234 Get_Name_String (Fname);
1235 Set_Msg_Name_Buffer;
1237 if not (Int_File and Debug_Flag_Dot_K) then
1238 Set_Msg_Char (':');
1239 Set_Msg_Int (Int (Get_Logical_Line_Number (Loc)));
1240 end if;
1242 -- If in current file, add text "at line "
1244 else
1245 Set_At;
1246 Set_Msg_Str ("line ");
1247 Set_Msg_Int (Int (Get_Logical_Line_Number (Loc)));
1248 end if;
1250 -- Deal with the instantiation case. We may have a reference to,
1251 -- e.g. a type, that is declared within a generic template, and
1252 -- what we are really referring to is the occurrence in an instance.
1253 -- In this case, the line number of the instantiation is also of
1254 -- interest, and we add a notation:
1256 -- , instance at xxx
1258 -- where xxx is a line number output using this same routine (and
1259 -- the recursion can go further if the instantiation is itself in
1260 -- a generic template).
1262 -- The flag location passed to us in this situation is indeed the
1263 -- line number within the template, but as described in Sinput.L
1264 -- (file sinput-l.ads, section "Handling Generic Instantiations")
1265 -- we can retrieve the location of the instantiation itself from
1266 -- this flag location value.
1268 -- Note: this processing is suppressed if Suppress_Instance_Location
1269 -- is set True. This is used to prevent redundant annotations of the
1270 -- location of the instantiation in the case where we are placing
1271 -- the messages on the instantiation in any case.
1273 if Instantiation (Sindex_Loc) /= No_Location
1274 and then not Suppress_Instance_Location
1275 then
1276 Set_Msg_Str (", instance ");
1277 Set_Msg_Insertion_Line_Number (Instantiation (Sindex_Loc), Flag);
1278 end if;
1279 end if;
1280 end Set_Msg_Insertion_Line_Number;
1282 ----------------------------
1283 -- Set_Msg_Insertion_Name --
1284 ----------------------------
1286 procedure Set_Msg_Insertion_Name is
1287 begin
1288 if Error_Msg_Name_1 = No_Name then
1289 null;
1291 elsif Error_Msg_Name_1 = Error_Name then
1292 Set_Msg_Blank;
1293 Set_Msg_Str ("<error>");
1295 else
1296 Set_Msg_Blank_Conditional;
1297 Get_Unqualified_Decoded_Name_String (Error_Msg_Name_1);
1299 -- Remove %s or %b at end. These come from unit names. If the
1300 -- caller wanted the (unit) or (body), then they would have used
1301 -- the $ insertion character. Certainly no error message should
1302 -- ever have %b or %s explicitly occurring.
1304 if Name_Len > 2
1305 and then Name_Buffer (Name_Len - 1) = '%'
1306 and then (Name_Buffer (Name_Len) = 'b'
1307 or else
1308 Name_Buffer (Name_Len) = 's')
1309 then
1310 Name_Len := Name_Len - 2;
1311 end if;
1313 -- Remove upper case letter at end, again, we should not be getting
1314 -- such names, and what we hope is that the remainder makes sense.
1316 if Name_Len > 1 and then Name_Buffer (Name_Len) in 'A' .. 'Z' then
1317 Name_Len := Name_Len - 1;
1318 end if;
1320 -- If operator name or character literal name, just print it as is
1321 -- Also print as is if it ends in a right paren (case of x'val(nnn))
1323 if Name_Buffer (1) = '"'
1324 or else Name_Buffer (1) = '''
1325 or else Name_Buffer (Name_Len) = ')'
1326 then
1327 Set_Msg_Name_Buffer;
1329 -- Else output with surrounding quotes in proper casing mode
1331 else
1332 Set_Casing (Identifier_Casing (Flag_Source));
1333 Set_Msg_Quote;
1334 Set_Msg_Name_Buffer;
1335 Set_Msg_Quote;
1336 end if;
1337 end if;
1339 -- The following assignments ensure that other percent insertion
1340 -- characters will correspond to their appropriate Error_Msg_Name_#
1341 -- values as required.
1343 Error_Msg_Name_1 := Error_Msg_Name_2;
1344 Error_Msg_Name_2 := Error_Msg_Name_3;
1345 Error_Msg_Name_3 := Error_Msg_Name_4;
1346 Error_Msg_Name_4 := Error_Msg_Name_5;
1347 Error_Msg_Name_5 := Error_Msg_Name_6;
1348 end Set_Msg_Insertion_Name;
1350 ------------------------------------
1351 -- Set_Msg_Insertion_Name_Literal --
1352 ------------------------------------
1354 procedure Set_Msg_Insertion_Name_Literal is
1355 begin
1356 if Error_Msg_Name_1 = No_Name then
1357 null;
1359 elsif Error_Msg_Name_1 = Error_Name then
1360 Set_Msg_Blank;
1361 Set_Msg_Str ("<error>");
1363 else
1364 Set_Msg_Blank;
1365 Get_Name_String (Error_Msg_Name_1);
1366 Set_Msg_Quote;
1367 Set_Msg_Name_Buffer;
1368 Set_Msg_Quote;
1369 end if;
1371 -- The following assignments ensure that other percent insertion
1372 -- characters will correspond to their appropriate Error_Msg_Name_#
1373 -- values as required.
1375 Error_Msg_Name_1 := Error_Msg_Name_2;
1376 Error_Msg_Name_2 := Error_Msg_Name_3;
1377 Error_Msg_Name_3 := Error_Msg_Name_4;
1378 Error_Msg_Name_4 := Error_Msg_Name_5;
1379 Error_Msg_Name_5 := Error_Msg_Name_6;
1380 end Set_Msg_Insertion_Name_Literal;
1382 -------------------------------------
1383 -- Set_Msg_Insertion_Reserved_Name --
1384 -------------------------------------
1386 procedure Set_Msg_Insertion_Reserved_Name is
1387 begin
1388 Set_Msg_Blank_Conditional;
1389 Get_Name_String (Error_Msg_Name_1);
1390 Set_Msg_Quote;
1391 Set_Casing (Keyword_Casing (Flag_Source), All_Lower_Case);
1392 Set_Msg_Name_Buffer;
1393 Set_Msg_Quote;
1394 end Set_Msg_Insertion_Reserved_Name;
1396 -------------------------------------
1397 -- Set_Msg_Insertion_Reserved_Word --
1398 -------------------------------------
1400 procedure Set_Msg_Insertion_Reserved_Word
1401 (Text : String;
1402 J : in out Integer)
1404 begin
1405 Set_Msg_Blank_Conditional;
1406 Name_Len := 0;
1408 while J <= Text'Last and then Text (J) in 'A' .. 'Z' loop
1409 Add_Char_To_Name_Buffer (Text (J));
1410 J := J + 1;
1411 end loop;
1413 -- Here is where we make the special exception for RM
1415 if Name_Len = 2 and then Name_Buffer (1 .. 2) = "RM" then
1416 Set_Msg_Name_Buffer;
1418 -- We make a similar exception for SPARK
1420 elsif Name_Len = 5 and then Name_Buffer (1 .. 5) = "SPARK" then
1421 Set_Msg_Name_Buffer;
1423 -- Neither RM nor SPARK: case appropriately and add surrounding quotes
1425 else
1426 Set_Casing (Keyword_Casing (Flag_Source), All_Lower_Case);
1427 Set_Msg_Quote;
1428 Set_Msg_Name_Buffer;
1429 Set_Msg_Quote;
1430 end if;
1431 end Set_Msg_Insertion_Reserved_Word;
1433 -------------------------------------
1434 -- Set_Msg_Insertion_Run_Time_Name --
1435 -------------------------------------
1437 procedure Set_Msg_Insertion_Run_Time_Name is
1438 begin
1439 if Targparm.Run_Time_Name_On_Target /= No_Name then
1440 Set_Msg_Blank_Conditional;
1441 Set_Msg_Char ('(');
1442 Get_Name_String (Targparm.Run_Time_Name_On_Target);
1443 Set_Casing (Mixed_Case);
1444 Set_Msg_Str (Name_Buffer (1 .. Name_Len));
1445 Set_Msg_Char (')');
1446 end if;
1447 end Set_Msg_Insertion_Run_Time_Name;
1449 ----------------------------
1450 -- Set_Msg_Insertion_Uint --
1451 ----------------------------
1453 procedure Set_Msg_Insertion_Uint is
1454 begin
1455 Set_Msg_Blank;
1456 UI_Image (Error_Msg_Uint_1);
1458 for J in 1 .. UI_Image_Length loop
1459 Set_Msg_Char (UI_Image_Buffer (J));
1460 end loop;
1462 -- The following assignment ensures that a second caret insertion
1463 -- character will correspond to the Error_Msg_Uint_2 parameter.
1465 Error_Msg_Uint_1 := Error_Msg_Uint_2;
1466 end Set_Msg_Insertion_Uint;
1468 -----------------
1469 -- Set_Msg_Int --
1470 -----------------
1472 procedure Set_Msg_Int (Line : Int) is
1473 begin
1474 if Line > 9 then
1475 Set_Msg_Int (Line / 10);
1476 end if;
1478 Set_Msg_Char (Character'Val (Character'Pos ('0') + (Line rem 10)));
1479 end Set_Msg_Int;
1481 -------------------------
1482 -- Set_Msg_Name_Buffer --
1483 -------------------------
1485 procedure Set_Msg_Name_Buffer is
1486 begin
1487 Set_Msg_Str (Name_Buffer (1 .. Name_Len));
1488 Destroy_Global_Name_Buffer;
1489 end Set_Msg_Name_Buffer;
1491 -------------------
1492 -- Set_Msg_Quote --
1493 -------------------
1495 procedure Set_Msg_Quote is
1496 begin
1497 if not Manual_Quote_Mode then
1498 Set_Msg_Char ('"');
1499 end if;
1500 end Set_Msg_Quote;
1502 -----------------
1503 -- Set_Msg_Str --
1504 -----------------
1506 procedure Set_Msg_Str (Text : String) is
1507 begin
1508 -- Do replacement for special x'Class aspect names
1510 if Text = "_Pre" then
1511 Set_Msg_Str ("Pre'Class");
1513 elsif Text = "_Post" then
1514 Set_Msg_Str ("Post'Class");
1516 elsif Text = "_Type_Invariant" then
1517 Set_Msg_Str ("Type_Invariant'Class");
1519 elsif Text = "_pre" then
1520 Set_Msg_Str ("pre'class");
1522 elsif Text = "_post" then
1523 Set_Msg_Str ("post'class");
1525 elsif Text = "_type_invariant" then
1526 Set_Msg_Str ("type_invariant'class");
1528 elsif Text = "_PRE" then
1529 Set_Msg_Str ("PRE'CLASS");
1531 elsif Text = "_POST" then
1532 Set_Msg_Str ("POST'CLASS");
1534 elsif Text = "_TYPE_INVARIANT" then
1535 Set_Msg_Str ("TYPE_INVARIANT'CLASS");
1537 -- Normal case with no replacement
1539 else
1540 for J in Text'Range loop
1541 Set_Msg_Char (Text (J));
1542 end loop;
1543 end if;
1544 end Set_Msg_Str;
1546 ------------------------------
1547 -- Set_Next_Non_Deleted_Msg --
1548 ------------------------------
1550 procedure Set_Next_Non_Deleted_Msg (E : in out Error_Msg_Id) is
1551 begin
1552 if E = No_Error_Msg then
1553 return;
1555 else
1556 loop
1557 E := Errors.Table (E).Next;
1558 exit when E = No_Error_Msg or else not Errors.Table (E).Deleted;
1559 end loop;
1560 end if;
1561 end Set_Next_Non_Deleted_Msg;
1563 ------------------------------
1564 -- Set_Specific_Warning_Off --
1565 ------------------------------
1567 procedure Set_Specific_Warning_Off
1568 (Loc : Source_Ptr;
1569 Msg : String;
1570 Reason : String_Id;
1571 Config : Boolean;
1572 Used : Boolean := False)
1574 begin
1575 Specific_Warnings.Append
1576 ((Start => Loc,
1577 Msg => new String'(Msg),
1578 Stop => Source_Last (Get_Source_File_Index (Loc)),
1579 Reason => Reason,
1580 Open => True,
1581 Used => Used,
1582 Config => Config));
1583 end Set_Specific_Warning_Off;
1585 -----------------------------
1586 -- Set_Specific_Warning_On --
1587 -----------------------------
1589 procedure Set_Specific_Warning_On
1590 (Loc : Source_Ptr;
1591 Msg : String;
1592 Err : out Boolean)
1594 begin
1595 for J in 1 .. Specific_Warnings.Last loop
1596 declare
1597 SWE : Specific_Warning_Entry renames Specific_Warnings.Table (J);
1599 begin
1600 if Msg = SWE.Msg.all
1601 and then Loc > SWE.Start
1602 and then SWE.Open
1603 and then Get_Source_File_Index (SWE.Start) =
1604 Get_Source_File_Index (Loc)
1605 then
1606 SWE.Stop := Loc;
1607 SWE.Open := False;
1608 Err := False;
1610 -- If a config pragma is specifically cancelled, consider
1611 -- that it is no longer active as a configuration pragma.
1613 SWE.Config := False;
1614 return;
1615 end if;
1616 end;
1617 end loop;
1619 Err := True;
1620 end Set_Specific_Warning_On;
1622 ---------------------------
1623 -- Set_Warnings_Mode_Off --
1624 ---------------------------
1626 procedure Set_Warnings_Mode_Off (Loc : Source_Ptr; Reason : String_Id) is
1627 begin
1628 -- Don't bother with entries from instantiation copies, since we will
1629 -- already have a copy in the template, which is what matters.
1631 if Instantiation (Get_Source_File_Index (Loc)) /= No_Location then
1632 return;
1633 end if;
1635 -- If all warnings are suppressed by command line switch, this can
1636 -- be ignored, unless we are in GNATprove_Mode which requires pragma
1637 -- Warnings to be stored for the formal verification backend.
1639 if Warning_Mode = Suppress
1640 and then not GNATprove_Mode
1641 then
1642 return;
1643 end if;
1645 -- If last entry in table already covers us, this is a redundant pragma
1646 -- Warnings (Off) and can be ignored.
1648 if Warnings.Last >= Warnings.First
1649 and then Warnings.Table (Warnings.Last).Start <= Loc
1650 and then Loc <= Warnings.Table (Warnings.Last).Stop
1651 then
1652 return;
1653 end if;
1655 -- If none of those special conditions holds, establish a new entry,
1656 -- extending from the location of the pragma to the end of the current
1657 -- source file. This ending point will be adjusted by a subsequent
1658 -- corresponding pragma Warnings (On).
1660 Warnings.Append
1661 ((Start => Loc,
1662 Stop => Source_Last (Get_Source_File_Index (Loc)),
1663 Reason => Reason));
1664 end Set_Warnings_Mode_Off;
1666 --------------------------
1667 -- Set_Warnings_Mode_On --
1668 --------------------------
1670 procedure Set_Warnings_Mode_On (Loc : Source_Ptr) is
1671 begin
1672 -- Don't bother with entries from instantiation copies, since we will
1673 -- already have a copy in the template, which is what matters.
1675 if Instantiation (Get_Source_File_Index (Loc)) /= No_Location then
1676 return;
1677 end if;
1679 -- If all warnings are suppressed by command line switch, this can
1680 -- be ignored, unless we are in GNATprove_Mode which requires pragma
1681 -- Warnings to be stored for the formal verification backend.
1683 if Warning_Mode = Suppress
1684 and then not GNATprove_Mode
1685 then
1686 return;
1687 end if;
1689 -- If the last entry in the warnings table covers this pragma, then
1690 -- we adjust the end point appropriately.
1692 if Warnings.Last >= Warnings.First
1693 and then Warnings.Table (Warnings.Last).Start <= Loc
1694 and then Loc <= Warnings.Table (Warnings.Last).Stop
1695 then
1696 Warnings.Table (Warnings.Last).Stop := Loc;
1697 end if;
1698 end Set_Warnings_Mode_On;
1700 -------------------
1701 -- Sloc_In_Range --
1702 -------------------
1704 function Sloc_In_Range (Loc, Start, Stop : Source_Ptr) return Boolean is
1705 Cur_Loc : Source_Ptr := Loc;
1707 begin
1708 while Cur_Loc /= No_Location loop
1709 if Start <= Cur_Loc and then Cur_Loc <= Stop then
1710 return True;
1711 end if;
1713 Cur_Loc := Instantiation_Location (Cur_Loc);
1714 end loop;
1716 return False;
1717 end Sloc_In_Range;
1719 --------------------------------
1720 -- Validate_Specific_Warnings --
1721 --------------------------------
1723 procedure Validate_Specific_Warnings (Eproc : Error_Msg_Proc) is
1724 begin
1725 if not Warn_On_Warnings_Off then
1726 return;
1727 end if;
1729 for J in Specific_Warnings.First .. Specific_Warnings.Last loop
1730 declare
1731 SWE : Specific_Warning_Entry renames Specific_Warnings.Table (J);
1733 begin
1734 if not SWE.Config then
1736 -- Warn for unmatched Warnings (Off, ...)
1738 if SWE.Open then
1739 Eproc.all
1740 ("?.w?pragma Warnings Off with no matching Warnings On",
1741 SWE.Start);
1743 -- Warn for ineffective Warnings (Off, ..)
1745 elsif not SWE.Used
1747 -- Do not issue this warning for -Wxxx messages since the
1748 -- back-end doesn't report the information. Note that there
1749 -- is always an asterisk at the start of every message.
1751 and then not
1752 (SWE.Msg'Length > 3 and then SWE.Msg (2 .. 3) = "-W")
1753 then
1754 Eproc.all
1755 ("?.w?no warning suppressed by this pragma", SWE.Start);
1756 end if;
1757 end if;
1758 end;
1759 end loop;
1760 end Validate_Specific_Warnings;
1762 -------------------------------------
1763 -- Warning_Specifically_Suppressed --
1764 -------------------------------------
1766 function Warning_Specifically_Suppressed
1767 (Loc : Source_Ptr;
1768 Msg : String_Ptr;
1769 Tag : String := "") return String_Id
1771 begin
1772 -- Loop through specific warning suppression entries
1774 for J in Specific_Warnings.First .. Specific_Warnings.Last loop
1775 declare
1776 SWE : Specific_Warning_Entry renames Specific_Warnings.Table (J);
1778 begin
1779 -- Pragma applies if it is a configuration pragma, or if the
1780 -- location is in range of a specific non-configuration pragma.
1782 if SWE.Config
1783 or else Sloc_In_Range (Loc, SWE.Start, SWE.Stop)
1784 then
1785 if Matches (Msg.all, SWE.Msg.all)
1786 or else Matches (Tag, SWE.Msg.all)
1787 then
1788 SWE.Used := True;
1789 return SWE.Reason;
1790 end if;
1791 end if;
1792 end;
1793 end loop;
1795 return No_String;
1796 end Warning_Specifically_Suppressed;
1798 ------------------------------
1799 -- Warning_Treated_As_Error --
1800 ------------------------------
1802 function Warning_Treated_As_Error (Msg : String) return Boolean is
1803 begin
1804 for J in 1 .. Warnings_As_Errors_Count loop
1805 if Matches (Msg, Warnings_As_Errors (J).all) then
1806 return True;
1807 end if;
1808 end loop;
1810 return False;
1811 end Warning_Treated_As_Error;
1813 -------------------------
1814 -- Warnings_Suppressed --
1815 -------------------------
1817 function Warnings_Suppressed (Loc : Source_Ptr) return String_Id is
1818 begin
1819 -- Loop through table of ON/OFF warnings
1821 for J in Warnings.First .. Warnings.Last loop
1822 if Sloc_In_Range (Loc, Warnings.Table (J).Start,
1823 Warnings.Table (J).Stop)
1824 then
1825 return Warnings.Table (J).Reason;
1826 end if;
1827 end loop;
1829 if Warning_Mode = Suppress then
1830 return Null_String_Id;
1831 else
1832 return No_String;
1833 end if;
1834 end Warnings_Suppressed;
1836 end Erroutc;