[Ada] Ada/C++ missing call to allocation of C++ object with defaults
Arnaud Charlet
charlet@adacore.com
Wed Oct 3 08:09:00 GMT 2012
When the type of an object is a CPP untagged type, the object is allocated
in memory through the "new" construct, and the object initialization
requires calling its C++ constructor passing defaults, the Ada compiler
did not generate the call to a C++ constructor which has all parameters with
defaults (and hence it covers the default C++ constructor). The following
test now executes well.
// c_class.h
class Tester {
public:
Tester(unsigned int a_num = 5, char* a_className = 0);
};
// c_class.cc
#include "c_class.h"
#include <iostream>
Tester::Tester(unsigned int a_num, char* a_className) {
std::cout << " ctor Tester called " << a_num << ":";
if (a_className == 0) {
std::cout << "null";
} else {
std::cout << a_className;
}
std::cout << std::endl;
}
-- c_class_h.ads
with Interfaces.C; use Interfaces.C;
with Interfaces.C.Strings;
package c_class_h is
package Class_Tester is
type Tester is limited record
null;
end record;
pragma Import (CPP, Tester);
function New_Tester
(a_num : unsigned := 5;
a_className : Interfaces.C.Strings.chars_ptr
:= Interfaces.C.Strings.Null_Ptr)
return Tester; -- c_class.h:3
pragma CPP_Constructor (New_Tester, "_ZN6TesterC1EjPc");
end;
use Class_Tester;
end c_class_h;
project Ada2Cppc is
for Languages use ("Ada", "C++");
for Main use ("main.adb");
package Naming is
for Implementation_Suffix ("C++") use ".cc";
end Naming;
for Source_Dirs use (".");
package Compiler is
for Default_Switches ("ada") use ("-gnat05");
end Compiler;
package Builder is
for Default_Switches ("ada") use ("-g");
end Builder;
package Ide is
for Compiler_Command ("ada") use "gnatmake";
for Compiler_Command ("c") use "gcc";
end Ide;
end Ada2Cppc;
Command: gprbuild -q -P ada2cppc.gpr; ./main
Output:
ctor Tester called 5:null
Tested on x86_64-pc-linux-gnu, committed on trunk
2012-10-03 Javier Miranda <miranda@adacore.com>
* exp_ch4.adb (Expand_N_Allocator_Expression): Minor code
reorganization and cleanup. Done to ensure proper management of
the C++ constructor covering tagged and untagged types and also
non-default constructors.
* exp_ch6.ads, exp_ch6.adb (Make_CPP_Constructor_Call_In_Allocator):
New subprogram.
-------------- next part --------------
Index: exp_ch4.adb
===================================================================
--- exp_ch4.adb (revision 192027)
+++ exp_ch4.adb (working copy)
@@ -867,6 +867,15 @@
-- Start of processing for Expand_Allocator_Expression
begin
+ -- Handle call to C++ constructor
+
+ if Is_CPP_Constructor_Call (Exp) then
+ Make_CPP_Constructor_Call_In_Allocator
+ (Allocator => N,
+ Function_Call => Exp);
+ return;
+ end if;
+
-- In the case of an Ada 2012 allocator whose initial value comes from a
-- function call, pass "the accessibility level determined by the point
-- of call" (AI05-0234) to the function. Conceptually, this belongs in
@@ -899,59 +908,7 @@
-- Case of tagged type or type requiring finalization
if Is_Tagged_Type (T) or else Needs_Finalization (T) then
- if Is_CPP_Constructor_Call (Exp) then
- -- Generate:
- -- Pnnn : constant ptr_T := new (T);
- -- Init (Pnnn.all,...);
-
- -- Allocate the object without an expression
-
- Node := Relocate_Node (N);
- Set_Expression (Node, New_Reference_To (Etype (Exp), Loc));
-
- -- Avoid its expansion to avoid generating a call to the default
- -- C++ constructor.
-
- Set_Analyzed (Node);
-
- Temp := Make_Temporary (Loc, 'P', N);
-
- Temp_Decl :=
- Make_Object_Declaration (Loc,
- Defining_Identifier => Temp,
- Constant_Present => True,
- Object_Definition => New_Reference_To (PtrT, Loc),
- Expression => Node);
- Insert_Action (N, Temp_Decl);
-
- Apply_Accessibility_Check (Temp);
-
- -- Locate the enclosing list and insert the C++ constructor call
-
- declare
- P : Node_Id;
-
- begin
- P := Parent (Node);
- while not Is_List_Member (P) loop
- P := Parent (P);
- end loop;
-
- Insert_List_After_And_Analyze (P,
- Build_Initialization_Call (Loc,
- Id_Ref =>
- Make_Explicit_Dereference (Loc,
- Prefix => New_Reference_To (Temp, Loc)),
- Typ => Etype (Exp),
- Constructor_Ref => Exp));
- end;
-
- Rewrite (N, New_Reference_To (Temp, Loc));
- Analyze_And_Resolve (N, PtrT);
- return;
- end if;
-
-- Ada 2005 (AI-318-02): If the initialization expression is a call
-- to a build-in-place function, then access to the allocated object
-- must be passed to the function. Currently we limit such functions
Index: exp_ch6.adb
===================================================================
--- exp_ch6.adb (revision 192025)
+++ exp_ch6.adb (working copy)
@@ -9121,6 +9121,96 @@
end if;
end Make_Build_In_Place_Call_In_Object_Declaration;
+ --------------------------------------------
+ -- Make_CPP_Constructor_Call_In_Allocator --
+ --------------------------------------------
+
+ procedure Make_CPP_Constructor_Call_In_Allocator
+ (Allocator : Node_Id;
+ Function_Call : Node_Id)
+ is
+ Loc : constant Source_Ptr := Sloc (Function_Call);
+ Acc_Type : constant Entity_Id := Etype (Allocator);
+ Function_Id : constant Entity_Id := Entity (Name (Function_Call));
+ Result_Subt : constant Entity_Id := Available_View (Etype (Function_Id));
+
+ New_Allocator : Node_Id;
+ Return_Obj_Access : Entity_Id;
+ Tmp_Obj : Node_Id;
+
+ begin
+ pragma Assert (Nkind (Allocator) = N_Allocator
+ and then Nkind (Function_Call) = N_Function_Call);
+ pragma Assert (Convention (Function_Id) = Convention_CPP
+ and then Is_Constructor (Function_Id));
+ pragma Assert (Is_Constrained (Underlying_Type (Result_Subt)));
+
+ -- Replace the initialized allocator of form "new T'(Func (...))" with
+ -- an uninitialized allocator of form "new T", where T is the result
+ -- subtype of the called function. The call to the function is handled
+ -- separately further below.
+
+ New_Allocator :=
+ Make_Allocator (Loc,
+ Expression => New_Reference_To (Result_Subt, Loc));
+ Set_No_Initialization (New_Allocator);
+
+ -- Copy attributes to new allocator. Note that the new allocator
+ -- logically comes from source if the original one did, so copy the
+ -- relevant flag. This ensures proper treatment of the restriction
+ -- No_Implicit_Heap_Allocations in this case.
+
+ Set_Storage_Pool (New_Allocator, Storage_Pool (Allocator));
+ Set_Procedure_To_Call (New_Allocator, Procedure_To_Call (Allocator));
+ Set_Comes_From_Source (New_Allocator, Comes_From_Source (Allocator));
+
+ Rewrite (Allocator, New_Allocator);
+
+ -- Create a new access object and initialize it to the result of the
+ -- new uninitialized allocator. Note: we do not use Allocator as the
+ -- Related_Node of Return_Obj_Access in call to Make_Temporary below
+ -- as this would create a sort of infinite "recursion".
+
+ Return_Obj_Access := Make_Temporary (Loc, 'R');
+ Set_Etype (Return_Obj_Access, Acc_Type);
+
+ -- Generate:
+ -- Rnnn : constant ptr_T := new (T);
+ -- Init (Rnn.all,...);
+
+ Tmp_Obj :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Return_Obj_Access,
+ Constant_Present => True,
+ Object_Definition => New_Reference_To (Acc_Type, Loc),
+ Expression => Relocate_Node (Allocator));
+ Insert_Action (Allocator, Tmp_Obj);
+
+ Insert_List_After_And_Analyze (Tmp_Obj,
+ Build_Initialization_Call (Loc,
+ Id_Ref =>
+ Make_Explicit_Dereference (Loc,
+ Prefix => New_Reference_To (Return_Obj_Access, Loc)),
+ Typ => Etype (Function_Id),
+ Constructor_Ref => Function_Call));
+
+ -- Finally, replace the allocator node with a reference to the result of
+ -- the function call itself (which will effectively be an access to the
+ -- object created by the allocator).
+
+ Rewrite (Allocator, New_Reference_To (Return_Obj_Access, Loc));
+
+ -- Ada 2005 (AI-251): If the type of the allocator is an interface then
+ -- generate an implicit conversion to force displacement of the "this"
+ -- pointer.
+
+ if Is_Interface (Designated_Type (Acc_Type)) then
+ Rewrite (Allocator, Convert_To (Acc_Type, Relocate_Node (Allocator)));
+ end if;
+
+ Analyze_And_Resolve (Allocator, Acc_Type);
+ end Make_CPP_Constructor_Call_In_Allocator;
+
-----------------------------------
-- Needs_BIP_Finalization_Master --
-----------------------------------
Index: exp_ch6.ads
===================================================================
--- exp_ch6.ads (revision 192025)
+++ exp_ch6.ads (working copy)
@@ -205,6 +205,16 @@
-- for which Is_Build_In_Place_Call is True, or an N_Qualified_Expression
-- node applied to such a function call.
+ procedure Make_CPP_Constructor_Call_In_Allocator
+ (Allocator : Node_Id;
+ Function_Call : Node_Id);
+ -- Handle a call to a CPP constructor that occurs as the expression that
+ -- initializes an allocator, by passing access to the allocated object as
+ -- an additional parameter of the constructor call. A new access object is
+ -- declared that is initialized to the result of the allocator, passed to
+ -- the constructor, and the allocator is rewritten to refer to that access
+ -- object. Function_Call must denote a call to a CPP_Constructor function.
+
function Needs_BIP_Alloc_Form (Func_Id : Entity_Id) return Boolean;
-- Ada 2005 (AI-318-02): Return True if the function needs an implicit
-- BIP_Alloc_Form parameter (see type BIP_Formal_Kind).
More information about the Gcc-patches
mailing list