14e2aad8b30071c920f6da64ee4fb48e4910658f
[gcc.git] / gcc / ada / erroutc.adb
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-2020, 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 ------------------------------------------------------------------------------
25
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.
31
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;
47
48 package body Erroutc is
49
50 -----------------------
51 -- Local Subprograms --
52 -----------------------
53
54 function Matches (S : String; P : String) return Boolean;
55 -- Returns true if the String S patches the pattern P, which can contain
56 -- wildcard chars (*). The entire pattern must match the entire string.
57 -- Case is ignored in the comparison (so X matches x).
58
59 function Sloc_In_Range (Loc, Start, Stop : Source_Ptr) return Boolean;
60 -- Return whether Loc is in the range Start .. Stop, taking instantiation
61 -- locations of Loc into account. This is useful for suppressing warnings
62 -- from generic instantiations by using pragma Warnings around generic
63 -- instances, as needed in GNATprove.
64
65 ---------------
66 -- Add_Class --
67 ---------------
68
69 procedure Add_Class is
70 begin
71 if Class_Flag then
72 Class_Flag := False;
73 Set_Msg_Char (''');
74 Get_Name_String (Name_Class);
75 Set_Casing (Identifier_Casing (Flag_Source));
76 Set_Msg_Name_Buffer;
77 end if;
78 end Add_Class;
79
80 ----------------------
81 -- Buffer_Ends_With --
82 ----------------------
83
84 function Buffer_Ends_With (C : Character) return Boolean is
85 begin
86 return Msglen > 0 and then Msg_Buffer (Msglen) = C;
87 end Buffer_Ends_With;
88
89 function Buffer_Ends_With (S : String) return Boolean is
90 Len : constant Natural := S'Length;
91 begin
92 return Msglen > Len
93 and then Msg_Buffer (Msglen - Len) = ' '
94 and then Msg_Buffer (Msglen - Len + 1 .. Msglen) = S;
95 end Buffer_Ends_With;
96
97 -------------------
98 -- Buffer_Remove --
99 -------------------
100
101 procedure Buffer_Remove (C : Character) is
102 begin
103 if Buffer_Ends_With (C) then
104 Msglen := Msglen - 1;
105 end if;
106 end Buffer_Remove;
107
108 procedure Buffer_Remove (S : String) is
109 begin
110 if Buffer_Ends_With (S) then
111 Msglen := Msglen - S'Length;
112 end if;
113 end Buffer_Remove;
114
115 -----------------------------
116 -- Check_Duplicate_Message --
117 -----------------------------
118
119 procedure Check_Duplicate_Message (M1, M2 : Error_Msg_Id) is
120 L1, L2 : Error_Msg_Id;
121 N1, N2 : Error_Msg_Id;
122
123 procedure Delete_Msg (Delete, Keep : Error_Msg_Id);
124 -- Called to delete message Delete, keeping message Keep. Marks msg
125 -- Delete and all its continuations with deleted flag set to True.
126 -- Also makes sure that for the error messages that are retained the
127 -- preferred message is the one retained (we prefer the shorter one in
128 -- the case where one has an Instance tag). Note that we always know
129 -- that Keep has at least as many continuations as Delete (since we
130 -- always delete the shorter sequence).
131
132 ----------------
133 -- Delete_Msg --
134 ----------------
135
136 procedure Delete_Msg (Delete, Keep : Error_Msg_Id) is
137 D, K : Error_Msg_Id;
138
139 begin
140 D := Delete;
141 K := Keep;
142
143 loop
144 Errors.Table (D).Deleted := True;
145
146 -- Adjust error message count
147
148 if Errors.Table (D).Info then
149
150 if Errors.Table (D).Warn then
151 Warning_Info_Messages := Warning_Info_Messages - 1;
152 Warnings_Detected := Warnings_Detected - 1;
153 else
154 Report_Info_Messages := Report_Info_Messages - 1;
155 end if;
156
157 elsif Errors.Table (D).Warn or else Errors.Table (D).Style then
158 Warnings_Detected := Warnings_Detected - 1;
159
160 -- Note: we do not need to decrement Warnings_Treated_As_Errors
161 -- because this only gets incremented if we actually output the
162 -- message, which we won't do if we are deleting it here!
163
164 elsif Errors.Table (D).Check then
165 Check_Messages := Check_Messages - 1;
166
167 else
168 Total_Errors_Detected := Total_Errors_Detected - 1;
169
170 if Errors.Table (D).Serious then
171 Serious_Errors_Detected := Serious_Errors_Detected - 1;
172 end if;
173 end if;
174
175 -- Substitute shorter of the two error messages
176
177 if Errors.Table (K).Text'Length > Errors.Table (D).Text'Length then
178 Errors.Table (K).Text := Errors.Table (D).Text;
179 end if;
180
181 D := Errors.Table (D).Next;
182 K := Errors.Table (K).Next;
183
184 if D = No_Error_Msg or else not Errors.Table (D).Msg_Cont then
185 return;
186 end if;
187 end loop;
188 end Delete_Msg;
189
190 -- Start of processing for Check_Duplicate_Message
191
192 begin
193 -- Both messages must be non-continuation messages and not deleted
194
195 if Errors.Table (M1).Msg_Cont
196 or else Errors.Table (M2).Msg_Cont
197 or else Errors.Table (M1).Deleted
198 or else Errors.Table (M2).Deleted
199 then
200 return;
201 end if;
202
203 -- Definitely not equal if message text does not match
204
205 if not Same_Error (M1, M2) then
206 return;
207 end if;
208
209 -- Same text. See if all continuations are also identical
210
211 L1 := M1;
212 L2 := M2;
213
214 loop
215 N1 := Errors.Table (L1).Next;
216 N2 := Errors.Table (L2).Next;
217
218 -- If M1 continuations have run out, we delete M1, either the
219 -- messages have the same number of continuations, or M2 has
220 -- more and we prefer the one with more anyway.
221
222 if N1 = No_Error_Msg or else not Errors.Table (N1).Msg_Cont then
223 Delete_Msg (M1, M2);
224 return;
225
226 -- If M2 continuations have run out, we delete M2
227
228 elsif N2 = No_Error_Msg or else not Errors.Table (N2).Msg_Cont then
229 Delete_Msg (M2, M1);
230 return;
231
232 -- Otherwise see if continuations are the same, if not, keep both
233 -- sequences, a curious case, but better to keep everything.
234
235 elsif not Same_Error (N1, N2) then
236 return;
237
238 -- If continuations are the same, continue scan
239
240 else
241 L1 := N1;
242 L2 := N2;
243 end if;
244 end loop;
245 end Check_Duplicate_Message;
246
247 ------------------------
248 -- Compilation_Errors --
249 ------------------------
250
251 function Compilation_Errors return Boolean is
252 Warnings_Count : constant Int
253 := Warnings_Detected - Warning_Info_Messages;
254 begin
255 if Total_Errors_Detected /= 0 then
256 return True;
257
258 elsif Warnings_Treated_As_Errors /= 0 then
259 return True;
260
261 -- We should never treat warnings that originate from a
262 -- Compile_Time_Warning pragma as an error. Warnings_Count is the sum
263 -- of both "normal" and Compile_Time_Warning warnings. This means
264 -- that there only is one or more non-Compile_Time_Warning warnings
265 -- if Warnings_Count is greater than
266 -- Count_Compile_Time_Pragma_Warnings.
267 elsif Warning_Mode = Treat_As_Error
268 and then Warnings_Count > Count_Compile_Time_Pragma_Warnings
269 then
270 return True;
271 end if;
272
273 return False;
274 end Compilation_Errors;
275
276 ----------------------------------------
277 -- Count_Compile_Time_Pragma_Warnings --
278 ----------------------------------------
279
280 function Count_Compile_Time_Pragma_Warnings return Int is
281 Result : Int := 0;
282 begin
283 for J in 1 .. Errors.Last loop
284 begin
285 if Errors.Table (J).Warn and Errors.Table (J).Compile_Time_Pragma
286 then
287 Result := Result + 1;
288 end if;
289 end;
290 end loop;
291 return Result;
292 end Count_Compile_Time_Pragma_Warnings;
293
294 ------------------
295 -- Debug_Output --
296 ------------------
297
298 procedure Debug_Output (N : Node_Id) is
299 begin
300 if Debug_Flag_1 then
301 Write_Str ("*** following error message posted on node id = #");
302 Write_Int (Int (N));
303 Write_Str (" ***");
304 Write_Eol;
305 end if;
306 end Debug_Output;
307
308 ----------
309 -- dmsg --
310 ----------
311
312 procedure dmsg (Id : Error_Msg_Id) is
313 E : Error_Msg_Object renames Errors.Table (Id);
314
315 begin
316 w ("Dumping error message, Id = ", Int (Id));
317 w (" Text = ", E.Text.all);
318 w (" Next = ", Int (E.Next));
319 w (" Prev = ", Int (E.Prev));
320 w (" Sfile = ", Int (E.Sfile));
321
322 Write_Str
323 (" Sptr = ");
324 Write_Location (E.Sptr);
325 Write_Eol;
326
327 Write_Str
328 (" Optr = ");
329 Write_Location (E.Optr);
330 Write_Eol;
331
332 w (" Line = ", Int (E.Line));
333 w (" Col = ", Int (E.Col));
334 w (" Warn = ", E.Warn);
335 w (" Warn_Err = ", E.Warn_Err);
336 w (" Warn_Chr = '" & E.Warn_Chr & ''');
337 w (" Style = ", E.Style);
338 w (" Serious = ", E.Serious);
339 w (" Uncond = ", E.Uncond);
340 w (" Msg_Cont = ", E.Msg_Cont);
341 w (" Deleted = ", E.Deleted);
342 w (" Node = ", Int (E.Node));
343
344 Write_Eol;
345 end dmsg;
346
347 ------------------
348 -- Get_Location --
349 ------------------
350
351 function Get_Location (E : Error_Msg_Id) return Source_Ptr is
352 begin
353 return Errors.Table (E).Sptr;
354 end Get_Location;
355
356 ----------------
357 -- Get_Msg_Id --
358 ----------------
359
360 function Get_Msg_Id return Error_Msg_Id is
361 begin
362 return Cur_Msg;
363 end Get_Msg_Id;
364
365 ---------------------
366 -- Get_Warning_Tag --
367 ---------------------
368
369 function Get_Warning_Tag (Id : Error_Msg_Id) return String is
370 Warn : constant Boolean := Errors.Table (Id).Warn;
371 Warn_Chr : constant Character := Errors.Table (Id).Warn_Chr;
372 begin
373 if Warn and then Warn_Chr /= ' ' then
374 if Warn_Chr = '?' then
375 return "[enabled by default]";
376 elsif Warn_Chr = '*' then
377 return "[restriction warning]";
378 elsif Warn_Chr = '$' then
379 return "[-gnatel]";
380 elsif Warn_Chr in 'a' .. 'z' then
381 return "[-gnatw" & Warn_Chr & ']';
382 else pragma Assert (Warn_Chr in 'A' .. 'Z');
383 return "[-gnatw." & Fold_Lower (Warn_Chr) & ']';
384 end if;
385 else
386 return "";
387 end if;
388 end Get_Warning_Tag;
389
390 -------------
391 -- Matches --
392 -------------
393
394 function Matches (S : String; P : String) return Boolean is
395 Slast : constant Natural := S'Last;
396 PLast : constant Natural := P'Last;
397
398 SPtr : Natural := S'First;
399 PPtr : Natural := P'First;
400
401 begin
402 -- Loop advancing through characters of string and pattern
403
404 SPtr := S'First;
405 PPtr := P'First;
406 loop
407 -- Return True if pattern is a single asterisk
408
409 if PPtr = PLast and then P (PPtr) = '*' then
410 return True;
411
412 -- Return True if both pattern and string exhausted
413
414 elsif PPtr > PLast and then SPtr > Slast then
415 return True;
416
417 -- Return False, if one exhausted and not the other
418
419 elsif PPtr > PLast or else SPtr > Slast then
420 return False;
421
422 -- Case where pattern starts with asterisk
423
424 elsif P (PPtr) = '*' then
425
426 -- Try all possible starting positions in S for match with the
427 -- remaining characters of the pattern. This is the recursive
428 -- call that implements the scanner backup.
429
430 for J in SPtr .. Slast loop
431 if Matches (S (J .. Slast), P (PPtr + 1 .. PLast)) then
432 return True;
433 end if;
434 end loop;
435
436 return False;
437
438 -- Dealt with end of string and *, advance if we have a match
439
440 elsif Fold_Lower (S (SPtr)) = Fold_Lower (P (PPtr)) then
441 SPtr := SPtr + 1;
442 PPtr := PPtr + 1;
443
444 -- If first characters do not match, that's decisive
445
446 else
447 return False;
448 end if;
449 end loop;
450 end Matches;
451
452 -----------------------
453 -- Output_Error_Msgs --
454 -----------------------
455
456 procedure Output_Error_Msgs (E : in out Error_Msg_Id) is
457 P : Source_Ptr;
458 T : Error_Msg_Id;
459 S : Error_Msg_Id;
460
461 Flag_Num : Pos;
462 Mult_Flags : Boolean := False;
463
464 begin
465 S := E;
466
467 -- Skip deleted messages at start
468
469 if Errors.Table (S).Deleted then
470 Set_Next_Non_Deleted_Msg (S);
471 end if;
472
473 -- Figure out if we will place more than one error flag on this line
474
475 T := S;
476 while T /= No_Error_Msg
477 and then Errors.Table (T).Line = Errors.Table (E).Line
478 and then Errors.Table (T).Sfile = Errors.Table (E).Sfile
479 loop
480 if Errors.Table (T).Sptr > Errors.Table (E).Sptr then
481 Mult_Flags := True;
482 end if;
483
484 Set_Next_Non_Deleted_Msg (T);
485 end loop;
486
487 -- Output the error flags. The circuit here makes sure that the tab
488 -- characters in the original line are properly accounted for. The
489 -- eight blanks at the start are to match the line number.
490
491 if not Debug_Flag_2 then
492 Write_Str (" ");
493 P := Line_Start (Errors.Table (E).Sptr);
494 Flag_Num := 1;
495
496 -- Loop through error messages for this line to place flags
497
498 T := S;
499 while T /= No_Error_Msg
500 and then Errors.Table (T).Line = Errors.Table (E).Line
501 and then Errors.Table (T).Sfile = Errors.Table (E).Sfile
502 loop
503 declare
504 Src : Source_Buffer_Ptr
505 renames Source_Text (Errors.Table (T).Sfile);
506
507 begin
508 -- Loop to output blanks till current flag position
509
510 while P < Errors.Table (T).Sptr loop
511
512 -- Horizontal tab case, just echo the tab
513
514 if Src (P) = ASCII.HT then
515 Write_Char (ASCII.HT);
516 P := P + 1;
517
518 -- Deal with wide character case, but don't include brackets
519 -- notation in this circuit, since we know that this will
520 -- display unencoded (no one encodes brackets notation).
521
522 elsif Src (P) /= '['
523 and then Is_Start_Of_Wide_Char (Src, P)
524 then
525 Skip_Wide (Src, P);
526 Write_Char (' ');
527
528 -- Normal non-wide character case (or bracket)
529
530 else
531 P := P + 1;
532 Write_Char (' ');
533 end if;
534 end loop;
535
536 -- Output flag (unless already output, this happens if more
537 -- than one error message occurs at the same flag position).
538
539 if P = Errors.Table (T).Sptr then
540 if (Flag_Num = 1 and then not Mult_Flags)
541 or else Flag_Num > 9
542 then
543 Write_Char ('|');
544 else
545 Write_Char
546 (Character'Val (Character'Pos ('0') + Flag_Num));
547 end if;
548
549 -- Skip past the corresponding source text character
550
551 -- Horizontal tab case, we output a flag at the tab position
552 -- so now we output a tab to match up with the text.
553
554 if Src (P) = ASCII.HT then
555 Write_Char (ASCII.HT);
556 P := P + 1;
557
558 -- Skip wide character other than left bracket
559
560 elsif Src (P) /= '['
561 and then Is_Start_Of_Wide_Char (Src, P)
562 then
563 Skip_Wide (Src, P);
564
565 -- Skip normal non-wide character case (or bracket)
566
567 else
568 P := P + 1;
569 end if;
570 end if;
571 end;
572
573 Set_Next_Non_Deleted_Msg (T);
574 Flag_Num := Flag_Num + 1;
575 end loop;
576
577 Write_Eol;
578 end if;
579
580 -- Now output the error messages
581
582 T := S;
583 while T /= No_Error_Msg
584 and then Errors.Table (T).Line = Errors.Table (E).Line
585 and then Errors.Table (T).Sfile = Errors.Table (E).Sfile
586 loop
587 Write_Str (" >>> ");
588 Output_Msg_Text (T);
589
590 if Debug_Flag_2 then
591 while Column < 74 loop
592 Write_Char (' ');
593 end loop;
594
595 Write_Str (" <<<");
596 end if;
597
598 Write_Eol;
599 Set_Next_Non_Deleted_Msg (T);
600 end loop;
601
602 E := T;
603 end Output_Error_Msgs;
604
605 ------------------------
606 -- Output_Line_Number --
607 ------------------------
608
609 procedure Output_Line_Number (L : Logical_Line_Number) is
610 D : Int; -- next digit
611 C : Character; -- next character
612 Z : Boolean; -- flag for zero suppress
613 N, M : Int; -- temporaries
614
615 begin
616 if L = No_Line_Number then
617 Write_Str (" ");
618
619 else
620 Z := False;
621 N := Int (L);
622
623 M := 100_000;
624 while M /= 0 loop
625 D := Int (N / M);
626 N := N rem M;
627 M := M / 10;
628
629 if D = 0 then
630 if Z then
631 C := '0';
632 else
633 C := ' ';
634 end if;
635 else
636 Z := True;
637 C := Character'Val (D + 48);
638 end if;
639
640 Write_Char (C);
641 end loop;
642
643 Write_Str (". ");
644 end if;
645 end Output_Line_Number;
646
647 ---------------------
648 -- Output_Msg_Text --
649 ---------------------
650
651 procedure Output_Msg_Text (E : Error_Msg_Id) is
652 Offs : constant Nat := Column - 1;
653 -- Offset to start of message, used for continuations
654
655 Max : Integer;
656 -- Maximum characters to output on next line
657
658 Length : Nat;
659 -- Maximum total length of lines
660
661 E_Msg : Error_Msg_Object renames Errors.Table (E);
662 Text : constant String_Ptr := E_Msg.Text;
663 Ptr : Natural;
664 Split : Natural;
665 Start : Natural;
666 Tag : constant String := Get_Warning_Tag (E);
667 Txt : String_Ptr;
668 Len : Natural;
669
670 begin
671 -- Postfix warning tag to message if needed
672
673 if Tag /= "" and then Warning_Doc_Switch then
674 if Include_Subprogram_In_Messages then
675 Txt :=
676 new String'
677 (Subprogram_Name_Ptr (E_Msg.Node) &
678 ": " & Text.all & ' ' & Tag);
679 else
680 Txt := new String'(Text.all & ' ' & Tag);
681 end if;
682
683 elsif Include_Subprogram_In_Messages
684 and then (E_Msg.Warn or else E_Msg.Style)
685 then
686 Txt :=
687 new String'(Subprogram_Name_Ptr (E_Msg.Node) & ": " & Text.all);
688 else
689 Txt := Text;
690 end if;
691
692 -- For info messages, prefix message with "info: "
693
694 if E_Msg.Info then
695 Txt := new String'("info: " & Txt.all);
696
697 -- Warning treated as error
698
699 elsif E_Msg.Warn_Err then
700
701 -- We prefix with "error:" rather than warning: and postfix
702 -- [warning-as-error] at the end.
703
704 Warnings_Treated_As_Errors := Warnings_Treated_As_Errors + 1;
705 Txt := new String'("error: " & Txt.all & " [warning-as-error]");
706
707 -- Normal warning, prefix with "warning: "
708
709 elsif E_Msg.Warn then
710 Txt := new String'("warning: " & Txt.all);
711
712 -- No prefix needed for style message, "(style)" is there already
713
714 elsif E_Msg.Style then
715 null;
716
717 -- No prefix needed for check message, severity is there already
718
719 elsif E_Msg.Check then
720 null;
721
722 -- All other cases, add "error: " if unique error tag set
723
724 elsif Opt.Unique_Error_Tag then
725 Txt := new String'("error: " & Txt.all);
726 end if;
727
728 -- Set error message line length and length of message
729
730 if Error_Msg_Line_Length = 0 then
731 Length := Nat'Last;
732 else
733 Length := Error_Msg_Line_Length;
734 end if;
735
736 Max := Integer (Length - Column + 1);
737 Len := Txt'Length;
738
739 -- Here we have to split the message up into multiple lines
740
741 Ptr := 1;
742 loop
743 -- Make sure we do not have ludicrously small line
744
745 Max := Integer'Max (Max, 20);
746
747 -- If remaining text fits, output it respecting LF and we are done
748
749 if Len - Ptr < Max then
750 for J in Ptr .. Len loop
751 if Txt (J) = ASCII.LF then
752 Write_Eol;
753 Write_Spaces (Offs);
754 else
755 Write_Char (Txt (J));
756 end if;
757 end loop;
758
759 return;
760
761 -- Line does not fit
762
763 else
764 Start := Ptr;
765
766 -- First scan forward looking for a hard end of line
767
768 for Scan in Ptr .. Ptr + Max - 1 loop
769 if Txt (Scan) = ASCII.LF then
770 Split := Scan - 1;
771 Ptr := Scan + 1;
772 goto Continue;
773 end if;
774 end loop;
775
776 -- Otherwise scan backwards looking for a space
777
778 for Scan in reverse Ptr .. Ptr + Max - 1 loop
779 if Txt (Scan) = ' ' then
780 Split := Scan - 1;
781 Ptr := Scan + 1;
782 goto Continue;
783 end if;
784 end loop;
785
786 -- If we fall through, no space, so split line arbitrarily
787
788 Split := Ptr + Max - 1;
789 Ptr := Split + 1;
790 end if;
791
792 <<Continue>>
793 if Start <= Split then
794 Write_Line (Txt (Start .. Split));
795 Write_Spaces (Offs);
796 end if;
797
798 Max := Integer (Length - Column + 1);
799 end loop;
800 end Output_Msg_Text;
801
802 ---------------------
803 -- Prescan_Message --
804 ---------------------
805
806 procedure Prescan_Message (Msg : String) is
807 J : Natural;
808
809 begin
810 -- Nothing to do for continuation line
811
812 if Msg (Msg'First) = '\' then
813 return;
814 end if;
815
816 -- Set initial values of globals (may be changed during scan)
817
818 Is_Serious_Error := True;
819 Is_Unconditional_Msg := False;
820 Is_Warning_Msg := False;
821 Has_Double_Exclam := False;
822
823 -- Check style message
824
825 Is_Style_Msg :=
826 Msg'Length > 7 and then Msg (Msg'First .. Msg'First + 6) = "(style)";
827
828 -- Check info message
829
830 Is_Info_Msg :=
831 Msg'Length > 6 and then Msg (Msg'First .. Msg'First + 5) = "info: ";
832
833 -- Check check message
834
835 Is_Check_Msg :=
836 (Msg'Length > 8 and then Msg (Msg'First .. Msg'First + 7) = "medium: ")
837 or else
838 (Msg'Length > 6 and then Msg (Msg'First .. Msg'First + 5) = "high: ")
839 or else
840 (Msg'Length > 5 and then Msg (Msg'First .. Msg'First + 4) = "low: ");
841
842 -- Loop through message looking for relevant insertion sequences
843
844 J := Msg'First;
845 while J <= Msg'Last loop
846
847 -- If we have a quote, don't look at following character
848
849 if Msg (J) = ''' then
850 J := J + 2;
851
852 -- Warning message (? or < insertion sequence)
853
854 elsif Msg (J) = '?' or else Msg (J) = '<' then
855 Is_Warning_Msg := Msg (J) = '?' or else Error_Msg_Warn;
856 Warning_Msg_Char := ' ';
857 J := J + 1;
858
859 if Is_Warning_Msg then
860 declare
861 C : constant Character := Msg (J - 1);
862 begin
863 if J <= Msg'Last then
864 if Msg (J) = C then
865 Warning_Msg_Char := '?';
866 J := J + 1;
867
868 elsif J < Msg'Last and then Msg (J + 1) = C
869 and then (Msg (J) in 'a' .. 'z' or else
870 Msg (J) in 'A' .. 'Z' or else
871 Msg (J) = '*' or else
872 Msg (J) = '$')
873 then
874 Warning_Msg_Char := Msg (J);
875 J := J + 2;
876 end if;
877 end if;
878 end;
879 end if;
880
881 -- Bomb if untagged warning message. This code can be uncommented
882 -- for debugging when looking for untagged warning messages.
883
884 -- if Is_Warning_Msg and then Warning_Msg_Char = ' ' then
885 -- raise Program_Error;
886 -- end if;
887
888 -- Unconditional message (! insertion)
889
890 elsif Msg (J) = '!' then
891 Is_Unconditional_Msg := True;
892 J := J + 1;
893
894 if J <= Msg'Last and then Msg (J) = '!' then
895 Has_Double_Exclam := True;
896 J := J + 1;
897 end if;
898
899 -- Non-serious error (| insertion)
900
901 elsif Msg (J) = '|' then
902 Is_Serious_Error := False;
903 J := J + 1;
904
905 else
906 J := J + 1;
907 end if;
908 end loop;
909
910 if Is_Info_Msg or Is_Warning_Msg or Is_Style_Msg or Is_Check_Msg then
911 Is_Serious_Error := False;
912 end if;
913 end Prescan_Message;
914
915 --------------------
916 -- Purge_Messages --
917 --------------------
918
919 procedure Purge_Messages (From : Source_Ptr; To : Source_Ptr) is
920 E : Error_Msg_Id;
921
922 function To_Be_Purged (E : Error_Msg_Id) return Boolean;
923 -- Returns True for a message that is to be purged. Also adjusts
924 -- error counts appropriately.
925
926 ------------------
927 -- To_Be_Purged --
928 ------------------
929
930 function To_Be_Purged (E : Error_Msg_Id) return Boolean is
931 begin
932 if E /= No_Error_Msg
933 and then Errors.Table (E).Sptr > From
934 and then Errors.Table (E).Sptr < To
935 then
936 if Errors.Table (E).Warn or else Errors.Table (E).Style then
937 Warnings_Detected := Warnings_Detected - 1;
938
939 else
940 Total_Errors_Detected := Total_Errors_Detected - 1;
941
942 if Errors.Table (E).Serious then
943 Serious_Errors_Detected := Serious_Errors_Detected - 1;
944 end if;
945 end if;
946
947 return True;
948
949 else
950 return False;
951 end if;
952 end To_Be_Purged;
953
954 -- Start of processing for Purge_Messages
955
956 begin
957 while To_Be_Purged (First_Error_Msg) loop
958 First_Error_Msg := Errors.Table (First_Error_Msg).Next;
959 end loop;
960
961 E := First_Error_Msg;
962 while E /= No_Error_Msg loop
963 while To_Be_Purged (Errors.Table (E).Next) loop
964 Errors.Table (E).Next :=
965 Errors.Table (Errors.Table (E).Next).Next;
966 end loop;
967
968 E := Errors.Table (E).Next;
969 end loop;
970 end Purge_Messages;
971
972 ----------------
973 -- Same_Error --
974 ----------------
975
976 function Same_Error (M1, M2 : Error_Msg_Id) return Boolean is
977 Msg1 : constant String_Ptr := Errors.Table (M1).Text;
978 Msg2 : constant String_Ptr := Errors.Table (M2).Text;
979
980 Msg2_Len : constant Integer := Msg2'Length;
981 Msg1_Len : constant Integer := Msg1'Length;
982
983 begin
984 return
985 Msg1.all = Msg2.all
986 or else
987 (Msg1_Len - 10 > Msg2_Len
988 and then
989 Msg2.all = Msg1.all (1 .. Msg2_Len)
990 and then
991 Msg1 (Msg2_Len + 1 .. Msg2_Len + 10) = ", instance")
992 or else
993 (Msg2_Len - 10 > Msg1_Len
994 and then
995 Msg1.all = Msg2.all (1 .. Msg1_Len)
996 and then
997 Msg2 (Msg1_Len + 1 .. Msg1_Len + 10) = ", instance");
998 end Same_Error;
999
1000 -------------------
1001 -- Set_Msg_Blank --
1002 -------------------
1003
1004 procedure Set_Msg_Blank is
1005 begin
1006 if Msglen > 0
1007 and then Msg_Buffer (Msglen) /= ' '
1008 and then Msg_Buffer (Msglen) /= '('
1009 and then Msg_Buffer (Msglen) /= '-'
1010 and then not Manual_Quote_Mode
1011 then
1012 Set_Msg_Char (' ');
1013 end if;
1014 end Set_Msg_Blank;
1015
1016 -------------------------------
1017 -- Set_Msg_Blank_Conditional --
1018 -------------------------------
1019
1020 procedure Set_Msg_Blank_Conditional is
1021 begin
1022 if Msglen > 0
1023 and then Msg_Buffer (Msglen) /= ' '
1024 and then Msg_Buffer (Msglen) /= '('
1025 and then Msg_Buffer (Msglen) /= '"'
1026 and then not Manual_Quote_Mode
1027 then
1028 Set_Msg_Char (' ');
1029 end if;
1030 end Set_Msg_Blank_Conditional;
1031
1032 ------------------
1033 -- Set_Msg_Char --
1034 ------------------
1035
1036 procedure Set_Msg_Char (C : Character) is
1037 begin
1038
1039 -- The check for message buffer overflow is needed to deal with cases
1040 -- where insertions get too long (in particular a child unit name can
1041 -- be very long).
1042
1043 if Msglen < Max_Msg_Length then
1044 Msglen := Msglen + 1;
1045 Msg_Buffer (Msglen) := C;
1046 end if;
1047 end Set_Msg_Char;
1048
1049 ---------------------------------
1050 -- Set_Msg_Insertion_File_Name --
1051 ---------------------------------
1052
1053 procedure Set_Msg_Insertion_File_Name is
1054 begin
1055 if Error_Msg_File_1 = No_File then
1056 null;
1057
1058 elsif Error_Msg_File_1 = Error_File_Name then
1059 Set_Msg_Blank;
1060 Set_Msg_Str ("<error>");
1061
1062 else
1063 Set_Msg_Blank;
1064 Get_Name_String (Error_Msg_File_1);
1065 Set_Msg_Quote;
1066 Set_Msg_Name_Buffer;
1067 Set_Msg_Quote;
1068 end if;
1069
1070 -- The following assignments ensure that the second and third {
1071 -- insertion characters will correspond to the Error_Msg_File_2 and
1072 -- Error_Msg_File_3 values and We suppress possible validity checks in
1073 -- case operating in -gnatVa mode, and Error_Msg_File_2 or
1074 -- Error_Msg_File_3 is not needed and has not been set.
1075
1076 declare
1077 pragma Suppress (Range_Check);
1078 begin
1079 Error_Msg_File_1 := Error_Msg_File_2;
1080 Error_Msg_File_2 := Error_Msg_File_3;
1081 end;
1082 end Set_Msg_Insertion_File_Name;
1083
1084 -----------------------------------
1085 -- Set_Msg_Insertion_Line_Number --
1086 -----------------------------------
1087
1088 procedure Set_Msg_Insertion_Line_Number (Loc, Flag : Source_Ptr) is
1089 Sindex_Loc : Source_File_Index;
1090 Sindex_Flag : Source_File_Index;
1091 Fname : File_Name_Type;
1092 Int_File : Boolean;
1093
1094 procedure Set_At;
1095 -- Outputs "at " unless last characters in buffer are " from ". Certain
1096 -- messages read better with from than at.
1097
1098 ------------
1099 -- Set_At --
1100 ------------
1101
1102 procedure Set_At is
1103 begin
1104 if Msglen < 6
1105 or else Msg_Buffer (Msglen - 5 .. Msglen) /= " from "
1106 then
1107 Set_Msg_Str ("at ");
1108 end if;
1109 end Set_At;
1110
1111 -- Start of processing for Set_Msg_Insertion_Line_Number
1112
1113 begin
1114 Set_Msg_Blank;
1115
1116 if Loc = No_Location then
1117 Set_At;
1118 Set_Msg_Str ("unknown location");
1119
1120 elsif Loc = System_Location then
1121 Set_Msg_Str ("in package System");
1122 Set_Msg_Insertion_Run_Time_Name;
1123
1124 elsif Loc = Standard_Location then
1125 Set_Msg_Str ("in package Standard");
1126
1127 elsif Loc = Standard_ASCII_Location then
1128 Set_Msg_Str ("in package Standard.ASCII");
1129
1130 else
1131 -- Add "at file-name:" if reference is to other than the source
1132 -- file in which the error message is placed. Note that we check
1133 -- full file names, rather than just the source indexes, to
1134 -- deal with generic instantiations from the current file.
1135
1136 Sindex_Loc := Get_Source_File_Index (Loc);
1137 Sindex_Flag := Get_Source_File_Index (Flag);
1138
1139 if Full_File_Name (Sindex_Loc) /= Full_File_Name (Sindex_Flag) then
1140 Set_At;
1141 Fname := Reference_Name (Get_Source_File_Index (Loc));
1142 Int_File := Is_Internal_File_Name (Fname);
1143 Get_Name_String (Fname);
1144 Set_Msg_Name_Buffer;
1145
1146 if not (Int_File and Debug_Flag_Dot_K) then
1147 Set_Msg_Char (':');
1148 Set_Msg_Int (Int (Get_Logical_Line_Number (Loc)));
1149 end if;
1150
1151 -- If in current file, add text "at line "
1152
1153 else
1154 Set_At;
1155 Set_Msg_Str ("line ");
1156 Int_File := False;
1157 Set_Msg_Int (Int (Get_Logical_Line_Number (Loc)));
1158 end if;
1159
1160 -- Deal with the instantiation case. We may have a reference to,
1161 -- e.g. a type, that is declared within a generic template, and
1162 -- what we are really referring to is the occurrence in an instance.
1163 -- In this case, the line number of the instantiation is also of
1164 -- interest, and we add a notation:
1165
1166 -- , instance at xxx
1167
1168 -- where xxx is a line number output using this same routine (and
1169 -- the recursion can go further if the instantiation is itself in
1170 -- a generic template).
1171
1172 -- The flag location passed to us in this situation is indeed the
1173 -- line number within the template, but as described in Sinput.L
1174 -- (file sinput-l.ads, section "Handling Generic Instantiations")
1175 -- we can retrieve the location of the instantiation itself from
1176 -- this flag location value.
1177
1178 -- Note: this processing is suppressed if Suppress_Instance_Location
1179 -- is set True. This is used to prevent redundant annotations of the
1180 -- location of the instantiation in the case where we are placing
1181 -- the messages on the instantiation in any case.
1182
1183 if Instantiation (Sindex_Loc) /= No_Location
1184 and then not Suppress_Instance_Location
1185 then
1186 Set_Msg_Str (", instance ");
1187 Set_Msg_Insertion_Line_Number (Instantiation (Sindex_Loc), Flag);
1188 end if;
1189 end if;
1190 end Set_Msg_Insertion_Line_Number;
1191
1192 ----------------------------
1193 -- Set_Msg_Insertion_Name --
1194 ----------------------------
1195
1196 procedure Set_Msg_Insertion_Name is
1197 begin
1198 if Error_Msg_Name_1 = No_Name then
1199 null;
1200
1201 elsif Error_Msg_Name_1 = Error_Name then
1202 Set_Msg_Blank;
1203 Set_Msg_Str ("<error>");
1204
1205 else
1206 Set_Msg_Blank_Conditional;
1207 Get_Unqualified_Decoded_Name_String (Error_Msg_Name_1);
1208
1209 -- Remove %s or %b at end. These come from unit names. If the
1210 -- caller wanted the (unit) or (body), then they would have used
1211 -- the $ insertion character. Certainly no error message should
1212 -- ever have %b or %s explicitly occurring.
1213
1214 if Name_Len > 2
1215 and then Name_Buffer (Name_Len - 1) = '%'
1216 and then (Name_Buffer (Name_Len) = 'b'
1217 or else
1218 Name_Buffer (Name_Len) = 's')
1219 then
1220 Name_Len := Name_Len - 2;
1221 end if;
1222
1223 -- Remove upper case letter at end, again, we should not be getting
1224 -- such names, and what we hope is that the remainder makes sense.
1225
1226 if Name_Len > 1 and then Name_Buffer (Name_Len) in 'A' .. 'Z' then
1227 Name_Len := Name_Len - 1;
1228 end if;
1229
1230 -- If operator name or character literal name, just print it as is
1231 -- Also print as is if it ends in a right paren (case of x'val(nnn))
1232
1233 if Name_Buffer (1) = '"'
1234 or else Name_Buffer (1) = '''
1235 or else Name_Buffer (Name_Len) = ')'
1236 then
1237 Set_Msg_Name_Buffer;
1238
1239 -- Else output with surrounding quotes in proper casing mode
1240
1241 else
1242 Set_Casing (Identifier_Casing (Flag_Source));
1243 Set_Msg_Quote;
1244 Set_Msg_Name_Buffer;
1245 Set_Msg_Quote;
1246 end if;
1247 end if;
1248
1249 -- The following assignments ensure that the second and third percent
1250 -- insertion characters will correspond to the Error_Msg_Name_2 and
1251 -- Error_Msg_Name_3 as required. We suppress possible validity checks in
1252 -- case operating in -gnatVa mode, and Error_Msg_Name_1/2 is not needed
1253 -- and has not been set.
1254
1255 declare
1256 pragma Suppress (Range_Check);
1257 begin
1258 Error_Msg_Name_1 := Error_Msg_Name_2;
1259 Error_Msg_Name_2 := Error_Msg_Name_3;
1260 end;
1261 end Set_Msg_Insertion_Name;
1262
1263 ------------------------------------
1264 -- Set_Msg_Insertion_Name_Literal --
1265 ------------------------------------
1266
1267 procedure Set_Msg_Insertion_Name_Literal is
1268 begin
1269 if Error_Msg_Name_1 = No_Name then
1270 null;
1271
1272 elsif Error_Msg_Name_1 = Error_Name then
1273 Set_Msg_Blank;
1274 Set_Msg_Str ("<error>");
1275
1276 else
1277 Set_Msg_Blank;
1278 Get_Name_String (Error_Msg_Name_1);
1279 Set_Msg_Quote;
1280 Set_Msg_Name_Buffer;
1281 Set_Msg_Quote;
1282 end if;
1283
1284 -- The following assignments ensure that the second and third % or %%
1285 -- insertion characters will correspond to the Error_Msg_Name_2 and
1286 -- Error_Msg_Name_3 values and We suppress possible validity checks in
1287 -- case operating in -gnatVa mode, and Error_Msg_Name_2 or
1288 -- Error_Msg_Name_3 is not needed and has not been set.
1289
1290 declare
1291 pragma Suppress (Range_Check);
1292 begin
1293 Error_Msg_Name_1 := Error_Msg_Name_2;
1294 Error_Msg_Name_2 := Error_Msg_Name_3;
1295 end;
1296 end Set_Msg_Insertion_Name_Literal;
1297
1298 -------------------------------------
1299 -- Set_Msg_Insertion_Reserved_Name --
1300 -------------------------------------
1301
1302 procedure Set_Msg_Insertion_Reserved_Name is
1303 begin
1304 Set_Msg_Blank_Conditional;
1305 Get_Name_String (Error_Msg_Name_1);
1306 Set_Msg_Quote;
1307 Set_Casing (Keyword_Casing (Flag_Source), All_Lower_Case);
1308 Set_Msg_Name_Buffer;
1309 Set_Msg_Quote;
1310 end Set_Msg_Insertion_Reserved_Name;
1311
1312 -------------------------------------
1313 -- Set_Msg_Insertion_Reserved_Word --
1314 -------------------------------------
1315
1316 procedure Set_Msg_Insertion_Reserved_Word
1317 (Text : String;
1318 J : in out Integer)
1319 is
1320 begin
1321 Set_Msg_Blank_Conditional;
1322 Name_Len := 0;
1323
1324 while J <= Text'Last and then Text (J) in 'A' .. 'Z' loop
1325 Add_Char_To_Name_Buffer (Text (J));
1326 J := J + 1;
1327 end loop;
1328
1329 -- Here is where we make the special exception for RM
1330
1331 if Name_Len = 2 and then Name_Buffer (1 .. 2) = "RM" then
1332 Set_Msg_Name_Buffer;
1333
1334 -- We make a similar exception for SPARK
1335
1336 elsif Name_Len = 5 and then Name_Buffer (1 .. 5) = "SPARK" then
1337 Set_Msg_Name_Buffer;
1338
1339 -- Neither RM nor SPARK: case appropriately and add surrounding quotes
1340
1341 else
1342 Set_Casing (Keyword_Casing (Flag_Source), All_Lower_Case);
1343 Set_Msg_Quote;
1344 Set_Msg_Name_Buffer;
1345 Set_Msg_Quote;
1346 end if;
1347 end Set_Msg_Insertion_Reserved_Word;
1348
1349 -------------------------------------
1350 -- Set_Msg_Insertion_Run_Time_Name --
1351 -------------------------------------
1352
1353 procedure Set_Msg_Insertion_Run_Time_Name is
1354 begin
1355 if Targparm.Run_Time_Name_On_Target /= No_Name then
1356 Set_Msg_Blank_Conditional;
1357 Set_Msg_Char ('(');
1358 Get_Name_String (Targparm.Run_Time_Name_On_Target);
1359 Set_Casing (Mixed_Case);
1360 Set_Msg_Str (Name_Buffer (1 .. Name_Len));
1361 Set_Msg_Char (')');
1362 end if;
1363 end Set_Msg_Insertion_Run_Time_Name;
1364
1365 ----------------------------
1366 -- Set_Msg_Insertion_Uint --
1367 ----------------------------
1368
1369 procedure Set_Msg_Insertion_Uint is
1370 begin
1371 Set_Msg_Blank;
1372 UI_Image (Error_Msg_Uint_1);
1373
1374 for J in 1 .. UI_Image_Length loop
1375 Set_Msg_Char (UI_Image_Buffer (J));
1376 end loop;
1377
1378 -- The following assignment ensures that a second caret insertion
1379 -- character will correspond to the Error_Msg_Uint_2 parameter. We
1380 -- suppress possible validity checks in case operating in -gnatVa mode,
1381 -- and Error_Msg_Uint_2 is not needed and has not been set.
1382
1383 declare
1384 pragma Suppress (Range_Check);
1385 begin
1386 Error_Msg_Uint_1 := Error_Msg_Uint_2;
1387 end;
1388 end Set_Msg_Insertion_Uint;
1389
1390 -----------------
1391 -- Set_Msg_Int --
1392 -----------------
1393
1394 procedure Set_Msg_Int (Line : Int) is
1395 begin
1396 if Line > 9 then
1397 Set_Msg_Int (Line / 10);
1398 end if;
1399
1400 Set_Msg_Char (Character'Val (Character'Pos ('0') + (Line rem 10)));
1401 end Set_Msg_Int;
1402
1403 -------------------------
1404 -- Set_Msg_Name_Buffer --
1405 -------------------------
1406
1407 procedure Set_Msg_Name_Buffer is
1408 begin
1409 Set_Msg_Str (Name_Buffer (1 .. Name_Len));
1410 end Set_Msg_Name_Buffer;
1411
1412 -------------------
1413 -- Set_Msg_Quote --
1414 -------------------
1415
1416 procedure Set_Msg_Quote is
1417 begin
1418 if not Manual_Quote_Mode then
1419 Set_Msg_Char ('"');
1420 end if;
1421 end Set_Msg_Quote;
1422
1423 -----------------
1424 -- Set_Msg_Str --
1425 -----------------
1426
1427 procedure Set_Msg_Str (Text : String) is
1428 begin
1429 -- Do replacement for special x'Class aspect names
1430
1431 if Text = "_Pre" then
1432 Set_Msg_Str ("Pre'Class");
1433
1434 elsif Text = "_Post" then
1435 Set_Msg_Str ("Post'Class");
1436
1437 elsif Text = "_Type_Invariant" then
1438 Set_Msg_Str ("Type_Invariant'Class");
1439
1440 elsif Text = "_pre" then
1441 Set_Msg_Str ("pre'class");
1442
1443 elsif Text = "_post" then
1444 Set_Msg_Str ("post'class");
1445
1446 elsif Text = "_type_invariant" then
1447 Set_Msg_Str ("type_invariant'class");
1448
1449 elsif Text = "_PRE" then
1450 Set_Msg_Str ("PRE'CLASS");
1451
1452 elsif Text = "_POST" then
1453 Set_Msg_Str ("POST'CLASS");
1454
1455 elsif Text = "_TYPE_INVARIANT" then
1456 Set_Msg_Str ("TYPE_INVARIANT'CLASS");
1457
1458 -- Normal case with no replacement
1459
1460 else
1461 for J in Text'Range loop
1462 Set_Msg_Char (Text (J));
1463 end loop;
1464 end if;
1465 end Set_Msg_Str;
1466
1467 ------------------------------
1468 -- Set_Next_Non_Deleted_Msg --
1469 ------------------------------
1470
1471 procedure Set_Next_Non_Deleted_Msg (E : in out Error_Msg_Id) is
1472 begin
1473 if E = No_Error_Msg then
1474 return;
1475
1476 else
1477 loop
1478 E := Errors.Table (E).Next;
1479 exit when E = No_Error_Msg or else not Errors.Table (E).Deleted;
1480 end loop;
1481 end if;
1482 end Set_Next_Non_Deleted_Msg;
1483
1484 ------------------------------
1485 -- Set_Specific_Warning_Off --
1486 ------------------------------
1487
1488 procedure Set_Specific_Warning_Off
1489 (Loc : Source_Ptr;
1490 Msg : String;
1491 Reason : String_Id;
1492 Config : Boolean;
1493 Used : Boolean := False)
1494 is
1495 begin
1496 Specific_Warnings.Append
1497 ((Start => Loc,
1498 Msg => new String'(Msg),
1499 Stop => Source_Last (Get_Source_File_Index (Loc)),
1500 Reason => Reason,
1501 Open => True,
1502 Used => Used,
1503 Config => Config));
1504 end Set_Specific_Warning_Off;
1505
1506 -----------------------------
1507 -- Set_Specific_Warning_On --
1508 -----------------------------
1509
1510 procedure Set_Specific_Warning_On
1511 (Loc : Source_Ptr;
1512 Msg : String;
1513 Err : out Boolean)
1514 is
1515 begin
1516 for J in 1 .. Specific_Warnings.Last loop
1517 declare
1518 SWE : Specific_Warning_Entry renames Specific_Warnings.Table (J);
1519
1520 begin
1521 if Msg = SWE.Msg.all
1522 and then Loc > SWE.Start
1523 and then SWE.Open
1524 and then Get_Source_File_Index (SWE.Start) =
1525 Get_Source_File_Index (Loc)
1526 then
1527 SWE.Stop := Loc;
1528 SWE.Open := False;
1529 Err := False;
1530
1531 -- If a config pragma is specifically cancelled, consider
1532 -- that it is no longer active as a configuration pragma.
1533
1534 SWE.Config := False;
1535 return;
1536 end if;
1537 end;
1538 end loop;
1539
1540 Err := True;
1541 end Set_Specific_Warning_On;
1542
1543 ---------------------------
1544 -- Set_Warnings_Mode_Off --
1545 ---------------------------
1546
1547 procedure Set_Warnings_Mode_Off (Loc : Source_Ptr; Reason : String_Id) is
1548 begin
1549 -- Don't bother with entries from instantiation copies, since we will
1550 -- already have a copy in the template, which is what matters.
1551
1552 if Instantiation (Get_Source_File_Index (Loc)) /= No_Location then
1553 return;
1554 end if;
1555
1556 -- If all warnings are suppressed by command line switch, this can
1557 -- be ignored, unless we are in GNATprove_Mode which requires pragma
1558 -- Warnings to be stored for the formal verification backend.
1559
1560 if Warning_Mode = Suppress
1561 and then not GNATprove_Mode
1562 then
1563 return;
1564 end if;
1565
1566 -- If last entry in table already covers us, this is a redundant pragma
1567 -- Warnings (Off) and can be ignored.
1568
1569 if Warnings.Last >= Warnings.First
1570 and then Warnings.Table (Warnings.Last).Start <= Loc
1571 and then Loc <= Warnings.Table (Warnings.Last).Stop
1572 then
1573 return;
1574 end if;
1575
1576 -- If none of those special conditions holds, establish a new entry,
1577 -- extending from the location of the pragma to the end of the current
1578 -- source file. This ending point will be adjusted by a subsequent
1579 -- corresponding pragma Warnings (On).
1580
1581 Warnings.Append
1582 ((Start => Loc,
1583 Stop => Source_Last (Get_Source_File_Index (Loc)),
1584 Reason => Reason));
1585 end Set_Warnings_Mode_Off;
1586
1587 --------------------------
1588 -- Set_Warnings_Mode_On --
1589 --------------------------
1590
1591 procedure Set_Warnings_Mode_On (Loc : Source_Ptr) is
1592 begin
1593 -- Don't bother with entries from instantiation copies, since we will
1594 -- already have a copy in the template, which is what matters.
1595
1596 if Instantiation (Get_Source_File_Index (Loc)) /= No_Location then
1597 return;
1598 end if;
1599
1600 -- If all warnings are suppressed by command line switch, this can
1601 -- be ignored, unless we are in GNATprove_Mode which requires pragma
1602 -- Warnings to be stored for the formal verification backend.
1603
1604 if Warning_Mode = Suppress
1605 and then not GNATprove_Mode
1606 then
1607 return;
1608 end if;
1609
1610 -- If the last entry in the warnings table covers this pragma, then
1611 -- we adjust the end point appropriately.
1612
1613 if Warnings.Last >= Warnings.First
1614 and then Warnings.Table (Warnings.Last).Start <= Loc
1615 and then Loc <= Warnings.Table (Warnings.Last).Stop
1616 then
1617 Warnings.Table (Warnings.Last).Stop := Loc;
1618 end if;
1619 end Set_Warnings_Mode_On;
1620
1621 -------------------
1622 -- Sloc_In_Range --
1623 -------------------
1624
1625 function Sloc_In_Range (Loc, Start, Stop : Source_Ptr) return Boolean is
1626 Cur_Loc : Source_Ptr := Loc;
1627
1628 begin
1629 while Cur_Loc /= No_Location loop
1630 if Start <= Cur_Loc and then Cur_Loc <= Stop then
1631 return True;
1632 end if;
1633
1634 Cur_Loc := Instantiation_Location (Cur_Loc);
1635 end loop;
1636
1637 return False;
1638 end Sloc_In_Range;
1639
1640 --------------------------------
1641 -- Validate_Specific_Warnings --
1642 --------------------------------
1643
1644 procedure Validate_Specific_Warnings (Eproc : Error_Msg_Proc) is
1645 begin
1646 if not Warn_On_Warnings_Off then
1647 return;
1648 end if;
1649
1650 for J in Specific_Warnings.First .. Specific_Warnings.Last loop
1651 declare
1652 SWE : Specific_Warning_Entry renames Specific_Warnings.Table (J);
1653
1654 begin
1655 if not SWE.Config then
1656
1657 -- Warn for unmatched Warnings (Off, ...)
1658
1659 if SWE.Open then
1660 Eproc.all
1661 ("?W?pragma Warnings Off with no matching Warnings On",
1662 SWE.Start);
1663
1664 -- Warn for ineffective Warnings (Off, ..)
1665
1666 elsif not SWE.Used
1667
1668 -- Do not issue this warning for -Wxxx messages since the
1669 -- back-end doesn't report the information. Note that there
1670 -- is always an asterisk at the start of every message.
1671
1672 and then not
1673 (SWE.Msg'Length > 3 and then SWE.Msg (2 .. 3) = "-W")
1674 then
1675 Eproc.all
1676 ("?W?no warning suppressed by this pragma", SWE.Start);
1677 end if;
1678 end if;
1679 end;
1680 end loop;
1681 end Validate_Specific_Warnings;
1682
1683 -------------------------------------
1684 -- Warning_Specifically_Suppressed --
1685 -------------------------------------
1686
1687 function Warning_Specifically_Suppressed
1688 (Loc : Source_Ptr;
1689 Msg : String_Ptr;
1690 Tag : String := "") return String_Id
1691 is
1692 begin
1693 -- Loop through specific warning suppression entries
1694
1695 for J in Specific_Warnings.First .. Specific_Warnings.Last loop
1696 declare
1697 SWE : Specific_Warning_Entry renames Specific_Warnings.Table (J);
1698
1699 begin
1700 -- Pragma applies if it is a configuration pragma, or if the
1701 -- location is in range of a specific non-configuration pragma.
1702
1703 if SWE.Config
1704 or else Sloc_In_Range (Loc, SWE.Start, SWE.Stop)
1705 then
1706 if Matches (Msg.all, SWE.Msg.all)
1707 or else Matches (Tag, SWE.Msg.all)
1708 then
1709 SWE.Used := True;
1710 return SWE.Reason;
1711 end if;
1712 end if;
1713 end;
1714 end loop;
1715
1716 return No_String;
1717 end Warning_Specifically_Suppressed;
1718
1719 ------------------------------
1720 -- Warning_Treated_As_Error --
1721 ------------------------------
1722
1723 function Warning_Treated_As_Error (Msg : String) return Boolean is
1724 begin
1725 for J in 1 .. Warnings_As_Errors_Count loop
1726 if Matches (Msg, Warnings_As_Errors (J).all) then
1727 return True;
1728 end if;
1729 end loop;
1730
1731 return False;
1732 end Warning_Treated_As_Error;
1733
1734 -------------------------
1735 -- Warnings_Suppressed --
1736 -------------------------
1737
1738 function Warnings_Suppressed (Loc : Source_Ptr) return String_Id is
1739 begin
1740 -- Loop through table of ON/OFF warnings
1741
1742 for J in Warnings.First .. Warnings.Last loop
1743 if Sloc_In_Range (Loc, Warnings.Table (J).Start,
1744 Warnings.Table (J).Stop)
1745 then
1746 return Warnings.Table (J).Reason;
1747 end if;
1748 end loop;
1749
1750 if Warning_Mode = Suppress then
1751 return Null_String_Id;
1752 else
1753 return No_String;
1754 end if;
1755 end Warnings_Suppressed;
1756
1757 end Erroutc;