* 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
+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
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);
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;
t = TREE_TYPE (reference_type);
- while (conversions)
+ for (; conversions; conversions = TREE_CHAIN (conversions))
{
tree fns = TREE_VALUE (conversions);
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
cand->second_conv->bad_p |= cand->convs[0]->bad_p;
}
}
- conversions = TREE_CHAIN (conversions);
}
candidates = splice_viable (candidates, pedantic, &any_viable_p);
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;
}
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)
&& (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))
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);
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)
num_convs = args[2] ? 3 : (args[1] ? 2 : 1);
convs = alloc_conversions (num_convs);
+ flags |= LOOKUP_ONLYCONVERTING;
for (i = 0; i < 2; ++i)
{
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
{
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
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)
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,
t1,
e1,
/*c_cast_p=*/false,
- LOOKUP_NO_TEMP_BIND);
+ LOOKUP_NO_TEMP_BIND|LOOKUP_ONLYCONVERTING);
if (conv)
return conv;
}
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
/* 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 "
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;
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)
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
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)
/* 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
/* 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))
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);
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);
if (winner && winner == cand)
continue;
+ if (DECL_NONCONVERTING_P (cand))
+ continue;
+
candidate = non_reference (TREE_TYPE (TREE_TYPE (cand)));
switch (TREE_CODE (candidate))
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
"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);
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);
/* 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;
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);
}
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);
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;
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.
return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
return convert_for_assignment (type, rhs, errtype, fndecl, parmnum,
- complain);
+ complain, flags);
}
\f
/* If RETVAL is the address of, or a reference to, a local variable or
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;
/* 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. */
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);
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
}
return convert_for_initialization (NULL_TREE, type, init,
- LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING,
+ flags,
"initialization", NULL_TREE, 0,
tf_warning_or_error);
}
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);
}
\f
/* Set of flags used within process_init_constructor to describe the
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
}
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)))
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,
}
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);
}
+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
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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) { }
+};