Scalar_Storage_Order must be consistent between any component of a composite type (array or record) and the composite type itself. We already enforced this in the case where the enclosing type has a Scalar_Storage_Order attribute definition, and the component type has none. We now also do so also in the opposite case when the enclosing type has no Scalar_Storage_Order clause, and any component does have one.
The following compilation must be rejected with the indicated error messages: $ gcc -c nat_comp_rev_el.ads nat_comp_rev_el.ads:26:04: composite type must have explicit scalar storage order nat_comp_rev_el.ads:27:04: composite type must have explicit scalar storage order nat_comp_rev_el.ads:29:07: composite type must have explicit scalar storage order nat_comp_rev_el.ads:34:07: composite type must have explicit scalar storage order with System; use System; package Nat_Comp_Rev_El is type U32 is mod 2**32; type LE_Record is record X : U32; end record; for LE_Record use record X at 0 range 0 .. 31; end record; for LE_Record'Bit_Order use Low_Order_First; for LE_Record'Scalar_Storage_Order use Low_Order_First; type BE_Record is record X : U32; end record; for BE_Record use record X at 0 range 0 .. 31; end record; for BE_Record'Bit_Order use High_Order_First; for BE_Record'Scalar_Storage_Order use High_Order_First; -- Reject the below declarations: the component type has an explicit SSO, -- so we also require one on the enclosing composite type. type Two_LE is array (1 .. 2) of LE_Record; type Two_BE is array (1 .. 2) of BE_Record; type Rec_LE is record Comp : LE_Record; X : Integer; end record; type Rec_BE is record Comp : BE_Record; X : Integer; end record; end Nat_Comp_Rev_El; Tested on x86_64-pc-linux-gnu, committed on trunk 2013-10-17 Thomas Quinot <qui...@adacore.com> * freeze.adb (Check_Component_Storage_Order): Reject a record or array type that does not have an explicit Scalar_Storage_Order attribute definition if a component of the record, or the elements of the array, have one. * gnat_rm.texi (attribute Scalar_Storage_Order): Document the above rule.
Index: gnat_rm.texi =================================================================== --- gnat_rm.texi (revision 203568) +++ gnat_rm.texi (working copy) @@ -8727,6 +8727,10 @@ if the component does not start on a byte boundary, then the scalar storage order specified for S and for the nested component type shall be identical. +If @var{S} appears as the type of a record or array component, the enclosing +record or array shall also have a @code{Scalar_Storage_Order} attribute +definition clause. + No component of a type that has a @code{Scalar_Storage_Order} attribute definition may be aliased. Index: freeze.adb =================================================================== --- freeze.adb (revision 203568) +++ freeze.adb (working copy) @@ -92,11 +92,15 @@ procedure Check_Component_Storage_Order (Encl_Type : Entity_Id; - Comp : Entity_Id); + Comp : Entity_Id; + ADC : Node_Id); -- For an Encl_Type that has a Scalar_Storage_Order attribute definition - -- clause, verify that the component type is compatible. For arrays, - -- Comp is Empty; for records, it is the entity of the component under - -- consideration. + -- clause, verify that the component type has an explicit and compatible + -- attribute/aspect. For arrays, Comp is Empty; for records, it is the + -- entity of the component under consideration. For an Encl_Type that + -- does not have a Scalar_Storage_Order attribute definition clause, + -- verify that the component also does not have such a clause. + -- ADC is the attribute definition clause if present (or Empty). procedure Check_Strict_Alignment (E : Entity_Id); -- E is a base type. If E is tagged or has a component that is aliased @@ -1068,11 +1072,12 @@ procedure Check_Component_Storage_Order (Encl_Type : Entity_Id; - Comp : Entity_Id) + Comp : Entity_Id; + ADC : Node_Id) is Comp_Type : Entity_Id; + Comp_ADC : Node_Id; Err_Node : Node_Id; - ADC : Node_Id; Comp_Byte_Aligned : Boolean; -- Set True for the record case, when Comp starts on a byte boundary @@ -1113,11 +1118,24 @@ -- the attribute definition clause is attached to the first subtype. Comp_Type := Base_Type (Comp_Type); - ADC := Get_Attribute_Definition_Clause - (First_Subtype (Comp_Type), - Attribute_Scalar_Storage_Order); + Comp_ADC := Get_Attribute_Definition_Clause + (First_Subtype (Comp_Type), + Attribute_Scalar_Storage_Order); - if Is_Record_Type (Comp_Type) or else Is_Array_Type (Comp_Type) then + -- Case of enclosing type not having explicit SSO: component cannot + -- have it either. + + if No (ADC) then + if Present (Comp_ADC) then + Error_Msg_N + ("composite type must have explicit scalar storage order", + Err_Node); + end if; + + -- Case of enclosing type having explicit SSO: check compatible + -- attribute on Comp_Type if composite. + + elsif Is_Record_Type (Comp_Type) or else Is_Array_Type (Comp_Type) then if Present (Comp) and then Chars (Comp) = Name_uParent then if Reverse_Storage_Order (Encl_Type) /= @@ -1142,6 +1160,9 @@ & "storage order as enclosing composite", Err_Node); end if; + -- Enclosing type has explicit SSO, non-composite component must not + -- be aliased. + elsif Component_Aliased then Error_Msg_N ("aliased component not permitted for type with " @@ -2312,11 +2333,12 @@ -- Check for scalar storage order - if Present (Get_Attribute_Definition_Clause - (Arr, Attribute_Scalar_Storage_Order)) - then - Check_Component_Storage_Order (Arr, Empty); - end if; + Check_Component_Storage_Order + (Encl_Type => Arr, + Comp => Empty, + ADC => Get_Attribute_Definition_Clause + (First_Subtype (Arr), + Attribute_Scalar_Storage_Order)); -- Processing that is done only for subtypes @@ -2999,15 +3021,16 @@ ("??scalar storage order specified but no component clause", ADC); end if; + end if; - -- Check attribute on component types + -- Check consistent attribute setting on component types - Comp := First_Component (Rec); - while Present (Comp) loop - Check_Component_Storage_Order (Rec, Comp); - Next_Component (Comp); - end loop; - end if; + Comp := First_Component (Rec); + while Present (Comp) loop + Check_Component_Storage_Order + (Encl_Type => Rec, Comp => Comp, ADC => ADC); + Next_Component (Comp); + end loop; -- Deal with Bit_Order aspect specifying a non-default bit order