-/* Determine whether or not the EXPR (of class type S) can be
- converted to T as in [over.match.ref]. */
-
-static conversion *
-convert_class_to_reference (tree reference_type, tree s, tree expr, int flags)
-{
- tree conversions;
- tree first_arg;
- conversion *conv;
- tree t;
- struct z_candidate *candidates;
- struct z_candidate *cand;
- bool any_viable_p;
-
- if (!expr)
- return NULL;
-
- conversions = lookup_conversions (s, /*lookup_template_convs_p=*/true);
- if (!conversions)
- return NULL;
-
- /* [over.match.ref]
-
- Assuming that "cv1 T" is the underlying type of the reference
- being initialized, and "cv S" is the type of the initializer
- expression, with S a class type, the candidate functions are
- selected as follows:
-
- --The conversion functions of S and its base classes are
- considered. Those that are not hidden within S and yield type
- "reference to cv2 T2", where "cv1 T" is reference-compatible
- (_dcl.init.ref_) with "cv2 T2", are candidate functions.
-
- The argument list has one argument, which is the initializer
- expression. */
-
- candidates = 0;
-
- /* Conceptually, we should take the address of EXPR and put it in
- the argument list. Unfortunately, however, that can result in
- error messages, which we should not issue now because we are just
- trying to find a conversion operator. Therefore, we use NULL,
- cast to the appropriate type. */
- first_arg = build_int_cst (build_pointer_type (s), 0);
-
- t = TREE_TYPE (reference_type);
-
- /* We're performing a user-defined conversion to a desired type, so set
- this for the benefit of add_candidates. */
- flags |= LOOKUP_NO_CONVERSION;
-
- for (; conversions; conversions = TREE_CHAIN (conversions))
- {
- tree fns = TREE_VALUE (conversions);
- tree binfo = TREE_PURPOSE (conversions);
- struct z_candidate *old_candidates = candidates;;
-
- add_candidates (fns, first_arg, NULL, reference_type,
- NULL_TREE, false,
- binfo, TYPE_BINFO (s),
- flags, &candidates);
-
- for (cand = candidates; cand != old_candidates; cand = cand->next)
- {
- /* Now, see if the conversion function really returns
- an lvalue of the appropriate type. From the
- point of view of unification, simply returning an
- rvalue of the right type is good enough. */
- tree f = cand->fn;
- tree t2 = TREE_TYPE (TREE_TYPE (f));
- if (TREE_CODE (t2) != REFERENCE_TYPE
- || !reference_compatible_p (t, TREE_TYPE (t2)))
- {
- cand->viable = 0;
- }
- else
- {
- conversion *identity_conv;
- /* Build a standard conversion sequence indicating the
- binding from the reference type returned by the
- function to the desired REFERENCE_TYPE. */
- identity_conv
- = build_identity_conv (TREE_TYPE (TREE_TYPE
- (TREE_TYPE (cand->fn))),
- NULL_TREE);
- cand->second_conv
- = (direct_reference_binding
- (reference_type, identity_conv));
- cand->second_conv->rvaluedness_matches_p
- = TYPE_REF_IS_RVALUE (TREE_TYPE (TREE_TYPE (cand->fn)))
- == TYPE_REF_IS_RVALUE (reference_type);
- cand->second_conv->bad_p |= cand->convs[0]->bad_p;
-
- /* Don't allow binding of lvalues to rvalue references. */
- if (TYPE_REF_IS_RVALUE (reference_type)
- && !TYPE_REF_IS_RVALUE (TREE_TYPE (TREE_TYPE (cand->fn))))
- cand->second_conv->bad_p = true;
- }
- }
- }
-
- candidates = splice_viable (candidates, pedantic, &any_viable_p);
- /* If none of the conversion functions worked out, let our caller
- know. */
- if (!any_viable_p)
- return NULL;
-
- cand = tourney (candidates);
- if (!cand)
- return NULL;
-
- /* Now that we know that this is the function we're going to use fix
- the dummy first argument. */
- gcc_assert (cand->first_arg == NULL_TREE
- || integer_zerop (cand->first_arg));
- cand->first_arg = build_this (expr);
-
- /* Build a user-defined conversion sequence representing the
- conversion. */
- conv = build_conv (ck_user,
- TREE_TYPE (TREE_TYPE (cand->fn)),
- build_identity_conv (TREE_TYPE (expr), expr));
- conv->cand = cand;
-
- if (cand->viable == -1)
- conv->bad_p = true;
-
- /* Merge it with the standard conversion sequence from the
- conversion function's return type to the desired type. */
- cand->second_conv = merge_conversion_sequences (conv, cand->second_conv);
-
- return cand->second_conv;
-}
-