Commit e57d93c6 by Jason Merrill Committed by Jason Merrill

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
parent 82725547
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> 2009-05-16 Jason Merrill <jason@redhat.com>
PR c++/40139 PR c++/40139
......
...@@ -190,7 +190,7 @@ static tree source_type (conversion *); ...@@ -190,7 +190,7 @@ static tree source_type (conversion *);
static void add_warning (struct z_candidate *, struct z_candidate *); static void add_warning (struct z_candidate *, struct z_candidate *);
static bool reference_related_p (tree, tree); static bool reference_related_p (tree, tree);
static bool reference_compatible_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 conversion *direct_reference_binding (tree, conversion *);
static bool promoted_arithmetic_type_p (tree); static bool promoted_arithmetic_type_p (tree);
static conversion *conditional_conversion (tree, tree); static conversion *conditional_conversion (tree, tree);
...@@ -993,7 +993,7 @@ reference_compatible_p (tree t1, tree t2) ...@@ -993,7 +993,7 @@ reference_compatible_p (tree t1, tree t2)
converted to T as in [over.match.ref]. */ converted to T as in [over.match.ref]. */
static conversion * 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 conversions;
tree arglist; tree arglist;
...@@ -1034,7 +1034,7 @@ convert_class_to_reference (tree reference_type, tree s, tree expr) ...@@ -1034,7 +1034,7 @@ convert_class_to_reference (tree reference_type, tree s, tree expr)
t = TREE_TYPE (reference_type); t = TREE_TYPE (reference_type);
while (conversions) for (; conversions; conversions = TREE_CHAIN (conversions))
{ {
tree fns = TREE_VALUE (conversions); tree fns = TREE_VALUE (conversions);
...@@ -1043,6 +1043,10 @@ convert_class_to_reference (tree reference_type, tree s, tree expr) ...@@ -1043,6 +1043,10 @@ convert_class_to_reference (tree reference_type, tree s, tree expr)
tree f = OVL_CURRENT (fns); tree f = OVL_CURRENT (fns);
tree t2 = TREE_TYPE (TREE_TYPE (f)); tree t2 = TREE_TYPE (TREE_TYPE (f));
if (DECL_NONCONVERTING_P (f)
&& (flags & LOOKUP_ONLYCONVERTING))
continue;
cand = NULL; cand = NULL;
/* If this is a template function, try to get an exact /* 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) ...@@ -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; cand->second_conv->bad_p |= cand->convs[0]->bad_p;
} }
} }
conversions = TREE_CHAIN (conversions);
} }
candidates = splice_viable (candidates, pedantic, &any_viable_p); 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) ...@@ -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 the reference is bound to the lvalue result of the conversion
in the second case. */ in the second case. */
conv = convert_class_to_reference (rto, from, expr); conv = convert_class_to_reference (rto, from, expr, flags);
if (conv) if (conv)
return conv; return conv;
} }
...@@ -1347,6 +1350,12 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags) ...@@ -1347,6 +1350,12 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
conversion operator). */ conversion operator). */
flags |= LOOKUP_NO_TEMP_BIND; 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, conv = implicit_conversion (to, from, expr, c_cast_p,
flags); flags);
if (!conv) if (!conv)
...@@ -1394,8 +1403,7 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p, ...@@ -1394,8 +1403,7 @@ 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) int convflags = (flags & (LOOKUP_NO_TEMP_BIND|LOOKUP_ONLYCONVERTING));
|LOOKUP_ONLYCONVERTING);
if (CLASS_TYPE_P (to) if (CLASS_TYPE_P (to)
&& !CLASSTYPE_NON_AGGREGATE (complete_type (to)) && !CLASSTYPE_NON_AGGREGATE (complete_type (to))
...@@ -1547,9 +1555,17 @@ add_function_candidate (struct z_candidate **candidates, ...@@ -1547,9 +1555,17 @@ add_function_candidate (struct z_candidate **candidates,
parmtype = build_pointer_type (parmtype); parmtype = build_pointer_type (parmtype);
} }
if ((flags & LOOKUP_NO_COPY_CTOR_CONVERSION) if (ctype && i == 0 && DECL_COPY_CONSTRUCTOR_P (fn))
&& ctype && i == 0 && DECL_COPY_CONSTRUCTOR_P (fn)) {
lflags |= LOOKUP_NO_CONVERSION; /* 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, t = implicit_conversion (parmtype, argtype, arg,
/*c_cast_p=*/false, lflags); /*c_cast_p=*/false, lflags);
...@@ -1612,7 +1628,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj, ...@@ -1612,7 +1628,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
parmnode = parmlist; parmnode = parmlist;
argnode = arglist; argnode = arglist;
viable = 1; viable = 1;
flags = LOOKUP_NORMAL; flags = LOOKUP_IMPLICIT;
/* Don't bother looking up the same type twice. */ /* Don't bother looking up the same type twice. */
if (*candidates && (*candidates)->fn == totype) if (*candidates && (*candidates)->fn == totype)
...@@ -1679,6 +1695,7 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname, ...@@ -1679,6 +1695,7 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
num_convs = args[2] ? 3 : (args[1] ? 2 : 1); num_convs = args[2] ? 3 : (args[1] ? 2 : 1);
convs = alloc_conversions (num_convs); convs = alloc_conversions (num_convs);
flags |= LOOKUP_ONLYCONVERTING;
for (i = 0; i < 2; ++i) for (i = 0; i < 2; ++i)
{ {
...@@ -2268,7 +2285,7 @@ add_builtin_candidates (struct z_candidate **candidates, enum tree_code code, ...@@ -2268,7 +2285,7 @@ add_builtin_candidates (struct z_candidate **candidates, enum tree_code code,
for (; convs; convs = TREE_CHAIN (convs)) for (; convs; convs = TREE_CHAIN (convs))
{ {
type = TREE_TYPE (TREE_TYPE (OVL_CURRENT (TREE_VALUE (convs)))); type = TREE_TYPE (convs);
if (i == 0 && ref1 if (i == 0 && ref1
&& (TREE_CODE (type) != REFERENCE_TYPE && (TREE_CODE (type) != REFERENCE_TYPE
...@@ -2785,6 +2802,10 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) ...@@ -2785,6 +2802,10 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
{ {
tree fn = OVL_CURRENT (fns); tree fn = OVL_CURRENT (fns);
if (DECL_NONCONVERTING_P (fn)
&& (flags & LOOKUP_ONLYCONVERTING))
continue;
/* [over.match.funcs] For conversion functions, the function /* [over.match.funcs] For conversion functions, the function
is considered to be a member of the class of the implicit is considered to be a member of the class of the implicit
object argument for the purpose of defining the type of 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) ...@@ -3214,7 +3235,7 @@ build_object_call (tree obj, tree args, tsubst_flags_t complain)
for (; convs; convs = TREE_CHAIN (convs)) for (; convs; convs = TREE_CHAIN (convs))
{ {
tree fns = TREE_VALUE (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 if ((TREE_CODE (totype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE) && TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
...@@ -3226,6 +3247,10 @@ build_object_call (tree obj, tree args, tsubst_flags_t complain) ...@@ -3226,6 +3247,10 @@ build_object_call (tree obj, tree args, tsubst_flags_t complain)
for (; fns; fns = OVL_NEXT (fns)) for (; fns; fns = OVL_NEXT (fns))
{ {
tree fn = OVL_CURRENT (fns); tree fn = OVL_CURRENT (fns);
if (DECL_NONCONVERTING_P (fn))
continue;
if (TREE_CODE (fn) == TEMPLATE_DECL) if (TREE_CODE (fn) == TEMPLATE_DECL)
add_template_conv_candidate add_template_conv_candidate
(&candidates, fn, obj, args, totype, (&candidates, fn, obj, args, totype,
...@@ -3348,7 +3373,7 @@ conditional_conversion (tree e1, tree e2) ...@@ -3348,7 +3373,7 @@ conditional_conversion (tree e1, tree e2)
t1, t1,
e1, e1,
/*c_cast_p=*/false, /*c_cast_p=*/false,
LOOKUP_NO_TEMP_BIND); LOOKUP_NO_TEMP_BIND|LOOKUP_ONLYCONVERTING);
if (conv) if (conv)
return conv; return conv;
} }
...@@ -3386,7 +3411,7 @@ conditional_conversion (tree e1, tree e2) ...@@ -3386,7 +3411,7 @@ conditional_conversion (tree e1, tree e2)
converted to the type that expression E2 would have if E2 were 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). */ converted to an rvalue (or the type it has, if E2 is an rvalue). */
return implicit_conversion (t2, t1, e1, /*c_cast_p=*/false, return implicit_conversion (t2, t1, e1, /*c_cast_p=*/false,
LOOKUP_NORMAL); LOOKUP_IMPLICIT);
} }
/* Implement [expr.cond]. ARG1, ARG2, and ARG3 are the three /* 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, ...@@ -4584,7 +4609,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
/* When converting from an init list we consider explicit /* When converting from an init list we consider explicit
constructors, but actually trying to call one is an error. */ 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) if (complain & tf_error)
error ("converting to %qT from initializer list would use " error ("converting to %qT from initializer list would use "
...@@ -7025,7 +7050,7 @@ can_convert_arg_bad (tree to, tree from, tree arg) ...@@ -7025,7 +7050,7 @@ can_convert_arg_bad (tree to, tree from, tree arg)
doing a bad conversion, convert_like will complain. */ doing a bad conversion, convert_like will complain. */
tree 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; conversion *conv;
void *p; void *p;
...@@ -7038,11 +7063,21 @@ perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain) ...@@ -7038,11 +7063,21 @@ perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
conv = implicit_conversion (type, TREE_TYPE (expr), expr, conv = implicit_conversion (type, TREE_TYPE (expr), expr,
/*c_cast_p=*/false, /*c_cast_p=*/false,
LOOKUP_NORMAL); flags);
if (!conv) if (!conv)
{ {
if (complain & tf_error) 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; expr = error_mark_node;
} }
else if (processing_template_decl) else if (processing_template_decl)
...@@ -7062,6 +7097,12 @@ perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain) ...@@ -7062,6 +7097,12 @@ perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
return expr; 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 /* Convert EXPR to TYPE (as a direct-initialization) if that is
permitted. If the conversion is valid, the converted expression is permitted. If the conversion is valid, the converted expression is
returned. Otherwise, NULL_TREE is returned, except in the case returned. Otherwise, NULL_TREE is returned, except in the case
......
...@@ -1963,8 +1963,8 @@ struct GTY(()) lang_decl { ...@@ -1963,8 +1963,8 @@ struct GTY(()) lang_decl {
is mutable. */ is mutable. */
#define DECL_MUTABLE_P(NODE) (DECL_LANG_FLAG_0 (NODE)) #define DECL_MUTABLE_P(NODE) (DECL_LANG_FLAG_0 (NODE))
/* Nonzero for _DECL means that this constructor is a non-converting /* Nonzero for _DECL means that this constructor or conversion function is
constructor. */ non-converting. */
#define DECL_NONCONVERTING_P(NODE) \ #define DECL_NONCONVERTING_P(NODE) \
(DECL_LANG_SPECIFIC (NODE)->decl_flags.nonconverting) (DECL_LANG_SPECIFIC (NODE)->decl_flags.nonconverting)
...@@ -3758,8 +3758,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG }; ...@@ -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 /* Even if the function found by lookup is a virtual function, it
should be called directly. */ should be called directly. */
#define LOOKUP_NONVIRTUAL (1 << 2) #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_ONLYCONVERTING (1 << 3)
#define LOOKUP_IMPLICIT (LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING)
/* If a temporary is created, it should be created so that it lives /* If a temporary is created, it should be created so that it lives
as long as the current variable bindings; otherwise it only lives as long as the current variable bindings; otherwise it only lives
until the end of the complete-expression. It also forces 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 }; ...@@ -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 /* Avoid user-defined conversions for the first parameter of a copy
constructor. */ constructor. */
#define LOOKUP_NO_COPY_CTOR_CONVERSION (LOOKUP_NO_NARROWING << 1) #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) \ #define LOOKUP_NAMESPACES_ONLY(F) \
(((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES)) (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
...@@ -4200,6 +4204,7 @@ extern tree initialize_reference (tree, tree, tree, tree *); ...@@ -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 make_temporary_var_for_ref_to_temp (tree, tree);
extern tree strip_top_quals (tree); extern tree strip_top_quals (tree);
extern tree perform_implicit_conversion (tree, tree, tsubst_flags_t); 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, extern tree perform_direct_initialization_if_possible (tree, tree, bool,
tsubst_flags_t); tsubst_flags_t);
extern tree in_charge_arg_for_name (tree); extern tree in_charge_arg_for_name (tree);
...@@ -5001,9 +5006,10 @@ extern void readonly_error (tree, const char *); ...@@ -5001,9 +5006,10 @@ extern void readonly_error (tree, const char *);
extern void complete_type_check_abstract (tree); extern void complete_type_check_abstract (tree);
extern int abstract_virtuals_error (tree, 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 void check_narrowing (tree, tree);
extern tree digest_init (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_scoped_ref (tree, tree, tree *);
extern tree build_x_arrow (tree); extern tree build_x_arrow (tree);
extern tree build_m_component_ref (tree, tree); extern tree build_m_component_ref (tree, tree);
......
...@@ -1181,6 +1181,9 @@ build_expr_type_conversion (int desires, tree expr, bool complain) ...@@ -1181,6 +1181,9 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
if (winner && winner == cand) if (winner && winner == cand)
continue; continue;
if (DECL_NONCONVERTING_P (cand))
continue;
candidate = non_reference (TREE_TYPE (TREE_TYPE (cand))); candidate = non_reference (TREE_TYPE (TREE_TYPE (cand)));
switch (TREE_CODE (candidate)) switch (TREE_CODE (candidate))
......
...@@ -5176,7 +5176,7 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) ...@@ -5176,7 +5176,7 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
return build_aggr_init_full_exprs (decl, init, flags); return build_aggr_init_full_exprs (decl, init, flags);
else if (TREE_CODE (init) != TREE_VEC) 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 if (pedantic && TREE_CODE (type) == ARRAY_TYPE
&& DECL_INITIAL (decl) && DECL_INITIAL (decl)
&& TREE_CODE (DECL_INITIAL (decl)) == STRING_CST && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
...@@ -8413,6 +8413,14 @@ grokdeclarator (const cp_declarator *declarator, ...@@ -8413,6 +8413,14 @@ grokdeclarator (const cp_declarator *declarator,
"class definition", "class definition",
name); 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, arg_types = grokparms (declarator->u.function.parameters,
&parms); &parms);
......
...@@ -1764,7 +1764,7 @@ maybe_emit_vtables (tree ctype) ...@@ -1764,7 +1764,7 @@ maybe_emit_vtables (tree ctype)
if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0) 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. */ /* It had better be all done at compile-time. */
gcc_assert (!expr); gcc_assert (!expr);
......
...@@ -1387,7 +1387,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, ...@@ -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 /* If store_init_value returns NULL_TREE, the INIT has been
recorded as the DECL_INITIAL for EXP. That means there's recorded as the DECL_INITIAL for EXP. That means there's
nothing more we have to do. */ nothing more we have to do. */
init = store_init_value (exp, init); init = store_init_value (exp, init, flags);
if (init) if (init)
finish_expr_stmt (init); finish_expr_stmt (init);
return; return;
......
...@@ -48,7 +48,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -48,7 +48,7 @@ along with GCC; see the file COPYING3. If not see
static tree pfn_from_ptrmemfunc (tree); static tree pfn_from_ptrmemfunc (tree);
static tree delta_from_ptrmemfunc (tree); static tree delta_from_ptrmemfunc (tree);
static tree convert_for_assignment (tree, tree, const char *, tree, int, 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 cp_pointer_int_sum (enum tree_code, tree, tree);
static tree rationalize_conditional_expr (enum tree_code, tree, static tree rationalize_conditional_expr (enum tree_code, tree,
tsubst_flags_t); tsubst_flags_t);
...@@ -6157,12 +6157,14 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs, ...@@ -6157,12 +6157,14 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
} }
if (modifycode == INIT_EXPR) 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, newrhs = convert_for_initialization (lhs, olhstype, newrhs, LOOKUP_NORMAL,
"initialization", NULL_TREE, 0, "initialization", NULL_TREE, 0,
complain); complain);
else else
newrhs = convert_for_assignment (olhstype, newrhs, "assignment", newrhs = convert_for_assignment (olhstype, newrhs, "assignment",
NULL_TREE, 0, complain); NULL_TREE, 0, complain, LOOKUP_IMPLICIT);
if (!same_type_p (lhstype, olhstype)) if (!same_type_p (lhstype, olhstype))
newrhs = cp_convert_and_check (lhstype, newrhs); newrhs = cp_convert_and_check (lhstype, newrhs);
...@@ -6568,7 +6570,7 @@ delta_from_ptrmemfunc (tree t) ...@@ -6568,7 +6570,7 @@ delta_from_ptrmemfunc (tree t)
static tree static tree
convert_for_assignment (tree type, tree rhs, convert_for_assignment (tree type, tree rhs,
const char *errtype, tree fndecl, int parmnum, const char *errtype, tree fndecl, int parmnum,
tsubst_flags_t complain) tsubst_flags_t complain, int flags)
{ {
tree rhstype; tree rhstype;
enum tree_code coder; enum tree_code coder;
...@@ -6689,7 +6691,8 @@ convert_for_assignment (tree type, tree rhs, ...@@ -6689,7 +6691,8 @@ convert_for_assignment (tree type, tree rhs,
TREE_NO_WARNING (rhs) = 1; 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. /* Convert RHS to be of type TYPE.
...@@ -6780,7 +6783,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags, ...@@ -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 ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
return convert_for_assignment (type, rhs, errtype, fndecl, parmnum, 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 /* If RETVAL is the address of, or a reference to, a local variable or
......
...@@ -586,7 +586,7 @@ split_nonconstant_init (tree dest, tree init) ...@@ -586,7 +586,7 @@ split_nonconstant_init (tree dest, tree init)
for static variable. In that case, caller must emit the code. */ for static variable. In that case, caller must emit the code. */
tree tree
store_init_value (tree decl, tree init) store_init_value (tree decl, tree init, int flags)
{ {
tree value, type; tree value, type;
...@@ -628,7 +628,7 @@ store_init_value (tree decl, tree init) ...@@ -628,7 +628,7 @@ store_init_value (tree decl, tree init)
/* End of special C++ code. */ /* End of special C++ code. */
/* Digest the specified initializer into an expression. */ /* 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 /* If the initializer is not a constant, fill in DECL_INITIAL with
the bits that are constant, and then return an expression that the bits that are constant, and then return an expression that
will perform the dynamic initialization. */ will perform the dynamic initialization. */
...@@ -717,7 +717,7 @@ check_narrowing (tree type, tree init) ...@@ -717,7 +717,7 @@ check_narrowing (tree type, tree init)
NESTED is true iff we are being called for an element of a CONSTRUCTOR. */ NESTED is true iff we are being called for an element of a CONSTRUCTOR. */
static tree 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); enum tree_code code = TREE_CODE (type);
...@@ -796,9 +796,9 @@ digest_init_r (tree type, tree init, bool nested) ...@@ -796,9 +796,9 @@ digest_init_r (tree type, tree init, bool nested)
if (cxx_dialect != cxx98 && nested) if (cxx_dialect != cxx98 && nested)
check_narrowing (type, init); 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, "initialization", NULL_TREE, 0,
tf_warning_or_error); tf_warning_or_error);
exp = &init; exp = &init;
/* Skip any conversions since we'll be outputting the underlying /* Skip any conversions since we'll be outputting the underlying
...@@ -842,7 +842,7 @@ digest_init_r (tree type, tree init, bool nested) ...@@ -842,7 +842,7 @@ digest_init_r (tree type, tree init, bool nested)
} }
return convert_for_initialization (NULL_TREE, type, init, return convert_for_initialization (NULL_TREE, type, init,
LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING, flags,
"initialization", NULL_TREE, 0, "initialization", NULL_TREE, 0,
tf_warning_or_error); tf_warning_or_error);
} }
...@@ -851,7 +851,13 @@ digest_init_r (tree type, tree init, bool nested) ...@@ -851,7 +851,13 @@ digest_init_r (tree type, tree init, bool nested)
tree tree
digest_init (tree type, tree init) 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 /* Set of flags used within process_init_constructor to describe the
...@@ -924,7 +930,7 @@ process_init_constructor_array (tree type, tree init) ...@@ -924,7 +930,7 @@ process_init_constructor_array (tree type, tree init)
else else
ce->index = size_int (i); ce->index = size_int (i);
gcc_assert (ce->value); 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) if (ce->value != error_mark_node)
gcc_assert (same_type_ignoring_top_level_qualifiers_p gcc_assert (same_type_ignoring_top_level_qualifiers_p
...@@ -1031,7 +1037,7 @@ process_init_constructor_record (tree type, tree init) ...@@ -1031,7 +1037,7 @@ process_init_constructor_record (tree type, tree init)
} }
gcc_assert (ce->value); gcc_assert (ce->value);
next = digest_init_r (type, ce->value, true); next = digest_init_r (type, ce->value, true, LOOKUP_IMPLICIT);
++idx; ++idx;
} }
else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field))) else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field)))
...@@ -1046,7 +1052,7 @@ process_init_constructor_record (tree type, tree init) ...@@ -1046,7 +1052,7 @@ process_init_constructor_record (tree type, tree init)
else else
next = build_constructor (init_list_type_node, NULL); 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. */ /* Warn when some struct elements are implicitly initialized. */
warning (OPT_Wmissing_field_initializers, warning (OPT_Wmissing_field_initializers,
...@@ -1156,7 +1162,7 @@ process_init_constructor_union (tree type, tree init) ...@@ -1156,7 +1162,7 @@ process_init_constructor_union (tree type, tree init)
} }
if (ce->value && ce->value != error_mark_node) 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); return picflag_from_initializer (ce->value);
} }
......
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> 2009-05-18 Dodji Seketeli <dodji@redhat.com>
PR debug/40109 PR debug/40109
......
// 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;
}
// 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) { }
};
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