Commit 45ffb6f7 by Jason Merrill Committed by Jason Merrill

DR 1402

	DR 1402
	* method.c (synthesized_method_walk): Replace uses of msg with diag.
	Correct handling of virtual bases with move operations.
	(process_subob_fn, walk_field_subobs): Replace uses of msg with diag.

From-SVN: r189426
parent 6bdf3519
2012-07-11 Jason Merrill <jason@redhat.com>
DR 1402
* method.c (synthesized_method_walk): Replace uses of msg with diag.
Correct handling of virtual bases with move operations.
(process_subob_fn, walk_field_subobs): Replace uses of msg with diag.
2012-07-11 Steven Bosscher <steven@gcc.gnu.org> 2012-07-11 Steven Bosscher <steven@gcc.gnu.org>
* method.c: Do not include tree-pass.h. * method.c: Do not include tree-pass.h.
......
...@@ -922,7 +922,7 @@ get_copy_assign (tree type) ...@@ -922,7 +922,7 @@ get_copy_assign (tree type)
static void static void
process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
bool *deleted_p, bool *constexpr_p, bool *no_implicit_p, bool *deleted_p, bool *constexpr_p, bool *no_implicit_p,
const char *msg, tree arg) bool diag, tree arg)
{ {
if (!fn || fn == error_mark_node) if (!fn || fn == error_mark_node)
goto bad; goto bad;
...@@ -942,7 +942,7 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, ...@@ -942,7 +942,7 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
{ {
if (deleted_p) if (deleted_p)
*deleted_p = true; *deleted_p = true;
if (msg) if (diag)
error ("union member %q+D with non-trivial %qD", arg, fn); error ("union member %q+D with non-trivial %qD", arg, fn);
} }
} }
...@@ -955,7 +955,7 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, ...@@ -955,7 +955,7 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn)) if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn))
{ {
*constexpr_p = false; *constexpr_p = false;
if (msg) if (diag)
{ {
inform (0, "defaulted constructor calls non-constexpr " inform (0, "defaulted constructor calls non-constexpr "
"%q+D", fn); "%q+D", fn);
...@@ -978,7 +978,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -978,7 +978,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
int quals, bool copy_arg_p, bool move_p, int quals, bool copy_arg_p, bool move_p,
bool assign_p, tree *spec_p, bool *trivial_p, bool assign_p, tree *spec_p, bool *trivial_p,
bool *deleted_p, bool *constexpr_p, bool *no_implicit_p, bool *deleted_p, bool *constexpr_p, bool *no_implicit_p,
const char *msg, int flags, tsubst_flags_t complain) bool diag, int flags, tsubst_flags_t complain)
{ {
tree field; tree field;
for (field = fields; field; field = DECL_CHAIN (field)) for (field = fields; field; field = DECL_CHAIN (field))
...@@ -995,13 +995,13 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -995,13 +995,13 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
bool bad = true; bool bad = true;
if (CP_TYPE_CONST_P (mem_type) && !CLASS_TYPE_P (mem_type)) if (CP_TYPE_CONST_P (mem_type) && !CLASS_TYPE_P (mem_type))
{ {
if (msg) if (diag)
error ("non-static const member %q#D, can%'t use default " error ("non-static const member %q#D, can%'t use default "
"assignment operator", field); "assignment operator", field);
} }
else if (TREE_CODE (mem_type) == REFERENCE_TYPE) else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
{ {
if (msg) if (diag)
error ("non-static reference member %q#D, can%'t use " error ("non-static reference member %q#D, can%'t use "
"default assignment operator", field); "default assignment operator", field);
} }
...@@ -1017,7 +1017,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -1017,7 +1017,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
if (DECL_INITIAL (field)) if (DECL_INITIAL (field))
{ {
if (msg && DECL_INITIAL (field) == error_mark_node) if (diag && DECL_INITIAL (field) == error_mark_node)
inform (0, "initializer for %q+#D is invalid", field); inform (0, "initializer for %q+#D is invalid", field);
if (trivial_p) if (trivial_p)
*trivial_p = false; *trivial_p = false;
...@@ -1040,14 +1040,14 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -1040,14 +1040,14 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
if (CP_TYPE_CONST_P (mem_type) if (CP_TYPE_CONST_P (mem_type)
&& default_init_uninitialized_part (mem_type)) && default_init_uninitialized_part (mem_type))
{ {
if (msg) if (diag)
error ("uninitialized non-static const member %q#D", error ("uninitialized non-static const member %q#D",
field); field);
bad = true; bad = true;
} }
else if (TREE_CODE (mem_type) == REFERENCE_TYPE) else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
{ {
if (msg) if (diag)
error ("uninitialized non-static reference member %q#D", error ("uninitialized non-static reference member %q#D",
field); field);
bad = true; bad = true;
...@@ -1063,7 +1063,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -1063,7 +1063,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
&& TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE) && TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE)
{ {
*constexpr_p = false; *constexpr_p = false;
if (msg) if (diag)
inform (0, "defaulted default constructor does not " inform (0, "defaulted default constructor does not "
"initialize %q+#D", field); "initialize %q+#D", field);
} }
...@@ -1077,7 +1077,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -1077,7 +1077,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
walk_field_subobs (TYPE_FIELDS (mem_type), fnname, sfk, quals, walk_field_subobs (TYPE_FIELDS (mem_type), fnname, sfk, quals,
copy_arg_p, move_p, assign_p, spec_p, trivial_p, copy_arg_p, move_p, assign_p, spec_p, trivial_p,
deleted_p, constexpr_p, no_implicit_p, deleted_p, constexpr_p, no_implicit_p,
msg, flags, complain); diag, flags, complain);
continue; continue;
} }
...@@ -1094,7 +1094,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -1094,7 +1094,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain); rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
constexpr_p, no_implicit_p, msg, field); constexpr_p, no_implicit_p, diag, field);
} }
} }
...@@ -1115,7 +1115,6 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, ...@@ -1115,7 +1115,6 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
VEC(tree,gc) *vbases; VEC(tree,gc) *vbases;
int i, quals, flags; int i, quals, flags;
tsubst_flags_t complain; tsubst_flags_t complain;
const char *msg;
bool ctor_p; bool ctor_p;
if (spec_p) if (spec_p)
...@@ -1239,25 +1238,21 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, ...@@ -1239,25 +1238,21 @@ 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)
{ {
tree basetype = BINFO_TYPE (base_binfo); tree basetype = BINFO_TYPE (base_binfo);
if (!assign_p && BINFO_VIRTUAL_P (base_binfo))
/* We'll handle virtual bases below. */
continue;
if (copy_arg_p) if (copy_arg_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);
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
constexpr_p, no_implicit_p, msg, basetype); constexpr_p, no_implicit_p, diag, basetype);
if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
{ {
/* In a constructor we also need to check the subobject /* In a constructor we also need to check the subobject
...@@ -1270,7 +1265,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, ...@@ -1270,7 +1265,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
throw) or exception-specification (a throw from one of the throw) or exception-specification (a throw from one of the
dtors would be a double-fault). */ dtors would be a double-fault). */
process_subob_fn (rval, false, NULL, NULL, process_subob_fn (rval, false, NULL, NULL,
deleted_p, NULL, NULL, NULL, deleted_p, NULL, NULL, false,
basetype); basetype);
} }
...@@ -1287,21 +1282,31 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, ...@@ -1287,21 +1282,31 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
} }
vbases = CLASSTYPE_VBASECLASSES (ctype); vbases = CLASSTYPE_VBASECLASSES (ctype);
if (vbases && assign_p && move_p) if (vbases == NULL)
/* No virtual bases to worry about. */;
else if (assign_p && move_p && no_implicit_p)
{ {
/* Don't implicitly declare a defaulted move assignment if a virtual
base has non-trivial move assignment, since moving the same base
more than once is dangerous. */
/* Should the spec be changed to allow vbases that only occur once? */ /* Should the spec be changed to allow vbases that only occur once? */
if (diag) FOR_EACH_VEC_ELT (tree, vbases, i, base_binfo)
error ("%qT has virtual bases, default move assignment operator " {
"cannot be generated", ctype); tree basetype = BINFO_TYPE (base_binfo);
else if (deleted_p) if (copy_arg_p)
*deleted_p = true; argtype = build_stub_type (basetype, quals, move_p);
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
if (rval && rval != error_mark_node
&& move_fn_p (rval) && !trivial_fn_p (rval))
{
*no_implicit_p = true;
break;
}
}
} }
else if (!assign_p) else if (!assign_p)
{ {
if (diag) if (constexpr_p)
msg = ("virtual base %qT does not have a move constructor "
"or trivial copy constructor");
if (vbases && constexpr_p)
*constexpr_p = false; *constexpr_p = false;
FOR_EACH_VEC_ELT (tree, vbases, i, base_binfo) FOR_EACH_VEC_ELT (tree, vbases, i, base_binfo)
{ {
...@@ -1311,35 +1316,29 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, ...@@ -1311,35 +1316,29 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
constexpr_p, no_implicit_p, msg, basetype); constexpr_p, no_implicit_p, diag, basetype);
if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
{ {
rval = locate_fn_flags (base_binfo, complete_dtor_identifier, rval = locate_fn_flags (base_binfo, complete_dtor_identifier,
NULL_TREE, flags, complain); NULL_TREE, flags, complain);
process_subob_fn (rval, false, NULL, NULL, process_subob_fn (rval, false, NULL, NULL,
deleted_p, NULL, NULL, NULL, deleted_p, NULL, NULL, false,
basetype); basetype);
} }
} }
} }
if (!diag)
/* Leave msg null. */; /* Now handle the non-static data members. */
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, walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals,
copy_arg_p, move_p, assign_p, spec_p, trivial_p, copy_arg_p, move_p, assign_p, spec_p, trivial_p,
deleted_p, constexpr_p, no_implicit_p, deleted_p, constexpr_p, no_implicit_p,
msg, flags, complain); diag, flags, complain);
if (ctor_p) if (ctor_p)
walk_field_subobs (TYPE_FIELDS (ctype), complete_dtor_identifier, walk_field_subobs (TYPE_FIELDS (ctype), complete_dtor_identifier,
sfk_destructor, TYPE_UNQUALIFIED, false, sfk_destructor, TYPE_UNQUALIFIED, false,
false, false, NULL, NULL, false, false, NULL, NULL,
deleted_p, NULL, deleted_p, NULL,
NULL, NULL, flags, complain); NULL, false, flags, complain);
pop_scope (scope); pop_scope (scope);
......
2012-07-11 Jason Merrill <jason@redhat.com>
DR 1402
* g++.g/cpp0x/defaulted37.C: New.
2012-07-11 Greta Yorsh <Greta.Yorsh@arm.com> 2012-07-11 Greta Yorsh <Greta.Yorsh@arm.com>
PR target/53859 PR target/53859
......
// DR 1402
// { dg-do compile { target c++11 } }
struct A
{
int moved = 0;
A& operator=(A&&) { ++moved; }
~A() { if (moved > 1) __builtin_abort(); }
};
struct B: virtual A { B& operator=(B&&) = default; };
struct C: virtual A { }; // { dg-error "operator=.const A&" }
int main()
{
B b1, b2;
b2 = static_cast<B&&>(b1);
C c1, c2;
c2 = static_cast<C&&>(c1); // { dg-error "operator=.const C&" }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment