This patch adds an enhancement for detecting and warning about constraint errors in aggregate types with uninitialized null-excluding components at compile-time. All composite types without aggregate initialization will now be recursivly checked for such null-excluding components without default initialization and extended information about the constraint error will be shown to the user.
------------ -- Source -- ------------ -- main.adb with Types; use Types; procedure Main is Obj_1 : Named_Ptr; -- OK pragma Unused (Obj_1); Obj_2 : Named_NE_Ptr; -- ERROR pragma Unused (Obj_2); Obj_3 : Anon_Array; -- OK Obj_4 : Anon_NE_Array; -- ERROR Obj_5 : Named_Array; -- OK Obj_6 : Named_NE_Array; -- ERROR Obj_7 : Named_Inc; -- OK pragma Unused (Obj_7); Obj_8 : Named_NE_Inc; -- ERROR pragma Unused (Obj_8); Obj_9 : Named_Priv; -- OK Obj_10 : Named_NE_Priv ; -- ERROR Obj_11 : Priv_1; -- OK pragma Unused (Obj_11); Obj_12 : Priv_2; -- OK Obj_13 : Priv_3; -- ERROR Obj_14 : Priv_4; -- OK Obj_15 : Priv_5; -- ERROR Obj_16 : Priv_6; -- OK Obj_17 : Priv_7; -- ERROR Obj_18 : Priv_8; -- ERROR Obj_19 : Priv_9; -- ERROR Obj_20 : Priv_10; -- ERROR Obj_21 : Prot_1; -- OK Obj_22 : Prot_2; -- ERROR Obj_23 : Prot_3; -- ERROR Obj_24 : Prot_4; -- ERROR Obj_25 : Prot_5; -- ERROR Obj_26 : Rec_1; -- ERROR Obj_27 : Rec_2; -- ERROR Obj_28 : Rec_3; -- ERROR Obj_29 : Rec_4; -- ERROR Obj_30 : Rec_5; -- ERROR Obj_31 : Rec_6; -- ERROR Obj_32 : Rec_7; -- ERROR Obj_33 : Rec_8; -- ERROR Obj_34 : Rec_9; -- OK Obj_35 : Rec_10; -- ERROR Obj_36 : Rec_11; -- ERROR Obj_37 : Rec_12; -- ERROR Obj_38 : Rec_13; -- ERROR Obj_39 : Tag_1; -- ERROR Obj_40 : Tag_2; -- ERROR Obj_41 : Tag_3; -- ERROR Obj_42 : Tag_4; -- ERROR Obj_43 : Task_1; -- OK Obj_44 : Named_Rec_Array; -- ERROR Obj_45 : Named_NE_Array_Array; -- ERROR Obj_46 : Rec_14; -- ERROR Obj_47 : array (1 .. 2) of Rec_14; -- ERROR begin null; end Main; -- types.ads package Types is -- Composite - array [sub]type, concurrent, incomplete, private, record, -- string literal subtype -- Concurrent - protected [sub]type, task [sub]type -- Incomplete - incomplete [sub]type -- Private - [limited] private [sub]type, record [sub]type with private -- Record - class-wide [sub]type, record [sub]type [with private] ------------------ -- Simple types -- ------------------ -- Access type Named_Ptr is access Integer; type Named_NE_Ptr is not null access Integer; -- Arrays --type Rec_4; type Anon_Array is array (1 .. 2) of access Integer; type Anon_NE_Array is array (1 .. 2) of not null access Integer; --type Named_Rec_Array is array (1 .. 2) of Rec_4; type Named_Array is array (1 .. 2) of Named_Ptr; type Named_NE_Array is array (1 .. 2) of Named_NE_Ptr; -- Incomplete type Named_Inc; type Named_NE_Inc; type Named_Inc is access Integer; type Named_NE_Inc is not null access Integer; -- Private type Named_Priv is private; type Named_NE_Priv is private; ------------------- -- Complex types -- ------------------- -- Private type Priv_1 is private; type Priv_2 is private; type Priv_3 is private; type Priv_4 is private; type Priv_5 is private; type Priv_6 is private; type Priv_7 is private; type Priv_8 is private; type Priv_9 is private; type Priv_10 is limited private; -- Protected protected type Prot_1 is end Prot_1; protected type Prot_2 is private Comp_1 : Named_Ptr; Comp_A : Named_NE_Ptr; end Prot_2; protected type Prot_3 is private Comp_1 : Anon_Array; Comp_2 : Anon_NE_Array; end Prot_3; protected type Prot_4 is private Comp_1 : Named_Array; Comp_2 : Named_NE_Ptr; end Prot_4; protected type Prot_5 is private Comp_1 : Named_Priv; Comp_2 : Named_NE_Priv; end Prot_5; -- Record type Rec_1 is record Comp_1 : Named_Ptr; Comp_2 : Named_NE_Ptr; end record; type Rec_2 is record Comp_1 : Anon_Array; Comp_2 : Anon_NE_Array; end record; type Rec_3 is record Comp_1 : Named_Array; Comp_2 : Named_NE_Ptr; end record; type Rec_4 is record Comp_1 : Named_Priv; Comp_2 : Named_NE_Priv; end record; type Named_Rec_Array is array (1 .. 2) of Rec_4; type Rec_5 is record Comp : Rec_1; end record; type Rec_6 is record Comp : Rec_2; end record; type Rec_7 is record Comp : Rec_3; end record; type Rec_8 is record Comp : Rec_4; end record; type Rec_9 is record Comp : Prot_1; end record; type Rec_10 is record Comp : Prot_2; end record; type Rec_11 is record Comp : Prot_3; end record; type Rec_12 is record Comp : Prot_4; end record; type Rec_13 is record Comp : Prot_5; end record; type Named_NE_Array_Array is array (1 .. 2) of Named_NE_Array; type Rec_14 is record Comp : Named_NE_Array_Array; end record; -- Tagged type Tag_1 is tagged record Comp_1 : Anon_Array; Comp_2 : Rec_8; end record; type Tag_2 is tagged limited record Comp_1 : Named_Priv; Comp_2 : Rec_7; end record; type Tag_3 is tagged limited private; type Iface is limited interface; type Tag_4 is limited new Iface with private; -- Task task type Task_1 is end Task_1; private ------------------- -- Simple types -- ------------------- -- Private type Named_Priv is access Integer; type Named_NE_Priv is not null access Integer; ------------------- -- Complex types -- ------------------- -- Private type Priv_1 is new Integer; type Priv_2 is access Integer; type Priv_3 is not null access Integer; type Priv_4 is array (1 .. 2) of access Integer; type Priv_5 is array (1 .. 2) of not null access Integer; type Priv_6 is array (1 .. 2) of Named_Ptr; type Priv_7 is array (1 .. 2) of Named_NE_Ptr; type Priv_8 is record Comp_1 : Named_Ptr; Comp_2 : Named_NE_Ptr; end record; type Priv_9 is record Comp : Rec_1; end record; type Priv_10 is limited record Comp_1 : Anon_Array; Comp_2 : Anon_NE_Array; end record; -- Tagged type Tag_3 is limited new Tag_2 with record Comp_3 : Rec_4; end record; type Tag_4 is limited new Iface with record Comp_1 : Named_Array; Comp_2 : Tag_3; end record; end Types; ---------------------------- -- Compilation and output -- ---------------------------- & gnatmake -q main.adb main.adb:6:04: warning: (Ada 2005) null-excluding objects must be initialized main.adb:6:04: warning: "Constraint_Error" will be raised at run time main.adb:9:04: warning: (Ada 2005) null-excluding objects must be initialized main.adb:9:04: warning: "Constraint_Error" will be raised at run time main.adb:11:04: warning: (Ada 2005) null-excluding objects must be initialized main.adb:11:04: warning: "Constraint_Error" will be raised at run time main.adb:14:04: warning: (Ada 2005) null-excluding objects must be initialized main.adb:14:04: warning: "Constraint_Error" will be raised at run time main.adb:17:04: warning: (Ada 2005) null-excluding component "Obj_10" of object "Obj_10" must be initialized main.adb:17:04: warning: "Constraint_Error" will be raised at run time main.adb:21:04: warning: (Ada 2005) null-excluding component "Obj_13" of object "Obj_13" must be initialized main.adb:21:04: warning: "Constraint_Error" will be raised at run time main.adb:23:04: warning: (Ada 2005) null-excluding objects must be initialized main.adb:23:04: warning: "Constraint_Error" will be raised at run time main.adb:25:04: warning: (Ada 2005) null-excluding objects must be initialized main.adb:25:04: warning: "Constraint_Error" will be raised at run time main.adb:26:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_18" must be initialized main.adb:26:04: warning: "Constraint_Error" will be raised at run time main.adb:27:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_19" must be initialized main.adb:27:04: warning: "Constraint_Error" will be raised at run time main.adb:28:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_20" must be initialized main.adb:28:04: warning: "Constraint_Error" will be raised at run time main.adb:30:04: warning: (Ada 2005) null-excluding component "Comp_A" of object "Obj_22" must be initialized main.adb:30:04: warning: "Constraint_Error" will be raised at run time main.adb:31:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_23" must be initialized main.adb:31:04: warning: "Constraint_Error" will be raised at run time main.adb:32:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_24" must be initialized main.adb:32:04: warning: "Constraint_Error" will be raised at run time main.adb:33:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_25" must be initialized main.adb:33:04: warning: "Constraint_Error" will be raised at run time main.adb:34:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_26" must be initialized main.adb:34:04: warning: "Constraint_Error" will be raised at run time main.adb:35:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_27" must be initialized main.adb:35:04: warning: "Constraint_Error" will be raised at run time main.adb:36:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_28" must be initialized main.adb:36:04: warning: "Constraint_Error" will be raised at run time main.adb:37:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_29" must be initialized main.adb:37:04: warning: "Constraint_Error" will be raised at run time main.adb:38:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_30" must be initialized main.adb:38:04: warning: "Constraint_Error" will be raised at run time main.adb:39:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_31" must be initialized main.adb:39:04: warning: "Constraint_Error" will be raised at run time main.adb:40:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_32" must be initialized main.adb:40:04: warning: "Constraint_Error" will be raised at run time main.adb:41:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_33" must be initialized main.adb:41:04: warning: "Constraint_Error" will be raised at run time main.adb:43:04: warning: (Ada 2005) null-excluding component "Comp_A" of object "Obj_35" must be initialized main.adb:43:04: warning: "Constraint_Error" will be raised at run time main.adb:44:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_36" must be initialized main.adb:44:04: warning: "Constraint_Error" will be raised at run time main.adb:45:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_37" must be initialized main.adb:45:04: warning: "Constraint_Error" will be raised at run time main.adb:46:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_38" must be initialized main.adb:46:04: warning: "Constraint_Error" will be raised at run time main.adb:47:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_39" must be initialized main.adb:47:04: warning: "Constraint_Error" will be raised at run time main.adb:48:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_40" must be initialized main.adb:48:04: warning: "Constraint_Error" will be raised at run time main.adb:49:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_41" must be initialized main.adb:49:04: warning: "Constraint_Error" will be raised at run time main.adb:50:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_42" must be initialized main.adb:50:04: warning: "Constraint_Error" will be raised at run time main.adb:52:04: warning: (Ada 2005) null-excluding component "Comp_2" of object "Obj_44" must be initialized main.adb:52:04: warning: "Constraint_Error" will be raised at run time main.adb:53:04: warning: (Ada 2005) null-excluding objects must be initialized main.adb:53:04: warning: "Constraint_Error" will be raised at run time main.adb:54:04: warning: (Ada 2005) null-excluding component "Comp" of object "Obj_46" must be initialized main.adb:54:04: warning: "Constraint_Error" will be raised at run time main.adb:55:04: warning: (Ada 2005) null-excluding component "Comp" of object "Obj_47" must be initialized main.adb:55:04: warning: "Constraint_Error" will be raised at run time cannot generate code for file types.ads (package spec) gnatmake: "types.ads" compilation error Tested on x86_64-pc-linux-gnu, committed on trunk 2017-05-02 Justin Squirek <squi...@adacore.com> * sem_ch3.adb (Check_For_Null_Excluding_Components): Created for recursivly searching composite-types for null-excluding access types and verifying them. (Analyze_Object_Declaration): Add a call to Check_Null_Excluding_Components for static verification of non-initialized objects. * checks.adb, checks.ads (Null_Exclusion_Static_Checks): Added a parameter for a composite-type's component and an extra case for printing component information.
Index: checks.adb =================================================================== --- checks.adb (revision 247461) +++ checks.adb (working copy) @@ -4037,7 +4037,10 @@ -- Null_Exclusion_Static_Checks -- ---------------------------------- - procedure Null_Exclusion_Static_Checks (N : Node_Id) is + procedure Null_Exclusion_Static_Checks + (N : Node_Id; + Comp : Node_Id := Empty) + is Error_Node : Node_Id; Expr : Node_Id; Has_Null : constant Boolean := Has_Null_Exclusion (N); @@ -4119,11 +4122,27 @@ Set_Expression (N, Make_Null (Sloc (N))); Set_Etype (Expression (N), Etype (Defining_Identifier (N))); - Apply_Compile_Time_Constraint_Error - (N => Expression (N), - Msg => - "(Ada 2005) null-excluding objects must be initialized??", - Reason => CE_Null_Not_Allowed); + if Present (Comp) then + + -- Specialize the error message to indicate that we are dealing + -- with an uninitialized composite object that has a defaulted + -- null-excluding component. + + Error_Msg_Name_1 := Chars (Defining_Identifier (Comp)); + Error_Msg_Name_2 := Chars (Defining_Identifier (N)); + + Apply_Compile_Time_Constraint_Error + (N => Expression (N), + Msg => "(Ada 2005) null-excluding component % of object % " & + "must be initialized??", + Reason => CE_Null_Not_Allowed); + else + Apply_Compile_Time_Constraint_Error + (N => Expression (N), + Msg => + "(Ada 2005) null-excluding objects must be initialized??", + Reason => CE_Null_Not_Allowed); + end if; end if; -- Check that a null-excluding component, formal or object is not being Index: checks.ads =================================================================== --- checks.ads (revision 247461) +++ checks.ads (working copy) @@ -915,8 +915,14 @@ -- Chars (Related_Id)_FIRST/_LAST. For suggested use of these parameters -- see the warning in the body of Sem_Ch3.Process_Range_Expr_In_Decl. - procedure Null_Exclusion_Static_Checks (N : Node_Id); + procedure Null_Exclusion_Static_Checks + (N : Node_Id; + Comp : Node_Id := Empty); -- Ada 2005 (AI-231): Check bad usages of the null-exclusion issue + -- + -- When a value for Comp is supplied (as in the case of an uninitialized + -- null-excluding component within a composite object), a reported error + -- will indicate the offending component instead of the object itself. procedure Remove_Checks (Expr : Node_Id); -- Remove all checks from Expr except those that are only executed Index: sem_ch3.adb =================================================================== --- sem_ch3.adb (revision 247461) +++ sem_ch3.adb (working copy) @@ -3588,6 +3588,13 @@ Prev_Entity : Entity_Id := Empty; + procedure Check_For_Null_Excluding_Components + (Obj_Typ : Entity_Id; + Obj_Decl : Node_Id); + -- Recursively verify that each null-excluding component of an object + -- declaration's type has explicit initialization, and generate + -- compile-time warnings for each one that does not. + function Count_Tasks (T : Entity_Id) return Uint; -- This function is called when a non-generic library level object of a -- task type is declared. Its function is to count the static number of @@ -3607,6 +3614,100 @@ -- Any other relevant delayed aspects on object declarations ??? + ----------------------------------------- + -- Check_For_Null_Excluding_Components -- + ----------------------------------------- + + procedure Check_For_Null_Excluding_Components + (Obj_Typ : Entity_Id; + Obj_Decl : Node_Id) + is + + procedure Check_Component + (Comp_Typ : Entity_Id; + Comp_Decl : Node_Id := Empty); + -- Perform compile-time null-exclusion checks on a given component + -- and all of its subcomponents, if any. + + --------------------- + -- Check_Component -- + --------------------- + + procedure Check_Component + (Comp_Typ : Entity_Id; + Comp_Decl : Node_Id := Empty) + is + Comp : Entity_Id; + T : Entity_Id; + + begin + -- Return without further checking if the component has explicit + -- initialization or does not come from source. + + if Present (Comp_Decl) then + if not Comes_From_Source (Comp_Decl) + or else Present (Expression (Comp_Decl)) + then + return; + end if; + end if; + + if Is_Incomplete_Or_Private_Type (Comp_Typ) + and then Present (Full_View (Comp_Typ)) + then + T := Full_View (Comp_Typ); + else + T := Comp_Typ; + end if; + + -- Verify a component of a null-excluding access type + + if Is_Access_Type (T) + and then Can_Never_Be_Null (T) + then + Null_Exclusion_Static_Checks (Obj_Decl, Comp_Decl); + + -- Check array type components + + elsif Is_Array_Type (T) then + -- There is no suitable component when the object is of an + -- array type. However, a namable component may appear at some + -- point during the recursive inspection, but not at the top + -- level. + + if Comp_Decl = Obj_Decl then + Check_Component (Component_Type (T)); + else + Check_Component (Component_Type (T), Comp_Decl); + end if; + + -- If T allows named components, then iterate through them, + -- recursively verifying all subcomponents. + + -- NOTE: Due to the complexities involved with checking components + -- of nontrivial types with discriminants (variant records and + -- the like), no static checking is performed on them. ??? + + elsif (Is_Concurrent_Type (T) + or else Is_Incomplete_Or_Private_Type (T) + or else Is_Record_Type (T)) + and then not Has_Discriminants (T) + then + Comp := First_Component (T); + while Present (Comp) loop + Check_Component (Etype (Comp), Parent (Comp)); + + Comp := Next_Component (Comp); + end loop; + end if; + end Check_Component; + + -- Start processing for Check_For_Null_Excluding_Components + + begin + Check_Component (Obj_Typ, Obj_Decl); + end Check_For_Null_Excluding_Components; + ----------------- -- Count_Tasks -- ----------------- @@ -3808,25 +3909,34 @@ -- Ada 2005 (AI-231): Propagate the null-excluding attribute and carry -- out some static checks. - if Ada_Version >= Ada_2005 and then Can_Never_Be_Null (T) then - + if Ada_Version >= Ada_2005 then -- In case of aggregates we must also take care of the correct -- initialization of nested aggregates bug this is done at the -- point of the analysis of the aggregate (see sem_aggr.adb) ??? - if Present (Expression (N)) - and then Nkind (Expression (N)) = N_Aggregate - then - null; + if Can_Never_Be_Null (T) then + if Present (Expression (N)) + and then Nkind (Expression (N)) = N_Aggregate + then + null; + + else + declare + Save_Typ : constant Entity_Id := Etype (Id); + begin + Set_Etype (Id, T); -- Temp. decoration for static checks + Null_Exclusion_Static_Checks (N); + Set_Etype (Id, Save_Typ); + end; + end if; + + -- We might be dealing with an object of a composite type containing + -- null-excluding components without an aggregate, so we must verify + -- that such components have default initialization. + else - declare - Save_Typ : constant Entity_Id := Etype (Id); - begin - Set_Etype (Id, T); -- Temp. decoration for static checks - Null_Exclusion_Static_Checks (N); - Set_Etype (Id, Save_Typ); - end; + Check_For_Null_Excluding_Components (T, N); end if; end if;