📄 call.c
字号:
return NULL_TREE;}/* Resolve an expression NAME1::NAME2::...::NAMEn to 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_NAME (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, scopes, name, parms) tree exp, scopes, 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 basename = resolve_scope_to_name (NULL_TREE, scopes); tree basetype, binfo, decl; tree type = TREE_TYPE (exp); if (type == error_mark_node || basename == NULL_TREE) return error_mark_node; basetype = IDENTIFIER_TYPE_VALUE (basename); if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); /* 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_typedef (basename, 0)) { 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 != get_type_value (name)) cp_error ("qualified type `%T' does not match destructor name `~%T'", basetype, name); return convert (void_type_node, exp); } if (! is_aggr_typedef (basename, 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_or_else (basetype, type))) { if (binfo == error_mark_node) return error_mark_node; if (TREE_CODE (exp) == INDIRECT_REF) decl = build_indirect_ref (convert_pointer_to (binfo, build_unary_op (ADDR_EXPR, exp, 0)), NULL_PTR); else decl = build_scoped_ref (exp, scopes); /* Call to a destructor. */ if (TREE_CODE (name) == BIT_NOT_EXPR) { /* Explicit call to destructor. */ name = TREE_OPERAND (name, 0); if (! (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 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);}/* 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, method_name, parmtypes, parm; tree last; int pass; enum access_type access = access_public; /* 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; 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; /* 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_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 (! ((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 convert (void_type_node, instance); } if (! TYPE_HAS_DESTRUCTOR (basetype)) return 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, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0); } { char *xref_name; /* Initialize name for error reporting. */ if (IDENTIFIER_OPNAME_P (name) && ! IDENTIFIER_TYPENAME_P (name)) { char *p = operator_name_string (name); xref_name = (char *)alloca (strlen (p) + 10); sprintf (xref_name, "operator %s", p); } else if (TREE_CODE (name) == SCOPE_REF) xref_name = IDENTIFIER_POINTER (TREE_OPERAND (name, 1)); else xref_name = IDENTIFIER_POINTER (name); GNU_xref_call (current_function_decl, xref_name); } if (instance == NULL_TREE) { basetype = NULL_TREE; /* Check cases where this is really a call to raise an exception. */ if (current_class_type && TREE_CODE (name) == IDENTIFIER_NODE) { basetype = purpose_member (name, CLASSTYPE_TAGS (current_class_type)); if (basetype) basetype = TREE_VALUE (basetype); } else if (TREE_CODE (name) == SCOPE_REF && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE) { if (! is_aggr_typedef (TREE_OPERAND (name, 0), 1)) return error_mark_node; basetype = purpose_member (TREE_OPERAND (name, 1), CLASSTYPE_TAGS (IDENTIFIER_TYPE_VALUE (TREE_OPERAND (name, 0)))); if (basetype) basetype = TREE_VALUE (basetype); } if (basetype != NULL_TREE) ; /* call to a constructor... */ else if (basetype_path) basetype = BINFO_TYPE (basetype_path); else if (IDENTIFIER_HAS_TYPE_VALUE (name)) { basetype = IDENTIFIER_TYPE_VALUE (name); name = constructor_name_full (basetype); } else { tree typedef_name = lookup_name (name, 1); if (typedef_name && TREE_CODE (typedef_name) == TYPE_DECL) { /* Canonicalize the typedef name. */ basetype = TREE_TYPE (typedef_name); name = TYPE_IDENTIFIER (basetype); } else { cp_error ("no constructor named `%T' in scope", name); return error_mark_node; } } if (! IS_AGGR_TYPE (basetype)) { non_aggr_error: if ((flags & LOOKUP_COMPLAIN) && TREE_CODE (basetype) != ERROR_MARK) cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'", name, instance, basetype); return error_mark_node; } } else if (instance == C_C_D || instance == current_class_decl) { /* When doing initialization, we side-effect the TREE_TYPE of C_C_D, hence we cannot set up BASETYPE from CURRENT_CLASS_TYPE. */ basetype = TREE_TYPE (C_C_D); /* Anything manifestly `this' in constructors and destructors has a known type, so virtual function tables are not needed. */ if (TYPE_VIRTUAL_P (basetype) && !(flags & LOOKUP_NONVIRTUAL)) need_vtbl = (dtor_label || ctor_label) ? unneeded : maybe_needed; /* If `this' is a signature pointer and `name' is not a constructor, we are calling a signature member function. In that case, set the `basetype' to the signature type and dereference the `optr' field. */ if (IS_SIGNATURE_POINTER (basetype) && TYPE_IDENTIFIER (basetype) != name) { basetype = SIGNATURE_TYPE (basetype); instance_ptr = build_optr_ref (instance); instance_ptr = convert (build_pointer_type (basetype), instance_ptr); basetype_path = TYPE_BINFO (basetype); } else { instance = C_C_D; instance_ptr = current_class_decl; basetype_path = TYPE_BINFO (current_class_type); } result = build_field_call (basetype_path, instance_ptr, name, parms); if (result) return result; } else if (TREE_CODE (instance) == RESULT_DECL) { basetype = TREE_TYPE (instance); /* Should we ever have to make a virtual function reference from a RESULT_DECL, know that it must be of fixed type within the scope of this function. */ if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype)) need_vtbl = maybe_needed; instance_ptr = build1 (ADDR_EXPR, build_pointer_type (basetype), instance); } else { /* The MAIN_VARIANT of the type that `instance_ptr' winds up being. */ tree inst_ptr_basetype; static_call_context = (TREE_CODE (instance) == INDIRECT_REF && TREE_CODE (TREE_OPERAND (instance, 0)) == NOP_EXPR && TREE_OPERAND (TREE_OPERAND (instance, 0), 0) == error_mark_node); if (TREE_CODE (instance) == OFFSET_REF) instance = resolve_offset_ref (instance);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -