📄 call.c
字号:
/* the base type of an instance variable is pointer to class */ basetype = TREE_TYPE (instance); if (TREE_CODE (basetype) == REFERENCE_TYPE) { basetype = TREE_TYPE (basetype); if (! IS_AGGR_TYPE (basetype)) goto non_aggr_error; /* Call to convert not needed because we are remaining within the same type. */ instance_ptr = build1 (NOP_EXPR, build_pointer_type (basetype), instance); inst_ptr_basetype = TYPE_MAIN_VARIANT (basetype); } else { if (! IS_AGGR_TYPE (basetype) && ! (TYPE_LANG_SPECIFIC (basetype) && (IS_SIGNATURE_POINTER (basetype) || IS_SIGNATURE_REFERENCE (basetype)))) goto non_aggr_error; /* If `instance' is a signature pointer/reference and `name' is not a constructor, we are calling a signature member function. In that case set the `basetype' to the signature type. */ if ((IS_SIGNATURE_POINTER (basetype) || IS_SIGNATURE_REFERENCE (basetype)) && TYPE_IDENTIFIER (basetype) != name) basetype = SIGNATURE_TYPE (basetype); if ((IS_SIGNATURE (basetype) && (instance_ptr = instance)) || (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, flags); 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_CONSTRUCTING (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? */ if (IS_SIGNATURE (basetype)) inst_ptr_basetype = basetype; else 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 (build_pointer_type (basetype), instance_ptr); if (instance_ptr == error_mark_node) return error_mark_node; } } /* After converting `instance_ptr' above, `inst_ptr_basetype' was not updated, so we use `basetype' instead. */ if (basetype_path == NULL_TREE && IS_SIGNATURE (basetype)) basetype_path = TYPE_BINFO (basetype); else if (basetype_path == NULL_TREE || BINFO_TYPE (basetype_path) != TYPE_MAIN_VARIANT (inst_ptr_basetype)) basetype_path = TYPE_BINFO (inst_ptr_basetype); result = build_field_call (basetype_path, instance_ptr, name, parms); 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, NULL_PTR); } else if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE) { /* This happens when called for operator new (). */ instance = build_indirect_ref (instance, NULL_PTR); } need_vtbl = maybe_needed; } } if (TYPE_SIZE (basetype) == 0) { /* This is worth complaining about, I think. */ cp_error ("cannot lookup method in incomplete type `%T'", basetype); return error_mark_node; } save_basetype = TYPE_MAIN_VARIANT (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))) all_virtual = 0;#endif last = NULL_TREE; for (parmtypes = NULL_TREE, 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 (TREE_VALUE (parm)) == OFFSET_REF && TREE_CODE (t) == METHOD_TYPE) { TREE_VALUE (parm) = build_unary_op (ADDR_EXPR, TREE_VALUE (parm), 0); }#if 0 /* This breaks reference-to-array parameters. */ 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)); }#endif if (t == error_mark_node) return error_mark_node; last = build_tree_list (NULL_TREE, t); parmtypes = chainon (parmtypes, last); } if (instance && IS_SIGNATURE (basetype)) { /* @@ Should this be the constp/volatilep flags for the optr field of the signature pointer? */ constp = TYPE_READONLY (basetype); volatilep = TYPE_VOLATILE (basetype); parms = tree_cons (NULL_TREE, instance_ptr, parms); } else if (instance) { /* TREE_READONLY (instance) fails for references. */ constp = TYPE_READONLY (TREE_TYPE (TREE_TYPE (instance_ptr))); volatilep = TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (instance_ptr))); 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); } constp = 0; volatilep = 0; instance_ptr = build_int_2 (0, 0); TREE_TYPE (instance_ptr) = build_pointer_type (basetype); parms = tree_cons (NULL_TREE, instance_ptr, parms); } parmtypes = tree_cons (NULL_TREE, TREE_TYPE (instance_ptr), parmtypes); if (last == NULL_TREE) last = parmtypes; /* Look up function name in the structure type definition. */ if ((IDENTIFIER_HAS_TYPE_VALUE (name) && ! IDENTIFIER_OPNAME_P (name) && IS_AGGR_TYPE (IDENTIFIER_TYPE_VALUE (name)) && TREE_CODE (IDENTIFIER_TYPE_VALUE (name)) != UNINSTANTIATED_P_TYPE) || 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 != NULL_TREE) { 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; } basetype = BINFO_TYPE (tmp); } else name_kind = "method"; } else name_kind = "method"; if (basetype_path == NULL_TREE || BINFO_TYPE (basetype_path) != TYPE_MAIN_VARIANT (basetype)) basetype_path = TYPE_BINFO (basetype); result = lookup_fnfields (basetype_path, name, (flags & LOOKUP_COMPLAIN)); if (result == error_mark_node) return error_mark_node;#if 0 /* 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) || name == constructor_name_full (save_basetype))); TREE_CHAIN (last) = NULL_TREE;#endif for (pass = 0; pass < 2; pass++) { struct candidate *candidates; struct candidate *cp; int len; unsigned best = 1; /* 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)); bzero ((char *) candidates, (ever_seen + 1) * sizeof (struct candidate)); cp = candidates; len = list_length (parms); ever_seen = 0; /* First see if a global function has a shot at it. */ if (flags & LOOKUP_GLOBAL) { tree friend_parms; tree parm = instance_ptr; if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE) parm = convert_from_reference (parm); else if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE) parm = build_indirect_ref (parm, "friendifying parms (compiler error)"); else my_friendly_abort (167); friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms)); cp->h_len = len; cp->harshness = (struct harshness_code *) alloca ((len + 1) * sizeof (struct harshness_code)); 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->h.code & EVIL_CODE) == 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].distance == 0 && cp->h.code < best) best = cp->h.code; 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. */ basetype_path = TREE_PURPOSE (baselink); function = TREE_VALUE (baselink); if (TREE_CODE (basetype_path) == TREE_LIST) basetype_path = TREE_VALUE (basetype_path); basetype = BINFO_TYPE (basetype_path);#if 0 /* Cast the instance variable if necessary. */ if (basetype != TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_VALUE (parms))))) { if (basetype == save_basetype) TREE_VALUE (parms) = instance_ptr; else { tree type = build_pointer_type (build_type_variant (basetype, constp, volatilep)); TREE_VALUE (parms) = convert_force (type, instance_ptr, 0); } } /* FIXME: this is the wrong place to get an error. Hopefully the access-control rewrite will make this change more cleanly. */ if (TREE_VALUE (parms) == error_mark_node) return error_mark_node;#endif 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++; if (pass > 0) found_fns = tree_cons (NULL_TREE, function, found_fns); /* Not looking for friends here. */ if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE && ! DECL_STATIC_FUNCTION_P (function)) continue;#if 0 if (pass == 0 && DECL_ASSEMBLER_NAME (function) == method_name) goto found;#endif if (pass > 0) { tree these_parms = parms;#ifdef GATHER_STATISTICS n_inner_fields_searched++;#endif cp->h_len = len; cp->harshness = (struct harshness_code *) alloca ((len + 1) * sizeof (struct harshness_code)); if (DECL_STATIC_FUNCTION_P (function)) these_parms = TREE_CHAIN (these_parms); compute_conversion_costs (function, these_parms, cp, len); if ((cp->h.code & EVIL_CODE) == 0) { cp->u.field = function; cp->function = function; cp->basetypes = basetype_path; /* Don't allow non-converting constructors to convert. */ if (flags & LOOKUP_ONLYCONVERTING && DECL_LANG_SPECIFIC (function) && DECL_NONCONVERTING_P (function)) continue; /* No "two-level" conversions. */ if (flags & LOOKUP_NO_CONVERSION && (cp->h.code & USER_CODE)) continue; cp++; } } } /* Now we have run through one link's member functions. arrange to head-insert this link's links. */ baselink = next_baselink (baselink); b_or_d += 1; /* Don't grab functions from base classes. lookup_fnfield will do the work to get us down into the right place. */ baselink = NULL_TREE; } if (pass == 0) { tree igv = lookup_name_nonclass (name); /* No exact match could be found. Now try to find match using default conversions. */ if ((flags & LOOKUP_GLOBAL) && igv) { if (TREE_CODE (igv) == FUNCTION_DECL) ever_seen += 1; else if (TREE_CODE (igv) == TREE_LIST) ever_seen += count_functions (igv); } if (ever_seen == 0) { if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN)) == LOOKUP_SPECULATIVELY)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -