method.c
来自「GCC编译器源代码」· C语言 代码 · 共 2,227 行 · 第 1/4 页
C
2,227 行
tree tparms; tree targs; int for_method;{ char *name = IDENTIFIER_POINTER (dname); /* member operators new and delete look like methods at this point. */ if (! for_method && parms != NULL_TREE && TREE_CODE (parms) == TREE_LIST) { if (dname == ansi_opname[(int) DELETE_EXPR]) return get_identifier ("__builtin_delete"); else if (dname == ansi_opname[(int) VEC_DELETE_EXPR]) return get_identifier ("__builtin_vec_delete"); else if (TREE_CHAIN (parms) == void_list_node) { if (dname == ansi_opname[(int) NEW_EXPR]) return get_identifier ("__builtin_new"); else if (dname == ansi_opname[(int) VEC_NEW_EXPR]) return get_identifier ("__builtin_vec_new"); } } OB_INIT (); if (for_method != 2) OB_PUTCP (name); /* Otherwise, we can divine that this is a constructor, and figure out its name without any extra encoding. */ OB_PUTC2 ('_', '_'); if (for_method) {#if 0 /* We can get away without doing this. */ OB_PUTC ('M');#endif if (tparms != NULL_TREE) OB_PUTC ('H'); { tree this_type = TREE_VALUE (parms); if (TREE_CODE (this_type) == RECORD_TYPE) /* a signature pointer */ parms = temp_tree_cons (NULL_TREE, SIGNATURE_TYPE (this_type), TREE_CHAIN (parms)); else parms = temp_tree_cons (NULL_TREE, TREE_TYPE (this_type), TREE_CHAIN (parms)); } } else if (tparms) OB_PUTC ('H'); else OB_PUTC ('F'); if (tparms) { build_template_parm_names (tparms, targs); OB_PUTC ('_'); } if (parms == NULL_TREE) OB_PUTC ('e'); else if (parms == void_list_node) OB_PUTC ('v'); else { ALLOCATE_TYPEVEC (parms); nofold = 0; if (for_method) { build_overload_name (TREE_VALUE (parms), 0, 0); typevec[maxtype++] = TREE_VALUE (parms); TREE_USED (TREE_VALUE (parms)) = 1; if (TREE_CHAIN (parms)) build_overload_name (TREE_CHAIN (parms), 0, 0); else OB_PUTC ('e'); } else build_overload_name (parms, 0, 0); DEALLOCATE_TYPEVEC (parms); } if (ret_type != NULL_TREE && for_method != 2) { /* Add the return type. */ OB_PUTC ('_'); build_overload_name (ret_type, 0, 0); } OB_FINISH (); { tree n = get_identifier (obstack_base (&scratch_obstack)); if (IDENTIFIER_OPNAME_P (dname)) IDENTIFIER_OPNAME_P (n) = 1; return n; }}/* Change the name of a function definition so that it may be overloaded. NAME is the name of the function to overload, PARMS is the parameter list (which determines what name the final function obtains). FOR_METHOD is 1 if this overload is being performed for a method, rather than a function type. It is 2 if this overload is being performed for a constructor. */treebuild_decl_overload (dname, parms, for_method) tree dname; tree parms; int for_method;{ return build_decl_overload_real (dname, parms, NULL_TREE, NULL_TREE, NULL_TREE, for_method); }/* Like build_decl_overload, but for template functions. */treebuild_template_decl_overload (dname, parms, ret_type, tparms, targs, for_method) tree dname; tree parms; tree ret_type; tree tparms; tree targs; int for_method;{ return build_decl_overload_real (dname, parms, ret_type, tparms, targs, for_method); }/* Build an overload name for the type expression TYPE. */treebuild_typename_overload (type) tree type;{ tree id; OB_INIT (); OB_PUTID (ansi_opname[(int) TYPE_EXPR]); nofold = 1; build_overload_name (type, 0, 1); id = get_identifier (obstack_base (&scratch_obstack)); IDENTIFIER_OPNAME_P (id) = 1;#if 0 IDENTIFIER_GLOBAL_VALUE (id) = TYPE_MAIN_DECL (type);#endif TREE_TYPE (id) = type; return id;}treebuild_overload_with_type (name, type) tree name, type;{ OB_INIT (); OB_PUTID (name); nofold = 1; build_overload_name (type, 0, 1); return get_identifier (obstack_base (&scratch_obstack));}treeget_id_2 (name, name2) char *name; tree name2;{ OB_INIT (); OB_PUTCP (name); OB_PUTID (name2); OB_FINISH (); return get_identifier (obstack_base (&scratch_obstack));}/* 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 (flag_ansi_overloading) return build_new_op (code, flags, xarg1, xarg2, arg3); if (xarg1 == error_mark_node) return error_mark_node; if (code == COND_EXPR) { if (xarg2 == error_mark_node || arg3 == error_mark_node) 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 = expr_tree_cons (NULL_TREE, xarg2, arg3); fnname = ansi_opname[(int) code]; if (flags & LOOKUP_GLOBAL) return build_overload_call (fnname, args, flags & LOOKUP_COMPLAIN); 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_expr_list (NULL_TREE, xarg1), flags & LOOKUP_COMPLAIN); arg1 = TREE_TYPE (xarg1); /* This handles the case where we're trying to delete X (*a)[10]; a=new X[5][10]; delete[] a; */ if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE) { /* Strip off the pointer and the array. */ arg1 = TREE_TYPE (TREE_TYPE (arg1)); while (TREE_CODE (arg1) == ARRAY_TYPE) arg1 = (TREE_TYPE (arg1)); arg1 = build_pointer_type (arg1); } rval = build_method_call (build_indirect_ref (build1 (NOP_EXPR, arg1, error_mark_node), NULL_PTR), fnname, expr_tree_cons (NULL_TREE, xarg1, build_expr_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. */ 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 = expr_tree_cons (NULL_TREE, xarg2, build_expr_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 = expr_tree_cons (NULL_TREE, xarg2, arg3); return build_method_call (xarg1, fnname, parms, NULL_TREE, LOOKUP_NORMAL); } else if (fields1) { parms = build_expr_list (NULL_TREE, xarg2); rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags); } else { parms = expr_tree_cons (NULL_TREE, xarg1, build_expr_list (NULL_TREE, xarg2)); rval = build_overload_call (fnname, parms, flags); } 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) 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) tree value, name;{ tree type; if (value == error_mark_node) { 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?