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>
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
* call.c (build_list_conv): Set list-initialization flags properly.
......
......@@ -634,6 +634,7 @@ build_aggr_conv (tree type, tree ctor, int flags)
unsigned HOST_WIDE_INT i = 0;
conversion *c;
tree field = next_initializable_field (TYPE_FIELDS (type));
tree empty_ctor = NULL_TREE;
for (; field; field = next_initializable_field (TREE_CHAIN (field)))
{
......@@ -647,8 +648,14 @@ build_aggr_conv (tree type, tree ctor, int flags)
if (TREE_CODE (type) == UNION_TYPE)
break;
}
else if (build_value_init (TREE_TYPE (field)) == error_mark_node)
return NULL;
else
{
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))
......@@ -1461,7 +1468,8 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
&& (flags & LOOKUP_NO_CONVERSION) == 0)
{
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)
&& !CLASSTYPE_NON_AGGREGATE (complete_type (to))
......@@ -2813,6 +2821,65 @@ merge_conversion_sequences (conversion *user_seq, conversion *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
conversion. This function is used for three the overloading situations
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)
if (ctors)
{
int ctorflags = flags;
bool try_single_arg = true;
ctors = BASELINK_FUNCTIONS (ctors);
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
from here. */
gcc_assert (!DECL_HAS_IN_CHARGE_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
constructor, try EXPR as a single argument. */
if (try_single_arg)
if (BRACE_ENCLOSED_INITIALIZER_P (expr))
{
args = make_tree_vector_single (expr);
add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false,
TYPE_BINFO (totype), TYPE_BINFO (totype),
ctorflags, &candidates);
/* List-initialization. */
add_list_candidates (ctors, first_arg, expr, totype, NULL_TREE,
false, TYPE_BINFO (totype), TYPE_BINFO (totype),
ctorflags, &candidates);
}
/* If we didn't find a suitable list constructor for an initializer-list,
try breaking it apart. */
if (!candidates && BRACE_ENCLOSED_INITIALIZER_P (expr))
else
{
args = ctor_to_vec (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;
args = make_tree_vector_single (expr);
add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false,
TYPE_BINFO (totype), TYPE_BINFO (totype),
ctorflags, &candidates);
......@@ -6233,8 +6276,6 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
tree orig_fns;
VEC(tree,gc) *orig_args = NULL;
void *p;
tree list = NULL_TREE;
bool try_normal;
gcc_assert (instance != NULL_TREE);
......@@ -6346,47 +6387,32 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
if (DECL_DESTRUCTOR_P (fn))
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
initializer, not T({ }). If the type doesn't have a list ctor (or no
viable list ctor), break apart the list into separate ctor args. */
try_normal = true;
initializer, not T({ }). */
if (DECL_CONSTRUCTOR_P (fn) && args != NULL && !VEC_empty (tree, *args)
&& BRACE_ENCLOSED_INITIALIZER_P (VEC_index (tree, *args, 0))
&& CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0)))
{
gcc_assert (VEC_length (tree, *args) == 1
&& !(flags & LOOKUP_ONLYCONVERTING));
list = VEC_index (tree, *args, 0);
if (TYPE_HAS_LIST_CTOR (basetype))
flags |= LOOKUP_LIST_ONLY;
else
try_normal = false;
add_list_candidates (fns, first_mem_arg, VEC_index (tree, *args, 0),
basetype, explicit_targs, template_only,
conversion_path, access_binfo, flags, &candidates);
}
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)
else
{
add_candidates (fns, first_mem_arg, user_args, optype,
explicit_targs, template_only, conversion_path,
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)
{
......
......@@ -1308,6 +1308,18 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
tree rval;
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
&& (flags & LOOKUP_ONLYCONVERTING))
{
......@@ -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
have already built up the constructor call so we could wrap it
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
init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
......
......@@ -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
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. */
next = build_constructor (init_list_type_node, NULL);
if (MAYBE_CLASS_TYPE_P (TREE_TYPE (field)))
{
next = build_functional_cast (TREE_TYPE (field), NULL_TREE,
tf_warning_or_error);
next = finish_compound_literal (TREE_TYPE (field), next);
/* direct-initialize the target. No temporary is going
to be involved. */
if (TREE_CODE (next) == TARGET_EXPR)
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);
......
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
* g++.dg/cpp0x/initlist36.C: New.
......
......@@ -18,4 +18,6 @@ int main()
{
B b0 = {{1}};
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