/* target hook for resolve_overloaded_builtin(). Returns a function call RTX if we can resolve the overloaded builtin */ tree spu_resolve_overloaded_builtin (tree fndecl, tree fnargs) { #define SCALAR_TYPE_P(t) (INTEGRAL_TYPE_P (t) \ || SCALAR_FLOAT_TYPE_P (t) \ || POINTER_TYPE_P (t)) spu_function_code new_fcode, fcode = DECL_FUNCTION_CODE (fndecl) - END_BUILTINS; struct spu_builtin_description *desc; tree match = NULL_TREE; /* The vector types are not available if the backend is not initialized. */ gcc_assert (!flag_preprocess_only); desc = &spu_builtins[fcode]; if (desc->type != B_OVERLOAD) return NULL_TREE; /* Compare the signature of each internal builtin function with the function arguments until a match is found. */ for (new_fcode = fcode + 1; spu_builtins[new_fcode].type == B_INTERNAL; new_fcode++) { tree decl = spu_builtins[new_fcode].fndecl; tree params = TYPE_ARG_TYPES (TREE_TYPE (decl)); tree arg, param; int p; for (param = params, arg = fnargs, p = 0; param != void_list_node; param = TREE_CHAIN (param), arg = TREE_CHAIN (arg), p++) { tree var, arg_type, param_type = TREE_VALUE (param); if (!arg) { error ("insufficient arguments to overloaded function %s", desc->name); return error_mark_node; } var = TREE_VALUE (arg); if (TREE_CODE (var) == NON_LVALUE_EXPR) var = TREE_OPERAND (var, 0); if (TREE_CODE (var) == ERROR_MARK) return NULL_TREE; /* Let somebody else deal with the problem. */ arg_type = TREE_TYPE (var); /* The intrinsics spec does not specify precisely how to resolve generic intrinsics. We require an exact match for vector types and let C do it's usual parameter type checking/promotions for scalar arguments, except for the first argument of intrinsics which don't have a vector parameter. */ if ((!SCALAR_TYPE_P (param_type) || !SCALAR_TYPE_P (arg_type) || ((fcode == SPU_SPLATS || fcode == SPU_PROMOTE || fcode == SPU_HCMPEQ || fcode == SPU_HCMPGT || fcode == SPU_MASKB || fcode == SPU_MASKH || fcode == SPU_MASKW) && p == 0)) && !comptypes (TYPE_MAIN_VARIANT (param_type), TYPE_MAIN_VARIANT (arg_type))) break; } if (param == void_list_node) { if (arg) { error ("too many arguments to overloaded function %s", desc->name); return error_mark_node; } match = decl; break; } } if (match == NULL_TREE) { error ("parameter list does not match a valid signature for %s()", desc->name); return error_mark_node; } return build_function_call (match, fnargs); #undef SCALAR_TYPE_P }
int objcp_comptypes (tree type1, tree type2) { return comptypes (type1, type2, COMPARE_STRICT); }
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; }
int c_types_compatible_p (tree x, tree y) { return comptypes (TYPE_MAIN_VARIANT (x), TYPE_MAIN_VARIANT (y)); }