📄 method.c
字号:
&& ! IDENTIFIER_LOCAL_VALUE (name));}#endif/* Given a tree_code CODE, and some arguments (at least one), attempt to use an overloaded operator on the arguments. For unary operators, only the first argument need be checked. For binary operators, both arguments may need to be checked. Member functions can convert class references to class pointers, for one-level deep indirection. More than that is not supported. Operators [](), ()(), and ->() must be member functions. We call function call building calls with LOOKUP_COMPLAIN if they are our only hope. This is true when we see a vanilla operator applied to something of aggregate type. If this fails, we are free to return `error_mark_node', because we will have reported the error. Operators NEW and DELETE overload in funny ways: operator new takes a single `size' parameter, and operator delete takes a pointer to the storage being deleted. When overloading these operators, success is assumed. If there is a failure, report an error message and return `error_mark_node'. *//* NOSTRICT */treebuild_opfncall (code, flags, xarg1, xarg2, arg3) enum tree_code code; int flags; tree xarg1, xarg2, arg3;{ tree rval = 0; tree arg1, arg2; tree type1, type2, fnname; tree fields1 = 0, parms = 0; tree global_fn; int try_second; int binary_is_unary; if (xarg1 == error_mark_node) return error_mark_node; if (code == COND_EXPR) { if (TREE_CODE (xarg2) == ERROR_MARK || TREE_CODE (arg3) == ERROR_MARK) return error_mark_node; } if (code == COMPONENT_REF) if (TREE_CODE (TREE_TYPE (xarg1)) == POINTER_TYPE) return rval; /* First, see if we can work with the first argument */ type1 = TREE_TYPE (xarg1); /* Some tree codes have length > 1, but we really only want to overload them if their first argument has a user defined type. */ switch (code) { case PREINCREMENT_EXPR: case PREDECREMENT_EXPR: case POSTINCREMENT_EXPR: case POSTDECREMENT_EXPR: case COMPONENT_REF: binary_is_unary = 1; try_second = 0; break; /* ARRAY_REFs and CALL_EXPRs must overload successfully. If they do not, return error_mark_node instead of NULL_TREE. */ case ARRAY_REF: if (xarg2 == error_mark_node) return error_mark_node; case CALL_EXPR: rval = error_mark_node; binary_is_unary = 0; try_second = 0; break; case VEC_NEW_EXPR: case NEW_EXPR: { tree args = tree_cons (NULL_TREE, xarg2, arg3); fnname = ansi_opname[(int) code]; if (flags & LOOKUP_GLOBAL) return build_overload_call (fnname, args, flags & LOOKUP_COMPLAIN, (struct candidate *)0); rval = build_method_call (build_indirect_ref (build1 (NOP_EXPR, xarg1, error_mark_node), "new"), fnname, args, NULL_TREE, flags); if (rval == error_mark_node) /* User might declare fancy operator new, but invoke it like standard one. */ return rval; TREE_TYPE (rval) = xarg1; TREE_CALLS_NEW (rval) = 1; return rval; } break; case VEC_DELETE_EXPR: case DELETE_EXPR: { fnname = ansi_opname[(int) code]; if (flags & LOOKUP_GLOBAL) return build_overload_call (fnname, build_tree_list (NULL_TREE, xarg1), flags & LOOKUP_COMPLAIN, (struct candidate *)0); rval = build_method_call (build_indirect_ref (build1 (NOP_EXPR, TREE_TYPE (xarg1), error_mark_node), NULL_PTR), fnname, tree_cons (NULL_TREE, xarg1, build_tree_list (NULL_TREE, xarg2)), NULL_TREE, flags);#if 0 /* This can happen when operator delete is protected. */ my_friendly_assert (rval != error_mark_node, 250); TREE_TYPE (rval) = void_type_node;#endif return rval; } break; default: binary_is_unary = 0; try_second = tree_code_length [(int) code] == 2; if (try_second && xarg2 == error_mark_node) return error_mark_node; break; } if (try_second && xarg2 == error_mark_node) return error_mark_node; /* What ever it was, we do not know how to deal with it. */ if (type1 == NULL_TREE) return rval; if (TREE_CODE (type1) == OFFSET_TYPE) type1 = TREE_TYPE (type1); if (TREE_CODE (type1) == REFERENCE_TYPE) { arg1 = convert_from_reference (xarg1); type1 = TREE_TYPE (arg1); } else { arg1 = xarg1; } if (!IS_AGGR_TYPE (type1) || TYPE_PTRMEMFUNC_P (type1)) { /* Try to fail. First, fail if unary */ if (! try_second) return rval; /* Second, see if second argument is non-aggregate. */ type2 = TREE_TYPE (xarg2); if (TREE_CODE (type2) == OFFSET_TYPE) type2 = TREE_TYPE (type2); if (TREE_CODE (type2) == REFERENCE_TYPE) { arg2 = convert_from_reference (xarg2); type2 = TREE_TYPE (arg2); } else { arg2 = xarg2; } if (!IS_AGGR_TYPE (type2)) return rval; try_second = 0; } if (try_second) { /* First arg may succeed; see whether second should. */ type2 = TREE_TYPE (xarg2); if (TREE_CODE (type2) == OFFSET_TYPE) type2 = TREE_TYPE (type2); if (TREE_CODE (type2) == REFERENCE_TYPE) { arg2 = convert_from_reference (xarg2); type2 = TREE_TYPE (arg2); } else { arg2 = xarg2; } if (! IS_AGGR_TYPE (type2)) try_second = 0; } if (type1 == unknown_type_node || (try_second && TREE_TYPE (xarg2) == unknown_type_node)) { /* This will not be implemented in the foreseeable future. */ return rval; } if (code == MODIFY_EXPR) fnname = ansi_assopname[(int) TREE_CODE (arg3)]; else fnname = ansi_opname[(int) code]; global_fn = lookup_name_nonclass (fnname); /* This is the last point where we will accept failure. This may be too eager if we wish an overloaded operator not to match, but would rather a normal operator be called on a type-converted argument. */ if (IS_AGGR_TYPE (type1)) { fields1 = lookup_fnfields (TYPE_BINFO (type1), fnname, 0); /* ARM $13.4.7, prefix/postfix ++/--. */ if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR) { xarg2 = integer_zero_node; binary_is_unary = 0; if (fields1) { tree t, t2; int have_postfix = 0; /* Look for an `operator++ (int)'. If they didn't have one, then we fall back to the old way of doing things. */ for (t = TREE_VALUE (fields1); t ; t = DECL_CHAIN (t)) { t2 = TYPE_ARG_TYPES (TREE_TYPE (t)); if (TREE_CHAIN (t2) != NULL_TREE && TREE_VALUE (TREE_CHAIN (t2)) == integer_type_node) { have_postfix = 1; break; } } if (! have_postfix) { char *op = POSTINCREMENT_EXPR ? "++" : "--"; /* There's probably a LOT of code in the world that relies upon this old behavior. */ if (! flag_traditional) pedwarn ("no `operator%s (int)' declared for postfix `%s', using prefix operator instead", op, op); xarg2 = NULL_TREE; binary_is_unary = 1; } } } } if (fields1 == NULL_TREE && global_fn == NULL_TREE) return rval; /* If RVAL winds up being `error_mark_node', we will return that... There is no way that normal semantics of these operators will succeed. */ /* This argument may be an uncommitted OFFSET_REF. This is the case for example when dealing with static class members which are referenced from their class name rather than from a class instance. */ if (TREE_CODE (xarg1) == OFFSET_REF && TREE_CODE (TREE_OPERAND (xarg1, 1)) == VAR_DECL) xarg1 = TREE_OPERAND (xarg1, 1); if (try_second && xarg2 && TREE_CODE (xarg2) == OFFSET_REF && TREE_CODE (TREE_OPERAND (xarg2, 1)) == VAR_DECL) xarg2 = TREE_OPERAND (xarg2, 1); if (global_fn) flags |= LOOKUP_GLOBAL; if (code == CALL_EXPR) { /* This can only be a member function. */ return build_method_call (xarg1, fnname, xarg2, NULL_TREE, LOOKUP_NORMAL); } else if (tree_code_length[(int) code] == 1 || binary_is_unary) { parms = NULL_TREE; rval = build_method_call (xarg1, fnname, NULL_TREE, NULL_TREE, flags); } else if (code == COND_EXPR) { parms = tree_cons (0, xarg2, build_tree_list (NULL_TREE, arg3)); rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags); } else if (code == METHOD_CALL_EXPR) { /* must be a member function. */ parms = tree_cons (NULL_TREE, xarg2, arg3); return build_method_call (xarg1, fnname, parms, NULL_TREE, LOOKUP_NORMAL); } else if (fields1) { parms = build_tree_list (NULL_TREE, xarg2); rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags); } else { parms = tree_cons (NULL_TREE, xarg1, build_tree_list (NULL_TREE, xarg2)); rval = build_overload_call (fnname, parms, flags, (struct candidate *)0); } return rval;}/* This function takes an identifier, ID, and attempts to figure out what it means. There are a number of possible scenarios, presented in increasing order of hair: 1) not in a class's scope 2) in class's scope, member name of the class's method 3) in class's scope, but not a member name of the class 4) in class's scope, member name of a class's variable NAME is $1 from the bison rule. It is an IDENTIFIER_NODE. VALUE is $$ from the bison rule. It is the value returned by lookup_name ($1) yychar is the pending input character (suitably encoded :-). As a last ditch, try to look up the name as a label and return that address. Values which are declared as being of REFERENCE_TYPE are automatically dereferenced here (as a hack to make the compiler faster). */treehack_identifier (value, name, yychar) tree value, name; int yychar;{ tree type; if (TREE_CODE (value) == ERROR_MARK) { if (current_class_name) { tree fields = lookup_fnfields (TYPE_BINFO (current_class_type), name, 1); if (fields == error_mark_node) return error_mark_node; if (fields) { tree fndecl; fndecl = TREE_VALUE (fields); my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 251); if (DECL_CHAIN (fndecl) == NULL_TREE) { warning ("methods cannot be converted to function pointers"); return fndecl; } else { error ("ambiguous request for method pointer `%s'", IDENTIFIER_POINTER (name)); return error_mark_node; } } } if (flag_labels_ok && IDENTIFIER_LABEL_VALUE (name)) { return IDENTIFIER_LABEL_VALUE (name); } return error_mark_node; } type = TREE_TYPE (value); if (TREE_CODE (value) == FIELD_DECL) { if (current_class_decl == NULL_TREE) { error ("request for member `%s' in static member function", IDENTIFIER_POINTER (DECL_NAME (value))); return error_mark_node; } TREE_USED (current_class_decl) = 1; /* Mark so that if we are in a constructor, and then find that this field was initialized by a base initializer, we can emit an error message. */ TREE_USED (value) = 1; return build_component_ref (C_C_D, name, 0, 1); } if (really_overloaded_fn (value)) { tree t = get_first_fn (value); for (; t; t = DECL_CHAIN (t)) { if (TREE_CODE (t) == TEMPLATE_DECL) continue; assemble_external (t); TREE_USED (t) = 1; } } else if (TREE_CODE (value) == TREE_LIST) { tree t = value; while (t && TREE_CODE (t) == TREE_LIST) { assemble_external (TREE_VALUE (t)); TREE_USED (t) = 1; t = TREE_CHAIN (t); } } else { assemble_external (value); TREE_USED (value) = 1; } if (TREE_CODE_CLASS (TREE_CODE (value)) == 'd' && DECL_NONLOCAL (value)) { if (DECL_LANG_SPECIFIC (value) && DECL_CLASS_CONTEXT (value) != current_class_type) { tree path; enum access_type access; register tree context = (TREE_CODE (value) == FUNCTION_DECL && DECL_VIRTUAL_P (value)) ? DECL_CLASS_CONTEXT (value) : DECL_CONTEXT (value); get_base_distance (context, current_class_type, 0, &path); if (path) { access = compute_access (path, value); if (access != access_public) { if (TREE_CODE (value) == VAR_DECL) error ("static member `%s' is %s", IDENTIFIER_POINTER (name), TREE_PRIVATE (value) ? "private" : "from a private base class"); else error ("enum `%s' is from private base class", IDENTIFIER_POINTER (name)); return error_mark_node; } } } return value; } if (TREE_CODE (value) == TREE_LIST && TREE_NONLOCAL_FLAG (value)) { if (type == 0) { error ("request for member `%s' is ambiguous in multiple inheritance lattice", IDENTIFIER_POINTER (name)); return error_mark_node; } return value; } if (TREE_CODE (type) == REFERENCE_TYPE) { my_friendly_assert (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL || TREE_CODE (value) == RESULT_DECL, 252); return convert_from_reference (value); } return value;}#if 0/* Given an object OF, and a type conversion operator COMPONENT build a call to the conversion operator, if a call is requested, or return the address (as a pointer to member function) if one is not. OF can be a TYPE_DECL or any kind of datum that would normally be passed to `build_component_ref'. It may also be NULL_TREE, in which case `current_class_type' and `current_class_decl' provide default values. BASETYPE_PATH, if non-null, is the path of basetypes to go through before we get the the instance of interest. PROTECT says whether we apply C++ scoping rules or not. */treebuild_component_type_expr (of, component, basetype_path, protect) tree of, component, basetype_path; int protect;{ tree cname = NULL_TREE; tree tmp, last; tree name; int flags = protect ? LOOKUP_NORMAL : LOOKUP_COMPLAIN; if (of) my_friendly_assert (IS_AGGR_TYPE (TREE_TYPE (of)), 253); my_friendly_assert (TREE_CODE (component) == TYPE_EXPR, 254); tmp = TREE_OPERAND (component, 0); last = NULL_TREE; while (tmp) { switch (TREE_CODE (tmp)) { case CALL_EXPR: if (last) TREE_OPERAND (last, 0) = TREE_OPERAND (tmp, 0); else TREE_OPERAND (component, 0) = TREE_OPERAND (tmp, 0); last = groktypename (build_tree_list (TREE_TYPE (component), TREE_OPERAND (component, 0))); name = build_typename_overload (last); TREE_TYPE (name) = last; if (TREE_OPERAND (tmp, 0) && TREE_OPERAND (tmp, 0) != void_list_node) { cp_error ("`operator %T' requires empty parameter list", last); TREE_OPERAND (tmp, 0) = NULL_TREE; } if (of && TREE_CODE (of) != TYPE_DECL) return build_method_call (of, name, NULL_TREE, NULL_TREE, flags); else if (of) { tree this_this; if (current_class_decl == NULL_TREE) { cp_error ("object required for `operator %T' call", TREE_TYPE (name)); return error_mark_node; } this_this = convert_pointer_to (TREE_TYPE (of), current_class_decl); this_this = build_indirect_ref (this_this, NULL_PTR); return build_method_call (this_this, name, NULL_TREE, NULL_TREE, flags | LOOKUP_NONVIRTUAL); } else if (current_class_decl) return build_method_call (tmp, name, NULL_TREE, NULL_TREE, flags); cp_error ("object required for `operator %T' call", TREE_TYPE (name)); return error_mark_node; case INDIRECT_REF: case ADDR_EXPR: case ARRAY_REF: break; case SCOPE_REF: my_friendly_assert (cname == 0, 255);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -