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;
-- 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 --
-------------------------------------
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);
elsif Is_Class_Wide_Type (P_Type) then
- -- No need to do anything else compiling under restriction
- -- No_Dispatching_Calls. During the semantic analysis we
- -- already notified such violation.
+ if Is_Mutably_Tagged_Type (P_Type) then
- if Restriction_Active (No_Dispatching_Calls) then
- return;
- end if;
+ -- In mutably tagged case, rewrite
+ -- T'Class'Input (Strm)
+ -- as (roughly)
+ -- declare
+ -- Result : T'Class;
+ -- T'Class'Read (Strm, Result);
+ -- begin
+ -- Result;
+ -- end;
- declare
- Rtyp : constant Entity_Id := Root_Type (P_Type);
+ declare
+ Result_Temp : constant Entity_Id :=
+ Make_Temporary (Loc, 'I');
- Expr : Node_Id; -- call to Descendant_Tag
- Get_Tag : Node_Id; -- expression to read the 'Tag
+ -- 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));
- 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;
+ function Result_Temp_Name return Node_Id is
+ (New_Occurrence_Of (Result_Temp, Loc));
- 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)));
+ 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;
- Set_Etype (Expr, RTE (RE_Tag));
+ -- No need to do anything else compiling under restriction
+ -- No_Dispatching_Calls. During the semantic analysis we
+ -- already notified such violation.
- -- 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).
+ if Restriction_Active (No_Dispatching_Calls) then
+ return;
+ end if;
- 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
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)).
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);
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;
-- 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
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;
-- 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.
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;
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
-- 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 --
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;
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,
-- 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;
-------------------------------------
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;
---------------------------
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;
-------------------------------
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.
-
- -- 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)));
+ 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));
- -- 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;
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;
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;
-- 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 --
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 :=
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;
---------------------------
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
-- 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
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