Aspect/pragma [Type_]Invariant may be placed illegally on a public type or
a private type without public declaration. This patch gives a different error
message for each case. Now, compiling the following code generates 4 different
messages:

$ gcc -c -gnat12 inv.ads
inv.ads:5:11: aspect "Type_Invariant" only allowed for private type
inv.ads:9:11: aspect "Invariant" only allowed for private type
inv.ads:14:11: aspect "Type_Invariant" only allowed for private type declared 
in visible part
inv.ads:18:11: aspect "Invariant" only allowed for private type declared in 
visible part
---
     1  package Inv is
     2     type Wrap is record
     3        X : Integer;
     4     end record
     5       with Type_Invariant => X mod 2 = 1;
     6     type Wrap2 is record
     7        X : Integer;
     8     end record
     9       with Invariant => X mod 2 = 1;
    10  private
    11     type Wrap3 is record
    12        X : Integer;
    13     end record
    14       with Type_Invariant => X mod 2 = 1;
    15     type Wrap4 is record
    16        X : Integer;
    17     end record
    18       with Invariant => X mod 2 = 1;
    19  end Inv;

Tested on x86_64-pc-linux-gnu, committed on trunk

2011-09-06  Yannick Moy  <m...@adacore.com>

        * sem_ch13.adb (Analyze_Aspect_Specifications, case
        Aspect_Invariant): Do not issue error at this point on illegal
        pragma placement, as this is checked later on when analyzing
        the corresponding pragma.
        * sem_prag.adb (Error_Pragma_Arg_Alternate_Name): New procedure
        similar to Error_Pragma_Arg, except the source name of the
        aspect/pragma to use in warnings may be equal to parameter
        Alt_Name (Analyze_Pragma, case Pragma_Invariant): refine error
        message to distinguish source name of pragma/aspect, and whether
        the illegality resides in the type being public, or being private
        without a public declaration

Index: sem_prag.adb
===================================================================
--- sem_prag.adb        (revision 178579)
+++ sem_prag.adb        (working copy)
@@ -29,63 +29,65 @@
 --  to complete the syntax checks. Certain pragmas are handled partially or
 --  completely by the parser (see Par.Prag for further details).
 
-with Atree;    use Atree;
-with Casing;   use Casing;
-with Checks;   use Checks;
-with Csets;    use Csets;
-with Debug;    use Debug;
-with Einfo;    use Einfo;
-with Elists;   use Elists;
-with Errout;   use Errout;
-with Exp_Dist; use Exp_Dist;
-with Exp_Util; use Exp_Util;
-with Freeze;   use Freeze;
-with Lib;      use Lib;
-with Lib.Writ; use Lib.Writ;
-with Lib.Xref; use Lib.Xref;
-with Namet.Sp; use Namet.Sp;
-with Nlists;   use Nlists;
-with Nmake;    use Nmake;
-with Opt;      use Opt;
-with Output;   use Output;
-with Par_SCO;  use Par_SCO;
-with Restrict; use Restrict;
-with Rident;   use Rident;
-with Rtsfind;  use Rtsfind;
-with Sem;      use Sem;
-with Sem_Aux;  use Sem_Aux;
-with Sem_Ch3;  use Sem_Ch3;
-with Sem_Ch6;  use Sem_Ch6;
-with Sem_Ch8;  use Sem_Ch8;
-with Sem_Ch12; use Sem_Ch12;
-with Sem_Ch13; use Sem_Ch13;
-with Sem_Disp; use Sem_Disp;
-with Sem_Dist; use Sem_Dist;
-with Sem_Elim; use Sem_Elim;
-with Sem_Eval; use Sem_Eval;
-with Sem_Intr; use Sem_Intr;
-with Sem_Mech; use Sem_Mech;
-with Sem_Res;  use Sem_Res;
-with Sem_Type; use Sem_Type;
-with Sem_Util; use Sem_Util;
-with Sem_VFpt; use Sem_VFpt;
-with Sem_Warn; use Sem_Warn;
-with Stand;    use Stand;
-with Sinfo;    use Sinfo;
-with Sinfo.CN; use Sinfo.CN;
-with Sinput;   use Sinput;
-with Snames;   use Snames;
-with Stringt;  use Stringt;
-with Stylesw;  use Stylesw;
+with System.Case_Util;
+
+with Atree;            use Atree;
+with Casing;           use Casing;
+with Checks;           use Checks;
+with Csets;            use Csets;
+with Debug;            use Debug;
+with Einfo;            use Einfo;
+with Elists;           use Elists;
+with Errout;           use Errout;
+with Exp_Dist;         use Exp_Dist;
+with Exp_Util;         use Exp_Util;
+with Freeze;           use Freeze;
+with Lib;              use Lib;
+with Lib.Writ;         use Lib.Writ;
+with Lib.Xref;         use Lib.Xref;
+with Namet.Sp;         use Namet.Sp;
+with Nlists;           use Nlists;
+with Nmake;            use Nmake;
+with Opt;              use Opt;
+with Output;           use Output;
+with Par_SCO;          use Par_SCO;
+with Restrict;         use Restrict;
+with Rident;           use Rident;
+with Rtsfind;          use Rtsfind;
+with Sem;              use Sem;
+with Sem_Aux;          use Sem_Aux;
+with Sem_Ch3;          use Sem_Ch3;
+with Sem_Ch6;          use Sem_Ch6;
+with Sem_Ch8;          use Sem_Ch8;
+with Sem_Ch12;         use Sem_Ch12;
+with Sem_Ch13;         use Sem_Ch13;
+with Sem_Disp;         use Sem_Disp;
+with Sem_Dist;         use Sem_Dist;
+with Sem_Elim;         use Sem_Elim;
+with Sem_Eval;         use Sem_Eval;
+with Sem_Intr;         use Sem_Intr;
+with Sem_Mech;         use Sem_Mech;
+with Sem_Res;          use Sem_Res;
+with Sem_Type;         use Sem_Type;
+with Sem_Util;         use Sem_Util;
+with Sem_VFpt;         use Sem_VFpt;
+with Sem_Warn;         use Sem_Warn;
+with Stand;            use Stand;
+with Sinfo;            use Sinfo;
+with Sinfo.CN;         use Sinfo.CN;
+with Sinput;           use Sinput;
+with Snames;           use Snames;
+with Stringt;          use Stringt;
+with Stylesw;          use Stylesw;
 with Table;
-with Targparm; use Targparm;
-with Tbuild;   use Tbuild;
+with Targparm;         use Targparm;
+with Tbuild;           use Tbuild;
 with Ttypes;
-with Uintp;    use Uintp;
-with Uname;    use Uname;
-with Urealp;   use Urealp;
-with Validsw;  use Validsw;
-with Warnsw;   use Warnsw;
+with Uintp;            use Uintp;
+with Uname;            use Uname;
+with Urealp;           use Urealp;
+with Validsw;          use Validsw;
+with Warnsw;           use Warnsw;
 
 package body Sem_Prag is
 
@@ -646,6 +648,17 @@
       --  Similar to above form of Error_Pragma_Arg except that two messages
       --  are provided, the second is a continuation comment starting with \.
 
+      procedure Error_Pragma_Arg_Alternate_Name
+        (Msg      : String;
+         Arg      : Node_Id;
+         Alt_Name : Name_Id);
+      pragma No_Return (Error_Pragma_Arg_Alternate_Name);
+      --  Outputs error message for current pragma, similar to
+      --  Error_Pragma_Arg, except the source name of the aspect/pragma to use
+      --  in warnings may be equal to Alt_Name (which should be equivalent to
+      --  the name used in pragma). The location for the source name should be
+      --  pointed to by Arg.
+
       procedure Error_Pragma_Arg_Ident (Msg : String; Arg : Node_Id);
       pragma No_Return (Error_Pragma_Arg_Ident);
       --  Outputs error message for current pragma. The message may contain
@@ -2427,6 +2440,34 @@
          Error_Pragma_Arg (Msg2, Arg);
       end Error_Pragma_Arg;
 
+      -------------------------------------
+      -- Error_Pragma_Arg_Alternate_Name --
+      -------------------------------------
+
+      procedure Error_Pragma_Arg_Alternate_Name
+        (Msg      : String;
+         Arg      : Node_Id;
+         Alt_Name : Name_Id)
+      is
+         MsgF        : String := Msg;
+         Source_Name : String := Exact_Source_Name (Sloc (Arg));
+         Alter_Name  : String := Get_Name_String (Alt_Name);
+
+      begin
+         System.Case_Util.To_Lower (Source_Name);
+         System.Case_Util.To_Lower (Alter_Name);
+
+         if Source_Name = Alter_Name then
+            Error_Msg_Name_1 := Alt_Name;
+         else
+            Error_Msg_Name_1 := Pname;
+         end if;
+
+         Fix_Error (MsgF);
+         Error_Msg_N (MsgF, Get_Pragma_Arg (Arg));
+         raise Pragma_Exit;
+      end Error_Pragma_Arg_Alternate_Name;
+
       ----------------------------
       -- Error_Pragma_Arg_Ident --
       ----------------------------
@@ -10140,9 +10181,16 @@
             then
                null;
 
+            elsif In_Private_Part (Current_Scope) then
+               Error_Pragma_Arg_Alternate_Name
+                 ("pragma% only allowed for private type " &
+                  "declared in visible part", Arg1,
+                  Alt_Name => Name_Type_Invariant);
+
             else
-               Error_Pragma_Arg
-                 ("pragma% only allowed for private type", Arg1);
+               Error_Pragma_Arg_Alternate_Name
+                 ("pragma% only allowed for private type", Arg1,
+                  Alt_Name => Name_Type_Invariant);
             end if;
 
             --  Note that the type has at least one invariant, and also that
Index: sem_ch13.adb
===================================================================
--- sem_ch13.adb        (revision 178578)
+++ sem_ch13.adb        (working copy)
@@ -1289,26 +1289,10 @@
                when Aspect_Invariant      |
                     Aspect_Type_Invariant =>
 
-                  --  Check placement legality: An invariant must apply to a
-                  --  private type, or appear in the private part of a spec.
-                  --  Analysis of the pragma will verify that in the private
-                  --  part it applies to a completion.
+                  --  Analysis of the pragma will verify placement legality:
+                  --  an invariant must apply to a private type, or appear in
+                  --  the private part of a spec and apply to a completion.
 
-                  if Nkind_In (N, N_Private_Type_Declaration,
-                                  N_Private_Extension_Declaration)
-                  then
-                     null;
-
-                  elsif Nkind (N) = N_Full_Type_Declaration
-                    and then In_Private_Part (Current_Scope)
-                  then
-                     null;
-
-                  else
-                     Error_Msg_N
-                       ("invariant aspect must apply to a private type", N);
-                  end if;
-
                   --  Construct the pragma
 
                   Aitem :=

Reply via email to