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:
parent
12c574caf6
commit
238e471cad
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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. */
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
43
gcc/testsuite/g++.dg/cpp0x/dc1.C
Normal file
43
gcc/testsuite/g++.dg/cpp0x/dc1.C
Normal 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; }
|
23
gcc/testsuite/g++.dg/cpp0x/dc2.C
Normal file
23
gcc/testsuite/g++.dg/cpp0x/dc2.C
Normal 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" }
|
||||
};
|
63
gcc/testsuite/g++.dg/cpp0x/dc3.C
Normal file
63
gcc/testsuite/g++.dg/cpp0x/dc3.C
Normal 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; }
|
7
gcc/testsuite/g++.dg/cpp0x/dc4.C
Normal file
7
gcc/testsuite/g++.dg/cpp0x/dc4.C
Normal file
@ -0,0 +1,7 @@
|
||||
// { dg-do compile }
|
||||
// { dg-options "--std=c++98" }
|
||||
|
||||
struct X {
|
||||
X() {}
|
||||
X(int) : X() {} // { dg-warning "delegating constructors" }
|
||||
};
|
28
gcc/testsuite/g++.dg/cpp0x/dc5.C
Normal file
28
gcc/testsuite/g++.dg/cpp0x/dc5.C
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user