public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++0x Constructor Delegation
@ 2007-03-03 19:04 Pedro Lamarão
  2007-03-03 19:27 ` Andrew Pinski
  2007-08-17 20:44 ` C++0x Constructor Delegation take 2 Jason Merrill
  0 siblings, 2 replies; 9+ messages in thread
From: Pedro Lamarão @ 2007-03-03 19:04 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 772 bytes --]

This patch implements the "Delegating Constructor" feature in C++0x. 
mode. The feature is included in the current working draft.

With constructor delegation one is allowed to try code such as:

struct A {

     int handle;

     A (int i) : handle(i) { }

     A () : A(-1) { } // Delegate construction.

};

Tested on i686-pc-linux-gnu with no regressions.


2007-03-03  Pedro Lamarão  <pedro.lamarao@mndfck.org>

	* init.c(expand_member_init): accept constructor delegation
	in C++0x mode.
	(emit_mem_initializers): check for a target constructor
	and delegate.
	(perform_target_ctor): new function.


2007-03-03  Pedro Lamarão  <pedro.lamarao@mndfck.org>

	* g++.dg/cpp0x/dc_01.C: new file.
	* g++.dg/cpp0x/dc_02.C: new file.
	* g++.dg/cpp0x/dc_03.C: new file.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: dc.patch --]
[-- Type: text/x-patch; name="dc.patch", Size: 2578 bytes --]

Index: init.c
===================================================================
--- init.c	(revisão 36)
+++ 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.  */
@@ -664,11 +688,41 @@ sort_mem_initializers (tree t, tree mem_
 void
 emit_mem_initializers (tree mem_inits)
 {
+  tree init;
+  tree target_ctor = NULL_TREE;
+
   /* We will already have issued an error message about the fact that
      the type is incomplete.  */
   if (!COMPLETE_TYPE_P (current_class_type))
     return;
 
+  /* Search for target constructors. */
+  for (init = mem_inits; init; init = TREE_CHAIN (init))
+    {
+      if ((TYPE_P (TREE_PURPOSE (init))
+	   || TREE_CODE (TREE_PURPOSE (init)) == TYPE_DECL)
+	  && same_type_p(TREE_PURPOSE (init), current_class_type))
+	{
+	  target_ctor = TREE_VALUE (init);
+	  break;
+	}
+    }
+
+  /* If we have a target constructor, validate it and delegate. */
+  if (target_ctor != NULL_TREE)
+    {
+      if (TREE_CHAIN (mem_inits) != NULL_TREE)
+	{
+	  error ("target constructor must be the only initializer");  
+	  return;
+	}
+      else
+	{
+	  perform_target_ctor (target_ctor);
+	  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);
@@ -994,6 +1048,10 @@ expand_member_init (tree name)
       tree virtual_binfo;
       int i;
 
+      /* In C++0x we accept constructor delegation. */
+      if (flag_cpp0x && same_type_p (basetype, current_class_type))
+	return basetype;
+
       if (current_template_parms)
 	return basetype;
 

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: dc_testsuite.patch --]
[-- Type: text/x-patch; name="dc_testsuite.patch", Size: 2845 bytes --]

Index: g++.dg/cpp0x/dc_01.C
===================================================================
--- g++.dg/cpp0x/dc_01.C	(revisão 0)
+++ 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: g++.dg/cpp0x/dc_02.C
===================================================================
--- g++.dg/cpp0x/dc_02.C	(revisão 0)
+++ 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: g++.dg/cpp0x/dc_03.C
===================================================================
--- g++.dg/cpp0x/dc_03.C	(revisão 0)
+++ 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; }

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: C++0x Constructor Delegation
  2007-03-03 19:04 C++0x Constructor Delegation Pedro Lamarão
@ 2007-03-03 19:27 ` Andrew Pinski
  2007-03-04 18:11   ` Mark Mitchell
  2007-08-17 20:44 ` C++0x Constructor Delegation take 2 Jason Merrill
  1 sibling, 1 reply; 9+ messages in thread
From: Andrew Pinski @ 2007-03-03 19:27 UTC (permalink / raw)
  To: Pedro Lamarão; +Cc: gcc-patches

On 3/3/07, Pedro Lamarão <pedro.lamarao@mndfck.org> wrote:
> This patch implements the "Delegating Constructor" feature in C++0x.
> mode. The feature is included in the current working draft.
>
> With constructor delegation one is allowed to try code such as:
>
> struct A {
>
>      int handle;
>
>      A (int i) : handle(i) { }
>
>      A () : A(-1) { } // Delegate construction.
>
> };
>
> Tested on i686-pc-linux-gnu with no regressions.
>
>
> 2007-03-03  Pedro Lamarão  <pedro.lamarao@mndfck.org>
>
>         * init.c(expand_member_init): accept constructor delegation
>         in C++0x mode.
>         (emit_mem_initializers): check for a target constructor
>         and delegate.
>         (perform_target_ctor): new function.

I think emit_mem_initializers check could be improved, and only have a
loop in the case of the error and also only in C++0x mode because it
might slow down the compiler too much.
Something like:
#define CTOR_DELAGE_P(type)   (TYPE_P (TREE_PURPOSE (init)) \
	   || TREE_CODE (TREE_PURPOSE (init)) == TYPE_DECL) \
	  && same_type_p(TREE_PURPOSE (init), current_class_type))

if (flag_cpp0x)
{
      if (!CTOR_DELAGE_P (TREE_PURPOSE (mem_inits))
          || TREE_CHAIN (mem_inits))
      {
         for (init = mem_inits; init; init = TREE_CHAIN (init))
         {
            if (CTOR_DELAGE_P (TREE_PURPOSE (mem_inits)))
            {
               error ("target constructor must be the only initializer");
               return;
            }
         }
      }
      else
      {
	  perform_target_ctor (TREE_VALUE (mem_inits));
	  return;
     }
}

Note I wrote this in the email editor so I could have mistakes,

Even though the common case in C++0x will be slower, the C++98/03 case
is not going to be much slower.

Thanks,
Andrew Pinski

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: C++0x Constructor Delegation
  2007-03-03 19:27 ` Andrew Pinski
@ 2007-03-04 18:11   ` Mark Mitchell
  2007-03-04 20:50     ` Pedro Lamarão
  0 siblings, 1 reply; 9+ messages in thread
From: Mark Mitchell @ 2007-03-04 18:11 UTC (permalink / raw)
  To: Andrew Pinski; +Cc: Pedro Lamarão, gcc-patches

Andrew Pinski wrote:

> I think emit_mem_initializers check could be improved, and only have a
> loop in the case of the error and also only in C++0x mode because it
> might slow down the compiler too much.

Rather, this check should just be done in the parser, as it can know
what names indicate a base/member and which name a constructor.  It just
has to maintain a seen-delegate bit.  That follows the principle of
keeping invalid representations contained as tightly as possible within
the C++ front end.

-- 
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: C++0x Constructor Delegation
  2007-03-04 18:11   ` Mark Mitchell
@ 2007-03-04 20:50     ` Pedro Lamarão
  0 siblings, 0 replies; 9+ messages in thread
From: Pedro Lamarão @ 2007-03-04 20:50 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Andrew Pinski, gcc-patches

Mark Mitchell escreveu:
> Andrew Pinski wrote:
>
>   
>> I think emit_mem_initializers check could be improved, and only have a
>> loop in the case of the error and also only in C++0x mode because it
>> might slow down the compiler too much.
>>     
>
> Rather, this check should just be done in the parser, as it can know
> what names indicate a base/member and which name a constructor.  It just
> has to maintain a seen-delegate bit.  That follows the principle of
> keeping invalid representations contained as tightly as possible within
> the C++ front end.
>   

I do have a different version of the patch with checks in 
cp_parser_mem_initializer_list.
I'll polish it a little and send it for review.

--
 Pedro Lamarão

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: C++0x Constructor Delegation take 2
  2007-03-03 19:04 C++0x Constructor Delegation Pedro Lamarão
  2007-03-03 19:27 ` Andrew Pinski
@ 2007-08-17 20:44 ` Jason Merrill
  1 sibling, 0 replies; 9+ messages in thread
From: Jason Merrill @ 2007-08-17 20:44 UTC (permalink / raw)
  To: pedro.lamarao, gcc-patches List, Douglas Gregor

Sorry about the delay in reviewing this.  Just to make sure, do you have 
a copyright assignment on file with the FSF?

It seems to me that we could move the new code in 
cp_parser_mem_initializer_list inside the existing "if (mem_initializer 
!= error_mark_node)" block rather than testing that same condition 
repeatedly.

More significantly, in cases like this where the C++0x syntax is 
ill-formed in C++98, please give a useful diagnostic ("you need to use 
-std=gnu++0x") rather than fall back on the old error.

Jason

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: C++0x Constructor Delegation take 2
@ 2009-08-28  0:38 Jason Merrill
  0 siblings, 0 replies; 9+ messages in thread
From: Jason Merrill @ 2009-08-28  0:38 UTC (permalink / raw)
  To: Pedro Lamarão, gcc-patches List

 > http://gcc.gnu.org/ml/gcc-patches/2007-04/msg00620.html

Thanks a lot for the submission, and I'm sorry it has taken this long to 
review the patch.  Please do CC me on C++ patches, and ping me if a week 
goes by without a review.

I agree with Doug's comments.

The tests for flag_cpp0x now need to be "cxx_dialect != cxx98".

> +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);
> +    }
> +}

This assumes that we'll only do delegation for the complete constructor, 
which is not the case.  For instance, this testcase breaks:

int c;
struct A
{
   A() { ++c; }
};

struct B: virtual A
{
   B(): B (1) {}
   B(int) {}
};

struct C: public B
{
   C(): A(), B() { }
};

int main()
{
   C cee;
   if (c > 1)
     return c;
   else if (c == 0)
     return 1;
}

We end up constructing the A subobject twice, because the B() 
not-in-charge constructor calls the B(int) in-charge constructor, which 
wrongly calls the A constructor.

Jason

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: C++0x Constructor Delegation take 2
  2007-04-24 15:42 ` Doug Gregor
@ 2007-06-29 22:05   ` Doug Gregor
  0 siblings, 0 replies; 9+ messages in thread
From: Doug Gregor @ 2007-06-29 22:05 UTC (permalink / raw)
  To: Pedro Lamarão; +Cc: gcc-patches

Hi Pedro,

With your patch, I'm starting to see a new failure in C++0x mode. I'm
not sure if this is a change from C++98 to C++0x, or whether it's
revealing a bug in the delegating constructors code:

The test case is gcc/testsuite/g++.dg/init/brace6.C in Subversion,
also shown below. In C++0x mode, we don't emit the error for the
second dg-error and we emit something different for the third
dg-error.

  - Doug

/* PR c++/30759 */
/* { dg-do "compile" } */

struct A {
   A(int) { }
};

struct B {
   B(const B&);
   int b;
};

struct C {};

struct D { int c; };

int main()
{
   int i = { 1 };
   int j = { 1, 2 }; /* { dg-error "requires one element" } */
   A a = { 6 }; /* { dg-error "initializer for non" } */
   B b = { 6 }; /* { dg-error "initializer for non" } */
   C c = { 6 }; /* { dg-error "too many initializers" } */
   D d = { 6 };
}


On 4/24/07, Doug Gregor <doug.gregor@gmail.com> wrote:
> Hi Pedro,
>
> I have a few small comments to make about this version of the patch.
> Otherwise, it looks good to me. However, I don't have the ability to
> approve it. Nathan, could you take a look?
>
> 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 }
>
> I suggest using "-std=c++0x", since delegating constructors are in the
> C++0x Working Paper (we're not relying on extensions at all).
>
> +/* 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)
>
> I suggest adding a comment stating that this routine implements the
> delegating constructors feature of C++0x.
>
>   - Doug
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: C++0x Constructor Delegation take 2
  2007-04-12  4:53 Pedro Lamarão
@ 2007-04-24 15:42 ` Doug Gregor
  2007-06-29 22:05   ` Doug Gregor
  0 siblings, 1 reply; 9+ messages in thread
From: Doug Gregor @ 2007-04-24 15:42 UTC (permalink / raw)
  To: Pedro Lamarão, Nathan Sidwell; +Cc: gcc-patches

Hi Pedro,

I have a few small comments to make about this version of the patch.
Otherwise, it looks good to me. However, I don't have the ability to
approve it. Nathan, could you take a look?

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 }

I suggest using "-std=c++0x", since delegating constructors are in the
C++0x Working Paper (we're not relying on extensions at all).

+/* 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)

I suggest adding a comment stating that this routine implements the
delegating constructors feature of C++0x.

  - Doug

^ permalink raw reply	[flat|nested] 9+ messages in thread

* C++0x Constructor Delegation take 2
@ 2007-04-12  4:53 Pedro Lamarão
  2007-04-24 15:42 ` Doug Gregor
  0 siblings, 1 reply; 9+ messages in thread
From: Pedro Lamarão @ 2007-04-12  4:53 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 630 bytes --]

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.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: dc.patch --]
[-- Type: text/x-patch; name="dc.patch", Size: 6911 bytes --]

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)
 	{

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2009-08-27 21:39 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-03-03 19:04 C++0x Constructor Delegation Pedro Lamarão
2007-03-03 19:27 ` Andrew Pinski
2007-03-04 18:11   ` Mark Mitchell
2007-03-04 20:50     ` Pedro Lamarão
2007-08-17 20:44 ` C++0x Constructor Delegation take 2 Jason Merrill
2007-04-12  4:53 Pedro Lamarão
2007-04-24 15:42 ` Doug Gregor
2007-06-29 22:05   ` Doug Gregor
2009-08-28  0:38 Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).