If we have a situation similar to
My_Label;
loop
...
end loop;
where we have a semicolon instead of a colon after My_Label, the
compiler used to simply complain that it expected end; instead
of end loop; With this change it now flags the bad semicolon
as shown in by this test program:
1. procedure Colon is
2. Count : Positive := 1;
3. begin
4. My_Loop;
|
>>> ";" should be ":"
5. loop
6. exit My_Loop when Count > 100;
7. Count := Count + 1;
8. end loop My_Loop;
9. Bad_While;
|
>>> ";" should be ":"
10. while Count > 10 loop
11. Count := Count + 1;
12. end loop Bad_While;
13. Bad_Block;
|
>>> ";" should be ":"
14. begin
15. Count := 23;
16. end Bad_Block;
17. end Colon;
Tested on x86_64-pc-linux-gnu, committed on trunk
2014-01-27 Robert Dewar <[email protected]>
* par-ch5.adb (P_Sequence_Of_Statements): Make entry in
Suspicious_Labels table if we have identifier; followed by loop
or block.
* par-endh.adb (Evaluate_End_Entry): Search Suspicious_Labels table.
* par.adb (Suspicious_Labels): New table.
Index: par-endh.adb
===================================================================
--- par-endh.adb (revision 207120)
+++ par-endh.adb (working copy)
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2012, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2013, Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
@@ -711,18 +711,68 @@
------------------------
procedure Evaluate_End_Entry (SS_Index : Nat) is
+ STE : Scope_Table_Entry renames Scope.Table (SS_Index);
+
begin
- Column_OK := (End_Column = Scope.Table (SS_Index).Ecol);
+ Column_OK := (End_Column = STE.Ecol);
- Token_OK := (End_Type = Scope.Table (SS_Index).Etyp or else
- (End_Type = E_Name and then
- Scope.Table (SS_Index).Etyp >= E_Name));
+ Token_OK := (End_Type = STE.Etyp
+ or else (End_Type = E_Name and then STE.Etyp >= E_Name));
Label_OK := End_Labl_Present
- and then
- (Same_Label (End_Labl, Scope.Table (SS_Index).Labl)
- or else Scope.Table (SS_Index).Labl = Error);
+ and then (Same_Label (End_Labl, STE.Labl)
+ or else STE.Labl = Error);
+ -- Special case to consider. Suppose we have the suspicious label case,
+ -- e.g. a situation like:
+
+ -- My_Label;
+ -- declare
+ -- ...
+ -- begin
+ -- ...
+ -- end My_Label;
+
+ -- This is the case where we want to use the entry in the suspicous
+ -- label table to flag the semicolon saying it should be a colon.
+
+ -- Label_OK will be false because the label does not match (we have
+ -- My_Label on the end line, and the generated name for the scope). Also
+ -- End_Labl_Present will be True.
+
+ if not Label_OK
+ and then End_Labl_Present
+ and then not Comes_From_Source (Scope.Table (SS_Index).Labl)
+ then
+ -- Here is where we will search the suspicious labels table
+
+ for J in 1 .. Suspicious_Labels.Last loop
+ declare
+ SLE : Suspicious_Label_Entry renames
+ Suspicious_Labels.Table (J);
+ begin
+ -- See if character name of label matches
+
+ if Chars (Name (SLE.Proc_Call)) = Chars (End_Labl)
+
+ -- And first token of loop/block identifies this entry
+
+ and then SLE.Start_Token = STE.Sloc
+ then
+ -- We have the special case, issue the error message
+
+ Error_Msg -- CODEFIX
+ (""";"" should be "":""", SLE.Semicolon_Loc);
+
+ -- And indicate we consider the Label OK after all
+
+ Label_OK := True;
+ exit;
+ end if;
+ end;
+ end loop;
+ end if;
+
-- Compute setting of Syntax_OK. We definitely have a syntax error
-- if the Token does not match properly or if P_End_Scan detected
-- a syntax error such as a missing semicolon.
Index: par.adb
===================================================================
--- par.adb (revision 207120)
+++ par.adb (working copy)
@@ -535,6 +535,66 @@
Table_Increment => 100,
Table_Name => "Scope");
+ ------------------------------------------
+ -- Table for Handling Suspicious Labels --
+ ------------------------------------------
+
+ -- This is a special data structure which is used to deal very spefifically
+ -- with the following error case
+
+ -- label;
+ -- loop
+ -- ...
+ -- end loop label;
+
+ -- Similar cases apply to FOR, WHILE, DECLARE, or BEGIN
+
+ -- In each case the opening line looks like a procedure call because of
+ -- the semicolon. And the end line looks illegal because of an unexpected
+ -- label. If we did nothing special, we would just diagnose the label on
+ -- the end as unexpected. But that does not help point to the real error
+ -- which is that the semicolon after label should be a colon.
+
+ -- To deal with this, we build an entry in the Suspicious_Labels table
+ -- whenever we encounter an identifier followed by a semicolon, followed
+ -- by one of LOOP, FOR, WHILE, DECLARE, BEGIN. Then this entry is used to
+ -- issue the right message when we hit the END that confirms that this was
+ -- a bad label.
+
+ type Suspicious_Label_Entry is record
+ Proc_Call : Node_Id;
+ -- Node for the procedure call statement built for the label; construct
+
+ Semicolon_Loc : Source_Ptr;
+ -- Location of the possibly wrong semicolon
+
+ Start_Token : Source_Ptr;
+ -- Source location of the LOOP, FOR, WHILE, DECLARE, BEGIN token
+ end record;
+
+ package Suspicious_Labels is new Table.Table (
+ Table_Component_Type => Suspicious_Label_Entry,
+ Table_Index_Type => Int,
+ Table_Low_Bound => 1,
+ Table_Initial => 50,
+ Table_Increment => 100,
+ Table_Name => "Suspicious_Labels");
+
+ -- Now when we are about to issue a message complaining about an END label
+ -- that should not be there because it appears to end a construct that has
+ -- no label, we first search the suspicious labels table entry, using the
+ -- source location stored in the scope table as a key. If we find a match,
+ -- then we check that the label on the end matches the name in the call,
+ -- and if so, we issue a message saying the semicolon should be a colon.
+
+ -- Quite a bit of work, but really helpful in the case where it helps, and
+ -- the need for this is based on actual experience with tracking down this
+ -- kind of error (the eye often easily mistakes semicolon for colon!)
+
+ -- Note: we actually have enough information to patch up the tree, but
+ -- this may not be worth the effort! Also we could deal with the same
+ -- situation for EXIT with a label, but for now don't bother with that!
+
---------------------------------
-- Parsing Routines by Chapter --
---------------------------------
Index: par-ch5.adb
===================================================================
--- par-ch5.adb (revision 207120)
+++ par-ch5.adb (working copy)
@@ -506,6 +506,24 @@
Scan; -- past semicolon
Statement_Required := False;
+ -- Here is the special test for a suspicious label, more
+ -- accurately a suspicious name, which we think perhaps
+ -- should have been a label. If next token is one of
+ -- LOOP, FOR, WHILE, DECLARE, BEGIN, then make an entry
+ -- in the suspicious label table.
+
+ if Token = Tok_Loop or else
+ Token = Tok_For or else
+ Token = Tok_While or else
+ Token = Tok_Declare or else
+ Token = Tok_Begin
+ then
+ Suspicious_Labels.Append
+ ((Proc_Call => Id_Node,
+ Semicolon_Loc => Prev_Token_Ptr,
+ Start_Token => Token_Ptr));
+ end if;
+
-- Check for case of "go to" in place of "goto"
elsif Token = Tok_Identifier