Commit 4c9b3895 by Jason Merrill Committed by Jason Merrill

DR 990

	DR 990
	* call.c (add_list_candidates): Prefer the default constructor.
	(build_aggr_conv): Treat missing initializers like { }.
	* typeck2.c (process_init_constructor_record): Likewise.
	* init.c (expand_default_init): Use digest_init for
	direct aggregate initialization, too.

	* call.c (add_list_candidates): Split out...
	(build_user_type_conversion_1): ...from here.
	(build_new_method_call): And here.
	(implicit_conversion): Propagate LOOKUP_NO_NARROWING.

From-SVN: r160132
parent e5901560
2010-06-01 Jason Merrill <jason@redhat.com> 2010-06-01 Jason Merrill <jason@redhat.com>
DR 990
* call.c (add_list_candidates): Prefer the default constructor.
(build_aggr_conv): Treat missing initializers like { }.
* typeck2.c (process_init_constructor_record): Likewise.
* init.c (expand_default_init): Use digest_init for
direct aggregate initialization, too.
* call.c (add_list_candidates): Split out...
(build_user_type_conversion_1): ...from here.
(build_new_method_call): And here.
(implicit_conversion): Propagate LOOKUP_NO_NARROWING.
PR c++/44358 PR c++/44358
* call.c (build_list_conv): Set list-initialization flags properly. * call.c (build_list_conv): Set list-initialization flags properly.
......
...@@ -634,6 +634,7 @@ build_aggr_conv (tree type, tree ctor, int flags) ...@@ -634,6 +634,7 @@ build_aggr_conv (tree type, tree ctor, int flags)
unsigned HOST_WIDE_INT i = 0; unsigned HOST_WIDE_INT i = 0;
conversion *c; conversion *c;
tree field = next_initializable_field (TYPE_FIELDS (type)); tree field = next_initializable_field (TYPE_FIELDS (type));
tree empty_ctor = NULL_TREE;
for (; field; field = next_initializable_field (TREE_CHAIN (field))) for (; field; field = next_initializable_field (TREE_CHAIN (field)))
{ {
...@@ -647,8 +648,14 @@ build_aggr_conv (tree type, tree ctor, int flags) ...@@ -647,8 +648,14 @@ build_aggr_conv (tree type, tree ctor, int flags)
if (TREE_CODE (type) == UNION_TYPE) if (TREE_CODE (type) == UNION_TYPE)
break; break;
} }
else if (build_value_init (TREE_TYPE (field)) == error_mark_node) else
return NULL; {
if (empty_ctor == NULL_TREE)
empty_ctor = build_constructor (init_list_type_node, NULL);
if (!can_convert_arg (TREE_TYPE (field), TREE_TYPE (empty_ctor),
empty_ctor, flags))
return NULL;
}
} }
if (i < CONSTRUCTOR_NELTS (ctor)) if (i < CONSTRUCTOR_NELTS (ctor))
...@@ -1461,7 +1468,8 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p, ...@@ -1461,7 +1468,8 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
&& (flags & LOOKUP_NO_CONVERSION) == 0) && (flags & LOOKUP_NO_CONVERSION) == 0)
{ {
struct z_candidate *cand; struct z_candidate *cand;
int convflags = (flags & (LOOKUP_NO_TEMP_BIND|LOOKUP_ONLYCONVERTING)); int convflags = (flags & (LOOKUP_NO_TEMP_BIND|LOOKUP_ONLYCONVERTING
|LOOKUP_NO_NARROWING));
if (CLASS_TYPE_P (to) if (CLASS_TYPE_P (to)
&& !CLASSTYPE_NON_AGGREGATE (complete_type (to)) && !CLASSTYPE_NON_AGGREGATE (complete_type (to))
...@@ -2813,6 +2821,65 @@ merge_conversion_sequences (conversion *user_seq, conversion *std_seq) ...@@ -2813,6 +2821,65 @@ merge_conversion_sequences (conversion *user_seq, conversion *std_seq)
return std_seq; return std_seq;
} }
/* Handle overload resolution for initializing an object of class type from
an initializer list. First we look for a suitable constructor that
takes a std::initializer_list; if we don't find one, we then look for a
non-list constructor.
Parameters are as for add_candidates, except that the arguments are in
the form of a CONSTRUCTOR (the initializer list) rather than a VEC, and
the RETURN_TYPE parameter is replaced by TOTYPE, the desired type. */
static void
add_list_candidates (tree fns, tree first_arg,
tree init_list, tree totype,
tree explicit_targs, bool template_only,
tree conversion_path, tree access_path,
int flags,
struct z_candidate **candidates)
{
VEC(tree,gc) *args;
gcc_assert (*candidates == NULL);
/* For list-initialization we consider explicit constructors, but
give an error if one is selected. */
flags &= ~LOOKUP_ONLYCONVERTING;
/* And we don't allow narrowing conversions. We also use this flag to
avoid the copy constructor call for copy-list-initialization. */
flags |= LOOKUP_NO_NARROWING;
/* Always use the default constructor if the list is empty (DR 990). */
if (CONSTRUCTOR_NELTS (init_list) == 0
&& TYPE_HAS_DEFAULT_CONSTRUCTOR (totype))
;
/* If the class has a list ctor, try passing the list as a single
argument first, but only consider list ctors. */
else if (TYPE_HAS_LIST_CTOR (totype))
{
flags |= LOOKUP_LIST_ONLY;
args = make_tree_vector_single (init_list);
add_candidates (fns, first_arg, args, NULL_TREE,
explicit_targs, template_only, conversion_path,
access_path, flags, candidates);
if (any_strictly_viable (*candidates))
return;
}
args = ctor_to_vec (init_list);
/* We aren't looking for list-ctors anymore. */
flags &= ~LOOKUP_LIST_ONLY;
/* We allow more user-defined conversions within an init-list. */
flags &= ~LOOKUP_NO_CONVERSION;
/* But not for the copy ctor. */
flags |= LOOKUP_NO_COPY_CTOR_CONVERSION;
add_candidates (fns, first_arg, args, NULL_TREE,
explicit_targs, template_only, conversion_path,
access_path, flags, candidates);
}
/* Returns the best overload candidate to perform the requested /* Returns the best overload candidate to perform the requested
conversion. This function is used for three the overloading situations conversion. This function is used for three the overloading situations
described in [over.match.copy], [over.match.conv], and [over.match.ref]. described in [over.match.copy], [over.match.conv], and [over.match.ref].
...@@ -2872,49 +2939,25 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) ...@@ -2872,49 +2939,25 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
if (ctors) if (ctors)
{ {
int ctorflags = flags; int ctorflags = flags;
bool try_single_arg = true;
ctors = BASELINK_FUNCTIONS (ctors); ctors = BASELINK_FUNCTIONS (ctors);
first_arg = build_int_cst (build_pointer_type (totype), 0); first_arg = build_int_cst (build_pointer_type (totype), 0);
if (BRACE_ENCLOSED_INITIALIZER_P (expr))
{
/* For list-initialization we consider explicit constructors, but
give an error if one is selected. */
ctorflags &= ~LOOKUP_ONLYCONVERTING;
/* If the class has a list ctor, try passing the list as a single
argument first, but only consider list ctors. */
if (TYPE_HAS_LIST_CTOR (totype))
ctorflags |= LOOKUP_LIST_ONLY;
else
try_single_arg = false;
}
/* We should never try to call the abstract or base constructor /* We should never try to call the abstract or base constructor
from here. */ from here. */
gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (OVL_CURRENT (ctors)) gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (OVL_CURRENT (ctors))
&& !DECL_HAS_VTT_PARM_P (OVL_CURRENT (ctors))); && !DECL_HAS_VTT_PARM_P (OVL_CURRENT (ctors)));
/* If EXPR is not an initializer-list, or if totype has a list if (BRACE_ENCLOSED_INITIALIZER_P (expr))
constructor, try EXPR as a single argument. */
if (try_single_arg)
{ {
args = make_tree_vector_single (expr); /* List-initialization. */
add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false, add_list_candidates (ctors, first_arg, expr, totype, NULL_TREE,
TYPE_BINFO (totype), TYPE_BINFO (totype), false, TYPE_BINFO (totype), TYPE_BINFO (totype),
ctorflags, &candidates); ctorflags, &candidates);
} }
else
/* If we didn't find a suitable list constructor for an initializer-list,
try breaking it apart. */
if (!candidates && BRACE_ENCLOSED_INITIALIZER_P (expr))
{ {
args = ctor_to_vec (expr); args = make_tree_vector_single (expr);
/* We aren't looking for list-ctors anymore. */
ctorflags &= ~LOOKUP_LIST_ONLY;
/* We still allow more conversions within an init-list. */
ctorflags &= ~LOOKUP_NO_CONVERSION;
/* But not for the copy ctor. */
ctorflags |= LOOKUP_NO_COPY_CTOR_CONVERSION;
add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false, add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false,
TYPE_BINFO (totype), TYPE_BINFO (totype), TYPE_BINFO (totype), TYPE_BINFO (totype),
ctorflags, &candidates); ctorflags, &candidates);
...@@ -6233,8 +6276,6 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args, ...@@ -6233,8 +6276,6 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
tree orig_fns; tree orig_fns;
VEC(tree,gc) *orig_args = NULL; VEC(tree,gc) *orig_args = NULL;
void *p; void *p;
tree list = NULL_TREE;
bool try_normal;
gcc_assert (instance != NULL_TREE); gcc_assert (instance != NULL_TREE);
...@@ -6346,47 +6387,32 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args, ...@@ -6346,47 +6387,32 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
if (DECL_DESTRUCTOR_P (fn)) if (DECL_DESTRUCTOR_P (fn))
name = complete_dtor_identifier; name = complete_dtor_identifier;
first_mem_arg = instance_ptr;
/* Get the high-water mark for the CONVERSION_OBSTACK. */
p = conversion_obstack_alloc (0);
/* If CONSTRUCTOR_IS_DIRECT_INIT is set, this was a T{ } form /* If CONSTRUCTOR_IS_DIRECT_INIT is set, this was a T{ } form
initializer, not T({ }). If the type doesn't have a list ctor (or no initializer, not T({ }). */
viable list ctor), break apart the list into separate ctor args. */
try_normal = true;
if (DECL_CONSTRUCTOR_P (fn) && args != NULL && !VEC_empty (tree, *args) if (DECL_CONSTRUCTOR_P (fn) && args != NULL && !VEC_empty (tree, *args)
&& BRACE_ENCLOSED_INITIALIZER_P (VEC_index (tree, *args, 0)) && BRACE_ENCLOSED_INITIALIZER_P (VEC_index (tree, *args, 0))
&& CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0))) && CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0)))
{ {
gcc_assert (VEC_length (tree, *args) == 1 gcc_assert (VEC_length (tree, *args) == 1
&& !(flags & LOOKUP_ONLYCONVERTING)); && !(flags & LOOKUP_ONLYCONVERTING));
list = VEC_index (tree, *args, 0);
if (TYPE_HAS_LIST_CTOR (basetype)) add_list_candidates (fns, first_mem_arg, VEC_index (tree, *args, 0),
flags |= LOOKUP_LIST_ONLY; basetype, explicit_targs, template_only,
else conversion_path, access_binfo, flags, &candidates);
try_normal = false;
} }
else
first_mem_arg = instance_ptr;
/* Get the high-water mark for the CONVERSION_OBSTACK. */
p = conversion_obstack_alloc (0);
any_viable_p = false;
if (try_normal)
{ {
add_candidates (fns, first_mem_arg, user_args, optype, add_candidates (fns, first_mem_arg, user_args, optype,
explicit_targs, template_only, conversion_path, explicit_targs, template_only, conversion_path,
access_binfo, flags, &candidates); access_binfo, flags, &candidates);
candidates = splice_viable (candidates, pedantic, &any_viable_p);
}
if (!any_viable_p && list)
{
VEC(tree,gc) *list_args = ctor_to_vec (list);
flags &= ~LOOKUP_LIST_ONLY;
add_candidates (fns, first_mem_arg, list_args, optype,
explicit_targs, template_only, conversion_path,
access_binfo, flags, &candidates);
candidates = splice_viable (candidates, pedantic, &any_viable_p);
} }
any_viable_p = false;
candidates = splice_viable (candidates, pedantic, &any_viable_p);
if (!any_viable_p) if (!any_viable_p)
{ {
......
...@@ -1308,6 +1308,18 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, ...@@ -1308,6 +1308,18 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
tree rval; tree rval;
VEC(tree,gc) *parms; VEC(tree,gc) *parms;
if (init && BRACE_ENCLOSED_INITIALIZER_P (init)
&& CP_AGGREGATE_TYPE_P (type))
{
/* A brace-enclosed initializer for an aggregate. In C++0x this can
happen for direct-initialization, too. */
init = digest_init (type, init);
init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init);
TREE_SIDE_EFFECTS (init) = 1;
finish_expr_stmt (init);
return;
}
if (init && TREE_CODE (init) != TREE_LIST if (init && TREE_CODE (init) != TREE_LIST
&& (flags & LOOKUP_ONLYCONVERTING)) && (flags & LOOKUP_ONLYCONVERTING))
{ {
...@@ -1320,12 +1332,6 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, ...@@ -1320,12 +1332,6 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
to run a new constructor; and catching an exception, where we to run a new constructor; and catching an exception, where we
have already built up the constructor call so we could wrap it have already built up the constructor call so we could wrap it
in an exception region. */; in an exception region. */;
else if (BRACE_ENCLOSED_INITIALIZER_P (init)
&& CP_AGGREGATE_TYPE_P (type))
{
/* A brace-enclosed initializer for an aggregate. */
init = digest_init (type, init);
}
else else
init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags); init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
......
...@@ -1165,17 +1165,15 @@ process_init_constructor_record (tree type, tree init) ...@@ -1165,17 +1165,15 @@ process_init_constructor_record (tree type, tree init)
default-initialization, we can't rely on the back end to do it default-initialization, we can't rely on the back end to do it
for us, so build up TARGET_EXPRs. If the type in question is for us, so build up TARGET_EXPRs. If the type in question is
a class, just build one up; if it's an array, recurse. */ a class, just build one up; if it's an array, recurse. */
next = build_constructor (init_list_type_node, NULL);
if (MAYBE_CLASS_TYPE_P (TREE_TYPE (field))) if (MAYBE_CLASS_TYPE_P (TREE_TYPE (field)))
{ {
next = build_functional_cast (TREE_TYPE (field), NULL_TREE, next = finish_compound_literal (TREE_TYPE (field), next);
tf_warning_or_error);
/* direct-initialize the target. No temporary is going /* direct-initialize the target. No temporary is going
to be involved. */ to be involved. */
if (TREE_CODE (next) == TARGET_EXPR) if (TREE_CODE (next) == TARGET_EXPR)
TARGET_EXPR_DIRECT_INIT_P (next) = true; TARGET_EXPR_DIRECT_INIT_P (next) = true;
} }
else
next = build_constructor (init_list_type_node, NULL);
next = digest_init_r (TREE_TYPE (field), next, true, LOOKUP_IMPLICIT); next = digest_init_r (TREE_TYPE (field), next, true, LOOKUP_IMPLICIT);
......
2010-06-01 Jason Merrill <jason@redhat.com> 2010-06-01 Jason Merrill <jason@redhat.com>
DR 990
* g++.dg/cpp0x/initlist37.C: New.
* g++.dg/cpp0x/initlist38.C: New.
PR c++/44358 PR c++/44358
* g++.dg/cpp0x/initlist36.C: New. * g++.dg/cpp0x/initlist36.C: New.
......
...@@ -18,4 +18,6 @@ int main() ...@@ -18,4 +18,6 @@ int main()
{ {
B b0 = {{1}}; B b0 = {{1}};
B b1 = {{1.0}}; // { dg-error "narrowing" } B b1 = {{1.0}}; // { dg-error "narrowing" }
B b2 {1.0}; // { dg-error "narrowing" }
A a {1.0}; // { dg-error "narrowing" }
} }
// DR 990
// { dg-options "-std=c++0x" }
#include <initializer_list>
struct S {
S(std::initializer_list<double>); // #1
S(std::initializer_list<int>); // #2
S(); // #3
// ...
};
S s1 = { 1.0, 2.0, 3.0 }; // invoke #1
S s2 = { 1, 2, 3 }; // invoke #2
S s3 = { }; // invoke #3 (for value-initialization)
// Test some other situations, too.
void f (S);
int main()
{
S s4 { };
f({ });
S {};
}
// DR 990
// { dg-options "-std=c++0x" }
#include <initializer_list>
struct A {
A(std::initializer_list<int>); // #1
};
struct B {
A a;
};
void f (B);
int main()
{
B{};
f({});
B b0 = { };
B b1 { }; // OK, uses #1
B b2 { 1 }; // { dg-error "conversion" }
}
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