When the type of an object is a CPP type and the object initialization
requires calling its default C++ constructor, 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 must now compile and execute well.
// c_class.h
class Tester {
public:
Tester(unsigned int a_num = 5, char* a_className = 0);
virtual int dummy();
};
// 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";
}
std::cout << std::endl;
}
int Tester::dummy() {
}
-- c_class_h.ads
pragma Ada_2005;
pragma Style_Checks (Off);
with Interfaces.C; use Interfaces.C;
with Interfaces.C.Strings;
package c_class_h is
package Class_Tester is
type Tester is tagged 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;
pragma CPP_Constructor (New_Tester, "_ZN6TesterC1EjPc");
function dummy (this : access Tester) return int;
pragma Import (CPP, dummy, "_ZN6Tester5dummyEv");
end;
use Class_Tester;
end c_class_h;
-- main.adb
with c_class_h; use c_class_h;
procedure Main is
use Class_Tester;
Obj : Tester; -- Test
pragma Unreferenced (Obj);
begin
null;
end main;
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 (".");
for Object_Dir use "obj";
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:
mkdir obj
gprclean -q -P ada2cppc.gpr
gprbuild -q -P ada2cppc.gpr
obj/main
Output:
ctor Tester called 5:null
Tested on x86_64-pc-linux-gnu, committed on trunk
2012-10-02 Javier Miranda <[email protected]>
* exp_disp.adb (Set_CPP_Constructors): Handle constructor with default
parameters that covers the default constructor.
Index: exp_disp.adb
===================================================================
--- exp_disp.adb (revision 191972)
+++ exp_disp.adb (working copy)
@@ -8537,6 +8537,10 @@
Body_Stmts : List_Id;
Init_Tags_List : List_Id;
+ Covers_Default_Constructor : Entity_Id := Empty;
+
+ -- Start of processing for Set_CPP_Constructor
+
begin
pragma Assert (Is_CPP_Class (Typ));
@@ -8622,7 +8626,9 @@
Defining_Identifier =>
Make_Defining_Identifier (Loc,
Chars (Defining_Identifier (P))),
- Parameter_Type => New_Copy_Tree (Parameter_Type (P))));
+ Parameter_Type =>
+ New_Copy_Tree (Parameter_Type (P)),
+ Expression => New_Copy_Tree (Expression (P))));
Next (P);
end loop;
end if;
@@ -8713,6 +8719,17 @@
Discard_Node (Wrapper_Body_Node);
Set_Init_Proc (Typ, Wrapper_Id);
+
+ -- If this constructor has parameters and all its parameters
+ -- have defaults then it covers the default constructor. The
+ -- semantic analyzer ensures that only one constructor with
+ -- defaults covers the default constructor.
+
+ if Present (Parameter_Specifications (Parent (E)))
+ and then Needs_No_Actuals (E)
+ then
+ Covers_Default_Constructor := Wrapper_Id;
+ end if;
end if;
Next_Entity (E);
@@ -8725,6 +8742,46 @@
Set_Is_Abstract_Type (Typ);
end if;
+ -- Handle constructor that has all its parameters with defaults and
+ -- hence it covers the default constructor. We generate a wrapper IP
+ -- which calls the covering constructor.
+
+ if Present (Covers_Default_Constructor) then
+ Loc := Sloc (Covers_Default_Constructor);
+
+ Body_Stmts := New_List (
+ Make_Procedure_Call_Statement (Loc,
+ Name =>
+ New_Reference_To (Covers_Default_Constructor, Loc),
+ Parameter_Associations => New_List (
+ Make_Identifier (Loc, Name_uInit))));
+
+ Wrapper_Id :=
+ Make_Defining_Identifier (Loc, Make_Init_Proc_Name (Typ));
+
+ Wrapper_Body_Node :=
+ Make_Subprogram_Body (Loc,
+ Specification =>
+ Make_Procedure_Specification (Loc,
+ Defining_Unit_Name => Wrapper_Id,
+ Parameter_Specifications => New_List (
+ Make_Parameter_Specification (Loc,
+ Defining_Identifier =>
+ Make_Defining_Identifier (Loc, Name_uInit),
+ Parameter_Type =>
+ New_Reference_To (Typ, Loc)))),
+
+ Declarations => No_List,
+
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => Body_Stmts,
+ Exception_Handlers => No_List));
+
+ Discard_Node (Wrapper_Body_Node);
+ Set_Init_Proc (Typ, Wrapper_Id);
+ end if;
+
-- If the CPP type has constructors then it must import also the default
-- C++ constructor. It is required for default initialization of objects
-- of the type. It is also required to elaborate objects of Ada types