From: Steve Baird <ba...@adacore.com> Fix bugs related to mutably tagged types in streaming operations, Put_Image attributes, aggregates, composite equality comparisons with mutably-tagged components, and other issues.
gcc/ada/ChangeLog: * exp_aggr.adb (Build_Record_Aggr_Code.Gen_Assign): In the case of an aggregate component where the component type is mutably tagged and the component value is provided by a qualified aggregate (and qualified with a specific type), avoid incorrectly rejecting the inner aggregate for violating the rule that the type of an aggregate shall not be class-wide. * exp_attr.adb: For a predefined streaming operation (i.e., Read, Write, Input, or Output) of a class-wide type, the external name of the tag of the value is normally written out by Output and read in by Input. In the case of a mutably tagged type, this is instead done in Write and Read. * exp_ch4.adb (Expand_Composite_Equality): In the case of an equality comparison for a type having a mutably tagged component, we want the component comparison to compare two values of the mutably tagged type, not two values of the corresponding array-of-bytes-ish representation type. Even if there are no user-defined equality functions anywhere in sight, comparing the array values still doesn't work because undefined bits may end up participating in the comparison (resulting in an incorrect result of False). * exp_put_image.adb: In the case of a class-wide type, the predefined Image attribute includes the name of the specific type (and a "'" character, to follow qualified expression syntax) to indicate the tag of the value. With the introduction of mutably tagged types, this case can now arise in the case of a component (of either an enclosing array or an enclosing record), not just for a top-level object. So we factor the code to do this into a new procedure, Put_Specific_Type_Name_Qualifier, so that it can be called from more than one place. This reorganization also involves replacing the procedure Put_String_Exp with a new procedure, Put_String_Exp_To_Buffer, declared in a less nested scope. For mutably tagged components (at the source level) the component type (at the GNAT tree level) is an array of bytes (actually a two field record containing an array of bytes, but that's a detail). Appropriate conversions need to be generated so that we don't end up generating an image for an array of bytes; this is done at the same places where Put_Specific_Type_Name_Qualifier is called (for components) by calling Make_Mutably_Tagged_Conversion. * exp_strm.adb (Make_Field_Attribute): Add Make_Mutably_Tagged_Conversion call where we construct a Selected_Component node and the corresponding component type is the internal representation type for a mutably tagged type. (Stream_Base_Type): Return the mutably tagged type if given the corresponding internal representation type. * sem_ch3.adb (Array_Type_Declaration): In the case where the source-level component type of an array type is mutably tagged, set the Component_Type field of the base type of the declared array type (as opposed to that of the first subtype of the array type) to the corresponding internal representation type. * sem_ch4.adb (Analyze_Selected_Component): In the case of a selected component name which references a component whose type is the internal representation type of a mutably tagged type, generate a conversion to the mutably tagged type. Tested on x86_64-pc-linux-gnu, committed on master. --- gcc/ada/exp_aggr.adb | 5 +- gcc/ada/exp_attr.adb | 404 ++++++++++++++++++++++++-------------- gcc/ada/exp_ch4.adb | 10 +- gcc/ada/exp_put_image.adb | 343 ++++++++++++++++++-------------- gcc/ada/exp_strm.adb | 35 ++-- gcc/ada/sem_ch3.adb | 2 +- gcc/ada/sem_ch4.adb | 4 + 7 files changed, 498 insertions(+), 305 deletions(-) diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb index bdb4c8556f2..2f3bab44a78 100644 --- a/gcc/ada/exp_aggr.adb +++ b/gcc/ada/exp_aggr.adb @@ -1422,8 +1422,11 @@ package body Exp_Aggr is elsif Is_Mutably_Tagged_Type (Comp_Typ) and then Nkind (Expr) = N_Qualified_Expression then - Analyze_And_Resolve (Expr_Q, Etype (Expr)); + -- Avoid class-wide expected type for aggregate + -- (which would be rejected as illegal) + -- if the aggregate is explicitly qualified. + Analyze_And_Resolve (Expr_Q, Etype (Expr)); else Analyze_And_Resolve (Expr_Q, Comp_Typ); end if; diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb index 4f9f16cfa55..810248de1ac 100644 --- a/gcc/ada/exp_attr.adb +++ b/gcc/ada/exp_attr.adb @@ -1915,6 +1915,15 @@ package body Exp_Attr is -- call to the appropriate TSS procedure. Pname is the entity for the -- procedure to call. + procedure Read_Controlling_Tag + (P_Type : Entity_Id; Cntrl : out Node_Id); + -- Read the external tag from the stream and use it to construct the + -- controlling operand for a dispatching call. + + procedure Write_Controlling_Tag (P_Type : Entity_Id); + -- Write the external tag of the given attribute prefix type to + -- the stream. Also perform the accompanying accessibility check. + ------------------------------------- -- Build_And_Insert_Type_Attr_Subp -- ------------------------------------- @@ -2175,6 +2184,153 @@ package body Exp_Attr is Analyze (N); end Rewrite_Attribute_Proc_Call; + -------------------------- + -- Read_Controlling_Tag -- + -------------------------- + + procedure Read_Controlling_Tag + (P_Type : Entity_Id; Cntrl : out Node_Id) + is + Strm : constant Node_Id := First (Exprs); + Expr : Node_Id; -- call to Descendant_Tag + Get_Tag : Node_Id; -- expression to read the 'Tag + + begin + -- Read the internal tag (RM 13.13.2(34)) and use it to + -- initialize a dummy tag value. We used to unconditionally + -- generate: + -- + -- Descendant_Tag (String'Input (Strm), P_Type); + -- + -- which turns into a call to String_Input_Blk_IO. However, + -- if the input is malformed, that could try to read an + -- enormous String, causing chaos. So instead we call + -- String_Input_Tag, which does the same thing as + -- String_Input_Blk_IO, except that if the String is + -- absurdly long, it raises an exception. + -- + -- However, if the No_Stream_Optimizations restriction + -- is active, we disable this unnecessary attempt at + -- robustness; we really need to read the string + -- character-by-character. + -- + -- This value is used only to provide a controlling + -- argument for the eventual _Input call. Descendant_Tag is + -- called rather than Internal_Tag to ensure that we have a + -- tag for a type that is descended from the prefix type and + -- declared at the same accessibility level (the exception + -- Tag_Error will be raised otherwise). The level check is + -- required for Ada 2005 because tagged types can be + -- extended in nested scopes (AI-344). + + -- Note: we used to generate an explicit declaration of a + -- constant Ada.Tags.Tag object, and use an occurrence of + -- this constant in Cntrl, but this caused a secondary stack + -- leak. + + if Restriction_Active (No_Stream_Optimizations) then + Get_Tag := + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Standard_String, Loc), + Attribute_Name => Name_Input, + Expressions => New_List ( + Relocate_Node (Duplicate_Subexpr (Strm)))); + else + Get_Tag := + Make_Function_Call (Loc, + Name => + New_Occurrence_Of + (RTE (RE_String_Input_Tag), Loc), + Parameter_Associations => New_List ( + Relocate_Node (Duplicate_Subexpr (Strm)))); + end if; + + Expr := + Make_Function_Call (Loc, + Name => + New_Occurrence_Of (RTE (RE_Descendant_Tag), Loc), + Parameter_Associations => New_List ( + Get_Tag, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (P_Type, Loc), + Attribute_Name => Name_Tag))); + + Set_Etype (Expr, RTE (RE_Tag)); + + -- Construct a controlling operand for a dispatching call. + + Cntrl := Unchecked_Convert_To (P_Type, Expr); + Set_Etype (Cntrl, P_Type); + Set_Parent (Cntrl, N); + end Read_Controlling_Tag; + + ---------------------------- + -- Write_Controlling_Tag -- + ---------------------------- + + procedure Write_Controlling_Tag (P_Type : Entity_Id) is + Strm : constant Node_Id := First (Exprs); + Item : constant Node_Id := Next (Strm); + begin + -- Ada 2005 (AI-344): Check that the accessibility level + -- of the type of the output object is not deeper than + -- that of the attribute's prefix type. + + -- if Get_Access_Level (Item'Tag) + -- /= Get_Access_Level (P_Type'Tag) + -- then + -- raise Tag_Error; + -- end if; + + -- String'Output (Strm, External_Tag (Item'Tag)); + + -- We cannot figure out a practical way to implement this + -- accessibility check on virtual machines, so we omit it. + + if Ada_Version >= Ada_2005 + and then Tagged_Type_Expansion + then + Insert_Action (N, + Make_Implicit_If_Statement (N, + Condition => + Make_Op_Ne (Loc, + Left_Opnd => + Build_Get_Access_Level (Loc, + Make_Attribute_Reference (Loc, + Prefix => + Relocate_Node ( + Duplicate_Subexpr (Item, + Name_Req => True)), + Attribute_Name => Name_Tag)), + + Right_Opnd => + Make_Integer_Literal (Loc, + Type_Access_Level (P_Type))), + + Then_Statements => + New_List (Make_Raise_Statement (Loc, + New_Occurrence_Of ( + RTE (RE_Tag_Error), Loc))))); + end if; + + Insert_Action (N, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Standard_String, Loc), + Attribute_Name => Name_Output, + Expressions => New_List ( + Relocate_Node (Duplicate_Subexpr (Strm)), + Make_Function_Call (Loc, + Name => + New_Occurrence_Of (RTE (RE_External_Tag), Loc), + Parameter_Associations => New_List ( + Make_Attribute_Reference (Loc, + Prefix => + Relocate_Node + (Duplicate_Subexpr (Item, Name_Req => True)), + Attribute_Name => Name_Tag)))))); + end Write_Controlling_Tag; + Typ : constant Entity_Id := Etype (N); Btyp : constant Entity_Id := Base_Type (Typ); Ptyp : constant Entity_Id := Etype (Pref); @@ -4487,6 +4643,47 @@ package body Exp_Attr is elsif Is_Class_Wide_Type (P_Type) then + if Is_Mutably_Tagged_Type (P_Type) then + + -- In mutably tagged case, rewrite + -- T'Class'Input (Strm) + -- as (roughly) + -- declare + -- Result : T'Class; + -- T'Class'Read (Strm, Result); + -- begin + -- Result; + -- end; + + declare + Result_Temp : constant Entity_Id := + Make_Temporary (Loc, 'I'); + + -- Gets default initialization + Result_Temp_Decl : constant Node_Id := + Make_Object_Declaration (Loc, + Defining_Identifier => Result_Temp, + Object_Definition => + New_Occurrence_Of (P_Type, Loc)); + + function Result_Temp_Name return Node_Id is + (New_Occurrence_Of (Result_Temp, Loc)); + + Actions : constant List_Id := New_List ( + Result_Temp_Decl, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (P_Type, Loc), + Attribute_Name => Name_Read, + Expressions => New_List ( + Relocate_Node (Strm), Result_Temp_Name))); + begin + Rewrite (N, Make_Expression_With_Actions (Loc, + Actions, Result_Temp_Name)); + Analyze_And_Resolve (N, P_Type); + return; + end; + end if; + -- No need to do anything else compiling under restriction -- No_Dispatching_Calls. During the semantic analysis we -- already notified such violation. @@ -4495,86 +4692,8 @@ package body Exp_Attr is return; end if; - declare - Rtyp : constant Entity_Id := Root_Type (P_Type); - - Expr : Node_Id; -- call to Descendant_Tag - Get_Tag : Node_Id; -- expression to read the 'Tag - - begin - -- Read the internal tag (RM 13.13.2(34)) and use it to - -- initialize a dummy tag value. We used to unconditionally - -- generate: - -- - -- Descendant_Tag (String'Input (Strm), P_Type); - -- - -- which turns into a call to String_Input_Blk_IO. However, - -- if the input is malformed, that could try to read an - -- enormous String, causing chaos. So instead we call - -- String_Input_Tag, which does the same thing as - -- String_Input_Blk_IO, except that if the String is - -- absurdly long, it raises an exception. - -- - -- However, if the No_Stream_Optimizations restriction - -- is active, we disable this unnecessary attempt at - -- robustness; we really need to read the string - -- character-by-character. - -- - -- This value is used only to provide a controlling - -- argument for the eventual _Input call. Descendant_Tag is - -- called rather than Internal_Tag to ensure that we have a - -- tag for a type that is descended from the prefix type and - -- declared at the same accessibility level (the exception - -- Tag_Error will be raised otherwise). The level check is - -- required for Ada 2005 because tagged types can be - -- extended in nested scopes (AI-344). - - -- Note: we used to generate an explicit declaration of a - -- constant Ada.Tags.Tag object, and use an occurrence of - -- this constant in Cntrl, but this caused a secondary stack - -- leak. - - if Restriction_Active (No_Stream_Optimizations) then - Get_Tag := - Make_Attribute_Reference (Loc, - Prefix => - New_Occurrence_Of (Standard_String, Loc), - Attribute_Name => Name_Input, - Expressions => New_List ( - Relocate_Node (Duplicate_Subexpr (Strm)))); - else - Get_Tag := - Make_Function_Call (Loc, - Name => - New_Occurrence_Of - (RTE (RE_String_Input_Tag), Loc), - Parameter_Associations => New_List ( - Relocate_Node (Duplicate_Subexpr (Strm)))); - end if; - - Expr := - Make_Function_Call (Loc, - Name => - New_Occurrence_Of (RTE (RE_Descendant_Tag), Loc), - Parameter_Associations => New_List ( - Get_Tag, - Make_Attribute_Reference (Loc, - Prefix => New_Occurrence_Of (P_Type, Loc), - Attribute_Name => Name_Tag))); - - Set_Etype (Expr, RTE (RE_Tag)); - - -- Now we need to get the entity for the call, and construct - -- a function call node, where we preset a reference to Dnn - -- as the controlling argument (doing an unchecked convert - -- to the class-wide tagged type to make it look like a real - -- tagged object). - - Fname := Find_Prim_Op (Rtyp, TSS_Stream_Input); - Cntrl := Unchecked_Convert_To (P_Type, Expr); - Set_Etype (Cntrl, P_Type); - Set_Parent (Cntrl, N); - end; + Read_Controlling_Tag (P_Type, Cntrl); + Fname := Find_Prim_Op (Root_Type (P_Type), TSS_Stream_Input); -- For tagged types, use the primitive Input function @@ -5957,6 +6076,14 @@ package body Exp_Attr is Attr_Ref => N); end; + -- In the mutably tagged case, T'Class'Output calls T'Class'Write; + -- T'Write will take care of writing out the external tag. + + elsif Is_Mutably_Tagged_Type (P_Type) then + Set_Attribute_Name (N, Name_Write); + Analyze (N); + return; + -- Class-wide case, first output external tag, then dispatch -- to the appropriate primitive Output function (RM 13.13.2(31)). @@ -5970,68 +6097,7 @@ package body Exp_Attr is return; end if; - Tag_Write : declare - Strm : constant Node_Id := First (Exprs); - Item : constant Node_Id := Next (Strm); - - begin - -- Ada 2005 (AI-344): Check that the accessibility level - -- of the type of the output object is not deeper than - -- that of the attribute's prefix type. - - -- if Get_Access_Level (Item'Tag) - -- /= Get_Access_Level (P_Type'Tag) - -- then - -- raise Tag_Error; - -- end if; - - -- String'Output (Strm, External_Tag (Item'Tag)); - - -- We cannot figure out a practical way to implement this - -- accessibility check on virtual machines, so we omit it. - - if Ada_Version >= Ada_2005 - and then Tagged_Type_Expansion - then - Insert_Action (N, - Make_Implicit_If_Statement (N, - Condition => - Make_Op_Ne (Loc, - Left_Opnd => - Build_Get_Access_Level (Loc, - Make_Attribute_Reference (Loc, - Prefix => - Relocate_Node ( - Duplicate_Subexpr (Item, - Name_Req => True)), - Attribute_Name => Name_Tag)), - - Right_Opnd => - Make_Integer_Literal (Loc, - Type_Access_Level (P_Type))), - - Then_Statements => - New_List (Make_Raise_Statement (Loc, - New_Occurrence_Of ( - RTE (RE_Tag_Error), Loc))))); - end if; - - Insert_Action (N, - Make_Attribute_Reference (Loc, - Prefix => New_Occurrence_Of (Standard_String, Loc), - Attribute_Name => Name_Output, - Expressions => New_List ( - Relocate_Node (Duplicate_Subexpr (Strm)), - Make_Function_Call (Loc, - Name => - New_Occurrence_Of (RTE (RE_External_Tag), Loc), - Parameter_Associations => New_List ( - Make_Attribute_Reference (Loc, - Prefix => - Relocate_Node - (Duplicate_Subexpr (Item, Name_Req => True)), - Attribute_Name => Name_Tag)))))); - end Tag_Write; + Write_Controlling_Tag (P_Type); Pname := Find_Prim_Op (U_Type, TSS_Stream_Output); @@ -6793,6 +6859,7 @@ package body Exp_Attr is P_Type : constant Entity_Id := Entity (Pref); B_Type : constant Entity_Id := Base_Type (P_Type); U_Type : constant Entity_Id := Underlying_Type (P_Type); + Cntrl : Node_Id := Empty; -- nonempty only if P_Type mutably tagged Pname : Entity_Id; Decl : Node_Id; Prag : Node_Id; @@ -6941,6 +7008,11 @@ package body Exp_Attr is -- this will dispatch in the class-wide case which is what we want elsif Is_Tagged_Type (U_Type) then + + if Is_Mutably_Tagged_Type (U_Type) then + Read_Controlling_Tag (P_Type, Cntrl); + end if; + Pname := Find_Prim_Op (U_Type, TSS_Stream_Read); -- All other record type cases, including protected records. The @@ -7001,6 +7073,46 @@ package body Exp_Attr is Rewrite_Attribute_Proc_Call (Pname); + if Present (Cntrl) then + pragma Assert (Is_Mutably_Tagged_Type (U_Type)); + pragma Assert (Nkind (N) = N_Procedure_Call_Statement); + + -- Assign the Tag value that was read from the stream + -- to the tag of the out-mode actual parameter so that + -- we dispatch correctly. This isn't quite right. + -- We should assign a complete object (not just + -- the tag), but that would require a dispatching call to + -- perform default initialization of the source object and + -- dispatching default init calls are currently not supported. + + declare + function Select_Tag (Prefix : Node_Id) return Node_Id is + (Make_Selected_Component (Loc, + Prefix => Prefix, + Selector_Name => + New_Occurrence_Of (First_Tag_Component + (Etype (Prefix)), Loc))); + + Controlling_Actual : constant Node_Id := + Next (First (Parameter_Associations (N))); + + pragma Assert (Is_Controlling_Actual (Controlling_Actual)); + + Assign_Tag : Node_Id; + begin + Remove_Side_Effects (Controlling_Actual, Name_Req => True); + + Assign_Tag := + Make_Assignment_Statement (Loc, + Name => + Select_Tag (New_Copy_Tree (Controlling_Actual)), + Expression => Select_Tag (Cntrl)); + + Insert_Before (Before => N, Node => Assign_Tag); + Analyze (Assign_Tag); + end; + end if; + if not Is_Tagged_Type (P_Type) then Cached_Attribute_Ops.Read_Map.Set (U_Type, Pname); end if; @@ -8611,6 +8723,14 @@ package body Exp_Attr is -- this will dispatch in the class-wide case which is what we want elsif Is_Tagged_Type (U_Type) then + + -- If T'Class is mutably tagged, then the external tag + -- is written out by T'Class'Write, not by T'Class'Output. + + if Is_Mutably_Tagged_Type (U_Type) then + Write_Controlling_Tag (P_Type); + end if; + Pname := Find_Prim_Op (U_Type, TSS_Stream_Write); -- All other record type cases, including protected records. diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb index 76386fc9f6a..43c94f37ba1 100644 --- a/gcc/ada/exp_ch4.adb +++ b/gcc/ada/exp_ch4.adb @@ -2354,6 +2354,7 @@ package body Exp_Ch4 is Rhs : Node_Id) return Node_Id is Loc : constant Source_Ptr := Sloc (Nod); + CW_Comp : Boolean := False; Full_Type : Entity_Id; Eq_Op : Entity_Id; @@ -2383,10 +2384,17 @@ package body Exp_Ch4 is Full_Type := Underlying_Type (Full_Type); end if; + if Is_Class_Wide_Equivalent_Type (Full_Type) then + CW_Comp := True; + Full_Type := + Get_Corresponding_Mutably_Tagged_Type_If_Present (Full_Type); + pragma Assert (Is_Tagged_Type (Full_Type)); + end if; + -- Case of tagged record types if Is_Tagged_Type (Full_Type) then - Eq_Op := Find_Primitive_Eq (Comp_Type); + Eq_Op := Find_Primitive_Eq (if CW_Comp then Full_Type else Comp_Type); pragma Assert (Present (Eq_Op)); return diff --git a/gcc/ada/exp_put_image.adb b/gcc/ada/exp_put_image.adb index 40b2a65b821..ce3390b5038 100644 --- a/gcc/ada/exp_put_image.adb +++ b/gcc/ada/exp_put_image.adb @@ -77,8 +77,28 @@ package body Exp_Put_Image is -- reference). The Loc parameter is used as the Sloc of the created entity. function Put_Image_Base_Type (E : Entity_Id) return Entity_Id; - -- Returns the base type, except for an array type whose whose first - -- subtype is constrained, in which case it returns the first subtype. + -- For an array type whose whose first subtype is constrained, return + -- the first subtype. For the internal representation type corresponding + -- to a mutably tagged type, return the mutably tagged type. Otherwise, + -- return the base type. Similar to Exp_Strm.Stream_Base_Type. + + procedure Put_Specific_Type_Name_Qualifier + (Loc : Source_Ptr; + Stms : List_Id; + Tagged_Obj : Node_Id; + Buffer_Name : Node_Id; + Is_Interface_Type : Boolean); + -- Append to the given statement list calls to add into the + -- buffer the name of the given object's tag and then a "'". + + function Put_String_Exp_To_Buffer + (Loc : Source_Ptr; + String_Exp : Node_Id; + Buffer_Name : Node_Id; + Wide_Wide : Boolean := False) return Node_Id; + -- Generate a call to evaluate a String (or Wide_Wide_String, depending + -- on the Wide_Wide Boolean parameter) expression and output it into + -- the buffer. ------------------------------------- -- Build_Array_Put_Image_Procedure -- @@ -189,7 +209,7 @@ package body Exp_Put_Image is Ndim : constant Pos := Number_Dimensions (Typ); Ctyp : constant Entity_Id := Component_Type (Typ); - Stm : Node_Id; + Stms : List_Id := New_List; Exl : constant List_Id := New_List; PI_Entity : Entity_Id; @@ -220,15 +240,36 @@ package body Exp_Put_Image is Append_To (Exl, Make_Identifier (Loc, New_External_Name ('L', Dim))); end loop; - Stm := - Make_Attribute_Reference (Loc, - Prefix => New_Occurrence_Of (Put_Image_Base_Type (Ctyp), Loc), - Attribute_Name => Name_Put_Image, - Expressions => New_List ( - Make_Identifier (Loc, Name_S), - Make_Indexed_Component (Loc, - Prefix => Make_Identifier (Loc, Name_V), - Expressions => Exl))); + declare + Ctype_For_Call : constant Entity_Id := Put_Image_Base_Type (Ctyp); + Indexed_Comp : constant Node_Id := + Make_Indexed_Component (Loc, + Prefix => Make_Identifier (Loc, Name_V), + Expressions => Exl); + begin + if Is_Mutably_Tagged_Type (Ctype_For_Call) then + pragma Assert (not Is_Mutably_Tagged_Type (Component_Type (Typ))); + + Make_Mutably_Tagged_Conversion (Indexed_Comp, + Typ => Ctype_For_Call); + + pragma Assert (Is_Mutably_Tagged_Type (Etype (Indexed_Comp))); + + Put_Specific_Type_Name_Qualifier (Loc, + Stms => Stms, + Tagged_Obj => Indexed_Comp, + Buffer_Name => Make_Identifier (Loc, Name_S), + Is_Interface_Type => False); + end if; + + Append_To (Stms, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Ctype_For_Call, Loc), + Attribute_Name => Name_Put_Image, + Expressions => New_List ( + Make_Identifier (Loc, Name_S), + Indexed_Comp))); + end; -- The corresponding attribute for the component type of the array might -- be user-defined, and frozen after the array type. In that case, @@ -245,46 +286,42 @@ package body Exp_Put_Image is -- Loop through the dimensions, innermost first, generating a loop for -- each dimension. - declare - Stms : List_Id := New_List (Stm); - begin - for Dim in reverse 1 .. Ndim loop - declare - New_Stms : constant List_Id := New_List; - Between_Proc : RE_Id; - begin - -- For a one-dimensional array of elementary type, use - -- RE_Simple_Array_Between. The same applies to the last - -- dimension of a multidimensional array. + for Dim in reverse 1 .. Ndim loop + declare + New_Stms : constant List_Id := New_List; + Between_Proc : RE_Id; + begin + -- For a one-dimensional array of elementary type, use + -- RE_Simple_Array_Between. The same applies to the last + -- dimension of a multidimensional array. - if Is_Elementary_Type (Ctyp) and then Dim = Ndim then - Between_Proc := RE_Simple_Array_Between; - else - Between_Proc := RE_Array_Between; - end if; + if Is_Elementary_Type (Ctyp) and then Dim = Ndim then + Between_Proc := RE_Simple_Array_Between; + else + Between_Proc := RE_Array_Between; + end if; - Append_To (New_Stms, - Make_Procedure_Call_Statement (Loc, - Name => New_Occurrence_Of (RTE (RE_Array_Before), Loc), - Parameter_Associations => New_List - (Make_Identifier (Loc, Name_S)))); + Append_To (New_Stms, + Make_Procedure_Call_Statement (Loc, + Name => New_Occurrence_Of (RTE (RE_Array_Before), Loc), + Parameter_Associations => New_List + (Make_Identifier (Loc, Name_S)))); - Append_To - (New_Stms, - Wrap_In_Loop (Stms, Dim, Indices (Dim), Between_Proc)); + Append_To + (New_Stms, + Wrap_In_Loop (Stms, Dim, Indices (Dim), Between_Proc)); - Append_To (New_Stms, - Make_Procedure_Call_Statement (Loc, - Name => New_Occurrence_Of (RTE (RE_Array_After), Loc), - Parameter_Associations => New_List - (Make_Identifier (Loc, Name_S)))); + Append_To (New_Stms, + Make_Procedure_Call_Statement (Loc, + Name => New_Occurrence_Of (RTE (RE_Array_After), Loc), + Parameter_Associations => New_List + (Make_Identifier (Loc, Name_S)))); - Stms := New_Stms; - end; - end loop; + Stms := New_Stms; + end; + end loop; - Build_Put_Image_Proc (Loc, Typ, Decl, Pnam, Stms); - end; + Build_Put_Image_Proc (Loc, Typ, Decl, Pnam, Stms); end Build_Array_Put_Image_Procedure; ------------------------------------- @@ -379,7 +416,8 @@ package body Exp_Put_Image is begin -- We have built a dispatching call to handle calls to -- descendants (since they are not available through rtsfind). - -- Further details available in the body of Put_String_Exp. + -- Further details available in the body of + -- Put_String_Exp_To_Buffer. return Put_Call; end; @@ -691,19 +729,33 @@ package body Exp_Put_Image is --------------------------- procedure Append_Component_Attr (Clist : List_Id; C : Entity_Id) is - Component_Typ : constant Entity_Id := - Put_Image_Base_Type - (Get_Corresponding_Mutably_Tagged_Type_If_Present (Etype (C))); + Component_Typ : constant Entity_Id := Put_Image_Base_Type (Etype (C)); + Selected_Comp : constant Node_Id := + Make_Selected_Component (Loc, + Prefix => Make_Identifier (Loc, Name_V), + Selector_Name => New_Occurrence_Of (C, Loc)); begin + if Is_Mutably_Tagged_Type (Component_Typ) then + pragma Assert (not Is_Mutably_Tagged_Type (Etype (C))); + + Make_Mutably_Tagged_Conversion (Selected_Comp, + Typ => Component_Typ); + + pragma Assert (Is_Mutably_Tagged_Type (Etype (Selected_Comp))); + + Put_Specific_Type_Name_Qualifier (Loc, + Stms => Clist, + Tagged_Obj => Selected_Comp, + Buffer_Name => Make_Identifier (Loc, Name_S), + Is_Interface_Type => False); + end if; + Append_To (Clist, Make_Attribute_Reference (Loc, Prefix => New_Occurrence_Of (Component_Typ, Loc), Attribute_Name => Name_Put_Image, - Expressions => New_List ( - Make_Identifier (Loc, Name_S), - Make_Selected_Component (Loc, - Prefix => Make_Identifier (Loc, Name_V), - Selector_Name => New_Occurrence_Of (C, Loc))))); + Expressions => New_List (Make_Identifier (Loc, Name_S), + Selected_Comp))); end Append_Component_Attr; ------------------------------- @@ -1303,105 +1355,20 @@ package body Exp_Put_Image is New_Occurrence_Of (Sink_Entity, Loc)))); Actions : List_Id; - function Put_String_Exp (String_Exp : Node_Id; - Wide_Wide : Boolean := False) return Node_Id; - -- Generate a call to evaluate a String (or Wide_Wide_String, depending - -- on the Wide_Wide Boolean parameter) expression and output it into - -- the buffer. - - -------------------- - -- Put_String_Exp -- - -------------------- - - function Put_String_Exp (String_Exp : Node_Id; - Wide_Wide : Boolean := False) return Node_Id is - Put_Id : constant RE_Id := - (if Wide_Wide then RE_Wide_Wide_Put else RE_Put_UTF_8); - - -- We could build a nondispatching call here, but to make - -- that work we'd have to change Rtsfind spec to make available - -- corresponding callees out of Ada.Strings.Text_Buffers.Unbounded - -- (as opposed to from Ada.Strings.Text_Buffers). Seems simpler to - -- introduce a type conversion and leave it to the optimizer to - -- eliminate the dispatching. This does not *introduce* any problems - -- if a no-dispatching-allowed restriction is in effect, since we - -- are already in the middle of generating a call to T'Class'Image. - - Sink_Exp : constant Node_Id := - Make_Type_Conversion (Loc, - Subtype_Mark => - New_Occurrence_Of - (Class_Wide_Type (RTE (RE_Root_Buffer_Type)), Loc), - Expression => New_Occurrence_Of (Sink_Entity, Loc)); - begin - return - Make_Procedure_Call_Statement (Loc, - Name => New_Occurrence_Of (RTE (Put_Id), Loc), - Parameter_Associations => New_List (Sink_Exp, String_Exp)); - end Put_String_Exp; - - -- Local variables - - Tag_Node : Node_Id; - -- Start of processing for Build_Image_Call begin if Is_Class_Wide_Type (U_Type) then + Actions := New_List (Sink_Decl); - -- For interface types we must generate code to displace the pointer - -- to the object to reference the base of the underlying object. + Put_Specific_Type_Name_Qualifier (Loc, + Stms => Actions, + Tagged_Obj => Image_Prefix, + Buffer_Name => New_Occurrence_Of (Sink_Entity, Loc), + Is_Interface_Type => Is_Interface (U_Type)); - -- Generate: - -- To_Tag_Ptr (Image_Prefix'Address).all - - -- Note that Image_Prefix'Address is recursively expanded into a - -- call to Ada.Tags.Base_Address (Image_Prefix'Address). - - if Is_Interface (U_Type) then - Tag_Node := - Make_Explicit_Dereference (Loc, - Unchecked_Convert_To (RTE (RE_Tag_Ptr), - Make_Attribute_Reference (Loc, - Prefix => Duplicate_Subexpr (Image_Prefix), - Attribute_Name => Name_Address))); - - -- Common case - - else - Tag_Node := - Make_Attribute_Reference (Loc, - Prefix => Duplicate_Subexpr (Image_Prefix), - Attribute_Name => Name_Tag); - end if; - - -- Generate qualified-expression syntax; qualification name comes - -- from calling Ada.Tags.Wide_Wide_Expanded_Name. - - declare - -- The copy of Image_Prefix will be evaluated before the - -- original, which is ok if no side effects are involved. - - pragma Assert (Side_Effect_Free (Image_Prefix)); - - Specific_Type_Name : constant Node_Id := - Put_String_Exp - (Make_Function_Call (Loc, - Name => New_Occurrence_Of - (RTE (RE_Wide_Wide_Expanded_Name), Loc), - Parameter_Associations => New_List (Tag_Node)), - Wide_Wide => True); - - Qualification : constant Node_Id := - Put_String_Exp (Make_String_Literal (Loc, "'")); - begin - Actions := New_List - (Sink_Decl, - Specific_Type_Name, - Qualification, - Put_Im, - Result_Decl); - end; + Append_To (Actions, Put_Im); + Append_To (Actions, Result_Decl); else Actions := New_List (Sink_Decl, Put_Im, Result_Decl); end if; @@ -1485,9 +1452,89 @@ package body Exp_Put_Image is return E; elsif Is_Private_Type (Base_Type (E)) and not Is_Private_Type (E) then return Implementation_Base_Type (E); + elsif Is_Mutably_Tagged_CW_Equivalent_Type (E) then + return Get_Corresponding_Mutably_Tagged_Type_If_Present (E); else return Base_Type (E); end if; end Put_Image_Base_Type; + -------------------------------------- + -- Put_Specific_Type_Name_Qualifier -- + -------------------------------------- + + procedure Put_Specific_Type_Name_Qualifier + (Loc : Source_Ptr; + Stms : List_Id; + Tagged_Obj : Node_Id; + Buffer_Name : Node_Id; + Is_Interface_Type : Boolean) + is + Tag_Node : Node_Id; + begin + if Is_Interface_Type then + Tag_Node := + Make_Explicit_Dereference (Loc, + Unchecked_Convert_To (RTE (RE_Tag_Ptr), + Make_Attribute_Reference (Loc, + Prefix => New_Copy_Tree (Tagged_Obj), + Attribute_Name => Name_Address))); + else + Tag_Node := + Make_Attribute_Reference (Loc, + Prefix => New_Copy_Tree (Tagged_Obj), + Attribute_Name => Name_Tag); + end if; + + Append_To (Stms, + Put_String_Exp_To_Buffer (Loc, + String_Exp => + Make_Function_Call (Loc, + Name => New_Occurrence_Of + (RTE (RE_Wide_Wide_Expanded_Name), Loc), + Parameter_Associations => New_List (Tag_Node)), + Buffer_Name => Buffer_Name, + Wide_Wide => True)); + + Append_To (Stms, + Put_String_Exp_To_Buffer (Loc, + String_Exp => Make_String_Literal (Loc, "'"), + Buffer_Name => New_Copy_Tree (Buffer_Name))); + end Put_Specific_Type_Name_Qualifier; + + ------------------------------ + -- Put_String_Exp_To_Buffer -- + ------------------------------ + + function Put_String_Exp_To_Buffer + (Loc : Source_Ptr; + String_Exp : Node_Id; + Buffer_Name : Node_Id; + Wide_Wide : Boolean := False) return Node_Id + is + Put_Id : constant RE_Id := + (if Wide_Wide then RE_Wide_Wide_Put else RE_Put_UTF_8); + + -- We could build a nondispatching call here, but to make + -- that work we'd have to change Rtsfind spec to make available + -- corresponding callees out of Ada.Strings.Text_Buffers.Unbounded + -- (as opposed to from Ada.Strings.Text_Buffers). Seems simpler to + -- introduce a type conversion and leave it to the optimizer to + -- eliminate the dispatching. This does not *introduce* any problems + -- if a no-dispatching-allowed restriction is in effect, since we + -- are already in the middle of generating a call to T'Class'Image. + + Sink_Exp : constant Node_Id := + Make_Type_Conversion (Loc, + Subtype_Mark => + New_Occurrence_Of + (Class_Wide_Type (RTE (RE_Root_Buffer_Type)), Loc), + Expression => Buffer_Name); + begin + return + Make_Procedure_Call_Statement (Loc, + Name => New_Occurrence_Of (RTE (Put_Id), Loc), + Parameter_Associations => New_List (Sink_Exp, String_Exp)); + end Put_String_Exp_To_Buffer; + end Exp_Put_Image; diff --git a/gcc/ada/exp_strm.adb b/gcc/ada/exp_strm.adb index 250efd2dc90..5e1c9134fb5 100644 --- a/gcc/ada/exp_strm.adb +++ b/gcc/ada/exp_strm.adb @@ -29,6 +29,7 @@ with Einfo.Entities; use Einfo.Entities; with Einfo.Utils; use Einfo.Utils; with Elists; use Elists; with Exp_Util; use Exp_Util; +with Mutably_Tagged; use Mutably_Tagged; with Namet; use Namet; with Nlists; use Nlists; with Nmake; use Nmake; @@ -101,13 +102,10 @@ package body Exp_Strm is -- Loc parameter is used as the Sloc of the created entity. function Stream_Base_Type (E : Entity_Id) return Entity_Id; - -- Stream attributes work on the basis of the base type except for the - -- array case. For the array case, we do not go to the base type, but - -- to the first subtype if it is constrained. This avoids problems with - -- incorrect conversions in the packed array case. Stream_Base_Type is - -- exactly this function (returns the base type, unless we have an array - -- type whose first subtype is constrained, in which case it returns the - -- first subtype). + -- For an array type whose whose first subtype is constrained, return + -- the first subtype. For the internal representation type corresponding + -- to a mutably tagged type, return the mutably tagged type. Otherwise, + -- return the base type. Similar to Exp_Put_Image.Put_Image_Base_Type. -------------------------------- -- Build_Array_Input_Function -- @@ -1502,6 +1500,7 @@ package body Exp_Strm is function Make_Field_Attribute (C : Entity_Id) return Node_Id is Field_Typ : constant Entity_Id := Stream_Base_Type (Etype (C)); + Selected : Node_Id; TSS_Names : constant array (Name_Input .. Name_Write) of TSS_Name_Type := @@ -1524,15 +1523,23 @@ package body Exp_Strm is return Make_Null_Statement (Loc); end if; + Selected := Make_Selected_Component (Loc, + Prefix => Make_Identifier (Loc, Name_V), + Selector_Name => New_Occurrence_Of (C, Loc)); + + if Is_Mutably_Tagged_CW_Equivalent_Type (Etype (C)) then + Make_Mutably_Tagged_Conversion + (Selected, + Typ => Get_Corresponding_Mutably_Tagged_Type_If_Present + (Etype (C))); + end if; + return Make_Attribute_Reference (Loc, Prefix => New_Occurrence_Of (Field_Typ, Loc), Attribute_Name => Nam, - Expressions => New_List ( - Make_Identifier (Loc, Name_S), - Make_Selected_Component (Loc, - Prefix => Make_Identifier (Loc, Name_V), - Selector_Name => New_Occurrence_Of (C, Loc)))); + Expressions => New_List (Make_Identifier (Loc, Name_S), + Selected)); end Make_Field_Attribute; --------------------------- @@ -1808,6 +1815,10 @@ package body Exp_Strm is function Stream_Base_Type (E : Entity_Id) return Entity_Id is begin + if Is_Class_Wide_Equivalent_Type (E) then + return Corresponding_Mutably_Tagged_Type (E); + end if; + if Is_Array_Type (E) and then Is_First_Subtype (E) then diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb index 5354d82bd7d..9fb2030a42b 100644 --- a/gcc/ada/sem_ch3.adb +++ b/gcc/ada/sem_ch3.adb @@ -6819,7 +6819,7 @@ package body Sem_Ch3 is -- that the element type is constrained. if Is_Mutably_Tagged_Type (Element_Type) then - Set_Component_Type (T, + Set_Component_Type (Base_Type (T), Class_Wide_Equivalent_Type (Element_Type)); elsif not Is_Definite_Subtype (Element_Type) then diff --git a/gcc/ada/sem_ch4.adb b/gcc/ada/sem_ch4.adb index 22a04e3ba9b..018c8a07932 100644 --- a/gcc/ada/sem_ch4.adb +++ b/gcc/ada/sem_ch4.adb @@ -5603,6 +5603,10 @@ package body Sem_Ch4 is if No (Act_Decl) then Set_Etype (N, Etype (Comp)); + if Is_Mutably_Tagged_CW_Equivalent_Type (Etype (N)) then + Make_Mutably_Tagged_Conversion (N); + end if; + else -- If discriminants were present in the component -- declaration, they have been replaced by the -- 2.43.0