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  <de...@adacore.com>

        * 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

Reply via email to