📄 cp-method.c
字号:
try_second = 0; break; case POSTDECREMENT_EXPR: code = PREDECREMENT_EXPR; binary_is_unary = 1; try_second = 0; break; case PREDECREMENT_EXPR: case POSTINCREMENT_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 NEW_EXPR: { /* For operators `new' (`delete'), only check visibility if we are in a constructor (destructor), and we are allocating for that constructor's (destructor's) type. */ fnname = ansi_opname[(int) NEW_EXPR]; if (flags & LOOKUP_GLOBAL) return build_overload_call (fnname, tree_cons (NULL_TREE, xarg2, arg3), flags & LOOKUP_COMPLAIN, 0); if (current_function_decl == NULL_TREE || !DECL_CONSTRUCTOR_P (current_function_decl) || current_class_type != TYPE_MAIN_VARIANT (type1)) flags = LOOKUP_COMPLAIN; rval = build_method_call (build1 (NOP_EXPR, xarg1, error_mark_node), fnname, tree_cons (NULL_TREE, xarg2, arg3), 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 DELETE_EXPR: { /* See comment above. */ fnname = ansi_opname[(int) DELETE_EXPR]; if (flags & LOOKUP_GLOBAL) return build_overload_call (fnname, tree_cons (NULL_TREE, xarg1, build_tree_list (NULL_TREE, xarg2)), flags & LOOKUP_COMPLAIN, 0); if (current_function_decl == NULL_TREE || !DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (current_function_decl)) || current_class_type != TYPE_MAIN_VARIANT (type1)) flags = LOOKUP_COMPLAIN; rval = build_method_call (build1 (NOP_EXPR, TREE_TYPE (xarg1), error_mark_node), fnname, tree_cons (NULL_TREE, xarg1, build_tree_list (NULL_TREE, xarg2)), NULL_TREE, flags); /* This happens when the user mis-declares `operator delete'. Should now be impossible. */ my_friendly_assert (rval != error_mark_node, 250); TREE_TYPE (rval) = void_type_node; 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)) { /* 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 forseeable future. */ return rval; } if (code == MODIFY_EXPR) fnname = ansi_assopname[(int) TREE_CODE (arg3)]; else fnname = ansi_opname[(int) code]; global_fn = IDENTIFIER_GLOBAL_VALUE (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); 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 & LOOKUP_COMPLAIN, 0); } /* If we did not win, do not lose yet, since type conversion may work. */ if (TREE_CODE (rval) == ERROR_MARK) { if (flags & LOOKUP_COMPLAIN) return rval; return 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, 0); 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; if (yychar == '(') if (! ((TYPE_LANG_SPECIFIC (type) && TYPE_OVERLOADS_CALL_EXPR (type)) || (TREE_CODE (type) == REFERENCE_TYPE && TYPE_LANG_SPECIFIC (TREE_TYPE (type)) && TYPE_OVERLOADS_CALL_EXPR (TREE_TYPE (type)))) && TREE_CODE (type) != FUNCTION_TYPE && TREE_CODE (type) != METHOD_TYPE && (TREE_CODE (type) != POINTER_TYPE || (TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE && TREE_CODE (TREE_TYPE (type)) != METHOD_TYPE))) { error ("component `%s' is not a method", IDENTIFIER_POINTER (name)); return error_mark_node; } /* 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 (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_CLASS_CONTEXT (value) != current_class_type) { tree path; enum visibility_type visibility; 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); visibility = compute_visibility (path, value); if (visibility != visibility_public) { if (TREE_CODE (value) == VAR_DECL) error ("static member `%s' is from private base class", IDENTIFIER_POINTER (name)); 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, 252); if (DECL_REFERENCE_SLOT (value)) return DECL_REFERENCE_SLOT (value); } return value;}/* 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); if (TREE_OPERAND (tmp, 0) && TREE_OPERAND (tmp, 0) != void_list_node) { error ("operator <typename> requires empty parameter list"); TREE_OPERAND (tmp, 0) = NULL_TREE; } last = groktypename (build_tree_list (TREE_TYPE (component), TREE_OPERAND (component, 0))); name = build_typename_overload (last); TREE_TYPE (name) = last; 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) { error ("object required for `operator <typename>' call"); return error_mark_node; } this_this = convert_pointer_to (TREE_TYPE (of), current_class_decl); 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); error ("object required for `operator <typename>' call"); return error_mark_node; case INDIRECT_REF: case ADDR_EXPR: case ARRAY_REF: break; case SCOPE_REF: my_friendly_assert (cname == 0, 255); cname = TREE_OPERAND (tmp, 0); tmp = TREE_OPERAND (tmp, 1); break; default: my_friendly_abort (77); } last = tmp; tmp = 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 (of && TREE_CODE (of) == TYPE_DECL) { if (cname == NULL_TREE) { cname = DECL_NAME (of); of = NULL_TREE; } else my_friendly_assert (cname == DECL_NAME (of), 256); } if (of) { tree this_this; if (current_class_decl == NULL_TREE) { error ("object required for `operator <typename>' call"); return error_mark_node; } this_this = convert_pointer_to (TREE_TYPE (of), current_class_decl); return build_component_ref (this_this, name, 0, protect); } else if (cname) return build_offset_ref (cname, name); else if (current_class_name) return build_offset_ref (current_class_name, name); error ("object required for `operator <typename>' member reference"); return error_mark_node;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -