Implement C++0x unrestricted unions (N2544)
Implement C++0x unrestricted unions (N2544) * class.c (check_field_decl): Loosen union handling in C++0x. * method.c (walk_field_subobs): Split out from... (synthesized_method_walk): ...here. Set msg before loops. (process_subob_fn): Check for triviality in union members. * init.c (sort_mem_initializers): Splice out uninitialized anonymous unions and union members. (push_base_cleanups): Don't automatically destroy anonymous unions and union members. From-SVN: r162187
This commit is contained in:
parent
a9c5db803f
commit
57ece25833
@ -1,3 +1,15 @@
|
|||||||
|
2010-07-14 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
|
Implement C++0x unrestricted unions (N2544)
|
||||||
|
* class.c (check_field_decl): Loosen union handling in C++0x.
|
||||||
|
* method.c (walk_field_subobs): Split out from...
|
||||||
|
(synthesized_method_walk): ...here. Set msg before loops.
|
||||||
|
(process_subob_fn): Check for triviality in union members.
|
||||||
|
* init.c (sort_mem_initializers): Splice out uninitialized
|
||||||
|
anonymous unions and union members.
|
||||||
|
(push_base_cleanups): Don't automatically destroy anonymous unions
|
||||||
|
and union members.
|
||||||
|
|
||||||
2010-07-13 Jason Merrill <jason@redhat.com>
|
2010-07-13 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
PR c++/44909
|
PR c++/44909
|
||||||
|
@ -2864,9 +2864,9 @@ check_field_decl (tree field,
|
|||||||
{
|
{
|
||||||
tree type = strip_array_types (TREE_TYPE (field));
|
tree type = strip_array_types (TREE_TYPE (field));
|
||||||
|
|
||||||
/* An anonymous union cannot contain any fields which would change
|
/* In C++98 an anonymous union cannot contain any fields which would change
|
||||||
the settings of CANT_HAVE_CONST_CTOR and friends. */
|
the settings of CANT_HAVE_CONST_CTOR and friends. */
|
||||||
if (ANON_UNION_TYPE_P (type))
|
if (ANON_UNION_TYPE_P (type) && cxx_dialect < cxx0x)
|
||||||
;
|
;
|
||||||
/* And, we don't set TYPE_HAS_CONST_COPY_CTOR, etc., for anonymous
|
/* And, we don't set TYPE_HAS_CONST_COPY_CTOR, etc., for anonymous
|
||||||
structs. So, we recurse through their fields here. */
|
structs. So, we recurse through their fields here. */
|
||||||
@ -2888,8 +2888,10 @@ check_field_decl (tree field,
|
|||||||
make it through without complaint. */
|
make it through without complaint. */
|
||||||
abstract_virtuals_error (field, type);
|
abstract_virtuals_error (field, type);
|
||||||
|
|
||||||
if (TREE_CODE (t) == UNION_TYPE)
|
if (TREE_CODE (t) == UNION_TYPE && cxx_dialect < cxx0x)
|
||||||
{
|
{
|
||||||
|
static bool warned;
|
||||||
|
int oldcount = errorcount;
|
||||||
if (TYPE_NEEDS_CONSTRUCTING (type))
|
if (TYPE_NEEDS_CONSTRUCTING (type))
|
||||||
error ("member %q+#D with constructor not allowed in union",
|
error ("member %q+#D with constructor not allowed in union",
|
||||||
field);
|
field);
|
||||||
@ -2898,8 +2900,12 @@ check_field_decl (tree field,
|
|||||||
if (TYPE_HAS_COMPLEX_COPY_ASSIGN (type))
|
if (TYPE_HAS_COMPLEX_COPY_ASSIGN (type))
|
||||||
error ("member %q+#D with copy assignment operator not allowed in union",
|
error ("member %q+#D with copy assignment operator not allowed in union",
|
||||||
field);
|
field);
|
||||||
/* Don't bother diagnosing move assop now; C++0x has more
|
if (!warned && errorcount > oldcount)
|
||||||
flexible unions. */
|
{
|
||||||
|
inform (DECL_SOURCE_LOCATION (field), "unrestricted unions "
|
||||||
|
"only available with -std=c++0x or -std=gnu++0x");
|
||||||
|
warned = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -708,23 +708,34 @@ sort_mem_initializers (tree t, tree mem_inits)
|
|||||||
|
|
||||||
If a ctor-initializer specifies more than one mem-initializer for
|
If a ctor-initializer specifies more than one mem-initializer for
|
||||||
multiple members of the same union (including members of
|
multiple members of the same union (including members of
|
||||||
anonymous unions), the ctor-initializer is ill-formed. */
|
anonymous unions), the ctor-initializer is ill-formed.
|
||||||
|
|
||||||
|
Here we also splice out uninitialized union members. */
|
||||||
if (uses_unions_p)
|
if (uses_unions_p)
|
||||||
{
|
{
|
||||||
tree last_field = NULL_TREE;
|
tree last_field = NULL_TREE;
|
||||||
for (init = sorted_inits; init; init = TREE_CHAIN (init))
|
tree *p;
|
||||||
|
for (p = &sorted_inits; *p; )
|
||||||
{
|
{
|
||||||
tree field;
|
tree field;
|
||||||
tree field_type;
|
tree field_type;
|
||||||
int done;
|
int done;
|
||||||
|
|
||||||
/* Skip uninitialized members and base classes. */
|
init = *p;
|
||||||
if (!TREE_VALUE (init)
|
|
||||||
|| TREE_CODE (TREE_PURPOSE (init)) != FIELD_DECL)
|
field = TREE_PURPOSE (init);
|
||||||
continue;
|
|
||||||
|
/* Skip base classes. */
|
||||||
|
if (TREE_CODE (field) != FIELD_DECL)
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
/* If this is an anonymous union with no explicit initializer,
|
||||||
|
splice it out. */
|
||||||
|
if (!TREE_VALUE (init) && ANON_UNION_TYPE_P (TREE_TYPE (field)))
|
||||||
|
goto splice;
|
||||||
|
|
||||||
/* See if this field is a member of a union, or a member of a
|
/* See if this field is a member of a union, or a member of a
|
||||||
structure contained in a union, etc. */
|
structure contained in a union, etc. */
|
||||||
field = TREE_PURPOSE (init);
|
|
||||||
for (field_type = DECL_CONTEXT (field);
|
for (field_type = DECL_CONTEXT (field);
|
||||||
!same_type_p (field_type, t);
|
!same_type_p (field_type, t);
|
||||||
field_type = TYPE_CONTEXT (field_type))
|
field_type = TYPE_CONTEXT (field_type))
|
||||||
@ -732,14 +743,19 @@ sort_mem_initializers (tree t, tree mem_inits)
|
|||||||
break;
|
break;
|
||||||
/* If this field is not a member of a union, skip it. */
|
/* If this field is not a member of a union, skip it. */
|
||||||
if (TREE_CODE (field_type) != UNION_TYPE)
|
if (TREE_CODE (field_type) != UNION_TYPE)
|
||||||
continue;
|
goto next;
|
||||||
|
|
||||||
|
/* If this union member has no explicit initializer, splice
|
||||||
|
it out. */
|
||||||
|
if (!TREE_VALUE (init))
|
||||||
|
goto splice;
|
||||||
|
|
||||||
/* It's only an error if we have two initializers for the same
|
/* It's only an error if we have two initializers for the same
|
||||||
union type. */
|
union type. */
|
||||||
if (!last_field)
|
if (!last_field)
|
||||||
{
|
{
|
||||||
last_field = field;
|
last_field = field;
|
||||||
continue;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if LAST_FIELD and the field initialized by INIT are
|
/* See if LAST_FIELD and the field initialized by INIT are
|
||||||
@ -785,6 +801,13 @@ sort_mem_initializers (tree t, tree mem_inits)
|
|||||||
while (!done);
|
while (!done);
|
||||||
|
|
||||||
last_field = field;
|
last_field = field;
|
||||||
|
|
||||||
|
next:
|
||||||
|
p = &TREE_CHAIN (*p);
|
||||||
|
continue;
|
||||||
|
splice:
|
||||||
|
*p = TREE_CHAIN (*p);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3353,21 +3376,27 @@ push_base_cleanups (void)
|
|||||||
finish_decl_cleanup (NULL_TREE, expr);
|
finish_decl_cleanup (NULL_TREE, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Don't automatically destroy union members. */
|
||||||
|
if (TREE_CODE (current_class_type) == UNION_TYPE)
|
||||||
|
return;
|
||||||
|
|
||||||
for (member = TYPE_FIELDS (current_class_type); member;
|
for (member = TYPE_FIELDS (current_class_type); member;
|
||||||
member = TREE_CHAIN (member))
|
member = TREE_CHAIN (member))
|
||||||
{
|
{
|
||||||
if (TREE_TYPE (member) == error_mark_node
|
tree this_type = TREE_TYPE (member);
|
||||||
|
if (this_type == error_mark_node
|
||||||
|| TREE_CODE (member) != FIELD_DECL
|
|| TREE_CODE (member) != FIELD_DECL
|
||||||
|| DECL_ARTIFICIAL (member))
|
|| DECL_ARTIFICIAL (member))
|
||||||
continue;
|
continue;
|
||||||
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
|
if (ANON_UNION_TYPE_P (this_type))
|
||||||
|
continue;
|
||||||
|
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (this_type))
|
||||||
{
|
{
|
||||||
tree this_member = (build_class_member_access_expr
|
tree this_member = (build_class_member_access_expr
|
||||||
(current_class_ref, member,
|
(current_class_ref, member,
|
||||||
/*access_path=*/NULL_TREE,
|
/*access_path=*/NULL_TREE,
|
||||||
/*preserve_reference=*/false,
|
/*preserve_reference=*/false,
|
||||||
tf_warning_or_error));
|
tf_warning_or_error));
|
||||||
tree this_type = TREE_TYPE (member);
|
|
||||||
expr = build_delete (this_type, this_member,
|
expr = build_delete (this_type, this_member,
|
||||||
sfk_complete_destructor,
|
sfk_complete_destructor,
|
||||||
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
|
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
|
||||||
|
248
gcc/cp/method.c
248
gcc/cp/method.c
@ -545,7 +545,8 @@ do_build_copy_constructor (tree fndecl)
|
|||||||
}
|
}
|
||||||
else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type))
|
else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type))
|
||||||
/* Just use the field; anonymous types can't have
|
/* Just use the field; anonymous types can't have
|
||||||
nontrivial copy ctors or assignment ops. */;
|
nontrivial copy ctors or assignment ops or this
|
||||||
|
function would be deleted. */;
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -663,7 +664,8 @@ do_build_copy_assign (tree fndecl)
|
|||||||
else if (ANON_AGGR_TYPE_P (expr_type)
|
else if (ANON_AGGR_TYPE_P (expr_type)
|
||||||
&& TYPE_FIELDS (expr_type) != NULL_TREE)
|
&& TYPE_FIELDS (expr_type) != NULL_TREE)
|
||||||
/* Just use the field; anonymous types can't have
|
/* Just use the field; anonymous types can't have
|
||||||
nontrivial copy ctors or assignment ops. */;
|
nontrivial copy ctors or assignment ops or this
|
||||||
|
function would be deleted. */;
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -912,8 +914,19 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
|
|||||||
*spec_p = merge_exception_specifiers (*spec_p, raises);
|
*spec_p = merge_exception_specifiers (*spec_p, raises);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trivial_p && !trivial_fn_p (fn))
|
if (!trivial_fn_p (fn))
|
||||||
*trivial_p = false;
|
{
|
||||||
|
if (trivial_p)
|
||||||
|
*trivial_p = false;
|
||||||
|
if (TREE_CODE (arg) == FIELD_DECL
|
||||||
|
&& TREE_CODE (DECL_CONTEXT (arg)) == UNION_TYPE)
|
||||||
|
{
|
||||||
|
if (deleted_p)
|
||||||
|
*deleted_p = true;
|
||||||
|
if (msg)
|
||||||
|
error ("union member %q+D with non-trivial %qD", arg, fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
|
if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
|
||||||
{
|
{
|
||||||
@ -929,6 +942,99 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
|
|||||||
*deleted_p = true;
|
*deleted_p = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subroutine of synthesized_method_walk to allow recursion into anonymous
|
||||||
|
aggregates. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
|
||||||
|
int quals, bool copy_arg_p, bool move_p,
|
||||||
|
bool assign_p, tree *spec_p, bool *trivial_p,
|
||||||
|
bool *deleted_p, const char *msg,
|
||||||
|
int flags, tsubst_flags_t complain)
|
||||||
|
{
|
||||||
|
tree field;
|
||||||
|
for (field = fields; field; field = TREE_CHAIN (field))
|
||||||
|
{
|
||||||
|
tree mem_type, argtype, rval;
|
||||||
|
|
||||||
|
if (TREE_CODE (field) != FIELD_DECL
|
||||||
|
|| DECL_ARTIFICIAL (field))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mem_type = strip_array_types (TREE_TYPE (field));
|
||||||
|
if (assign_p)
|
||||||
|
{
|
||||||
|
bool bad = true;
|
||||||
|
if (CP_TYPE_CONST_P (mem_type) && !CLASS_TYPE_P (mem_type))
|
||||||
|
{
|
||||||
|
if (msg)
|
||||||
|
error ("non-static const member %q#D, can't use default "
|
||||||
|
"assignment operator", field);
|
||||||
|
}
|
||||||
|
else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
|
||||||
|
{
|
||||||
|
if (msg)
|
||||||
|
error ("non-static reference member %q#D, can't use "
|
||||||
|
"default assignment operator", field);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bad = false;
|
||||||
|
|
||||||
|
if (bad && deleted_p)
|
||||||
|
*deleted_p = true;
|
||||||
|
}
|
||||||
|
else if (sfk == sfk_constructor)
|
||||||
|
{
|
||||||
|
bool bad = true;
|
||||||
|
if (CP_TYPE_CONST_P (mem_type)
|
||||||
|
&& (!CLASS_TYPE_P (mem_type)
|
||||||
|
|| !type_has_user_provided_default_constructor (mem_type)))
|
||||||
|
{
|
||||||
|
if (msg)
|
||||||
|
error ("uninitialized non-static const member %q#D",
|
||||||
|
field);
|
||||||
|
}
|
||||||
|
else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
|
||||||
|
{
|
||||||
|
if (msg)
|
||||||
|
error ("uninitialized non-static reference member %q#D",
|
||||||
|
field);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bad = false;
|
||||||
|
|
||||||
|
if (bad && deleted_p)
|
||||||
|
*deleted_p = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CLASS_TYPE_P (mem_type))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ANON_AGGR_TYPE_P (mem_type))
|
||||||
|
{
|
||||||
|
walk_field_subobs (TYPE_FIELDS (mem_type), fnname, sfk, quals,
|
||||||
|
copy_arg_p, move_p, assign_p, spec_p, trivial_p,
|
||||||
|
deleted_p, msg, flags, complain);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_arg_p)
|
||||||
|
{
|
||||||
|
int mem_quals = cp_type_quals (mem_type) | quals;
|
||||||
|
if (DECL_MUTABLE_P (field))
|
||||||
|
mem_quals &= ~TYPE_QUAL_CONST;
|
||||||
|
argtype = build_stub_type (mem_type, mem_quals, move_p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
argtype = NULL_TREE;
|
||||||
|
|
||||||
|
rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
|
||||||
|
|
||||||
|
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
|
||||||
|
msg, field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* The caller wants to generate an implicit declaration of SFK for CTYPE
|
/* The caller wants to generate an implicit declaration of SFK for CTYPE
|
||||||
which is const if relevant and CONST_P is set. If spec_p, trivial_p and
|
which is const if relevant and CONST_P is set. If spec_p, trivial_p and
|
||||||
deleted_p are non-null, set their referent appropriately. If diag is
|
deleted_p are non-null, set their referent appropriately. If diag is
|
||||||
@ -940,7 +1046,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
|
|||||||
tree *spec_p, bool *trivial_p, bool *deleted_p,
|
tree *spec_p, bool *trivial_p, bool *deleted_p,
|
||||||
bool diag)
|
bool diag)
|
||||||
{
|
{
|
||||||
tree binfo, base_binfo, field, scope, fnname, rval, argtype;
|
tree binfo, base_binfo, scope, fnname, rval, argtype;
|
||||||
bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
|
bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
|
||||||
VEC(tree,gc) *vbases;
|
VEC(tree,gc) *vbases;
|
||||||
int i, quals, flags;
|
int i, quals, flags;
|
||||||
@ -1052,6 +1158,15 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
|
|||||||
quals = TYPE_UNQUALIFIED;
|
quals = TYPE_UNQUALIFIED;
|
||||||
argtype = NULL_TREE;
|
argtype = NULL_TREE;
|
||||||
|
|
||||||
|
if (!diag)
|
||||||
|
msg = NULL;
|
||||||
|
else if (assign_p)
|
||||||
|
msg = ("base %qT does not have a move assignment operator or trivial "
|
||||||
|
"copy assignment operator");
|
||||||
|
else
|
||||||
|
msg = ("base %qT does not have a move constructor or trivial "
|
||||||
|
"copy constructor");
|
||||||
|
|
||||||
for (binfo = TYPE_BINFO (ctype), i = 0;
|
for (binfo = TYPE_BINFO (ctype), i = 0;
|
||||||
BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
|
BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
|
||||||
{
|
{
|
||||||
@ -1060,15 +1175,6 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
|
|||||||
argtype = build_stub_type (basetype, quals, move_p);
|
argtype = build_stub_type (basetype, quals, move_p);
|
||||||
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
|
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
|
||||||
|
|
||||||
if (!diag)
|
|
||||||
msg = NULL;
|
|
||||||
else if (assign_p)
|
|
||||||
msg = ("base %qT does not have a move assignment operator or trivial "
|
|
||||||
"copy assignment operator");
|
|
||||||
else
|
|
||||||
msg = ("base %qT does not have a move constructor or trivial "
|
|
||||||
"copy constructor");
|
|
||||||
|
|
||||||
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
|
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
|
||||||
msg, BINFO_TYPE (base_binfo));
|
msg, BINFO_TYPE (base_binfo));
|
||||||
|
|
||||||
@ -1094,105 +1200,31 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
|
|||||||
*deleted_p = true;
|
*deleted_p = true;
|
||||||
}
|
}
|
||||||
else if (!assign_p)
|
else if (!assign_p)
|
||||||
for (i = 0; VEC_iterate (tree, vbases, i, base_binfo); ++i)
|
|
||||||
{
|
|
||||||
if (copy_arg_p)
|
|
||||||
argtype = build_stub_type (BINFO_TYPE (base_binfo), quals, move_p);
|
|
||||||
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
|
|
||||||
|
|
||||||
if (!diag)
|
|
||||||
msg = NULL;
|
|
||||||
else if (assign_p)
|
|
||||||
msg = ("virtual base %qT does not have a move assignment "
|
|
||||||
"operator or trivial copy assignment operator");
|
|
||||||
else
|
|
||||||
msg = ("virtual base %qT does not have a move constructor "
|
|
||||||
"or trivial copy constructor");
|
|
||||||
|
|
||||||
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
|
|
||||||
msg, BINFO_TYPE (base_binfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (field = TYPE_FIELDS (ctype); field; field = TREE_CHAIN (field))
|
|
||||||
{
|
{
|
||||||
tree mem_type;
|
if (diag)
|
||||||
|
msg = ("virtual base %qT does not have a move constructor "
|
||||||
if (TREE_CODE (field) != FIELD_DECL
|
"or trivial copy constructor");
|
||||||
|| DECL_ARTIFICIAL (field))
|
for (i = 0; VEC_iterate (tree, vbases, i, base_binfo); ++i)
|
||||||
continue;
|
|
||||||
|
|
||||||
mem_type = strip_array_types (TREE_TYPE (field));
|
|
||||||
if (assign_p)
|
|
||||||
{
|
{
|
||||||
bool bad = true;
|
if (copy_arg_p)
|
||||||
if (CP_TYPE_CONST_P (mem_type) && !CLASS_TYPE_P (mem_type))
|
argtype = build_stub_type (BINFO_TYPE (base_binfo), quals, move_p);
|
||||||
{
|
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
|
||||||
if (diag)
|
|
||||||
error ("non-static const member %q#D, can't use default "
|
|
||||||
"assignment operator", field);
|
|
||||||
}
|
|
||||||
else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
|
|
||||||
{
|
|
||||||
if (diag)
|
|
||||||
error ("non-static reference member %q#D, can't use "
|
|
||||||
"default assignment operator", field);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
bad = false;
|
|
||||||
|
|
||||||
if (bad && deleted_p)
|
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
|
||||||
*deleted_p = true;
|
msg, BINFO_TYPE (base_binfo));
|
||||||
}
|
}
|
||||||
else if (sfk == sfk_constructor)
|
|
||||||
{
|
|
||||||
bool bad = true;
|
|
||||||
if (CP_TYPE_CONST_P (mem_type)
|
|
||||||
&& (!CLASS_TYPE_P (mem_type)
|
|
||||||
|| !type_has_user_provided_default_constructor (mem_type)))
|
|
||||||
{
|
|
||||||
if (diag)
|
|
||||||
error ("uninitialized non-static const member %q#D",
|
|
||||||
field);
|
|
||||||
}
|
|
||||||
else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
|
|
||||||
{
|
|
||||||
if (diag)
|
|
||||||
error ("uninitialized non-static reference member %q#D",
|
|
||||||
field);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
bad = false;
|
|
||||||
|
|
||||||
if (bad && deleted_p)
|
|
||||||
*deleted_p = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CLASS_TYPE_P (mem_type)
|
|
||||||
|| ANON_AGGR_TYPE_P (mem_type))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (copy_arg_p)
|
|
||||||
{
|
|
||||||
int mem_quals = cp_type_quals (mem_type) | quals;
|
|
||||||
if (DECL_MUTABLE_P (field))
|
|
||||||
mem_quals &= ~TYPE_QUAL_CONST;
|
|
||||||
argtype = build_stub_type (mem_type, mem_quals, move_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
|
|
||||||
|
|
||||||
if (!diag)
|
|
||||||
msg = NULL;
|
|
||||||
else if (assign_p)
|
|
||||||
msg = ("non-static data member %qD does not have a move "
|
|
||||||
"assignment operator or trivial copy assignment operator");
|
|
||||||
else
|
|
||||||
msg = ("non-static data member %qD does not have a move "
|
|
||||||
"constructor or trivial copy constructor");
|
|
||||||
|
|
||||||
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
|
|
||||||
msg, field);
|
|
||||||
}
|
}
|
||||||
|
if (!diag)
|
||||||
|
/* Leave msg null. */;
|
||||||
|
else if (assign_p)
|
||||||
|
msg = ("non-static data member %qD does not have a move "
|
||||||
|
"assignment operator or trivial copy assignment operator");
|
||||||
|
else
|
||||||
|
msg = ("non-static data member %qD does not have a move "
|
||||||
|
"constructor or trivial copy constructor");
|
||||||
|
walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals,
|
||||||
|
copy_arg_p, move_p, assign_p, spec_p, trivial_p,
|
||||||
|
deleted_p, msg, flags, complain);
|
||||||
|
|
||||||
pop_scope (scope);
|
pop_scope (scope);
|
||||||
|
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
2010-07-14 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
|
Implement C++0x unrestricted unions (N2544)
|
||||||
|
* g++.dg/cpp0x/union1.C: New.
|
||||||
|
* g++.dg/cpp0x/union2.C: New.
|
||||||
|
* g++.dg/cpp0x/union3.C: New.
|
||||||
|
* g++.dg/cpp0x/defaulted2.C: Adjust.
|
||||||
|
* g++.old-deja/g++.bugs/900121_02.C: Adjust.
|
||||||
|
* g++.old-deja/g++.ext/anon2.C: Adjust.
|
||||||
|
* g++.old-deja/g++.mike/misc6.C: Adjust.
|
||||||
|
|
||||||
2010-07-14 Janus Weil <janus@gcc.gnu.org>
|
2010-07-14 Janus Weil <janus@gcc.gnu.org>
|
||||||
|
|
||||||
PR fortran/44925
|
PR fortran/44925
|
||||||
|
@ -54,7 +54,7 @@ G::G() = default;
|
|||||||
|
|
||||||
union U
|
union U
|
||||||
{
|
{
|
||||||
G g; // { dg-error "constructor" }
|
G g; // { dg-error "union member.*non-trivial" }
|
||||||
};
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@ -62,5 +62,7 @@ int main()
|
|||||||
F f;
|
F f;
|
||||||
F f2(f); // { dg-error "use" }
|
F f2(f); // { dg-error "use" }
|
||||||
B* b = new const B; // { dg-error "uninitialized const" }
|
B* b = new const B; // { dg-error "uninitialized const" }
|
||||||
|
U u; // { dg-error "deleted" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// { dg-prune-output "implicitly deleted because" }
|
||||||
|
34
gcc/testsuite/g++.dg/cpp0x/union1.C
Normal file
34
gcc/testsuite/g++.dg/cpp0x/union1.C
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Negative test for C++0x unrestricted unions
|
||||||
|
// { dg-options -std=c++0x }
|
||||||
|
// { dg-prune-output "implicitly deleted because" }
|
||||||
|
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
A();
|
||||||
|
A(const A&);
|
||||||
|
~A();
|
||||||
|
};
|
||||||
|
|
||||||
|
union B
|
||||||
|
{
|
||||||
|
A a; // { dg-error "union member" }
|
||||||
|
};
|
||||||
|
|
||||||
|
B b; // { dg-error "B::B\\(\\)" }
|
||||||
|
B b2(b); // { dg-error "B::B\\(const B&\\)" }
|
||||||
|
|
||||||
|
struct C
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
A a; // { dg-error "union member" }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
C c; // { dg-error "C::C\\(\\)" }
|
||||||
|
C c2(c); // { dg-error "C::C\\(const C&\\)" }
|
||||||
|
|
||||||
|
// { dg-error "B::~B" "" { target *-*-* } 17 }
|
||||||
|
// { dg-error "B::~B" "" { target *-*-* } 18 }
|
||||||
|
// { dg-error "C::~C" "" { target *-*-* } 28 }
|
||||||
|
// { dg-error "C::~C" "" { target *-*-* } 29 }
|
34
gcc/testsuite/g++.dg/cpp0x/union2.C
Normal file
34
gcc/testsuite/g++.dg/cpp0x/union2.C
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Positive test for C++0x unrestricted unions
|
||||||
|
// { dg-options -std=c++0x }
|
||||||
|
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
A();
|
||||||
|
A(const A&);
|
||||||
|
~A();
|
||||||
|
};
|
||||||
|
|
||||||
|
union B
|
||||||
|
{
|
||||||
|
A a;
|
||||||
|
B();
|
||||||
|
B(const B&);
|
||||||
|
~B();
|
||||||
|
};
|
||||||
|
|
||||||
|
B b;
|
||||||
|
B b2(b);
|
||||||
|
|
||||||
|
struct C
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
A a;
|
||||||
|
};
|
||||||
|
C();
|
||||||
|
C(const C&);
|
||||||
|
~C();
|
||||||
|
};
|
||||||
|
|
||||||
|
C c;
|
||||||
|
C c2(c);
|
69
gcc/testsuite/g++.dg/cpp0x/union3.C
Normal file
69
gcc/testsuite/g++.dg/cpp0x/union3.C
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Runtime test for C++0x unrestricted unions
|
||||||
|
// { dg-options -std=c++0x }
|
||||||
|
// { dg-do run }
|
||||||
|
|
||||||
|
int c, d;
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
A(): i(1) { ++c; }
|
||||||
|
A(const A&): i(2) { ++c; }
|
||||||
|
~A() { ++d; }
|
||||||
|
};
|
||||||
|
|
||||||
|
union B
|
||||||
|
{
|
||||||
|
A a;
|
||||||
|
B() { }
|
||||||
|
B(const B& b) { }
|
||||||
|
~B() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct C
|
||||||
|
{
|
||||||
|
union { A a; };
|
||||||
|
C() { }
|
||||||
|
C(const C&) { }
|
||||||
|
~C() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
union D
|
||||||
|
{
|
||||||
|
A a;
|
||||||
|
D(): a() { }
|
||||||
|
D(const D& d): a(d.a) { }
|
||||||
|
~D() { a.~A(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct E
|
||||||
|
{
|
||||||
|
union { A a; };
|
||||||
|
E(): a() { }
|
||||||
|
E(const E& e): a (e.a) { }
|
||||||
|
~E() { a.~A(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
B b1;
|
||||||
|
B b2(b1);
|
||||||
|
|
||||||
|
C c1;
|
||||||
|
C c2(c1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c != 0 || d != 0)
|
||||||
|
return c+d*10;
|
||||||
|
|
||||||
|
{
|
||||||
|
D d1;
|
||||||
|
D d2(d1);
|
||||||
|
|
||||||
|
E e1;
|
||||||
|
E e2(e1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c != 4 || d != 4)
|
||||||
|
return c*100+d*1000;
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
// { dg-do assemble }
|
// { dg-do assemble }
|
||||||
|
// { dg-prune-output "note" }
|
||||||
|
|
||||||
// g++ 1.36.1 bug 900121_02
|
// g++ 1.36.1 bug 900121_02
|
||||||
|
|
||||||
// Assignment of structs is defined as memberwise assignment,
|
// Assignment of structs is defined as memberwise assignment,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// { dg-do assemble }
|
// { dg-do assemble }
|
||||||
// { dg-options "" }
|
// { dg-options "" }
|
||||||
|
// { dg-prune-output "note" }
|
||||||
|
|
||||||
struct S
|
struct S
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
// { dg-do assemble }
|
// { dg-do assemble }
|
||||||
|
// { dg-prune-output "note" }
|
||||||
|
|
||||||
// GROUPS uncaught
|
// GROUPS uncaught
|
||||||
// Cfront bug A.4 (See Language System Release Notes for the
|
// Cfront bug A.4 (See Language System Release Notes for the
|
||||||
// SPARCompiler C++ version 3.0)
|
// SPARCompiler C++ version 3.0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user