When restriction No_Implicit_Heap_Allocation is active, the compiler rejects a protected type that includes private components of dynamic size, This patch extends the corresponding warning to the declaration of discriminated objects.
Given the following gnat.adc file: pragma profile (Ravenscar); compiling p.adb must yield: p.adb:13:04: warning: in instantiation at a-cbhama.ads:448 p.adb:13:04: warning: component "TC" of non-static size will violate restriction No_Implicit_Heap_Allocation p.adb:19:04: violation of restriction "no_implicit_heap_allocations" p.adb:19:04: from profile "ravenscar" at gnat.adc:14 --- with Ada.Containers.Bounded_Hashed_Maps; with Ada.Text_IO; with Ada.Strings; with Ada.Strings.Hash; -- package body Flight_Data.Hash with -- SPARK_Mode -- is package body P is subtype GUFI is String (1 .. 36); --key subtype Flight_ID is Integer range 1 ..5000; --element function eq (Left, Right : Flight_ID) return Boolean is (Left = Right); package Flight_Maps is new Ada.Containers.Bounded_Hashed_Maps (Key_Type => GUFI, Element_Type => Flight_Id, Hash => Ada.Strings.Hash, Equivalent_Keys => "="); use Flight_Maps; The_Hash_Table : Map (Capacity => 2000, Modulus => Flight_Maps.Default_Modulus (2000)); procedure Go is Cur : Cursor; My_Gufi : GUFI := GUFI'(others => 'a'); begin Include(The_Hash_Table, My_GUFI, 12); Cur := Find(The_Hash_Table, My_GUFI); Ada.Text_IO.Put_Line (Flight_ID'Image(Element(Cur))); end Go; end P; --- with Ada.Containers.Formal_Hashed_Maps; with Ada.Text_IO; with Ada.Strings; with Ada.Strings.Hash; package P is procedure Go; end P; Tested on x86_64-pc-linux-gnu, committed on trunk 2017-05-02 Ed Schonberg <schonb...@adacore.com> * exp_ch9.adb (Discriminated_Size): Moved to sem_util. * sem_util.ads, sem_util.adb (Discriminated_Size): Predicate moved here from exp_ch9, to recognize objects whose creation requires dynamic allocation, so that the proper warning can be emitted when restriction No_Implicit_Heap_Allocation is in effect. * sem_ch3.adb (Analyze_Object_Declaration): Use Discriminated_Size to emit proper warning when an object that requires dynamic allocation is declared.
Index: sem_ch3.adb =================================================================== --- sem_ch3.adb (revision 247468) +++ sem_ch3.adb (working copy) @@ -3133,6 +3133,9 @@ when N_Derived_Type_Definition => Derived_Type_Declaration (T, N, T /= Def_Id); + if Ekind (T) /= E_Void and then Has_Predicates (T) then -- ???? + Set_Has_Predicates (Def_Id); + end if; when N_Enumeration_Type_Definition => Enumeration_Type_Declaration (T, Def); @@ -3588,6 +3591,11 @@ Prev_Entity : Entity_Id := Empty; + procedure Check_Dynamic_Object (Typ : Entity_Id); + -- A library-level object with non-static discriminant constraints may + -- require dynamic allocation. The declaration is illegal if the + -- profile includes the restriction No_Implicit_Heap_Allocations. + procedure Check_For_Null_Excluding_Components (Obj_Typ : Entity_Id; Obj_Decl : Node_Id); @@ -3614,6 +3622,45 @@ -- Any other relevant delayed aspects on object declarations ??? + procedure Check_Dynamic_Object (Typ : Entity_Id) is + Comp : Entity_Id; + Obj_Type : Entity_Id; + + begin + Obj_Type := Typ; + if Is_Private_Type (Obj_Type) + and then Present (Full_View (Obj_Type)) + then + Obj_Type := Full_View (Obj_Type); + end if; + + if Known_Static_Esize (Obj_Type) then + return; + end if; + + if Restriction_Active (No_Implicit_Heap_Allocations) + and then Expander_Active + and then Has_Discriminants (Obj_Type) + then + Comp := First_Component (Obj_Type); + while Present (Comp) loop + if Known_Static_Esize (Etype (Comp)) then + null; + + elsif not Discriminated_Size (Comp) + and then Comes_From_Source (Comp) + then + Error_Msg_NE ("component& of non-static size will violate " + & "restriction No_Implicit_Heap_Allocation?", N, Comp); + + elsif Is_Record_Type (Etype (Comp)) then + Check_Dynamic_Object (Etype (Comp)); + end if; + Next_Component (Comp); + end loop; + end if; + end Check_Dynamic_Object; + ----------------------------------------- -- Check_For_Null_Excluding_Components -- ----------------------------------------- @@ -4068,6 +4115,10 @@ Object_Definition (N)); end if; + if Is_Library_Level_Entity (Id) then + Check_Dynamic_Object (T); + end if; + -- There are no aliased objects in SPARK if Aliased_Present (N) then @@ -15458,6 +15509,10 @@ and then Has_Non_Trivial_Precondition (Parent_Subp) and then Present (Interfaces (Derived_Type)) then + + -- Add useful attributes of subprogram before the freeze point, + -- in case freezing is delayed or there are previous errors. + Set_Is_Dispatching_Operation (New_Subp); declare Index: exp_ch9.adb =================================================================== --- exp_ch9.adb (revision 247461) +++ exp_ch9.adb (working copy) @@ -8725,12 +8725,6 @@ -- to the internal body, for possible inlining later on. The source -- operation is invisible to the back-end and is never actually called. - function Discriminated_Size (Comp : Entity_Id) return Boolean; - -- If a component size is not static then a warning will be emitted - -- in Ravenscar or other restricted contexts. When a component is non- - -- static because of a discriminant constraint we can specialize the - -- warning by mentioning discriminants explicitly. - procedure Expand_Entry_Declaration (Decl : Node_Id); -- Create the entry barrier and the procedure body for entry declaration -- Decl. All generated subprograms are added to Entry_Bodies_Array. @@ -8758,63 +8752,6 @@ end if; end Check_Inlining; - ------------------------ - -- Discriminated_Size -- - ------------------------ - - function Discriminated_Size (Comp : Entity_Id) return Boolean is - Typ : constant Entity_Id := Etype (Comp); - Index : Node_Id; - - function Non_Static_Bound (Bound : Node_Id) return Boolean; - -- Check whether the bound of an index is non-static and does denote - -- a discriminant, in which case any protected object of the type - -- will have a non-static size. - - ---------------------- - -- Non_Static_Bound -- - ---------------------- - - function Non_Static_Bound (Bound : Node_Id) return Boolean is - begin - if Is_OK_Static_Expression (Bound) then - return False; - - elsif Is_Entity_Name (Bound) - and then Present (Discriminal_Link (Entity (Bound))) - then - return False; - - else - return True; - end if; - end Non_Static_Bound; - - -- Start of processing for Discriminated_Size - - begin - if not Is_Array_Type (Typ) then - return False; - end if; - - if Ekind (Typ) = E_Array_Subtype then - Index := First_Index (Typ); - while Present (Index) loop - if Non_Static_Bound (Low_Bound (Index)) - or else Non_Static_Bound (High_Bound (Index)) - then - return False; - end if; - - Next_Index (Index); - end loop; - - return True; - end if; - - return False; - end Discriminated_Size; - --------------------------- -- Static_Component_Size -- --------------------------- Index: sem_util.adb =================================================================== --- sem_util.adb (revision 247461) +++ sem_util.adb (working copy) @@ -6312,6 +6312,70 @@ return Make_Level_Literal (Type_Access_Level (Etype (Expr))); end Dynamic_Accessibility_Level; + ------------------------ + -- Discriminated_Size -- + ------------------------ + + function Discriminated_Size (Comp : Entity_Id) return Boolean is + Typ : constant Entity_Id := Etype (Comp); + Index : Node_Id; + + function Non_Static_Bound (Bound : Node_Id) return Boolean; + -- Check whether the bound of an index is non-static and does denote + -- a discriminant, in which case any object of the type (protected + -- or otherwise) will have a non-static size. + + ---------------------- + -- Non_Static_Bound -- + ---------------------- + + function Non_Static_Bound (Bound : Node_Id) return Boolean is + begin + if Is_OK_Static_Expression (Bound) then + return False; + + -- If the bound is given by a discriminant it is non-static + -- (A static constraint replaces the reference with the value). + -- In an protected object the discriminant has been replaced by + -- the corresponding discriminal within the protected operation. + + elsif Is_Entity_Name (Bound) + and then + (Ekind (Entity (Bound)) = E_Discriminant + or else Present (Discriminal_Link (Entity (Bound)))) + then + return False; + + else + return True; + end if; + end Non_Static_Bound; + + -- Start of processing for Discriminated_Size + + begin + if not Is_Array_Type (Typ) then + return False; + end if; + + if Ekind (Typ) = E_Array_Subtype then + Index := First_Index (Typ); + while Present (Index) loop + if Non_Static_Bound (Low_Bound (Index)) + or else Non_Static_Bound (High_Bound (Index)) + then + return False; + end if; + + Next_Index (Index); + end loop; + + return True; + end if; + + return False; + end Discriminated_Size; + ----------------------------------- -- Effective_Extra_Accessibility -- ----------------------------------- Index: sem_util.ads =================================================================== --- sem_util.ads (revision 247461) +++ sem_util.ads (working copy) @@ -601,6 +601,14 @@ -- accessibility levels are tracked at runtime (access parameters and Ada -- 2012 stand-alone objects). + function Discriminated_Size (Comp : Entity_Id) return Boolean; + -- If a component size is not static then a warning will be emitted + -- in Ravenscar or other restricted contexts. When a component is non- + -- static because of a discriminant constraint we can specialize the + -- warning by mentioning discriminants explicitly. This was created for + -- private components of protected objects, but is generally useful when + -- retriction (No_Implicit_Heap_Allocation) is active. + function Effective_Extra_Accessibility (Id : Entity_Id) return Entity_Id; -- Same as Einfo.Extra_Accessibility except thtat object renames -- are looked through.