📄 cp-call.c
字号:
/* Functions related to invoking methods and overloaded functions. Copyright (C) 1987, 1992 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com)This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *//* High-level class interface. */#include "config.h"#include "tree.h"#include <stdio.h>#include "cp-tree.h"#include "flags.h"#include "cp-class.h"#include "obstack.h"#define obstack_chunk_alloc xmalloc#define obstack_chunk_free freeextern void sorry ();extern tree build_function_call_maybe ();extern int inhibit_warnings;extern int flag_assume_nonnull_objects;extern tree ctor_label, dtor_label;/* From cp-typeck.c: */extern tree unary_complex_lvalue ();/* Compute the ease with which a conversion can be performed between an expected and the given type. */static int convert_harshness ();#define EVIL_HARSHNESS(ARG) ((ARG) & 1)#define USER_HARSHNESS(ARG) ((ARG) & 2)#define CONTRAVARIANT_HARSHNESS(ARG) ((ARG) & 4)#define BASE_DERIVED_HARSHNESS(ARG) ((ARG) & 8)#define INT_TO_BD_HARSHNESS(ARG) (((ARG) << 4) | 8)#define INT_FROM_BD_HARSHNESS(ARG) ((ARG) >> 4)#define INT_TO_EASY_HARSHNESS(ARG) ((ARG) << 4)#define INT_FROM_EASY_HARSHNESS(ARG) ((ARG) >> 4)#define ONLY_EASY_HARSHNESS(ARG) (((ARG) & 15) == 0)#define CONST_HARSHNESS(ARG) ((ARG) & 1024)/* Ordering function for overload resolution. */intrank_for_overload (x, y) struct candidate *x, *y;{ if (y->evil - x->evil) return y->evil - x->evil; if (CONST_HARSHNESS (y->harshness[0]) ^ CONST_HARSHNESS (x->harshness[0])) return y->harshness[0] - x->harshness[0]; if (y->user - x->user) return y->user - x->user; if (y->b_or_d - x->b_or_d) return y->b_or_d - x->b_or_d; return y->easy - x->easy;}/* TYPE is the type we wish to convert to. PARM is the parameter we have to work with. We use a somewhat arbitrary cost function to measure this conversion. */static intconvert_harshness (type, parmtype, parm) register tree type, parmtype; tree parm;{ register enum tree_code codel = TREE_CODE (type); register enum tree_code coder = TREE_CODE (parmtype);#ifdef GATHER_STATISTICS n_convert_harshness++;#endif if (TYPE_MAIN_VARIANT (parmtype) == TYPE_MAIN_VARIANT (type)) return 0; if (coder == ERROR_MARK) return 1; if (codel == POINTER_TYPE && (coder == METHOD_TYPE || coder == FUNCTION_TYPE)) { tree p1, p2; int harshness, new_harshness; /* Get to the METHOD_TYPE or FUNCTION_TYPE that this might be. */ type = TREE_TYPE (type); if (coder != TREE_CODE (type)) return 1; harshness = 0; /* We allow the default conversion between function type and pointer-to-function type for free. */ if (type == parmtype) return 0; /* Compare return types. */ p1 = TREE_TYPE (type); p2 = TREE_TYPE (parmtype); new_harshness = convert_harshness (p1, p2, 0); if (new_harshness & 1) return 1; if (BASE_DERIVED_HARSHNESS (new_harshness)) { tree binfo; /* This only works for pointers. */ if (TREE_CODE (p1) != POINTER_TYPE && TREE_CODE (p1) != REFERENCE_TYPE) return 1; p1 = TREE_TYPE (p1); p2 = TREE_TYPE (p2); if (CONTRAVARIANT_HARSHNESS (new_harshness)) binfo = get_binfo (p2, p1, 0); else binfo = get_binfo (p1, p2, 0); if (! BINFO_OFFSET_ZEROP (binfo)) { static int explained; if (CONTRAVARIANT_HARSHNESS (new_harshness)) message_2_types (sorry, "cannot cast `%d' to `%d' at function call site", p2, p1); else message_2_types (sorry, "cannot cast `%d' to `%d' at function call site", p1, p2); if (! explained++) sorry ("(because pointer values change during conversion)"); return 1; } } harshness |= new_harshness; p1 = TYPE_ARG_TYPES (type); p2 = TYPE_ARG_TYPES (parmtype); while (p1 && p2) { new_harshness = convert_harshness (TREE_VALUE (p1), TREE_VALUE (p2), 0); if (EVIL_HARSHNESS (new_harshness)) return 1; if (BASE_DERIVED_HARSHNESS (new_harshness)) { /* This only works for pointers and references. */ if (TREE_CODE (TREE_VALUE (p1)) != POINTER_TYPE && TREE_CODE (TREE_VALUE (p1)) != REFERENCE_TYPE) return 1; new_harshness ^= CONTRAVARIANT_HARSHNESS (new_harshness); harshness |= new_harshness; } /* This trick allows use to accumulate easy type conversions without messing up the bits that encode info about more involved things. */ else if (ONLY_EASY_HARSHNESS (new_harshness)) harshness += new_harshness; else harshness |= new_harshness; p1 = TREE_CHAIN (p1); p2 = TREE_CHAIN (p2); } if (p1 == p2) return harshness; if (p2) return 1; if (p1) return harshness | (TREE_PURPOSE (p1) == NULL_TREE); } else if (codel == POINTER_TYPE && coder == OFFSET_TYPE) { int harshness; /* Get to the OFFSET_TYPE that this might be. */ type = TREE_TYPE (type); if (coder != TREE_CODE (type)) return 1; harshness = 0; if (TYPE_OFFSET_BASETYPE (type) == TYPE_OFFSET_BASETYPE (parmtype)) harshness = 0; else if (UNIQUELY_DERIVED_FROM_P (TYPE_OFFSET_BASETYPE (type), TYPE_OFFSET_BASETYPE (parmtype))) harshness = INT_TO_BD_HARSHNESS (1); else if (UNIQUELY_DERIVED_FROM_P (TYPE_OFFSET_BASETYPE (parmtype), TYPE_OFFSET_BASETYPE (type))) harshness = CONTRAVARIANT_HARSHNESS (-1); else return 1; /* Now test the OFFSET_TYPE's target compatibility. */ type = TREE_TYPE (type); parmtype = TREE_TYPE (parmtype); } if (coder == UNKNOWN_TYPE) { if (codel == FUNCTION_TYPE || codel == METHOD_TYPE || (codel == POINTER_TYPE && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE))) return 0; return 1; } if (coder == VOID_TYPE) return 1; if (codel == ENUMERAL_TYPE || codel == INTEGER_TYPE) { /* Control equivalence of ints an enums. */ if (codel == ENUMERAL_TYPE && flag_int_enum_equivalence == 0) { /* Enums can be converted to ints, but not vice-versa. */ if (coder != ENUMERAL_TYPE || TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (parmtype)) return 1; } /* else enums and ints (almost) freely interconvert. */ if (coder == INTEGER_TYPE || coder == ENUMERAL_TYPE) { int easy = TREE_UNSIGNED (type) ^ TREE_UNSIGNED (parmtype); if (codel != coder) easy += 1; if (TYPE_MODE (type) != TYPE_MODE (parmtype)) easy += 2; return INT_TO_EASY_HARSHNESS (easy); } else if (coder == REAL_TYPE) return INT_TO_EASY_HARSHNESS (4); } if (codel == REAL_TYPE) if (coder == REAL_TYPE) /* Shun converting between float and double if a choice exists. */ { if (TYPE_MODE (type) != TYPE_MODE (parmtype)) return INT_TO_EASY_HARSHNESS (2); return 0; } else if (coder == INTEGER_TYPE || coder == ENUMERAL_TYPE) return INT_TO_EASY_HARSHNESS (4); /* convert arrays which have not previously been converted. */ if (codel == ARRAY_TYPE) codel = POINTER_TYPE; if (coder == ARRAY_TYPE) coder = POINTER_TYPE; /* Conversions among pointers */ if (codel == POINTER_TYPE && coder == POINTER_TYPE) { register tree ttl = TYPE_MAIN_VARIANT (TREE_TYPE (type)); register tree ttr = TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)); int penalty = 4 * (ttl != ttr); /* Anything converts to void *. void * converts to anything. Since these may be `const void *' (etc.) use VOID_TYPE instead of void_type_node. Otherwise, the targets must be the same, except that we do allow (at some cost) conversion between signed and unsinged pointer types. */ if ((TREE_CODE (ttl) == METHOD_TYPE || TREE_CODE (ttl) == FUNCTION_TYPE) && TREE_CODE (ttl) == TREE_CODE (ttr)) { if (comptypes (ttl, ttr, -1)) return INT_TO_EASY_HARSHNESS (penalty); return 1; } if (!(TREE_CODE (ttl) == VOID_TYPE || TREE_CODE (ttr) == VOID_TYPE || (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (ttr) && (ttl = unsigned_type (ttl), ttr = unsigned_type (ttr), penalty = 10, 0)) || (comp_target_types (ttl, ttr, 0)))) return 1; if (penalty == 10) return INT_TO_EASY_HARSHNESS (10); if (ttr == ttl) return INT_TO_BD_HARSHNESS (0); if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE) { int b_or_d = get_base_distance (ttl, ttr, 0, 0); if (b_or_d < 0) { b_or_d = get_base_distance (ttr, ttl, 0, 0); if (b_or_d < 0) return 1; return CONTRAVARIANT_HARSHNESS (-1); } return INT_TO_BD_HARSHNESS (b_or_d); } /* If converting from a `class*' to a `void*', make it less favorable than any inheritance relationship. */ if (TREE_CODE (ttl) == VOID_TYPE && IS_AGGR_TYPE (ttr)) return INT_TO_BD_HARSHNESS (CLASSTYPE_MAX_DEPTH (ttr)+1); return INT_TO_EASY_HARSHNESS (penalty); } if (codel == POINTER_TYPE && coder == INTEGER_TYPE) { /* This is not a bad match, but don't let it beat integer-enum combinations. */ if (parm && integer_zerop (parm)) return INT_TO_EASY_HARSHNESS (4); } /* C++: one of the types must be a reference type. */ { tree ttl, ttr; register tree intype = TYPE_MAIN_VARIANT (parmtype); register enum tree_code form = TREE_CODE (intype); int penalty; if (codel == REFERENCE_TYPE || coder == REFERENCE_TYPE) { ttl = TYPE_MAIN_VARIANT (type); if (codel == REFERENCE_TYPE) { ttl = TREE_TYPE (ttl); /* When passing a non-const argument into a const reference, dig it a little, so a non-const reference is preferred over this one. (mrs) */ if (TREE_READONLY (ttl) && ! TREE_READONLY (parm)) penalty = 2; else penalty = 0; ttl = TYPE_MAIN_VARIANT (ttl); if (form == OFFSET_TYPE) { intype = TREE_TYPE (intype); form = TREE_CODE (intype); } if (form == REFERENCE_TYPE) { intype = TYPE_MAIN_VARIANT (TREE_TYPE (intype)); if (ttl == intype) return 0; penalty = 2; } else { /* Can reference be built up? */ if (ttl == intype && penalty == 0) { /* Becuase the READONLY bits are not always in the type, this extra check is necessary. The problem should be fixed someplace else, and this extra code removed. Also, if type if a reference, the readonly bits could either be in the outer type (with reference) or on the inner type (the thing being referenced). (mrs) */ if (TREE_READONLY (parm) && ! (TYPE_READONLY (type) || (TREE_CODE (type) == REFERENCE_TYPE && TYPE_READONLY (TREE_TYPE (type))))) penalty = 2; else return 0; } else penalty = 2; } } else if (form == REFERENCE_TYPE) { if (parm) { tree tmp = convert_from_reference (parm); intype = TYPE_MAIN_VARIANT (TREE_TYPE (tmp)); } else { intype = parmtype; do { intype = TREE_TYPE (intype); } while (TREE_CODE (intype) == REFERENCE_TYPE); intype = TYPE_MAIN_VARIANT (intype); } if (ttl == intype) return 0; else penalty = 2; } if (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (intype)) { ttl = unsigned_type (ttl); intype = unsigned_type (intype); penalty += 2; } ttr = intype; /* If the initializer is not an lvalue, then it does not
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -