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 <[email protected]>
* 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 :=