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