This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++0x Constructor Delegation take 2
- From: Pedro Lamarão <pedro dot lamarao at mndfck dot org>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 12 Apr 2007 01:53:01 -0300
- Subject: C++0x Constructor Delegation take 2
It took me a while but here goes.
Tested the c++ front-end and libstdc++, no regressions.
--
Pedro Lamarão
2007-04-11 Pedro Lamarão <pedro.lamarao@mndfck.org>
* parser.c(cp_parser_mem_initializer_list): make sure the rules
constructor delegation are followed.
* init.c(expand_member_init): return properly if name is a
target constructor.
(emit_mem_initializers): if initializer is a target constructor,
delegate.
(perform_target_ctor): new function.
2007-04-11 Pedro Lamarão <pedro.lamarao@mndfck.org>
* g++.dg/cpp0x/dc_01.C: new test.
* g++.dg/cpp0x/dc_02.C: new test.
* g++.dg/cpp0x/dc_03.C: new test.
Index: gcc/testsuite/g++.dg/cpp0x/dc_02.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/dc_02.C (revisão 0)
+++ gcc/testsuite/g++.dg/cpp0x/dc_02.C (revisão 0)
@@ -0,0 +1,35 @@
+// { dg-do compile }
+// { dg-options --std=gnu++0x }
+
+struct A {
+
+ int i, j;
+
+ A () : A(0), j(0) { } // { dg-error "" "only initializer" }
+
+ A (int _i) : i(_i) { }
+
+};
+
+struct B {
+
+ int i, j;
+
+ B () : i(0), B(0) { } // { dg-error "" "only initializer" }
+
+ B (int _j) : j(_j) { }
+
+};
+
+struct C { };
+
+struct D : public C {
+
+ D () : C() { }
+
+ D (float) : D(), C() { } // { dg-error "" "only initializer" }
+
+ D (float, float): C(), D() { } // { dg-error "" "only initializer" }
+
+};
+
Index: gcc/testsuite/g++.dg/cpp0x/dc_01.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/dc_01.C (revisão 0)
+++ gcc/testsuite/g++.dg/cpp0x/dc_01.C (revisão 0)
@@ -0,0 +1,68 @@
+// { dg-do compile }
+// { dg-options --std=gnu++0x }
+
+struct B {
+
+ int i;
+
+ B (int _i) : i(_i) { }
+
+ ~B () { i = 0; }
+
+};
+
+struct A : public B {
+
+ A () : B(-1) { }
+
+ A (int i) : A() { }
+
+ A (double b) : A(static_cast<int>(b)) { }
+
+ A (double b, double b2) : A(b2) { }
+
+ ~A () { }
+
+};
+
+void f_A () { A a(2.0, 3.0); }
+
+struct C {
+
+ C () { }
+
+ virtual ~C() { }
+
+ virtual int f () = 0;
+
+};
+
+struct D : public C {
+
+ int i;
+
+ D (int _i) : C(), i(_i) { }
+
+ D () : D(-1) { }
+
+ virtual ~D() { }
+
+ virtual int f () { }
+
+};
+
+void f_D () { C* c = new D(); }
+
+template <typename T>
+struct E {
+
+ T t;
+
+ E () : E(T()) { }
+
+ E (T _t) : t(_t) { }
+
+};
+
+void f_E () { E<int> e; }
+
Index: gcc/testsuite/g++.dg/cpp0x/dc_03.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/dc_03.C (revisão 0)
+++ gcc/testsuite/g++.dg/cpp0x/dc_03.C (revisão 0)
@@ -0,0 +1,93 @@
+// { dg-do compile }
+// { dg-options --std=gnu++0x }
+
+struct x { };
+
+struct B {
+
+ int i;
+
+ B (int _i) : i(_i) { }
+
+ ~B () { i = 0; }
+
+};
+
+template <typename T>
+struct A : public B {
+
+ A () : B(-1) { }
+
+ ~A () { }
+
+};
+
+template <typename T>
+struct A<T*> : public B {
+
+ A () : B(-1) { }
+
+ A (int i) : A() { }
+
+ A (double b) : A(static_cast<int>(b)) { }
+
+ A (double b, double b2) : A(b2) { }
+
+ ~A () { }
+
+};
+
+void f_A () { A<x*> a(2.0, 3.0); }
+
+struct C {
+
+ C () { }
+
+ virtual ~C() { }
+
+ virtual int f () = 0;
+
+};
+
+template <typename T>
+struct D : public C {
+
+ int i;
+
+ D (int _i) : C(), i(_i) { }
+
+};
+
+template <>
+struct D<x> : public C {
+
+ int i;
+
+ D (int _i) : C(), i(_i) { }
+
+ D () : D(-1) { }
+
+ virtual ~D() { }
+
+ virtual int f () { }
+
+};
+
+void f_D () { D<x>* d = new D<x>(); }
+
+template <typename T>
+struct E {
+};
+
+template <>
+struct E<int> {
+
+ int i;
+
+ E () : E(0) { }
+
+ E (int _i) : i(_i) { }
+
+};
+
+void f_E () { E<int> e; }
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c (revisão 123734)
+++ gcc/cp/init.c (cópia de trabalho)
@@ -315,6 +315,30 @@ build_default_init (tree type, tree nelt
return build_zero_init (type, nelts, /*static_storage_p=*/false);
}
+/* Initialize current class with INIT, a TREE_LIST of
+ arguments for a target constructor. If TREE_LIST is void_type_node,
+ an empty initializer list was given. */
+
+static void
+perform_target_ctor (tree init)
+{
+ tree decl = current_class_ref;
+ tree type = current_class_type;
+
+ if (init == void_type_node)
+ init = NULL_TREE;
+
+ finish_expr_stmt (build_aggr_init (decl, init, 0));
+
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+ {
+ tree expr = build_delete (type, decl, sfk_complete_destructor,
+ LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+ if (expr != error_mark_node)
+ finish_eh_cleanup (expr);
+ }
+}
+
/* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of
arguments. If TREE_LIST is void_type_node, an empty initializer
list was given; if NULL_TREE no initializer was given. */
@@ -669,6 +693,16 @@ emit_mem_initializers (tree mem_inits)
if (!COMPLETE_TYPE_P (current_class_type))
return;
+ if (flag_cpp0x
+ && mem_inits
+ && TYPE_P (TREE_PURPOSE (mem_inits))
+ && same_type_p (TREE_PURPOSE (mem_inits), current_class_type))
+ {
+ gcc_assert (TREE_CHAIN (mem_inits) == NULL_TREE);
+ perform_target_ctor (TREE_VALUE (mem_inits));
+ return;
+ }
+
/* Sort the mem-initializers into the order in which the
initializations should be performed. */
mem_inits = sort_mem_initializers (current_class_type, mem_inits);
@@ -979,11 +1013,18 @@ expand_member_init (tree name)
}
else if (TYPE_P (name))
{
+ if (flag_cpp0x && same_type_p (name, current_class_type))
+ return name;
basetype = TYPE_MAIN_VARIANT (name);
name = TYPE_NAME (name);
}
else if (TREE_CODE (name) == TYPE_DECL)
- basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
+ {
+ if (flag_cpp0x
+ && same_type_p (TREE_TYPE (name), current_class_type))
+ return TREE_TYPE (name);
+ basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
+ }
else
basetype = NULL_TREE;
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revisão 123734)
+++ gcc/cp/parser.c (cópia de trabalho)
@@ -8466,6 +8466,7 @@ static void
cp_parser_mem_initializer_list (cp_parser* parser)
{
tree mem_initializer_list = NULL_TREE;
+ tree target_ctor = error_mark_node;
/* Let the semantic analysis code know that we are starting the
mem-initializer-list. */
@@ -8499,6 +8500,31 @@ cp_parser_mem_initializer_list (cp_parse
if (mem_initializer != error_mark_node)
mem_initializer = make_pack_expansion (mem_initializer);
}
+ if (target_ctor != error_mark_node
+ && mem_initializer != error_mark_node)
+ {
+ error ("seeing initializer for member %<%D%>; "
+ "previous target constructor for %T must be sole initializer",
+ TREE_PURPOSE (mem_initializer),
+ TREE_PURPOSE (target_ctor));
+ mem_initializer = error_mark_node;
+ }
+ /* Look for a target constructor. */
+ if (flag_cpp0x
+ && mem_initializer != error_mark_node
+ && TYPE_P (TREE_PURPOSE (mem_initializer))
+ && same_type_p (TREE_PURPOSE (mem_initializer), current_class_type))
+ {
+ if (mem_initializer_list)
+ {
+ error ("target constructor for %T must be sole initializer; "
+ "saw previous initializer for member %<%D%>",
+ TREE_PURPOSE (mem_initializer),
+ TREE_PURPOSE (mem_initializer_list));
+ mem_initializer = error_mark_node;
+ }
+ target_ctor = mem_initializer;
+ }
/* Add it to the list, unless it was erroneous. */
if (mem_initializer != error_mark_node)
{