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.

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

From-SVN: r182012
This commit is contained in:
Ville Voutilainen 2011-12-05 17:49:25 +02:00 committed by Jason Merrill
parent 12c574caf6
commit 238e471cad
13 changed files with 287 additions and 14 deletions

View 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

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

View 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. */

View 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 ();
}

View 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);

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

View 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

View File

@ -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; }

View File

@ -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" }
};

View File

@ -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; }

View File

@ -0,0 +1,7 @@
// { dg-do compile }
// { dg-options "--std=c++98" }
struct X {
X() {}
X(int) : X() {} // { dg-warning "delegating constructors" }
};

View File

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

View 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;