aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2009-05-18 17:48:02 -0400
committerJason Merrill <jason@gcc.gnu.org>2009-05-18 17:48:02 -0400
commite57d93c6bcfd50cdb3d1928d78e8fe0bb6ce517c (patch)
tree1cb5674ddf2e19bccf1158ba381c45a6b1606ef6 /gcc
parent82725547db6fba598916a16b027e06d16c5e6a57 (diff)
downloadgcc-e57d93c6bcfd50cdb3d1928d78e8fe0bb6ce517c.zip
gcc-e57d93c6bcfd50cdb3d1928d78e8fe0bb6ce517c.tar.gz
gcc-e57d93c6bcfd50cdb3d1928d78e8fe0bb6ce517c.tar.bz2
Implement explicit conversions ops as specified in N2437.
* decl.c (grokdeclarator): Handle explicit conversion ops. (check_initializer): Pass flags to store_init_value. * decl2.c (maybe_emit_vtables): Likewise. * init.c (expand_aggr_init_1): Likewise. * call.c (convert_class_to_reference): Take flags parm, check DECL_NONCONVERTING_P. (build_user_type_conversion_1): Check DECL_NONCONVERTING_P. (add_builtin_candidates): Simplify getting type of conversion. (build_object_call): Likewise. Check DECL_NONCONVERTING_P. (implicit_conversion): Pass through LOOKUP_ONLYCONVERTING. (reference_binding): Take flags parm. Direct-initialize copy parm. (add_function_candidate): Direct-initialize the copy parm. (add_conv_candidate): Use LOOKUP_IMPLICIT, not LOOKUP_NORMAL. (build_builtin_candidate): Add LOOKUP_ONLYCONVERTING. (conditional_conversion): Likewise. (convert_like_real): Only complain about DECL_NONCONVERTING_P constructors. (perform_implicit_conversion_flags): Add flags parm to perform_implicit_conversion. Improve diagnostics. * cp-tree.h (LOOKUP_IMPLICIT): New macro. (LOOKUP_COPY_PARM): New bit macro. * cvt.c (build_expr_type_conversion): Check DECL_NONCONVERTING_P. * typeck.c (convert_for_assignment): Take flags parm, pass it to perform_implicit_conversion_flags. (cp_build_modify_expr): Pass flags to convert_for_assignment. (convert_for_initialization): Likewise. * typeck2.c (store_init_value): Take flags parm, pass to digest_init_flags. (digest_init_flags): Add flags parm to digest_init. (digest_init_r): Take flags parm, pass to convert_for_initialization. (process_init_constructor_array): Pass it. (process_init_constructor_record): Likewise. (process_init_constructor_union): Likewise. From-SVN: r147677
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog37
-rw-r--r--gcc/cp/call.c79
-rw-r--r--gcc/cp/cp-tree.h14
-rw-r--r--gcc/cp/cvt.c3
-rw-r--r--gcc/cp/decl.c10
-rw-r--r--gcc/cp/decl2.c2
-rw-r--r--gcc/cp/init.c2
-rw-r--r--gcc/cp/typeck.c13
-rw-r--r--gcc/cp/typeck2.c28
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/explicit1.C58
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/explicit2.C29
12 files changed, 238 insertions, 42 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index af4b69c..813413e7 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,40 @@
+2009-05-18 Jason Merrill <jason@redhat.com>
+
+ Implement explicit conversions ops as specified in N2437.
+ * decl.c (grokdeclarator): Handle explicit conversion ops.
+ (check_initializer): Pass flags to store_init_value.
+ * decl2.c (maybe_emit_vtables): Likewise.
+ * init.c (expand_aggr_init_1): Likewise.
+ * call.c (convert_class_to_reference): Take flags parm,
+ check DECL_NONCONVERTING_P.
+ (build_user_type_conversion_1): Check DECL_NONCONVERTING_P.
+ (add_builtin_candidates): Simplify getting type of conversion.
+ (build_object_call): Likewise. Check DECL_NONCONVERTING_P.
+ (implicit_conversion): Pass through LOOKUP_ONLYCONVERTING.
+ (reference_binding): Take flags parm. Direct-initialize copy parm.
+ (add_function_candidate): Direct-initialize the copy parm.
+ (add_conv_candidate): Use LOOKUP_IMPLICIT, not LOOKUP_NORMAL.
+ (build_builtin_candidate): Add LOOKUP_ONLYCONVERTING.
+ (conditional_conversion): Likewise.
+ (convert_like_real): Only complain about DECL_NONCONVERTING_P
+ constructors.
+ (perform_implicit_conversion_flags): Add flags parm to
+ perform_implicit_conversion. Improve diagnostics.
+ * cp-tree.h (LOOKUP_IMPLICIT): New macro.
+ (LOOKUP_COPY_PARM): New bit macro.
+ * cvt.c (build_expr_type_conversion): Check DECL_NONCONVERTING_P.
+ * typeck.c (convert_for_assignment): Take flags parm, pass it to
+ perform_implicit_conversion_flags.
+ (cp_build_modify_expr): Pass flags to convert_for_assignment.
+ (convert_for_initialization): Likewise.
+ * typeck2.c (store_init_value): Take flags parm, pass to
+ digest_init_flags.
+ (digest_init_flags): Add flags parm to digest_init.
+ (digest_init_r): Take flags parm, pass to convert_for_initialization.
+ (process_init_constructor_array): Pass it.
+ (process_init_constructor_record): Likewise.
+ (process_init_constructor_union): Likewise.
+
2009-05-16 Jason Merrill <jason@redhat.com>
PR c++/40139
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 607e3ed..b33e903 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -190,7 +190,7 @@ static tree source_type (conversion *);
static void add_warning (struct z_candidate *, struct z_candidate *);
static bool reference_related_p (tree, tree);
static bool reference_compatible_p (tree, tree);
-static conversion *convert_class_to_reference (tree, tree, tree);
+static conversion *convert_class_to_reference (tree, tree, tree, int);
static conversion *direct_reference_binding (tree, conversion *);
static bool promoted_arithmetic_type_p (tree);
static conversion *conditional_conversion (tree, tree);
@@ -993,7 +993,7 @@ reference_compatible_p (tree t1, tree t2)
converted to T as in [over.match.ref]. */
static conversion *
-convert_class_to_reference (tree reference_type, tree s, tree expr)
+convert_class_to_reference (tree reference_type, tree s, tree expr, int flags)
{
tree conversions;
tree arglist;
@@ -1034,7 +1034,7 @@ convert_class_to_reference (tree reference_type, tree s, tree expr)
t = TREE_TYPE (reference_type);
- while (conversions)
+ for (; conversions; conversions = TREE_CHAIN (conversions))
{
tree fns = TREE_VALUE (conversions);
@@ -1043,6 +1043,10 @@ convert_class_to_reference (tree reference_type, tree s, tree expr)
tree f = OVL_CURRENT (fns);
tree t2 = TREE_TYPE (TREE_TYPE (f));
+ if (DECL_NONCONVERTING_P (f)
+ && (flags & LOOKUP_ONLYCONVERTING))
+ continue;
+
cand = NULL;
/* If this is a template function, try to get an exact
@@ -1101,7 +1105,6 @@ convert_class_to_reference (tree reference_type, tree s, tree expr)
cand->second_conv->bad_p |= cand->convs[0]->bad_p;
}
}
- conversions = TREE_CHAIN (conversions);
}
candidates = splice_viable (candidates, pedantic, &any_viable_p);
@@ -1303,7 +1306,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
the reference is bound to the lvalue result of the conversion
in the second case. */
- conv = convert_class_to_reference (rto, from, expr);
+ conv = convert_class_to_reference (rto, from, expr, flags);
if (conv)
return conv;
}
@@ -1347,6 +1350,12 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
conversion operator). */
flags |= LOOKUP_NO_TEMP_BIND;
+ /* Temporaries are copy-initialized, except for this hack to allow
+ explicit conversion ops to the copy ctor. See also
+ add_function_candidate. */
+ if (!(flags & LOOKUP_COPY_PARM))
+ flags |= LOOKUP_ONLYCONVERTING;
+
conv = implicit_conversion (to, from, expr, c_cast_p,
flags);
if (!conv)
@@ -1394,8 +1403,7 @@ 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));
if (CLASS_TYPE_P (to)
&& !CLASSTYPE_NON_AGGREGATE (complete_type (to))
@@ -1547,9 +1555,17 @@ add_function_candidate (struct z_candidate **candidates,
parmtype = build_pointer_type (parmtype);
}
- if ((flags & LOOKUP_NO_COPY_CTOR_CONVERSION)
- && ctype && i == 0 && DECL_COPY_CONSTRUCTOR_P (fn))
- lflags |= LOOKUP_NO_CONVERSION;
+ if (ctype && i == 0 && DECL_COPY_CONSTRUCTOR_P (fn))
+ {
+ /* Hack: Direct-initialize copy parm (i.e. suppress
+ LOOKUP_ONLYCONVERTING) to make explicit conversion ops
+ work. See also reference_binding. */
+ lflags |= LOOKUP_COPY_PARM;
+ if (flags & LOOKUP_NO_COPY_CTOR_CONVERSION)
+ lflags |= LOOKUP_NO_CONVERSION;
+ }
+ else
+ lflags |= LOOKUP_ONLYCONVERTING;
t = implicit_conversion (parmtype, argtype, arg,
/*c_cast_p=*/false, lflags);
@@ -1612,7 +1628,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
parmnode = parmlist;
argnode = arglist;
viable = 1;
- flags = LOOKUP_NORMAL;
+ flags = LOOKUP_IMPLICIT;
/* Don't bother looking up the same type twice. */
if (*candidates && (*candidates)->fn == totype)
@@ -1679,6 +1695,7 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
num_convs = args[2] ? 3 : (args[1] ? 2 : 1);
convs = alloc_conversions (num_convs);
+ flags |= LOOKUP_ONLYCONVERTING;
for (i = 0; i < 2; ++i)
{
@@ -2268,7 +2285,7 @@ add_builtin_candidates (struct z_candidate **candidates, enum tree_code code,
for (; convs; convs = TREE_CHAIN (convs))
{
- type = TREE_TYPE (TREE_TYPE (OVL_CURRENT (TREE_VALUE (convs))));
+ type = TREE_TYPE (convs);
if (i == 0 && ref1
&& (TREE_CODE (type) != REFERENCE_TYPE
@@ -2785,6 +2802,10 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
{
tree fn = OVL_CURRENT (fns);
+ if (DECL_NONCONVERTING_P (fn)
+ && (flags & LOOKUP_ONLYCONVERTING))
+ continue;
+
/* [over.match.funcs] For conversion functions, the function
is considered to be a member of the class of the implicit
object argument for the purpose of defining the type of
@@ -3214,7 +3235,7 @@ build_object_call (tree obj, tree args, tsubst_flags_t complain)
for (; convs; convs = TREE_CHAIN (convs))
{
tree fns = TREE_VALUE (convs);
- tree totype = TREE_TYPE (TREE_TYPE (OVL_CURRENT (fns)));
+ tree totype = TREE_TYPE (convs);
if ((TREE_CODE (totype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
@@ -3226,6 +3247,10 @@ build_object_call (tree obj, tree args, tsubst_flags_t complain)
for (; fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
+
+ if (DECL_NONCONVERTING_P (fn))
+ continue;
+
if (TREE_CODE (fn) == TEMPLATE_DECL)
add_template_conv_candidate
(&candidates, fn, obj, args, totype,
@@ -3348,7 +3373,7 @@ conditional_conversion (tree e1, tree e2)
t1,
e1,
/*c_cast_p=*/false,
- LOOKUP_NO_TEMP_BIND);
+ LOOKUP_NO_TEMP_BIND|LOOKUP_ONLYCONVERTING);
if (conv)
return conv;
}
@@ -3386,7 +3411,7 @@ conditional_conversion (tree e1, tree e2)
converted to the type that expression E2 would have if E2 were
converted to an rvalue (or the type it has, if E2 is an rvalue). */
return implicit_conversion (t2, t1, e1, /*c_cast_p=*/false,
- LOOKUP_NORMAL);
+ LOOKUP_IMPLICIT);
}
/* Implement [expr.cond]. ARG1, ARG2, and ARG3 are the three
@@ -4584,7 +4609,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
/* When converting from an init list we consider explicit
constructors, but actually trying to call one is an error. */
- if (DECL_NONCONVERTING_P (convfn))
+ if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn))
{
if (complain & tf_error)
error ("converting to %qT from initializer list would use "
@@ -7025,7 +7050,7 @@ can_convert_arg_bad (tree to, tree from, tree arg)
doing a bad conversion, convert_like will complain. */
tree
-perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
+perform_implicit_conversion_flags (tree type, tree expr, tsubst_flags_t complain, int flags)
{
conversion *conv;
void *p;
@@ -7038,11 +7063,21 @@ perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
conv = implicit_conversion (type, TREE_TYPE (expr), expr,
/*c_cast_p=*/false,
- LOOKUP_NORMAL);
+ flags);
+
if (!conv)
{
if (complain & tf_error)
- error ("could not convert %qE to %qT", expr, type);
+ {
+ /* If expr has unknown type, then it is an overloaded function.
+ Call instantiate_type to get good error messages. */
+ if (TREE_TYPE (expr) == unknown_type_node)
+ instantiate_type (type, expr, complain);
+ else if (invalid_nonstatic_memfn_p (expr, complain))
+ /* We gave an error. */;
+ else
+ error ("could not convert %qE to %qT", expr, type);
+ }
expr = error_mark_node;
}
else if (processing_template_decl)
@@ -7062,6 +7097,12 @@ perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
return expr;
}
+tree
+perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
+{
+ return perform_implicit_conversion_flags (type, expr, complain, LOOKUP_IMPLICIT);
+}
+
/* Convert EXPR to TYPE (as a direct-initialization) if that is
permitted. If the conversion is valid, the converted expression is
returned. Otherwise, NULL_TREE is returned, except in the case
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e6545f6..3dfd482 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1963,8 +1963,8 @@ struct GTY(()) lang_decl {
is mutable. */
#define DECL_MUTABLE_P(NODE) (DECL_LANG_FLAG_0 (NODE))
-/* Nonzero for _DECL means that this constructor is a non-converting
- constructor. */
+/* Nonzero for _DECL means that this constructor or conversion function is
+ non-converting. */
#define DECL_NONCONVERTING_P(NODE) \
(DECL_LANG_SPECIFIC (NODE)->decl_flags.nonconverting)
@@ -3758,8 +3758,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
/* Even if the function found by lookup is a virtual function, it
should be called directly. */
#define LOOKUP_NONVIRTUAL (1 << 2)
-/* Non-converting (i.e., "explicit") constructors are not tried. */
+/* Non-converting (i.e., "explicit") constructors are not tried. This flag
+ indicates that we are not performing direct-initialization. */
#define LOOKUP_ONLYCONVERTING (1 << 3)
+#define LOOKUP_IMPLICIT (LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING)
/* If a temporary is created, it should be created so that it lives
as long as the current variable bindings; otherwise it only lives
until the end of the complete-expression. It also forces
@@ -3793,6 +3795,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
/* Avoid user-defined conversions for the first parameter of a copy
constructor. */
#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)
#define LOOKUP_NAMESPACES_ONLY(F) \
(((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
@@ -4200,6 +4204,7 @@ extern tree initialize_reference (tree, tree, tree, tree *);
extern tree make_temporary_var_for_ref_to_temp (tree, tree);
extern tree strip_top_quals (tree);
extern tree perform_implicit_conversion (tree, tree, tsubst_flags_t);
+extern tree perform_implicit_conversion_flags (tree, tree, tsubst_flags_t, int);
extern tree perform_direct_initialization_if_possible (tree, tree, bool,
tsubst_flags_t);
extern tree in_charge_arg_for_name (tree);
@@ -5001,9 +5006,10 @@ extern void readonly_error (tree, const char *);
extern void complete_type_check_abstract (tree);
extern int abstract_virtuals_error (tree, tree);
-extern tree store_init_value (tree, tree);
+extern tree store_init_value (tree, tree, int);
extern void check_narrowing (tree, tree);
extern tree digest_init (tree, tree);
+extern tree digest_init_flags (tree, tree, int);
extern tree build_scoped_ref (tree, tree, tree *);
extern tree build_x_arrow (tree);
extern tree build_m_component_ref (tree, tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index c86fbdf..3fdebd7 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1181,6 +1181,9 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
if (winner && winner == cand)
continue;
+ if (DECL_NONCONVERTING_P (cand))
+ continue;
+
candidate = non_reference (TREE_TYPE (TREE_TYPE (cand)));
switch (TREE_CODE (candidate))
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index ed76dc3..e9ff87b 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5176,7 +5176,7 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
return build_aggr_init_full_exprs (decl, init, flags);
else if (TREE_CODE (init) != TREE_VEC)
{
- init_code = store_init_value (decl, init);
+ init_code = store_init_value (decl, init, flags);
if (pedantic && TREE_CODE (type) == ARRAY_TYPE
&& DECL_INITIAL (decl)
&& TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
@@ -8413,6 +8413,14 @@ grokdeclarator (const cp_declarator *declarator,
"class definition",
name);
}
+ else if (ctype && sfk == sfk_conversion)
+ {
+ if (explicitp == 1)
+ {
+ maybe_warn_cpp0x ("explicit conversion operators");
+ explicitp = 2;
+ }
+ }
arg_types = grokparms (declarator->u.function.parameters,
&parms);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 1f8e848..0e050dd 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1764,7 +1764,7 @@ maybe_emit_vtables (tree ctype)
if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
{
- tree expr = store_init_value (vtbl, DECL_INITIAL (vtbl));
+ tree expr = store_init_value (vtbl, DECL_INITIAL (vtbl), LOOKUP_NORMAL);
/* It had better be all done at compile-time. */
gcc_assert (!expr);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index d40a5e7..5fa5eb8 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1387,7 +1387,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
/* If store_init_value returns NULL_TREE, the INIT has been
recorded as the DECL_INITIAL for EXP. That means there's
nothing more we have to do. */
- init = store_init_value (exp, init);
+ init = store_init_value (exp, init, flags);
if (init)
finish_expr_stmt (init);
return;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 069a057..66472ee 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -48,7 +48,7 @@ along with GCC; see the file COPYING3. If not see
static tree pfn_from_ptrmemfunc (tree);
static tree delta_from_ptrmemfunc (tree);
static tree convert_for_assignment (tree, tree, const char *, tree, int,
- tsubst_flags_t);
+ tsubst_flags_t, int);
static tree cp_pointer_int_sum (enum tree_code, tree, tree);
static tree rationalize_conditional_expr (enum tree_code, tree,
tsubst_flags_t);
@@ -6157,12 +6157,14 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
}
if (modifycode == INIT_EXPR)
+ /* Calls with INIT_EXPR are all direct-initialization, so don't set
+ LOOKUP_ONLYCONVERTING. */
newrhs = convert_for_initialization (lhs, olhstype, newrhs, LOOKUP_NORMAL,
"initialization", NULL_TREE, 0,
complain);
else
newrhs = convert_for_assignment (olhstype, newrhs, "assignment",
- NULL_TREE, 0, complain);
+ NULL_TREE, 0, complain, LOOKUP_IMPLICIT);
if (!same_type_p (lhstype, olhstype))
newrhs = cp_convert_and_check (lhstype, newrhs);
@@ -6568,7 +6570,7 @@ delta_from_ptrmemfunc (tree t)
static tree
convert_for_assignment (tree type, tree rhs,
const char *errtype, tree fndecl, int parmnum,
- tsubst_flags_t complain)
+ tsubst_flags_t complain, int flags)
{
tree rhstype;
enum tree_code coder;
@@ -6689,7 +6691,8 @@ convert_for_assignment (tree type, tree rhs,
TREE_NO_WARNING (rhs) = 1;
}
- return perform_implicit_conversion (strip_top_quals (type), rhs, complain);
+ return perform_implicit_conversion_flags (strip_top_quals (type), rhs,
+ complain, flags);
}
/* Convert RHS to be of type TYPE.
@@ -6780,7 +6783,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
return convert_for_assignment (type, rhs, errtype, fndecl, parmnum,
- complain);
+ complain, flags);
}
/* If RETVAL is the address of, or a reference to, a local variable or
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 5ed7818..5783f67 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -586,7 +586,7 @@ split_nonconstant_init (tree dest, tree init)
for static variable. In that case, caller must emit the code. */
tree
-store_init_value (tree decl, tree init)
+store_init_value (tree decl, tree init, int flags)
{
tree value, type;
@@ -628,7 +628,7 @@ store_init_value (tree decl, tree init)
/* End of special C++ code. */
/* Digest the specified initializer into an expression. */
- value = digest_init (type, init);
+ value = digest_init_flags (type, init, flags);
/* If the initializer is not a constant, fill in DECL_INITIAL with
the bits that are constant, and then return an expression that
will perform the dynamic initialization. */
@@ -717,7 +717,7 @@ check_narrowing (tree type, tree init)
NESTED is true iff we are being called for an element of a CONSTRUCTOR. */
static tree
-digest_init_r (tree type, tree init, bool nested)
+digest_init_r (tree type, tree init, bool nested, int flags)
{
enum tree_code code = TREE_CODE (type);
@@ -796,9 +796,9 @@ digest_init_r (tree type, tree init, bool nested)
if (cxx_dialect != cxx98 && nested)
check_narrowing (type, init);
- init = convert_for_initialization (0, type, init, LOOKUP_NORMAL,
+ init = convert_for_initialization (0, type, init, flags,
"initialization", NULL_TREE, 0,
- tf_warning_or_error);
+ tf_warning_or_error);
exp = &init;
/* Skip any conversions since we'll be outputting the underlying
@@ -842,7 +842,7 @@ digest_init_r (tree type, tree init, bool nested)
}
return convert_for_initialization (NULL_TREE, type, init,
- LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING,
+ flags,
"initialization", NULL_TREE, 0,
tf_warning_or_error);
}
@@ -851,7 +851,13 @@ digest_init_r (tree type, tree init, bool nested)
tree
digest_init (tree type, tree init)
{
- return digest_init_r (type, init, false);
+ return digest_init_r (type, init, false, LOOKUP_IMPLICIT);
+}
+
+tree
+digest_init_flags (tree type, tree init, int flags)
+{
+ return digest_init_r (type, init, false, flags);
}
/* Set of flags used within process_init_constructor to describe the
@@ -924,7 +930,7 @@ process_init_constructor_array (tree type, tree init)
else
ce->index = size_int (i);
gcc_assert (ce->value);
- ce->value = digest_init_r (TREE_TYPE (type), ce->value, true);
+ ce->value = digest_init_r (TREE_TYPE (type), ce->value, true, LOOKUP_IMPLICIT);
if (ce->value != error_mark_node)
gcc_assert (same_type_ignoring_top_level_qualifiers_p
@@ -1031,7 +1037,7 @@ process_init_constructor_record (tree type, tree init)
}
gcc_assert (ce->value);
- next = digest_init_r (type, ce->value, true);
+ next = digest_init_r (type, ce->value, true, LOOKUP_IMPLICIT);
++idx;
}
else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field)))
@@ -1046,7 +1052,7 @@ process_init_constructor_record (tree type, tree init)
else
next = build_constructor (init_list_type_node, NULL);
- next = digest_init_r (TREE_TYPE (field), next, true);
+ next = digest_init_r (TREE_TYPE (field), next, true, LOOKUP_IMPLICIT);
/* Warn when some struct elements are implicitly initialized. */
warning (OPT_Wmissing_field_initializers,
@@ -1156,7 +1162,7 @@ process_init_constructor_union (tree type, tree init)
}
if (ce->value && ce->value != error_mark_node)
- ce->value = digest_init_r (TREE_TYPE (ce->index), ce->value, true);
+ ce->value = digest_init_r (TREE_TYPE (ce->index), ce->value, true, LOOKUP_IMPLICIT);
return picflag_from_initializer (ce->value);
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1e1c805..34a7a2d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2009-05-18 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/cpp0x/explicit1.C: New.
+ * g++.dg/cpp0x/explicit2.C: New.
+
2009-05-18 Dodji Seketeli <dodji@redhat.com>
PR debug/40109
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit1.C b/gcc/testsuite/g++.dg/cpp0x/explicit1.C
new file mode 100644
index 0000000..fe164fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit1.C
@@ -0,0 +1,58 @@
+// Test for explicit conversion ops from N2437.
+// { dg-options "-std=c++0x" }
+
+class U; class V;
+class T
+{
+public:
+ T( U const & );
+ //implicit converting ctor
+ explicit T( V const & );
+ // explicit ctor
+};
+class U
+{
+};
+class V
+{
+};
+class W
+{
+public:
+ operator T() const;
+};
+class X
+{
+public:
+ explicit operator T() const; // theoretical
+};
+int main()
+{
+ U u; V v; W w; X x;
+ // Direct initialization:
+ T t1( u );
+ T t2( v );
+ T t3( w );
+ T t4( x );
+ // Copy initialization:
+ T t5 = u;
+ T t6 = v; // { dg-error "" }
+ T t7 = w;
+ T t8 = x; // { dg-error "" }
+ // Cast notation:
+ T t9 = (T) u;
+ T t10 = (T) v;
+ T t11 = (T) w;
+ T t12 = (T) x;
+ // Static cast:
+ T t13 = static_cast<T>( u );
+ T t14 = static_cast<T>( v );
+ T t15 = static_cast<T>( w );
+ T t16 = static_cast<T>( x );
+ // Function-style cast:
+ T t17 = T( u );
+ T t18 = T( v );
+ T t19 = T( w );
+ T t20 = T( x );
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit2.C b/gcc/testsuite/g++.dg/cpp0x/explicit2.C
new file mode 100644
index 0000000..c2327c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit2.C
@@ -0,0 +1,29 @@
+// Test for explicit conversion ops in various conversion situations.
+// { dg-options "-std=c++0x" }
+
+typedef void (*pfn)();
+
+struct A
+{
+ explicit operator int() const;
+ explicit operator pfn() const;
+};
+
+int main()
+{
+ A a;
+ int i = a; // { dg-error "" }
+ const int &ir = a; // { dg-error "" }
+ a(); // { dg-error "" }
+ a + 1; // { dg-message "" } (error and note on same line)
+
+ int j (a);
+ (int)a;
+ static_cast<int>(a);
+}
+
+struct B
+{
+ int i;
+ B(const A& a): i(a) { }
+};