📄 cp-call.c
字号:
{ basetype = TREE_TYPE (basetype); instance_ptr = instance; } if (! IS_AGGR_TYPE (basetype)) goto non_aggr_error; if (! instance_ptr) { if ((lvalue_p (instance) && (instance_ptr = build_unary_op (ADDR_EXPR, instance, 0))) || (instance_ptr = unary_complex_lvalue (ADDR_EXPR, instance))) { if (instance_ptr == error_mark_node) return error_mark_node; } else if (TREE_CODE (instance) == NOP_EXPR || TREE_CODE (instance) == CONSTRUCTOR) { /* A cast is not an lvalue. Initialize a fresh temp with the value we are casting from, and proceed with that temporary. We can't cast to a reference type, so that simplifies the initialization to something we can manage. */ tree temp = get_temp_name (TREE_TYPE (instance), 0); if (IS_AGGR_TYPE (TREE_TYPE (instance))) expand_aggr_init (temp, instance, 0); else { store_init_value (temp, instance); expand_decl_init (temp); } instance = temp; instance_ptr = build_unary_op (ADDR_EXPR, instance, 0); } else { if (TREE_CODE (instance) != CALL_EXPR) my_friendly_abort (125); if (TYPE_NEEDS_CONSTRUCTOR (basetype)) instance = build_cplus_new (basetype, instance, 0); else { instance = get_temp_name (basetype, 0); TREE_ADDRESSABLE (instance) = 1; } instance_ptr = build_unary_op (ADDR_EXPR, instance, 0); } /* @@ Should we call comp_target_types here? */ inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr)); if (TYPE_MAIN_VARIANT (basetype) == TYPE_MAIN_VARIANT (inst_ptr_basetype)) basetype = inst_ptr_basetype; else { instance_ptr = convert (TYPE_POINTER_TO (basetype), instance_ptr); if (instance_ptr == error_mark_node) return error_mark_node; } } else inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr)); } if (basetype_path == NULL_TREE) basetype_path = TYPE_BINFO (inst_ptr_basetype); result = build_field_call (basetype_path, instance_ptr, name, parms, err_name); if (result) return result; if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype)) { if (TREE_SIDE_EFFECTS (instance_ptr)) { /* This action is needed because the instance is needed for providing the base of the virtual function table. Without using a SAVE_EXPR, the function we are building may be called twice, or side effects on the instance variable (such as a post-increment), may happen twice. */ instance_ptr = save_expr (instance_ptr); instance = build_indirect_ref (instance_ptr, 0); } else if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE) { /* This happens when called for operator new (). */ instance = build_indirect_ref (instance, 0); } need_vtbl = maybe_needed; } } if (TYPE_SIZE (basetype) == 0) { /* This is worth complaining about, I think. */ error_with_aggr_type (basetype, "cannot lookup method in incomplete type `%s'"); return error_mark_node; } save_basetype = basetype;#if 0 if (all_virtual == 1 && (! strncmp (IDENTIFIER_POINTER (name), OPERATOR_METHOD_FORMAT, OPERATOR_METHOD_LENGTH) || instance_ptr == NULL_TREE || (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype) == 0 /*&& TYPE_NEEDS_WRAPPER (basetype) == 0*/ ))) all_virtual = 0;#endif last = NULL_TREE; for (parmtypes = 0, parm = parms; parm; parm = TREE_CHAIN (parm)) { tree t = TREE_TYPE (TREE_VALUE (parm)); if (TREE_CODE (t) == OFFSET_TYPE) { /* Convert OFFSET_TYPE entities to their normal selves. */ TREE_VALUE (parm) = resolve_offset_ref (TREE_VALUE (parm)); t = TREE_TYPE (TREE_VALUE (parm)); } if (TREE_CODE (t) == ARRAY_TYPE) { /* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place. This eliminates needless calls to `compute_conversion_costs'. */ TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm)); t = TREE_TYPE (TREE_VALUE (parm)); } if (t == error_mark_node) return error_mark_node; last = build_tree_list (NULL_TREE, t); parmtypes = chainon (parmtypes, last); } if (instance) { constp = TREE_READONLY (instance); volatilep = TREE_THIS_VOLATILE (instance); parms = tree_cons (NULL_TREE, instance_ptr, parms); } else { /* Raw constructors are always in charge. */ if (TYPE_USES_VIRTUAL_BASECLASSES (basetype) && ! (flags & LOOKUP_HAS_IN_CHARGE)) { flags |= LOOKUP_HAS_IN_CHARGE; parms = tree_cons (NULL_TREE, integer_one_node, parms); parmtypes = tree_cons (NULL_TREE, integer_type_node, parmtypes); } if (flag_this_is_variable > 0) { constp = 0; volatilep = 0; parms = tree_cons (NULL_TREE, build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), integer_zero_node), parms); } else { constp = 0; volatilep = 0; instance_ptr = build_new (NULL_TREE, basetype, void_type_node, 0); if (instance_ptr == error_mark_node) return error_mark_node; instance_ptr = save_expr (instance_ptr); TREE_CALLS_NEW (instance_ptr) = 1; instance = build_indirect_ref (instance_ptr, 0); /* If it's a default argument initialized from a ctor, what we get from instance_ptr will match the arglist for the FUNCTION_DECL of the constructor. */ if (parms && TREE_CODE (TREE_VALUE (parms)) == CALL_EXPR && TREE_OPERAND (TREE_VALUE (parms), 1) && TREE_CALLS_NEW (TREE_VALUE (TREE_OPERAND (TREE_VALUE (parms), 1)))) parms = build_tree_list (NULL_TREE, instance_ptr); else parms = tree_cons (NULL_TREE, instance_ptr, parms); } } parmtypes = tree_cons (NULL_TREE, build_pointer_type (build_type_variant (basetype, constp, volatilep)), parmtypes); if (last == NULL_TREE) last = parmtypes; /* Look up function name in the structure type definition. */ if ((IDENTIFIER_HAS_TYPE_VALUE (name) && IS_AGGR_TYPE (IDENTIFIER_TYPE_VALUE (name))) || name == constructor_name (basetype)) { tree tmp = NULL_TREE; if (IDENTIFIER_TYPE_VALUE (name) == basetype || name == constructor_name (basetype)) tmp = TYPE_BINFO (basetype); else tmp = get_binfo (IDENTIFIER_TYPE_VALUE (name), basetype, 0); if (tmp != 0) { name_kind = "constructor"; if (TYPE_USES_VIRTUAL_BASECLASSES (basetype) && ! (flags & LOOKUP_HAS_IN_CHARGE)) { /* Constructors called for initialization only are never in charge. */ tree tmplist; flags |= LOOKUP_HAS_IN_CHARGE; tmplist = tree_cons (NULL_TREE, integer_zero_node, TREE_CHAIN (parms)); TREE_CHAIN (parms) = tmplist; tmplist = tree_cons (NULL_TREE, integer_type_node, TREE_CHAIN (parmtypes)); TREE_CHAIN (parmtypes) = tmplist; } #ifdef SOS if (TYPE_DYNAMIC (basetype) && dtbl_inserted == 0) { tree parm, parmtype; dtbl = get_sos_dtable (basetype); parm = tree_cons (NULL_TREE, dtbl, TREE_CHAIN (parms)); parmtype = tree_cons (NULL_TREE, build_pointer_type (ptr_type_node), TREE_CHAIN (parmtypes)); TREE_CHAIN (parms) = parm; TREE_CHAIN (parmtypes) = parmtype; dtbl_inserted = -1; }#endif /* constructors are in very specific places. */#ifdef SOS if (dtbl_inserted == -1) { TREE_CHAIN (parmtypes) = TREE_CHAIN (TREE_CHAIN (parmtypes)); TREE_CHAIN (parms) = TREE_CHAIN (TREE_CHAIN (parms)); dtbl_inserted = 0; }#endif basetype = BINFO_TYPE (tmp); } else name_kind = "method"; } else name_kind = "method"; if (basetype_path == NULL_TREE) basetype_path = TYPE_BINFO (basetype); result = lookup_fnfields (basetype_path, name, (flags & LOOKUP_COMPLAIN)); if (result == error_mark_node) return error_mark_node; /* Now, go look for this method name. We do not find destructors here. Putting `void_list_node' on the end of the parmtypes fakes out `build_decl_overload' into doing the right thing. */ TREE_CHAIN (last) = void_list_node; method_name = build_decl_overload (name, parmtypes, 1 + (name == constructor_name (save_basetype))); TREE_CHAIN (last) = NULL_TREE; for (pass = 0; pass < 2; pass++) { struct candidate *candidates; struct candidate *cp; int len; unsigned best = 2; /* This increments every time we go up the type hierarchy. The idea is to prefer a function of the derived class if possible. */ int b_or_d = 0; baselink = result; if (pass > 0) { candidates = (struct candidate *) alloca ((ever_seen+1) * sizeof (struct candidate)); cp = candidates; len = list_length (parms); /* First see if a global function has a shot at it. */ if (flags & LOOKUP_GLOBAL) { tree friend_parms; tree parm = TREE_VALUE (parms); if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE) friend_parms = parms; else if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE) { tree new_type; parm = build_indirect_ref (parm, "friendifying parms (compiler error)"); new_type = build_reference_type (TREE_TYPE (parm)); /* It is possible that this should go down a layer. */ new_type = build_type_variant (new_type, TREE_READONLY (parm), TREE_THIS_VOLATILE (parm)); parm = convert (new_type, parm); friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms)); } else my_friendly_assert (0, 167); cp->harshness = (unsigned short *)alloca ((len+1) * sizeof (short)); result = build_overload_call (name, friend_parms, 0, cp); /* If it turns out to be the one we were actually looking for (it was probably a friend function), the return the good result. */ if (TREE_CODE (result) == CALL_EXPR) return result; while (cp->evil == 0) { /* non-standard uses: set the field to 0 to indicate we are using a non-member function. */ cp->u.field = 0; if (cp->harshness[len] == 0 && cp->harshness[len] == 0 && cp->user == 0 && cp->b_or_d == 0 && cp->easy < best) best = cp->easy; cp += 1; } } } while (baselink) { /* We have a hit (of sorts). If the parameter list is "error_mark_node", or some variant thereof, it won't match any methods. Since we have verified that the is some method vaguely matching this one (in name at least), silently return. Don't stop for friends, however. */ tree basetypes = TREE_PURPOSE (baselink); function = TREE_VALUE (baselink); if (TREE_CODE (basetypes) == TREE_LIST) basetypes = TREE_VALUE (basetypes); basetype = BINFO_TYPE (basetypes); /* Cast the instance variable to the appropriate type. */ TREE_VALUE (parmtypes) = TYPE_POINTER_TO (basetype); if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function))) function = DECL_CHAIN (function); for (; function; function = DECL_CHAIN (function)) {#ifdef GATHER_STATISTICS n_inner_fields_searched++;#endif ever_seen++; /* Not looking for friends here. */ if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE && ! DECL_STATIC_FUNCTION_P (function)) continue; if (pass == 0 && DECL_ASSEMBLER_NAME (function) == method_name) { if (flags & LOOKUP_PROTECT) { visibility = compute_visibility (basetypes, function); if (visibility == visibility_protected && flags & LOOKUP_PROTECTED_OK) visibility = visibility_public; } if ((flags & LOOKUP_PROTECT) == 0 || visibility == visibility_public) goto found_and_ok; else if (visibility == visibility_private) saw_private = function; else if (visibility == visibility_protected) saw_protected = function; /* If we fail on the exact match, we have an immediate failure. */ goto found; } if (pass > 0) { tree these_parms = parms;#ifdef GATHER_STATISTICS n_inner_fields_searched++;#endif cp->harshness = (unsigned short *)alloca ((len+1) * sizeof (short)); if (DECL_STATIC_FUNCTION_P (function)) these_parms = TREE_CHAIN (these_parms); compute_conversion_costs (function, these_parms, cp, len); cp->b_or_d += b_or_d; if (cp->evil == 0) { cp->u.field = function; cp->function = function; if (flags & LOOKUP_PROTECT) { enum visibility_type this_v; this_v = compute_visibility (basetypes, function); if (this_v == visibility_protected && (flags & LOOKUP_PROTECTED_OK)) this_v = visibility_public; if (this_v != visibility_public) { if (this_v == visibility_private) saw_private = function; else saw_protected = function; continue; } } /* No "two-level" conversions. */ if (flags & LOOKUP_NO_CONVERSION && cp->user != 0) continue; /* If we used default parameters, we must check to see whether anyone else might use them also, and report a possible ambiguity. */ if (! TYPE_USES_MULTIPLE_INHERITANCE (save_basetype) && cp->harshness[len] == 0 && CONST_HARSHNESS (cp->harshness[0]) == 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -