Implement C++11 delegating constructors.
authorVille Voutilainen <ville.voutilainen@gmail.com>
Mon, 5 Dec 2011 15:49:25 +0000 (17:49 +0200)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 5 Dec 2011 15:49:25 +0000 (10:49 -0500)
* cp-tree.h (enum cpp0x_warn_str): Add CPP0X_DELEGATING_CTORS.
* error.c (maybe_warn_cpp0x): Adjust.
* parser.c (cp_parser_mem_initializer_list): Use it.  Diagnose
multiple initializers if a delegating initializer is present.
* call.c (build_special_member_call): Convert an assert into an if.
* init.c (perform_target_ctor): New.
(emit_mem_initializers): Use it.
(expand_member_init, expand_default_init): Adjust.

Co-Authored-By: Pedro Lamarão <pedro.lamarao@gmail.com>
From-SVN: r182012

13 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/error.c
gcc/cp/init.c
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/dc1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/dc2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/dc3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/dc4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/dc5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/meminit1.C

index fcd44f0..be5ebea 100644 (file)
@@ -1,3 +1,16 @@
+2011-12-05  Ville Voutilainen  <ville.voutilainen@gmail.com>
+           Pedro Lamarão  <pedro.lamarao@gmail.com>
+
+       Implement C++11 delegating constructors.
+       * cp-tree.h (enum cpp0x_warn_str): Add CPP0X_DELEGATING_CTORS.
+       * error.c (maybe_warn_cpp0x): Adjust.
+       * parser.c (cp_parser_mem_initializer_list): Use it.  Diagnose
+       multiple initializers if a delegating initializer is present.
+       * call.c (build_special_member_call): Convert an assert into an if.
+       * init.c (perform_target_ctor): New.
+       (emit_mem_initializers): Use it.
+       (expand_member_init, expand_default_init): Adjust.
+
 2011-12-05  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/51404
index 93d14be..d8fc4f1 100644 (file)
@@ -6978,8 +6978,10 @@ build_special_member_call (tree instance, tree name, VEC(tree,gc) **args,
                            current_in_charge_parm, integer_zero_node),
                    current_vtt_parm,
                    vtt);
-      gcc_assert (BINFO_SUBVTT_INDEX (binfo));
-      sub_vtt = fold_build_pointer_plus (vtt, BINFO_SUBVTT_INDEX (binfo));
+      if (BINFO_SUBVTT_INDEX (binfo))
+       sub_vtt = fold_build_pointer_plus (vtt, BINFO_SUBVTT_INDEX (binfo));
+      else
+       sub_vtt = vtt;
 
       if (args == NULL)
        {
index 3f4f408..dccf485 100644 (file)
@@ -404,7 +404,9 @@ typedef enum cpp0x_warn_str
   /* non-static data member initializers */
   CPP0X_NSDMI,
   /* user defined literals */
-  CPP0X_USER_DEFINED_LITERALS
+  CPP0X_USER_DEFINED_LITERALS,
+  /* delegating constructors */
+  CPP0X_DELEGATING_CTORS
 } cpp0x_warn_str;
   
 /* The various kinds of operation used by composite_pointer_type. */
index 4940a78..21d6781 100644 (file)
@@ -3304,6 +3304,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
                 "user-defined literals "
                 "only available with -std=c++11 or -std=gnu++11");
        break;
+      case CPP0X_DELEGATING_CTORS:
+       pedwarn (input_location, 0,
+                "delegating constructors "
+                "only available with -std=c++11 or -std=gnu++11");
+        break;
       default:
        gcc_unreachable ();
       }
index 7e9ad54..94bd34a 100644 (file)
@@ -485,6 +485,30 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
   return build_zero_init (type, NULL_TREE, /*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;
+
+  finish_expr_stmt (build_aggr_init (decl, init, LOOKUP_NORMAL,
+                                     tf_warning_or_error));
+  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+    {
+      tree expr = build_delete (type, decl, sfk_complete_destructor,
+                               LOOKUP_NORMAL
+                               |LOOKUP_NONVIRTUAL
+                               |LOOKUP_DESTRUCTOR,
+                               0, tf_warning_or_error);
+      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.  */
@@ -988,6 +1012,16 @@ emit_mem_initializers (tree mem_inits)
   if (!COMPLETE_TYPE_P (current_class_type))
     return;
 
+  if (mem_inits
+      && TYPE_P (TREE_PURPOSE (mem_inits))
+      && same_type_p (TREE_PURPOSE (mem_inits), current_class_type))
+    {
+      /* Delegating constructor. */
+      gcc_assert (TREE_CHAIN (mem_inits) == NULL_TREE);
+      perform_target_ctor (TREE_VALUE (mem_inits));
+      return;
+    }
+
   if (DECL_DEFAULTED_FN (current_function_decl))
     flags |= LOOKUP_DEFAULTED;
 
@@ -1318,8 +1352,9 @@ expand_member_init (tree name)
       tree virtual_binfo;
       int i;
 
-      if (current_template_parms)
-       return basetype;
+      if (same_type_p (basetype, current_class_type)
+         || current_template_parms)
+         return basetype;
 
       class_binfo = TYPE_BINFO (current_class_type);
       direct_binfo = NULL_TREE;
@@ -1578,13 +1613,33 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
   else
     parms = make_tree_vector_single (init);
 
-  if (true_exp == exp)
-    ctor_name = complete_ctor_identifier;
-  else
-    ctor_name = base_ctor_identifier;
-
-  rval = build_special_member_call (exp, ctor_name, &parms, binfo, flags,
-                                    complain);
+  if (exp == current_class_ref && current_function_decl
+      && DECL_HAS_IN_CHARGE_PARM_P (current_function_decl))
+    {
+      /* Delegating constructor. */
+      tree complete;
+      tree base;
+      complete = build_special_member_call (exp, complete_ctor_identifier,
+                                       &parms, binfo, flags,
+                                       complain);
+      base = build_special_member_call (exp, base_ctor_identifier,
+                                       &parms, binfo, flags,
+                                       complain);
+      rval = build3 (COND_EXPR, TREE_TYPE (complete),
+                   build2 (EQ_EXPR, boolean_type_node,
+                           current_in_charge_parm, integer_zero_node),
+                   base,
+                   complete);
+    }
+   else
+    {
+      if (true_exp == exp)
+       ctor_name = complete_ctor_identifier;
+      else
+       ctor_name = base_ctor_identifier;
+      rval = build_special_member_call (exp, ctor_name, &parms, binfo, flags,
+                                       complain);
+  }
 
   if (parms != NULL)
     release_tree_vector (parms);
index 69f1eab..9e7a398 100644 (file)
@@ -11321,6 +11321,7 @@ static void
 cp_parser_mem_initializer_list (cp_parser* parser)
 {
   tree mem_initializer_list = NULL_TREE;
+  tree target_ctor = error_mark_node;
   cp_token *token = cp_lexer_peek_token (parser->lexer);
 
   /* Let the semantic analysis code know that we are starting the
@@ -11358,6 +11359,27 @@ cp_parser_mem_initializer_list (cp_parser* parser)
           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 ("mem-initializer for %qD follows constructor delegation",
+                TREE_PURPOSE (mem_initializer));
+         mem_initializer = error_mark_node;
+       }
+      /* Look for a target constructor. */
+      if (mem_initializer != error_mark_node
+         && TYPE_P (TREE_PURPOSE (mem_initializer))
+         && same_type_p (TREE_PURPOSE (mem_initializer), current_class_type))
+       {
+         maybe_warn_cpp0x (CPP0X_DELEGATING_CTORS);
+         if (mem_initializer_list)
+           {
+             error ("constructor delegation follows mem-initializer for %qD",
+                    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)
        {
index 31aa738..3bda000 100644 (file)
@@ -1,3 +1,13 @@
+2011-12-05  Ville Voutilainen  <ville.voutilainen@gmail.com>
+           Pedro Lamarão <pedro.lamarao@gmail.com>
+
+       * g++.dg/cpp0x/dc1.C: New test.
+       * g++.dg/cpp0x/dc2.C: New test.
+       * g++.dg/cpp0x/dc3.C: New test.
+       * g++.dg/cpp0x/dc4.C: New test.
+       * g++.dg/cpp0x/dc5.C: New test.
+       * g++.dg/template/meminit1.C: Adjust expected error.
+
 2011-12-05  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/51404
diff --git a/gcc/testsuite/g++.dg/cpp0x/dc1.C b/gcc/testsuite/g++.dg/cpp0x/dc1.C
new file mode 100644 (file)
index 0000000..ba2e4f4
--- /dev/null
@@ -0,0 +1,43 @@
+// { dg-do compile }
+// { dg-options --std=c++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; }
diff --git a/gcc/testsuite/g++.dg/cpp0x/dc2.C b/gcc/testsuite/g++.dg/cpp0x/dc2.C
new file mode 100644 (file)
index 0000000..dda0b9f
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-do compile }
+// { dg-options --std=c++0x }
+
+struct A {
+       int i, j;
+       A () : A(0), j(0) { } // { dg-error "constructor delegation" }
+       A (int _i) : i(_i) { }
+};
+
+struct B {
+       int i, j;
+       B () : i(0), B(0) { } // { dg-error "constructor delegation" }
+       B (int _j) : j(_j) { }
+
+};
+
+struct C {};
+
+struct D : public C {
+       D () : C() { }
+       D (float) : D(), C() { } // { dg-error "constructor delegation" }
+       D (float, float): C(), D() { } // { dg-error "constructor delegation" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/dc3.C b/gcc/testsuite/g++.dg/cpp0x/dc3.C
new file mode 100644 (file)
index 0000000..b411c99
--- /dev/null
@@ -0,0 +1,63 @@
+// { dg-do compile }
+// { dg-options --std=c++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; }
diff --git a/gcc/testsuite/g++.dg/cpp0x/dc4.C b/gcc/testsuite/g++.dg/cpp0x/dc4.C
new file mode 100644 (file)
index 0000000..634b549
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-do compile }
+// { dg-options "--std=c++98" }
+
+struct X {
+  X() {}
+  X(int) : X() {} // { dg-warning "delegating constructors" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/dc5.C b/gcc/testsuite/g++.dg/cpp0x/dc5.C
new file mode 100644 (file)
index 0000000..0052b32
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-do run }
+// { dg-options "--std=c++0x" }
+
+#include <cassert>
+
+int count = 0;
+struct VB
+{
+  VB() {++count;}
+};
+
+struct B : virtual VB
+{
+  B() : B(42) {}
+  B(int)  {}
+};
+
+struct D : B
+{
+  D() {}
+  D(int) : D() {}
+};
+
+int main()
+{
+  D d{42};
+  assert(count == 1);
+}
index b1c4d42..19a1e54 100644 (file)
@@ -2,7 +2,7 @@
 template <class T >
 struct S
 {
-  S() : S() {} // { dg-error "base" }
+  S() : S() {} // { dg-message "delegating constructors" }
 };
 
-S<int> s; // { dg-message "required" }
+S<int> s;