tree cplus_expand_constant (tree cst) { switch (TREE_CODE (cst)) { case PTRMEM_CST: { tree type = TREE_TYPE (cst); tree member; /* Find the member. */ member = PTRMEM_CST_MEMBER (cst); /* We can't lower this until the class is complete. */ if (!COMPLETE_TYPE_P (DECL_CONTEXT (member))) return cst; if (TREE_CODE (member) == FIELD_DECL) { /* Find the offset for the field. */ cst = byte_position (member); while (!same_type_p (DECL_CONTEXT (member), TYPE_PTRMEM_CLASS_TYPE (type))) { /* The MEMBER must have been nestled within an anonymous aggregate contained in TYPE. Find the anonymous aggregate. */ member = lookup_anon_field (TYPE_PTRMEM_CLASS_TYPE (type), DECL_CONTEXT (member)); cst = size_binop (PLUS_EXPR, cst, byte_position (member)); } cst = fold (build_nop (type, cst)); } else { tree delta; tree pfn; expand_ptrmemfunc_cst (cst, &delta, &pfn); cst = build_ptrmemfunc1 (type, delta, pfn); } } break; case CONSTRUCTOR: { constructor_elt *elt; unsigned HOST_WIDE_INT idx; FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (cst), idx, elt) elt->value = cplus_expand_constant (elt->value); } default: /* There's nothing to do. */ break; } return cst; }
static tree get_tinfo_ptr (tree type) { tree decl = get_tinfo_decl (type); mark_used (decl); return build_nop (type_info_ptr_type, build_address (decl)); }
tree perform_qualification_conversions (tree type, tree expr) { tree expr_type; expr_type = TREE_TYPE (expr); if (TYPE_PTR_P (type) && TYPE_PTR_P (expr_type) && comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (expr_type))) return build_nop (type, expr); else if (TYPE_PTR_TO_MEMBER_P (type) && TYPE_PTR_TO_MEMBER_P (expr_type) && same_type_p (TYPE_PTRMEM_CLASS_TYPE (type), TYPE_PTRMEM_CLASS_TYPE (expr_type)) && comp_ptr_ttypes (TYPE_PTRMEM_POINTED_TO_TYPE (type), TYPE_PTRMEM_POINTED_TO_TYPE (expr_type))) return build_nop (type, expr); else return error_mark_node; }
static tree build_up_reference (tree type, tree arg, int flags, tree decl) { tree rval; tree argtype = TREE_TYPE (arg); tree target_type = TREE_TYPE (type); gcc_assert (TREE_CODE (type) == REFERENCE_TYPE); if ((flags & DIRECT_BIND) && ! real_lvalue_p (arg)) { /* Create a new temporary variable. We can't just use a TARGET_EXPR here because it needs to live as long as DECL. */ tree targ = arg; arg = make_temporary_var_for_ref_to_temp (decl, TREE_TYPE (arg)); /* Process the initializer for the declaration. */ DECL_INITIAL (arg) = targ; cp_finish_decl (arg, targ, /*init_const_expr_p=*/false, NULL_TREE, LOOKUP_ONLYCONVERTING|DIRECT_BIND); } else if (!(flags & DIRECT_BIND) && ! lvalue_p (arg)) return get_target_expr (arg); /* If we had a way to wrap this up, and say, if we ever needed its address, transform all occurrences of the register, into a memory reference we could win better. */ rval = cp_build_unary_op (ADDR_EXPR, arg, 1, tf_warning_or_error); if (rval == error_mark_node) return error_mark_node; if ((flags & LOOKUP_PROTECT) && TYPE_MAIN_VARIANT (argtype) != TYPE_MAIN_VARIANT (target_type) && MAYBE_CLASS_TYPE_P (argtype) && MAYBE_CLASS_TYPE_P (target_type)) { /* We go through lookup_base for the access control. */ tree binfo = lookup_base (argtype, target_type, ba_check, NULL); if (binfo == error_mark_node) return error_mark_node; if (binfo == NULL_TREE) return error_not_base_type (target_type, argtype); rval = build_base_path (PLUS_EXPR, rval, binfo, 1); } else rval = convert_to_pointer_force (build_pointer_type (target_type), rval); return build_nop (type, rval); }
tree convert (tree type, tree expr) { tree intype; if (type == error_mark_node || expr == error_mark_node) return error_mark_node; intype = TREE_TYPE (expr); if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype)) return fold_if_not_in_template (build_nop (type, expr)); return ocp_convert (type, expr, CONV_OLD_CONVERT, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION); }
tree cplus_expand_constant (tree cst) { switch (TREE_CODE (cst)) { case PTRMEM_CST: { tree type = TREE_TYPE (cst); tree member; /* Find the member. */ member = PTRMEM_CST_MEMBER (cst); if (TREE_CODE (member) == FIELD_DECL) { /* Find the offset for the field. */ cst = byte_position (member); while (!same_type_p (DECL_CONTEXT (member), TYPE_PTRMEM_CLASS_TYPE (type))) { /* The MEMBER must have been nestled within an anonymous aggregate contained in TYPE. Find the anonymous aggregate. */ member = lookup_anon_field (TYPE_PTRMEM_CLASS_TYPE (type), DECL_CONTEXT (member)); cst = size_binop (PLUS_EXPR, cst, byte_position (member)); } cst = fold (build_nop (type, cst)); } else { tree delta; tree pfn; expand_ptrmemfunc_cst (cst, &delta, &pfn); cst = build_ptrmemfunc1 (type, delta, pfn); } } break; default: /* There's nothing to do. */ break; } return cst; }
static tree convert_to_pointer_force (tree type, tree expr) { tree intype = TREE_TYPE (expr); enum tree_code form = TREE_CODE (intype); if (form == POINTER_TYPE) { intype = TYPE_MAIN_VARIANT (intype); if (TYPE_MAIN_VARIANT (type) != intype && 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; binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type), ba_unique, NULL); if (!binfo) { binfo = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), ba_unique, NULL); code = MINUS_EXPR; } if (binfo == error_mark_node) return error_mark_node; if (binfo) { expr = build_base_path (code, expr, binfo, 0); if (expr == error_mark_node) return error_mark_node; /* Add any qualifier conversions. */ if (!same_type_p (TREE_TYPE (TREE_TYPE (expr)), TREE_TYPE (type))) expr = build_nop (type, expr); return expr; } } } return cp_convert_to_pointer (type, expr); }
tree build_throw (tree exp) { if (exp == error_mark_node) return exp; if (processing_template_decl) { if (cfun) current_function_returns_abnormally = 1; exp = build_min (THROW_EXPR, void_type_node, exp); SET_EXPR_LOCATION (exp, input_location); return exp; } if (exp && null_node_p (exp)) warning (0, "throwing NULL, which has integral, not pointer type"); if (exp != NULL_TREE) { if (!is_admissible_throw_operand_or_catch_parameter (exp, true)) return error_mark_node; } if (! doing_eh ()) return error_mark_node; if (exp) { tree throw_type; tree temp_type; tree cleanup; tree object, ptr; tree tmp; tree allocate_expr; /* The CLEANUP_TYPE is the internal type of a destructor. */ if (!cleanup_type) { tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); cleanup_type = build_pointer_type (tmp); } if (!throw_fn) { tree name = get_identifier ("__cxa_throw"); throw_fn = get_global_binding (name); if (!throw_fn) { /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */ /* ??? Second argument is supposed to be "std::type_info*". */ tmp = build_function_type_list (void_type_node, ptr_type_node, ptr_type_node, cleanup_type, NULL_TREE); throw_fn = push_throw_library_fn (name, tmp); if (flag_tm) { tree itm_name = get_identifier ("_ITM_cxa_throw"); tree itm_fn = get_global_binding (itm_name); if (!itm_fn) itm_fn = push_throw_library_fn (itm_name, tmp); apply_tm_attr (itm_fn, get_identifier ("transaction_pure")); record_tm_replacement (throw_fn, itm_fn); } } } /* [except.throw] A throw-expression initializes a temporary object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from "array of T" or "function return T" to "pointer to T" or "pointer to function returning T" respectively. */ temp_type = is_bitfield_expr_with_lowered_type (exp); if (!temp_type) temp_type = cv_unqualified (type_decays_to (TREE_TYPE (exp))); /* OK, this is kind of wacky. The standard says that we call terminate when the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught (_except.throw_), calls a user function that exits via an uncaught exception. So we have to protect the actual initialization of the exception object with terminate(), but evaluate the expression first. Since there could be temps in the expression, we need to handle that, too. We also expand the call to __cxa_allocate_exception first (which doesn't matter, since it can't throw). */ /* Allocate the space for the exception. */ allocate_expr = do_allocate_exception (temp_type); allocate_expr = get_target_expr (allocate_expr); ptr = TARGET_EXPR_SLOT (allocate_expr); TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr); CLEANUP_EH_ONLY (allocate_expr) = 1; object = build_nop (build_pointer_type (temp_type), ptr); object = cp_build_fold_indirect_ref (object); /* And initialize the exception object. */ if (CLASS_TYPE_P (temp_type)) { int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING; vec<tree, va_gc> *exp_vec; bool converted = false; /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes treated as an rvalue for the purposes of overload resolution to favor move constructors over copy constructors. */ if (/* Must be a local, automatic variable. */ VAR_P (exp) && DECL_CONTEXT (exp) == current_function_decl && ! TREE_STATIC (exp) /* The variable must not have the `volatile' qualifier. */ && !(cp_type_quals (TREE_TYPE (exp)) & TYPE_QUAL_VOLATILE)) { tree moved = move (exp); exp_vec = make_tree_vector_single (moved); moved = (build_special_member_call (object, complete_ctor_identifier, &exp_vec, TREE_TYPE (object), flags|LOOKUP_PREFER_RVALUE, tf_none)); release_tree_vector (exp_vec); if (moved != error_mark_node) { exp = moved; converted = true; } } /* Call the copy constructor. */ if (!converted) { exp_vec = make_tree_vector_single (exp); exp = (build_special_member_call (object, complete_ctor_identifier, &exp_vec, TREE_TYPE (object), flags, tf_warning_or_error)); release_tree_vector (exp_vec); } if (exp == error_mark_node) { error (" in thrown expression"); return error_mark_node; } } else { tmp = decay_conversion (exp, tf_warning_or_error); if (tmp == error_mark_node) return error_mark_node; exp = build2 (INIT_EXPR, temp_type, object, tmp); } /* Mark any cleanups from the initialization as MUST_NOT_THROW, since they are run after the exception object is initialized. */ cp_walk_tree_without_duplicates (&exp, wrap_cleanups_r, 0); /* Prepend the allocation. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); /* Force all the cleanups to be evaluated here so that we don't have to do them during unwinding. */ exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); cleanup = NULL_TREE; if (type_build_dtor_call (TREE_TYPE (object))) { tree dtor_fn = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), complete_dtor_identifier, 0); dtor_fn = BASELINK_FUNCTIONS (dtor_fn); mark_used (dtor_fn); if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object))) { cxx_mark_addressable (dtor_fn); /* Pretend it's a normal function. */ cleanup = build1 (ADDR_EXPR, cleanup_type, dtor_fn); } } if (cleanup == NULL_TREE) cleanup = build_int_cst (cleanup_type, 0); /* ??? Indicate that this function call throws throw_type. */ tmp = cp_build_function_call_nary (throw_fn, tf_warning_or_error, ptr, throw_type, cleanup, NULL_TREE); /* Tack on the initialization stuff. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); } else { /* Rethrow current exception. */ if (!rethrow_fn) { tree name = get_identifier ("__cxa_rethrow"); rethrow_fn = get_global_binding (name); if (!rethrow_fn) /* Declare void __cxa_rethrow (void). */ rethrow_fn = push_throw_library_fn (name, build_function_type_list (void_type_node, NULL_TREE)); if (flag_tm) apply_tm_attr (rethrow_fn, get_identifier ("transaction_pure")); } /* ??? Indicate that this function call allows exceptions of the type of the enclosing catch block (if known). */ exp = cp_build_function_call_vec (rethrow_fn, NULL, tf_warning_or_error); } exp = build1 (THROW_EXPR, void_type_node, exp); SET_EXPR_LOCATION (exp, input_location); return exp; }
void maybe_add_lambda_conv_op (tree type) { bool nested = (cfun != NULL); bool nested_def = decl_function_context (TYPE_MAIN_DECL (type)); tree callop = lambda_function (type); if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE) return; if (processing_template_decl) return; bool const generic_lambda_p = (DECL_TEMPLATE_INFO (callop) && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop); if (!generic_lambda_p && DECL_INITIAL (callop) == NULL_TREE) { /* If the op() wasn't instantiated due to errors, give up. */ gcc_assert (errorcount || sorrycount); return; } /* Non-template conversion operators are defined directly with build_call_a and using DIRECT_ARGVEC for arguments (including 'this'). Templates are deferred and the CALL is built in-place. In the case of a deduced return call op, the decltype expression, DECLTYPE_CALL, used as a substitute for the return type is also built in-place. The arguments of DECLTYPE_CALL in the return expression may differ in flags from those in the body CALL. In particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in the body CALL, but not in DECLTYPE_CALL. */ vec<tree, va_gc> *direct_argvec = 0; tree decltype_call = 0, call = 0; tree fn_result = TREE_TYPE (TREE_TYPE (callop)); if (generic_lambda_p) { /* Prepare the dependent member call for the static member function '_FUN' and, potentially, prepare another call to be used in a decltype return expression for a deduced return call op to allow for simple implementation of the conversion operator. */ tree instance = build_nop (type, null_pointer_node); tree objfn = build_min (COMPONENT_REF, NULL_TREE, instance, DECL_NAME (callop), NULL_TREE); int nargs = list_length (DECL_ARGUMENTS (callop)) - 1; call = prepare_op_call (objfn, nargs); if (type_uses_auto (fn_result)) decltype_call = prepare_op_call (objfn, nargs); } else { direct_argvec = make_tree_vector (); direct_argvec->quick_push (build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)), null_pointer_node)); } /* Copy CALLOP's argument list (as per 'copy_list') as FN_ARGS in order to declare the static member function "_FUN" below. For each arg append to DIRECT_ARGVEC (for the non-template case) or populate the pre-allocated call args (for the template case). If a parameter pack is found, expand it, flagging it as PACK_EXPANSION_LOCAL_P for the body call. */ tree fn_args = NULL_TREE; { int ix = 0; tree src = DECL_CHAIN (DECL_ARGUMENTS (callop)); tree tgt; while (src) { tree new_node = copy_node (src); if (!fn_args) fn_args = tgt = new_node; else { TREE_CHAIN (tgt) = new_node; tgt = new_node; } mark_exp_read (tgt); if (generic_lambda_p) { if (DECL_PACK_P (tgt)) { tree a = make_pack_expansion (tgt); if (decltype_call) CALL_EXPR_ARG (decltype_call, ix) = copy_node (a); PACK_EXPANSION_LOCAL_P (a) = true; CALL_EXPR_ARG (call, ix) = a; } else { tree a = convert_from_reference (tgt); CALL_EXPR_ARG (call, ix) = a; if (decltype_call) CALL_EXPR_ARG (decltype_call, ix) = copy_node (a); } ++ix; } else vec_safe_push (direct_argvec, tgt); src = TREE_CHAIN (src); } } if (generic_lambda_p) { if (decltype_call) { ++processing_template_decl; fn_result = finish_decltype_type (decltype_call, /*id_expression_or_member_access_p=*/false, tf_warning_or_error); --processing_template_decl; } } else call = build_call_a (callop, direct_argvec->length (), direct_argvec->address ()); CALL_FROM_THUNK_P (call) = 1; tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop)); /* First build up the conversion op. */ tree rettype = build_pointer_type (stattype); tree name = mangle_conv_op_name_for_type (rettype); tree thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST); tree fntype = build_method_type_directly (thistype, rettype, void_list_node); tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype); tree fn = convfn; DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) DECL_ALIGN (fn) = 2 * BITS_PER_UNIT; SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR); grokclassfn (type, fn, NO_SPECIAL); set_linkage_according_to_type (type, fn); rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof); DECL_IN_AGGR_P (fn) = 1; DECL_ARTIFICIAL (fn) = 1; DECL_NOT_REALLY_EXTERN (fn) = 1; DECL_DECLARED_INLINE_P (fn) = 1; DECL_ARGUMENTS (fn) = build_this_parm (fntype, TYPE_QUAL_CONST); if (nested_def) DECL_INTERFACE_KNOWN (fn) = 1; if (generic_lambda_p) fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop)); add_method (type, fn, NULL_TREE); /* Generic thunk code fails for varargs; we'll complain in mark_used if the conversion op is used. */ if (varargs_function_p (callop)) { DECL_DELETED_FN (fn) = 1; return; } /* Now build up the thunk to be returned. */ name = get_identifier ("_FUN"); tree statfn = build_lang_decl (FUNCTION_DECL, name, stattype); fn = statfn; DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) DECL_ALIGN (fn) = 2 * BITS_PER_UNIT; grokclassfn (type, fn, NO_SPECIAL); set_linkage_according_to_type (type, fn); rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof); DECL_IN_AGGR_P (fn) = 1; DECL_ARTIFICIAL (fn) = 1; DECL_NOT_REALLY_EXTERN (fn) = 1; DECL_DECLARED_INLINE_P (fn) = 1; DECL_STATIC_FUNCTION_P (fn) = 1; DECL_ARGUMENTS (fn) = fn_args; for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg)) { /* Avoid duplicate -Wshadow warnings. */ DECL_NAME (arg) = NULL_TREE; DECL_CONTEXT (arg) = fn; } if (nested_def) DECL_INTERFACE_KNOWN (fn) = 1; if (generic_lambda_p) fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop)); add_method (type, fn, NULL_TREE); if (nested) push_function_context (); else /* Still increment function_depth so that we don't GC in the middle of an expression. */ ++function_depth; /* Generate the body of the thunk. */ start_preparsed_function (statfn, NULL_TREE, SF_PRE_PARSED | SF_INCLASS_INLINE); if (DECL_ONE_ONLY (statfn)) { /* Put the thunk in the same comdat group as the call op. */ cgraph_node::get_create (statfn)->add_to_same_comdat_group (cgraph_node::get_create (callop)); } tree body = begin_function_body (); tree compound_stmt = begin_compound_stmt (0); if (!generic_lambda_p) { set_flags_from_callee (call); if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call))) call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error); } call = convert_from_reference (call); finish_return_stmt (call); finish_compound_stmt (compound_stmt); finish_function_body (body); fn = finish_function (/*inline*/2); if (!generic_lambda_p) expand_or_defer_fn (fn); /* Generate the body of the conversion op. */ start_preparsed_function (convfn, NULL_TREE, SF_PRE_PARSED | SF_INCLASS_INLINE); body = begin_function_body (); compound_stmt = begin_compound_stmt (0); /* decl_needed_p needs to see that it's used. */ TREE_USED (statfn) = 1; finish_return_stmt (decay_conversion (statfn, tf_warning_or_error)); finish_compound_stmt (compound_stmt); finish_function_body (body); fn = finish_function (/*inline*/2); if (!generic_lambda_p) expand_or_defer_fn (fn); if (nested) pop_function_context (); else --function_depth; }
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; }
tree ocp_convert (tree type, tree expr, int convtype, int flags) { tree e = expr; enum tree_code code = TREE_CODE (type); const char *invalid_conv_diag; if (error_operand_p (e) || type == error_mark_node) return error_mark_node; complete_type (type); complete_type (TREE_TYPE (expr)); if ((invalid_conv_diag = targetm.invalid_conversion (TREE_TYPE (expr), type))) { error (invalid_conv_diag); return error_mark_node; } e = integral_constant_value (e); if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP)) /* We need a new temporary; don't take this shortcut. */; else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e))) { if (same_type_p (type, TREE_TYPE (e))) /* The call to fold will not always remove the NOP_EXPR as might be expected, since if one of the types is a typedef; the comparison in fold is just equality of pointers, not a call to comptypes. We don't call fold in this case because that can result in infinite recursion; fold will call convert, which will call ocp_convert, etc. */ return e; /* For complex data types, we need to perform componentwise conversion. */ else if (TREE_CODE (type) == COMPLEX_TYPE) return fold_if_not_in_template (convert_to_complex (type, e)); else if (TREE_CODE (e) == TARGET_EXPR) { /* Don't build a NOP_EXPR of class type. Instead, change the type of the temporary. */ TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type; return e; } else { /* We shouldn't be treating objects of ADDRESSABLE type as rvalues. */ gcc_assert (!TREE_ADDRESSABLE (type)); return fold_if_not_in_template (build_nop (type, e)); } } if (code == VOID_TYPE && (convtype & CONV_STATIC)) { e = convert_to_void (e, /*implicit=*/NULL, tf_warning_or_error); return e; } if (INTEGRAL_CODE_P (code)) { tree intype = TREE_TYPE (e); if (TREE_CODE (type) == ENUMERAL_TYPE) { /* enum = enum, enum = int, enum = float, (enum)pointer are all errors. */ if (((INTEGRAL_OR_ENUMERATION_TYPE_P (intype) || TREE_CODE (intype) == REAL_TYPE) && ! (convtype & CONV_STATIC)) || TREE_CODE (intype) == POINTER_TYPE) { if (flags & LOOKUP_COMPLAIN) permerror (input_location, "conversion from %q#T to %q#T", intype, type); if (!flag_permissive) return error_mark_node; } /* [expr.static.cast] 8. A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values. Otherwise, the resulting enumeration value is unspecified. */ if (TREE_CODE (expr) == INTEGER_CST && !int_fits_type_p (expr, type)) warning (OPT_Wconversion, "the result of the conversion is unspecified because " "%qE is outside the range of type %qT", expr, type); } if (MAYBE_CLASS_TYPE_P (intype)) { tree rval; rval = build_type_conversion (type, e); if (rval) return rval; if (flags & LOOKUP_COMPLAIN) error ("%q#T used where a %qT was expected", intype, type); return error_mark_node; } if (code == BOOLEAN_TYPE) return cp_truthvalue_conversion (e); return fold_if_not_in_template (convert_to_integer (type, e)); } if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type)) return fold_if_not_in_template (cp_convert_to_pointer (type, e)); if (code == VECTOR_TYPE) { tree in_vtype = TREE_TYPE (e); if (MAYBE_CLASS_TYPE_P (in_vtype)) { tree ret_val; ret_val = build_type_conversion (type, e); if (ret_val) return ret_val; if (flags & LOOKUP_COMPLAIN) error ("%q#T used where a %qT was expected", in_vtype, type); return error_mark_node; } return fold_if_not_in_template (convert_to_vector (type, e)); } if (code == REAL_TYPE || code == COMPLEX_TYPE) { if (MAYBE_CLASS_TYPE_P (TREE_TYPE (e))) { tree rval; rval = build_type_conversion (type, e); if (rval) return rval; else if (flags & LOOKUP_COMPLAIN) error ("%q#T used where a floating point value was expected", TREE_TYPE (e)); } if (code == REAL_TYPE) return fold_if_not_in_template (convert_to_real (type, e)); else if (code == COMPLEX_TYPE) return fold_if_not_in_template (convert_to_complex (type, e)); } /* New C++ semantics: since assignment is now based on memberwise copying, if the rhs type is derived from the lhs type, then we may still do a conversion. */ if (RECORD_OR_UNION_CODE_P (code)) { tree dtype = TREE_TYPE (e); tree ctor = NULL_TREE; dtype = TYPE_MAIN_VARIANT (dtype); /* Conversion between aggregate types. New C++ semantics allow objects of derived type to be cast to objects of base type. Old semantics only allowed this between pointers. There may be some ambiguity between using a constructor vs. using a type conversion operator when both apply. */ ctor = e; if (abstract_virtuals_error (NULL_TREE, type)) return error_mark_node; if (BRACE_ENCLOSED_INITIALIZER_P (ctor)) ctor = perform_implicit_conversion (type, ctor, tf_warning_or_error); else if ((flags & LOOKUP_ONLYCONVERTING) && ! (CLASS_TYPE_P (dtype) && DERIVED_FROM_P (type, dtype))) /* For copy-initialization, first we create a temp of the proper type with a user-defined conversion sequence, then we direct-initialize the target with the temp (see [dcl.init]). */ ctor = build_user_type_conversion (type, ctor, flags); else ctor = build_special_member_call (NULL_TREE, complete_ctor_identifier, build_tree_list (NULL_TREE, ctor), type, flags, tf_warning_or_error); if (ctor) return build_cplus_new (type, ctor); } if (flags & LOOKUP_COMPLAIN) error ("conversion from %qT to non-scalar type %qT requested", TREE_TYPE (expr), 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; }