call.c
来自「GCC编译器源代码」· C语言 代码 · 共 2,271 行 · 第 1/5 页
C
2,271 行
the name that names the above nested type. INNER_TYPES is a chain of nested type names (held together by SCOPE_REFs); OUTER_TYPE is the type we know to enclose INNER_TYPES. Returns NULL_TREE if there is an error. */treeresolve_scope_to_name (outer_type, inner_stuff) tree outer_type, inner_stuff;{ register tree tmp; tree inner_name, inner_type; if (outer_type == NULL_TREE && current_class_type != NULL_TREE) { /* We first try to look for a nesting in our current class context, then try any enclosing classes. */ tree type = current_class_type; while (type && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE)) { tree rval = resolve_scope_to_name (type, inner_stuff); if (rval != NULL_TREE) return rval; type = DECL_CONTEXT (TYPE_MAIN_DECL (type)); } } if (TREE_CODE (inner_stuff) == SCOPE_REF) { inner_name = TREE_OPERAND (inner_stuff, 0); inner_type = TREE_OPERAND (inner_stuff, 1); } else { inner_name = inner_stuff; inner_type = NULL_TREE; } if (outer_type == NULL_TREE) { tree x; /* If we have something that's already a type by itself, use that. */ if (IDENTIFIER_HAS_TYPE_VALUE (inner_name)) { if (inner_type) return resolve_scope_to_name (IDENTIFIER_TYPE_VALUE (inner_name), inner_type); return inner_name; } x = lookup_name (inner_name, 0); if (x && TREE_CODE (x) == NAMESPACE_DECL) { x = lookup_namespace_name (x, inner_type); return x; } return NULL_TREE; } if (! IS_AGGR_TYPE (outer_type)) return NULL_TREE; /* Look for member classes or enums. */ tmp = find_scoped_type (outer_type, inner_name, inner_type); /* If it's not a type in this class, then go down into the base classes and search there. */ if (! tmp && TYPE_BINFO (outer_type)) { tree binfos = TYPE_BINFO_BASETYPES (outer_type); int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; for (i = 0; i < n_baselinks; i++) { tree base_binfo = TREE_VEC_ELT (binfos, i); tmp = resolve_scope_to_name (BINFO_TYPE (base_binfo), inner_stuff); if (tmp) return tmp; } tmp = NULL_TREE; } return tmp;}/* Build a method call of the form `EXP->SCOPES::NAME (PARMS)'. This is how virtual function calls are avoided. */treebuild_scoped_method_call (exp, basetype, name, parms) tree exp, basetype, name, parms;{ /* Because this syntactic form does not allow a pointer to a base class to be `stolen', we need not protect the derived->base conversion that happens here. @@ But we do have to check access privileges later. */ tree binfo, decl; tree type = TREE_TYPE (exp); if (type == error_mark_node || basetype == error_mark_node) return error_mark_node; if (processing_template_decl) { if (TREE_CODE (name) == BIT_NOT_EXPR) { tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 1); name = build_min_nt (BIT_NOT_EXPR, type); } name = build_min_nt (SCOPE_REF, basetype, name); return build_min_nt (METHOD_CALL_EXPR, name, exp, parms, NULL_TREE); } if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); if (TREE_CODE (basetype) == TREE_VEC) { binfo = basetype; basetype = BINFO_TYPE (binfo); } else binfo = NULL_TREE; /* Destructors can be "called" for simple types; see 5.2.4 and 12.4 Note that explicit ~int is caught in the parser; this deals with typedefs and template parms. */ if (TREE_CODE (name) == BIT_NOT_EXPR && ! IS_AGGR_TYPE (basetype)) { if (type != basetype) cp_error ("type of `%E' does not match destructor type `%T' (type was `%T')", exp, basetype, type); name = TREE_OPERAND (name, 0); if (basetype != name && basetype != get_type_value (name)) cp_error ("qualified type `%T' does not match destructor name `~%T'", basetype, name); return cp_convert (void_type_node, exp); } if (! is_aggr_type (basetype, 1)) return error_mark_node; if (! IS_AGGR_TYPE (type)) { cp_error ("base object `%E' of scoped method call is of non-aggregate type `%T'", exp, type); return error_mark_node; } if (! binfo) { binfo = get_binfo (basetype, type, 1); if (binfo == error_mark_node) return error_mark_node; if (! binfo) error_not_base_type (basetype, type); } if (binfo) { if (TREE_CODE (exp) == INDIRECT_REF) decl = build_indirect_ref (convert_pointer_to_real (binfo, build_unary_op (ADDR_EXPR, exp, 0)), NULL_PTR); else decl = build_scoped_ref (exp, basetype); /* Call to a destructor. */ if (TREE_CODE (name) == BIT_NOT_EXPR) { /* Explicit call to destructor. */ name = TREE_OPERAND (name, 0); if (! (name == TYPE_MAIN_VARIANT (TREE_TYPE (decl)) || name == constructor_name (TREE_TYPE (decl)) || TREE_TYPE (decl) == get_type_value (name))) { cp_error ("qualified type `%T' does not match destructor name `~%T'", TREE_TYPE (decl), name); return error_mark_node; } if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl))) return cp_convert (void_type_node, exp); return build_delete (TREE_TYPE (decl), decl, integer_two_node, LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); } /* Call to a method. */ return build_method_call (decl, name, parms, binfo, LOOKUP_NORMAL|LOOKUP_NONVIRTUAL); } return error_mark_node;}static voidprint_candidates (candidates) tree candidates;{ cp_error_at ("candidates are: %D", TREE_VALUE (candidates)); candidates = TREE_CHAIN (candidates); while (candidates) { cp_error_at (" %D", TREE_VALUE (candidates)); candidates = TREE_CHAIN (candidates); }}static voidprint_n_candidates (candidates, n) struct candidate *candidates; int n;{ int i; cp_error_at ("candidates are: %D", candidates[0].function); for (i = 1; i < n; i++) cp_error_at (" %D", candidates[i].function);}/* We want the address of a function or method. We avoid creating a pointer-to-member function. */treebuild_addr_func (function) tree function;{ tree type = TREE_TYPE (function); /* We have to do these by hand to avoid real pointer to member functions. */ if (TREE_CODE (type) == METHOD_TYPE) { tree addr; type = build_pointer_type (type); if (mark_addressable (function) == 0) return error_mark_node; addr = build1 (ADDR_EXPR, type, function); /* Address of a static or external variable or function counts as a constant */ if (staticp (function)) TREE_CONSTANT (addr) = 1; function = addr; } else function = default_conversion (function); return function;}/* Build a CALL_EXPR, we can handle FUNCTION_TYPEs, METHOD_TYPEs, or POINTER_TYPE to those. Note, pointer to member function types (TYPE_PTRMEMFUNC_P) must be handled by our callers. */treebuild_call (function, result_type, parms) tree function, result_type, parms;{ int is_constructor = 0; function = build_addr_func (function); if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function))) { sorry ("unable to call pointer to member function here"); return error_mark_node; } if (TREE_CODE (function) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (TREE_OPERAND (function, 0))) is_constructor = 1; function = build_nt (CALL_EXPR, function, parms, NULL_TREE); TREE_HAS_CONSTRUCTOR (function) = is_constructor; TREE_TYPE (function) = result_type; TREE_SIDE_EFFECTS (function) = 1; return function;}static treedefault_parm_conversions (parms, last) tree parms, *last;{ tree parm, parmtypes = NULL_TREE; *last = NULL_TREE; for (parm = parms; parm; parm = TREE_CHAIN (parm)) { tree t = TREE_TYPE (TREE_VALUE (parm)); if (TREE_CODE (t) == OFFSET_TYPE || TREE_CODE (t) == METHOD_TYPE || TREE_CODE (t) == FUNCTION_TYPE) { 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); } return parmtypes;}/* Build something of the form ptr->method (args) or object.method (args). This can also build calls to constructors, and find friends. Member functions always take their class variable as a pointer. INSTANCE is a class instance. NAME is the name of the method desired, usually an IDENTIFIER_NODE. PARMS help to figure out what that NAME really refers to. BASETYPE_PATH, if non-NULL, contains a chain from the type of INSTANCE down to the real instance type to use for access checking. We need this information to get protected accesses correct. This parameter is used by build_member_call. FLAGS is the logical disjunction of zero or more LOOKUP_ flags. See cp-tree.h for more info. If this is all OK, calls build_function_call with the resolved member function. This function must also handle being called to perform initialization, promotion/coercion of arguments, and instantiation of default parameters. Note that NAME may refer to an instance variable name. If `operator()()' is defined for the type of that field, then we return that result. */treebuild_method_call (instance, name, parms, basetype_path, flags) tree instance, name, parms, basetype_path; int flags;{ register tree function, fntype, value_type; register tree basetype, save_basetype; register tree baselink, result, parmtypes; tree last; int pass; tree access = access_public_node; tree orig_basetype = basetype_path ? BINFO_TYPE (basetype_path) : NULL_TREE; /* Range of cases for vtable optimization. */ enum vtable_needs { not_needed, maybe_needed, unneeded, needed }; enum vtable_needs need_vtbl = not_needed; char *name_kind; tree save_name = name; int ever_seen = 0; tree instance_ptr = NULL_TREE; int all_virtual = flag_all_virtual; int static_call_context = 0; tree found_fns = NULL_TREE; /* Keep track of `const' and `volatile' objects. */ int constp, volatilep;#ifdef GATHER_STATISTICS n_build_method_call++;#endif if (instance == error_mark_node || name == error_mark_node || parms == error_mark_node || (instance != NULL_TREE && TREE_TYPE (instance) == error_mark_node)) return error_mark_node; if (processing_template_decl) { if (TREE_CODE (name) == BIT_NOT_EXPR) { tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 1); name = build_min_nt (BIT_NOT_EXPR, type); } return build_min_nt (METHOD_CALL_EXPR, name, instance, parms, NULL_TREE); } /* This is the logic that magically deletes the second argument to operator delete, if it is not needed. */ if (name == ansi_opname[(int) DELETE_EXPR] && list_length (parms)==2) { tree save_last = TREE_CHAIN (parms); tree result; /* get rid of unneeded argument */ TREE_CHAIN (parms) = NULL_TREE; result = build_method_call (instance, name, parms, basetype_path, (LOOKUP_SPECULATIVELY|flags) &~LOOKUP_COMPLAIN); /* If it finds a match, return it. */ if (result) return build_method_call (instance, name, parms, basetype_path, flags); /* If it doesn't work, two argument delete must work */ TREE_CHAIN (parms) = save_last; } /* We already know whether it's needed or not for vec delete. */ else if (name == ansi_opname[(int) VEC_DELETE_EXPR] && TYPE_LANG_SPECIFIC (TREE_TYPE (instance)) && ! TYPE_VEC_DELETE_TAKES_SIZE (TREE_TYPE (instance))) TREE_CHAIN (parms) = NULL_TREE; if (TREE_CODE (name) == BIT_NOT_EXPR) { flags |= LOOKUP_DESTRUCTOR; name = TREE_OPERAND (name, 0); if (parms) error ("destructors take no parameters"); basetype = TREE_TYPE (instance); if (TREE_CODE (basetype) == REFERENCE_TYPE) basetype = TREE_TYPE (basetype); if (! (name == basetype || (IS_AGGR_TYPE (basetype) && name == constructor_name (basetype)) || basetype == get_type_value (name))) { cp_error ("destructor name `~%D' does not match type `%T' of expression", name, basetype); return cp_convert (void_type_node, instance); } if (! TYPE_HAS_DESTRUCTOR (complete_type (basetype))) return cp_convert (void_type_node, instance); instance = default_conversion (instance); instance_ptr = build_unary_op (ADDR_EXPR, instance, 0); return build_delete (build_pointer_type (basetype), instance_ptr, integer_two_node,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?