tree convert_to_reference (tree reftype, tree expr, int convtype, int flags, tree decl) { tree type = TYPE_MAIN_VARIANT (TREE_TYPE (reftype)); tree intype; tree rval = NULL_TREE; tree rval_as_conversion = NULL_TREE; bool can_convert_intype_to_type; if (TREE_CODE (type) == FUNCTION_TYPE && TREE_TYPE (expr) == unknown_type_node) expr = instantiate_type (type, expr, (flags & LOOKUP_COMPLAIN) ? tf_warning_or_error : tf_none); if (expr == error_mark_node) return error_mark_node; intype = TREE_TYPE (expr); gcc_assert (TREE_CODE (intype) != REFERENCE_TYPE); gcc_assert (TREE_CODE (reftype) == REFERENCE_TYPE); intype = TYPE_MAIN_VARIANT (intype); can_convert_intype_to_type = can_convert (type, intype); if (!can_convert_intype_to_type && (convtype & CONV_IMPLICIT) && MAYBE_CLASS_TYPE_P (intype) && ! (flags & LOOKUP_NO_CONVERSION)) { /* Look for a user-defined conversion to lvalue that we can use. */ rval_as_conversion = build_type_conversion (reftype, expr); if (rval_as_conversion && rval_as_conversion != error_mark_node && real_lvalue_p (rval_as_conversion)) { expr = rval_as_conversion; rval_as_conversion = NULL_TREE; intype = type; can_convert_intype_to_type = 1; } } if (((convtype & CONV_STATIC) && can_convert (intype, type)) || ((convtype & CONV_IMPLICIT) && can_convert_intype_to_type)) { if (flags & LOOKUP_COMPLAIN) { tree ttl = TREE_TYPE (reftype); tree ttr = lvalue_type (expr); if (! real_lvalue_p (expr)) warn_ref_binding (reftype, intype, decl); if (! (convtype & CONV_CONST) && !at_least_as_qualified_p (ttl, ttr)) permerror (input_location, "conversion from %qT to %qT discards qualifiers", ttr, reftype); } return build_up_reference (reftype, expr, flags, decl); } else if ((convtype & CONV_REINTERPRET) && lvalue_p (expr)) { /* When casting an lvalue to a reference type, just convert into a pointer to the new type and deference it. This is allowed by San Diego WP section 5.2.9 paragraph 12, though perhaps it should be done directly (jason). (int &)ri ---> *(int*)&ri */ /* B* bp; A& ar = (A&)bp; is valid, but it's probably not what they meant. */ if (TREE_CODE (intype) == POINTER_TYPE && (comptypes (TREE_TYPE (intype), type, COMPARE_BASE | COMPARE_DERIVED))) warning (0, "casting %qT to %qT does not dereference pointer", intype, reftype); rval = cp_build_unary_op (ADDR_EXPR, expr, 0, tf_warning_or_error); if (rval != error_mark_node) rval = convert_force (build_pointer_type (TREE_TYPE (reftype)), rval, 0); if (rval != error_mark_node) rval = build1 (NOP_EXPR, reftype, rval); } else { rval = convert_for_initialization (NULL_TREE, type, expr, flags, "converting", 0, 0, tf_warning_or_error); if (rval == NULL_TREE || rval == error_mark_node) return rval; warn_ref_binding (reftype, intype, decl); rval = build_up_reference (reftype, rval, flags, decl); } if (rval) { /* If we found a way to convert earlier, then use it. */ return rval; } if (flags & LOOKUP_COMPLAIN) error ("cannot convert type %qT to type %qT", intype, reftype); return error_mark_node; }
static tree cp_convert_to_pointer (tree type, tree expr) { tree intype = TREE_TYPE (expr); enum tree_code form; tree rval; if (intype == error_mark_node) return error_mark_node; if (MAYBE_CLASS_TYPE_P (intype)) { intype = complete_type (intype); if (!COMPLETE_TYPE_P (intype)) { error ("can't convert from incomplete type %qT to %qT", intype, type); return error_mark_node; } rval = build_type_conversion (type, expr); if (rval) { if (rval == error_mark_node) error ("conversion of %qE from %qT to %qT is ambiguous", expr, intype, type); return rval; } } /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */ if (TREE_CODE (type) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE || VOID_TYPE_P (TREE_TYPE (type)))) { if (TYPE_PTRMEMFUNC_P (intype) || TREE_CODE (intype) == METHOD_TYPE) return convert_member_func_to_ptr (type, expr); if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) return build_nop (type, expr); intype = TREE_TYPE (expr); } if (expr == error_mark_node) return error_mark_node; form = TREE_CODE (intype); if (POINTER_TYPE_P (intype)) { intype = TYPE_MAIN_VARIANT (intype); if (TYPE_MAIN_VARIANT (type) != intype && TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && MAYBE_CLASS_TYPE_P (TREE_TYPE (type)) && MAYBE_CLASS_TYPE_P (TREE_TYPE (intype)) && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE) { enum tree_code code = PLUS_EXPR; tree binfo; tree intype_class; tree type_class; bool same_p; intype_class = TREE_TYPE (intype); type_class = TREE_TYPE (type); same_p = same_type_p (TYPE_MAIN_VARIANT (intype_class), TYPE_MAIN_VARIANT (type_class)); binfo = NULL_TREE; /* Try derived to base conversion. */ if (!same_p) binfo = lookup_base (intype_class, type_class, ba_check, NULL); if (!same_p && !binfo) { /* Try base to derived conversion. */ binfo = lookup_base (type_class, intype_class, ba_check, NULL); code = MINUS_EXPR; } if (binfo == error_mark_node) return error_mark_node; if (binfo || same_p) { if (binfo) expr = build_base_path (code, expr, binfo, 0); /* Add any qualifier conversions. */ return build_nop (type, expr); } } if (TYPE_PTRMEMFUNC_P (type)) { error ("cannot convert %qE from type %qT to type %qT", expr, intype, type); return error_mark_node; } return build_nop (type, expr); } else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)) || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))) return convert_ptrmem (type, expr, /*allow_inverse_p=*/false, /*c_cast_p=*/false); else if (TYPE_PTRMEMFUNC_P (intype)) { if (!warn_pmf2ptr) { if (TREE_CODE (expr) == PTRMEM_CST) return cp_convert_to_pointer (type, PTRMEM_CST_MEMBER (expr)); else if (TREE_CODE (expr) == OFFSET_REF) { tree object = TREE_OPERAND (expr, 0); return get_member_function_from_ptrfunc (&object, TREE_OPERAND (expr, 1)); } } error ("cannot convert %qE from type %qT to type %qT", expr, intype, type); return error_mark_node; } if (integer_zerop (expr)) { if (TYPE_PTRMEMFUNC_P (type)) return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0, /*c_cast_p=*/false); if (TYPE_PTRMEM_P (type)) { /* A NULL pointer-to-member is represented by -1, not by zero. */ expr = build_int_cst_type (type, -1); } else expr = build_int_cst (type, 0); return expr; } else if (TYPE_PTR_TO_MEMBER_P (type) && INTEGRAL_CODE_P (form)) { error ("invalid conversion from %qT to %qT", intype, type); return error_mark_node; } if (INTEGRAL_CODE_P (form)) { if (TYPE_PRECISION (intype) == POINTER_SIZE) return build1 (CONVERT_EXPR, type, expr); expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr); /* Modes may be different but sizes should be the same. There is supposed to be some integral type that is the same width as a pointer. */ gcc_assert (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) == GET_MODE_SIZE (TYPE_MODE (type))); return convert_to_pointer (type, expr); } if (type_unknown_p (expr)) return instantiate_type (type, expr, tf_warning_or_error); error ("cannot convert %qE from type %qT to type %qT", expr, intype, type); return error_mark_node; }
static tree cp_convert_to_pointer (tree type, tree expr, bool force) { tree intype = TREE_TYPE (expr); enum tree_code form; tree rval; if (intype == error_mark_node) return error_mark_node; if (IS_AGGR_TYPE (intype)) { intype = complete_type (intype); if (!COMPLETE_TYPE_P (intype)) { error ("can't convert from incomplete type `%T' to `%T'", intype, type); return error_mark_node; } rval = build_type_conversion (type, expr); if (rval) { if (rval == error_mark_node) error ("conversion of `%E' from `%T' to `%T' is ambiguous", expr, intype, type); return rval; } } /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */ if (TREE_CODE (type) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE || VOID_TYPE_P (TREE_TYPE (type)))) { /* Allow an implicit this pointer for pointer to member functions. */ if (TYPE_PTRMEMFUNC_P (intype)) { if (pedantic || warn_pmf2ptr) pedwarn ("converting from `%T' to `%T'", intype, type); if (TREE_CODE (expr) == PTRMEM_CST) expr = build_address (PTRMEM_CST_MEMBER (expr)); else { tree decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 0); decl = build_address (decl); expr = get_member_function_from_ptrfunc (&decl, expr); } } else if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE) { if (pedantic || warn_pmf2ptr) pedwarn ("converting from `%T' to `%T'", intype, type); expr = build_addr_func (expr); } if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) return build_nop (type, expr); intype = TREE_TYPE (expr); } if (expr == error_mark_node) return error_mark_node; form = TREE_CODE (intype); if (POINTER_TYPE_P (intype)) { intype = TYPE_MAIN_VARIANT (intype); if (TYPE_MAIN_VARIANT (type) != intype && TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype)) && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE) { enum tree_code code = PLUS_EXPR; tree binfo; tree intype_class; tree type_class; bool same_p; intype_class = TREE_TYPE (intype); type_class = TREE_TYPE (type); same_p = same_type_p (TYPE_MAIN_VARIANT (intype_class), TYPE_MAIN_VARIANT (type_class)); binfo = NULL_TREE; /* Try derived to base conversion. */ if (!same_p) binfo = lookup_base (intype_class, type_class, ba_check, NULL); if (!same_p && !binfo) { /* Try base to derived conversion. */ binfo = lookup_base (type_class, intype_class, ba_check, NULL); code = MINUS_EXPR; } if (binfo == error_mark_node) return error_mark_node; if (binfo || same_p) { if (binfo) expr = build_base_path (code, expr, binfo, 0); /* Add any qualifier conversions. */ return build_nop (type, expr); } } if (TYPE_PTRMEMFUNC_P (type)) { error ("cannot convert `%E' from type `%T' to type `%T'", expr, intype, type); return error_mark_node; } return build_nop (type, expr); } else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)) { tree b1; tree b2; tree binfo; enum tree_code code = PLUS_EXPR; base_kind bk; b1 = TYPE_PTRMEM_CLASS_TYPE (type); b2 = TYPE_PTRMEM_CLASS_TYPE (intype); binfo = lookup_base (b1, b2, ba_check, &bk); if (!binfo) { binfo = lookup_base (b2, b1, ba_check, &bk); code = MINUS_EXPR; } if (binfo == error_mark_node) return error_mark_node; if (bk == bk_via_virtual) { if (force) warning ("pointer to member cast from `%T' to `%T' is via virtual base", intype, type); else { error ("pointer to member cast from `%T' to `%T' is via virtual base", intype, type); return error_mark_node; } /* This is a reinterpret cast, whose result is unspecified. We choose to do nothing. */ return build1 (NOP_EXPR, type, expr); } if (TREE_CODE (expr) == PTRMEM_CST) expr = cplus_expand_constant (expr); if (binfo && !integer_zerop (BINFO_OFFSET (binfo))) expr = size_binop (code, build_nop (sizetype, expr), BINFO_OFFSET (binfo)); return build_nop (type, expr); } else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)) return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0); else if (TYPE_PTRMEMFUNC_P (intype)) { if (!warn_pmf2ptr) { if (TREE_CODE (expr) == PTRMEM_CST) return cp_convert_to_pointer (type, PTRMEM_CST_MEMBER (expr), force); else if (TREE_CODE (expr) == OFFSET_REF) { tree object = TREE_OPERAND (expr, 0); return get_member_function_from_ptrfunc (&object, TREE_OPERAND (expr, 1)); } } error ("cannot convert `%E' from type `%T' to type `%T'", expr, intype, type); return error_mark_node; } if (integer_zerop (expr)) { if (TYPE_PTRMEMFUNC_P (type)) return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0); if (TYPE_PTRMEM_P (type)) /* A NULL pointer-to-member is represented by -1, not by zero. */ expr = build_int_2 (-1, -1); else expr = build_int_2 (0, 0); TREE_TYPE (expr) = type; /* Fix up the representation of -1 if appropriate. */ force_fit_type (expr, 0); return expr; } else if (TYPE_PTR_TO_MEMBER_P (type) && INTEGRAL_CODE_P (form)) { error ("invalid conversion from '%T' to '%T'", intype, type); return error_mark_node; } if (INTEGRAL_CODE_P (form)) { if (TYPE_PRECISION (intype) == POINTER_SIZE) return build1 (CONVERT_EXPR, type, expr); expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr); /* Modes may be different but sizes should be the same. */ if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) != GET_MODE_SIZE (TYPE_MODE (type))) /* There is supposed to be some integral type that is the same width as a pointer. */ abort (); return convert_to_pointer (type, expr); } if (type_unknown_p (expr)) return instantiate_type (type, expr, tf_error | tf_warning); error ("cannot convert `%E' from type `%T' to type `%T'", expr, intype, type); return error_mark_node; }