aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2010-05-12 13:34:38 -0400
committerJason Merrill <jason@gcc.gnu.org>2010-05-12 13:34:38 -0400
commitd451d5b28fe184ef45c1275a544c91937b790bd8 (patch)
tree349a445b9584ca18552e20bbb78d6abc89307290 /gcc
parent404f08f8d52a28a0590e858c339c68ca7f78ccfd (diff)
downloadgcc-d451d5b28fe184ef45c1275a544c91937b790bd8.zip
gcc-d451d5b28fe184ef45c1275a544c91937b790bd8.tar.gz
gcc-d451d5b28fe184ef45c1275a544c91937b790bd8.tar.bz2
cp-tree.h (LOOKUP_LIST_ONLY): New.
* cp-tree.h (LOOKUP_LIST_ONLY): New. * call.c (add_candidates): Enforce it. (build_new_method_call): Try non-list ctor if no viable list ctor. (build_user_type_conversion_1): Likewise. From-SVN: r159334
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/call.c96
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/testsuite/ChangeLog2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist32.C21
5 files changed, 102 insertions, 24 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3872df2..97dcc8d 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,10 @@
2010-05-12 Jason Merrill <jason@redhat.com>
+ * cp-tree.h (LOOKUP_LIST_ONLY): New.
+ * call.c (add_candidates): Enforce it.
+ (build_new_method_call): Try non-list ctor if no viable list ctor.
+ (build_user_type_conversion_1): Likewise.
+
* call.c (add_candidates): Distinguish between type(x) and
x.operator type().
(convert_class_to_reference): Set LOOKUP_NO_CONVERSION.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 204a6bb..c618b29 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -2860,6 +2860,7 @@ 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);
@@ -2868,28 +2869,44 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
/* 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))
- args = make_tree_vector_single (expr);
+ ctorflags |= LOOKUP_LIST_ONLY;
else
- {
- args = ctor_to_vec (expr);
- /* 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;
- }
+ try_single_arg = false;
}
- else
- args = make_tree_vector_single (expr);
/* 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)));
- add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false,
- TYPE_BINFO (totype), TYPE_BINFO (totype),
- ctorflags, &candidates);
+ /* If EXPR is not an initializer-list, or if totype has a list
+ constructor, try EXPR as a single argument. */
+ if (try_single_arg)
+ {
+ 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);
+ }
+
+ /* 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);
+ /* 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,
+ TYPE_BINFO (totype), TYPE_BINFO (totype),
+ ctorflags, &candidates);
+ }
for (cand = candidates; cand; cand = cand->next)
{
@@ -4009,6 +4026,7 @@ add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
{
tree ctype;
const VEC(tree,gc) *non_static_args;
+ bool check_list_ctor;
bool check_converting;
unification_kind_t strict;
tree fn;
@@ -4020,6 +4038,7 @@ add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
fn = OVL_CURRENT (fns);
if (DECL_CONV_FN_P (fn))
{
+ check_list_ctor = false;
check_converting = !!(flags & LOOKUP_ONLYCONVERTING);
if (flags & LOOKUP_NO_CONVERSION)
/* We're doing return_type(x). */
@@ -4036,9 +4055,15 @@ add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
else
{
if (DECL_CONSTRUCTOR_P (fn))
- check_converting = !!(flags & LOOKUP_ONLYCONVERTING);
+ {
+ check_list_ctor = !!(flags & LOOKUP_LIST_ONLY);
+ check_converting = !!(flags & LOOKUP_ONLYCONVERTING);
+ }
else
- check_converting = false;
+ {
+ check_list_ctor = false;
+ check_converting = false;
+ }
strict = DEDUCE_CALL;
ctype = conversion_path ? BINFO_TYPE (conversion_path) : NULL_TREE;
}
@@ -4058,6 +4083,8 @@ add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
if (check_converting && DECL_NONCONVERTING_P (fn))
continue;
+ if (check_list_ctor && !is_list_ctor (fn))
+ continue;
/* Figure out which set of arguments to use. */
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
@@ -6188,6 +6215,8 @@ 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);
@@ -6300,15 +6329,20 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
name = complete_dtor_identifier;
/* If CONSTRUCTOR_IS_DIRECT_INIT is set, this was a T{ } form
- initializer, not T({ }). If the type doesn't have a list ctor,
- break apart the list into separate ctor args. */
+ 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;
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))
- && !TYPE_HAS_LIST_CTOR (basetype))
+ && CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0)))
{
gcc_assert (VEC_length (tree, *args) == 1);
- *args = ctor_to_vec (VEC_index (tree, *args, 0));
+ list = VEC_index (tree, *args, 0);
+
+ if (TYPE_HAS_LIST_CTOR (basetype))
+ flags |= LOOKUP_LIST_ONLY;
+ else
+ try_normal = false;
}
first_mem_arg = instance_ptr;
@@ -6316,11 +6350,25 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
/* Get the high-water mark for the CONVERSION_OBSTACK. */
p = conversion_obstack_alloc (0);
- add_candidates (fns, first_mem_arg, args ? *args : NULL, optype,
- explicit_targs, template_only, conversion_path,
- access_binfo, flags, &candidates);
+ any_viable_p = false;
+ if (try_normal)
+ {
+ 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);
+ }
- candidates = splice_viable (candidates, pedantic, &any_viable_p);
if (!any_viable_p)
{
if (complain & tf_error)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index df961e0..6b35fb9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4137,6 +4137,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
#define LOOKUP_NO_COPY_CTOR_CONVERSION (LOOKUP_NO_NARROWING << 1)
/* This is the first parameter of a copy constructor. */
#define LOOKUP_COPY_PARM (LOOKUP_NO_COPY_CTOR_CONVERSION << 1)
+/* We only want to consider list constructors. */
+#define LOOKUP_LIST_ONLY (LOOKUP_COPY_PARM << 1)
#define LOOKUP_NAMESPACES_ONLY(F) \
(((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index a431f8a..f0f5c23 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,7 @@
2010-05-12 Jason Merrill <jason@redhat.com>
+ * g++.dg/cpp0x/initlist32.C: New.
+
* g++.dg/template/conv11.C: New.
* g++.dg/conversion/op1.C: Adjust expected error.
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist32.C b/gcc/testsuite/g++.dg/cpp0x/initlist32.C
new file mode 100644
index 0000000..78bbb5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist32.C
@@ -0,0 +1,21 @@
+// Test that we try normal init if no list ctor is viable.
+// { dg-options "-std=c++0x" }
+
+#include <initializer_list>
+
+struct B {};
+
+struct C
+{
+ C(B);
+};
+
+struct A
+{
+ A(std::initializer_list<int>);
+ A(B) { }
+ A(C);
+};
+
+B b;
+A a{b};