📄 call.c
字号:
/* Functions related to invoking methods and overloaded functions. Copyright (C) 1987, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) and hacked by Brendan Kehoe (brendan@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, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* High-level class interface. */#include "config.h"#include "tree.h"#include <stdio.h>#include "cp-tree.h"#include "class.h"#include "output.h"#include "flags.h"#include "obstack.h"#define obstack_chunk_alloc xmalloc#define obstack_chunk_free freeextern void sorry ();extern int inhibit_warnings;extern int flag_assume_nonnull_objects;extern tree ctor_label, dtor_label;/* From 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 struct harshness_code convert_harshness ();#define EVIL_RETURN(ARG) ((ARG).code = EVIL_CODE, (ARG))#define STD_RETURN(ARG) ((ARG).code = STD_CODE, (ARG))#define QUAL_RETURN(ARG) ((ARG).code = QUAL_CODE, (ARG))#define TRIVIAL_RETURN(ARG) ((ARG).code = TRIVIAL_CODE, (ARG))#define ZERO_RETURN(ARG) ((ARG).code = 0, (ARG))/* Ordering function for overload resolution. Compare two candidates by gross quality. */intrank_for_overload (x, y) struct candidate *x, *y;{ if (y->h.code & (EVIL_CODE|ELLIPSIS_CODE|USER_CODE)) return y->h.code - x->h.code; if (x->h.code & (EVIL_CODE|ELLIPSIS_CODE|USER_CODE)) return -1; /* This is set by compute_conversion_costs, for calling a non-const member function from a const member function. */ if ((y->harshness[0].code & CONST_CODE) ^ (x->harshness[0].code & CONST_CODE)) return y->harshness[0].code - x->harshness[0].code; if (y->h.code & STD_CODE) { if (x->h.code & STD_CODE) return y->h.distance - x->h.distance; return 1; } if (x->h.code & STD_CODE) return -1; return y->h.code - x->h.code;}/* Compare two candidates, argument by argument. */intrank_for_ideal (x, y) struct candidate *x, *y;{ int i; if (x->h_len != y->h_len) abort (); for (i = 0; i < x->h_len; i++) { if (y->harshness[i].code - x->harshness[i].code) return y->harshness[i].code - x->harshness[i].code; if ((y->harshness[i].code & STD_CODE) && (y->harshness[i].distance - x->harshness[i].distance)) return y->harshness[i].distance - x->harshness[i].distance; /* They're both the same code. Now see if we're dealing with an integral promotion that needs a finer grain of accuracy. */ if (y->harshness[0].code & PROMO_CODE && (y->harshness[i].int_penalty ^ x->harshness[i].int_penalty)) return y->harshness[i].int_penalty - x->harshness[i].int_penalty; } return 0;}/* 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 struct harshness_codeconvert_harshness (type, parmtype, parm) register tree type, parmtype; tree parm;{ struct harshness_code h; register enum tree_code codel; register enum tree_code coder; int lvalue; h.code = 0; h.distance = 0; h.int_penalty = 0;#ifdef GATHER_STATISTICS n_convert_harshness++;#endif if (TREE_CODE (parmtype) == REFERENCE_TYPE) { if (parm) parm = convert_from_reference (parm); parmtype = TREE_TYPE (parmtype); lvalue = 1; } else if (parm) lvalue = lvalue_p (parm); else lvalue = 0; if (TYPE_PTRMEMFUNC_P (type)) type = TYPE_PTRMEMFUNC_FN_TYPE (type); if (TYPE_PTRMEMFUNC_P (parmtype)) parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype); codel = TREE_CODE (type); coder = TREE_CODE (parmtype); if (TYPE_MAIN_VARIANT (parmtype) == TYPE_MAIN_VARIANT (type)) return ZERO_RETURN (h); if (coder == ERROR_MARK) return EVIL_RETURN (h); if (codel == REFERENCE_TYPE) { tree ttl, ttr; int constp = parm ? TREE_READONLY (parm) : TYPE_READONLY (parmtype); int volatilep = (parm ? TREE_THIS_VOLATILE (parm) : TYPE_VOLATILE (parmtype)); register tree intype = TYPE_MAIN_VARIANT (parmtype); register enum tree_code form = TREE_CODE (intype); int penalty = 0; ttl = TREE_TYPE (type); /* Only allow const reference binding if we were given a parm to deal with, since it isn't really a conversion. This is a hack to prevent build_type_conversion from finding this conversion, but still allow overloading to find it. */ if (! lvalue && ! (parm && TYPE_READONLY (ttl))) return EVIL_RETURN (h); if (TYPE_READONLY (ttl) < constp || TYPE_VOLATILE (ttl) < volatilep) return EVIL_RETURN (h); /* When passing a non-const argument into a const reference, dig it a little, so a non-const reference is preferred over this one. */ penalty = ((TYPE_READONLY (ttl) > constp) + (TYPE_VOLATILE (ttl) > volatilep)); ttl = TYPE_MAIN_VARIANT (ttl); if (form == OFFSET_TYPE) { intype = TREE_TYPE (intype); form = TREE_CODE (intype); } ttr = intype; if (TREE_CODE (ttl) == ARRAY_TYPE && TREE_CODE (ttr) == ARRAY_TYPE) { if (comptypes (ttl, ttr, 1)) return ZERO_RETURN (h); return EVIL_RETURN (h); } h = convert_harshness (ttl, ttr, NULL_TREE); if (penalty && h.code == 0) { h.code = QUAL_CODE; h.int_penalty = penalty; } return h; } if (codel == POINTER_TYPE && fntype_p (parmtype)) { tree p1, p2; struct harshness_code h1, h2; /* Get to the METHOD_TYPE or FUNCTION_TYPE that this might be. */ type = TREE_TYPE (type); if (coder == POINTER_TYPE) { parmtype = TREE_TYPE (parmtype); coder = TREE_CODE (parmtype); } if (coder != TREE_CODE (type)) return EVIL_RETURN (h); if (type != parmtype && coder == METHOD_TYPE) { tree ttl = TYPE_METHOD_BASETYPE (type); tree ttr = TYPE_METHOD_BASETYPE (parmtype); int b_or_d = get_base_distance (ttr, ttl, 0, 0); if (b_or_d < 0) { b_or_d = get_base_distance (ttl, ttr, 0, 0); if (b_or_d < 0) return EVIL_RETURN (h); h.distance = -b_or_d; } else h.distance = b_or_d; h.code = STD_CODE; type = build_function_type (TREE_TYPE (type), TREE_CHAIN (TYPE_ARG_TYPES (type))); parmtype = build_function_type (TREE_TYPE (parmtype), TREE_CHAIN (TYPE_ARG_TYPES (parmtype))); } /* We allow the default conversion between function type and pointer-to-function type for free. */ if (comptypes (type, parmtype, 1)) return h; if (pedantic) return EVIL_RETURN (h); /* Compare return types. */ p1 = TREE_TYPE (type); p2 = TREE_TYPE (parmtype); h2 = convert_harshness (p1, p2, NULL_TREE); if (h2.code & EVIL_CODE) return h2; h1.code = TRIVIAL_CODE; h1.distance = 0; if (h2.distance != 0) { tree binfo; /* This only works for pointers. */ if (TREE_CODE (p1) != POINTER_TYPE && TREE_CODE (p1) != REFERENCE_TYPE) return EVIL_RETURN (h); p1 = TREE_TYPE (p1); p2 = TREE_TYPE (p2); /* Don't die if we happen to be dealing with void*. */ if (!IS_AGGR_TYPE (p1) || !IS_AGGR_TYPE (p2)) return EVIL_RETURN (h); if (h2.distance < 0) binfo = get_binfo (p2, p1, 0); else binfo = get_binfo (p1, p2, 0); if (! BINFO_OFFSET_ZEROP (binfo)) {#if 0 static int explained = 0; if (h2.distance < 0) message_2_types (sorry, "cannot cast `%s' to `%s' at function call site", p2, p1); else message_2_types (sorry, "cannot cast `%s' to `%s' at function call site", p1, p2); if (! explained++) sorry ("(because pointer values change during conversion)");#endif return EVIL_RETURN (h); } } h1.code |= h2.code; if (h2.distance > h1.distance) h1.distance = h2.distance; p1 = TYPE_ARG_TYPES (type); p2 = TYPE_ARG_TYPES (parmtype); while (p1 && TREE_VALUE (p1) != void_type_node && p2 && TREE_VALUE (p2) != void_type_node) { h2 = convert_harshness (TREE_VALUE (p1), TREE_VALUE (p2), NULL_TREE); if (h2.code & EVIL_CODE) return h2; if (h2.distance) { /* This only works for pointers and references. */ if (TREE_CODE (TREE_VALUE (p1)) != POINTER_TYPE && TREE_CODE (TREE_VALUE (p1)) != REFERENCE_TYPE) return EVIL_RETURN (h); h2.distance = - h2.distance; } h1.code |= h2.code; if (h2.distance > h1.distance) h1.distance = h2.distance; p1 = TREE_CHAIN (p1); p2 = TREE_CHAIN (p2); } if (p1 == p2) return h1; if (p2) { if (p1) return EVIL_RETURN (h); h1.code |= ELLIPSIS_CODE; return h1; } if (p1) { if (TREE_PURPOSE (p1) == NULL_TREE) h1.code |= EVIL_CODE; return h1; } } else if (codel == POINTER_TYPE && coder == OFFSET_TYPE) { tree ttl, ttr; /* Get to the OFFSET_TYPE that this might be. */ type = TREE_TYPE (type); if (coder != TREE_CODE (type)) return EVIL_RETURN (h); ttl = TYPE_OFFSET_BASETYPE (type); ttr = TYPE_OFFSET_BASETYPE (parmtype); if (ttl == ttr) h.code = 0; else { int b_or_d = get_base_distance (ttr, ttl, 0, 0); if (b_or_d < 0) { b_or_d = get_base_distance (ttl, ttr, 0, 0); if (b_or_d < 0) return EVIL_RETURN (h); h.distance = -b_or_d; } else h.distance = b_or_d; h.code = STD_CODE; } /* 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 TRIVIAL_RETURN (h); return EVIL_RETURN (h); } if (coder == VOID_TYPE) return EVIL_RETURN (h); if (codel == BOOLEAN_TYPE) { if (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE) return STD_RETURN (h); else if (coder == POINTER_TYPE || coder == OFFSET_TYPE) { /* Make this worse than any conversion to another pointer. FIXME this is how I think the language should work, but it may not end up being how the language is standardized (jason 1/30/95). */ h.distance = 32767; return STD_RETURN (h); } return EVIL_RETURN (h); } if (INTEGRAL_CODE_P (codel)) { /* 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 EVIL_RETURN (h); } /* else enums and ints (almost) freely interconvert. */ if (INTEGRAL_CODE_P (coder)) { if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (type_promotes_to (parmtype))) { h.code = PROMO_CODE;#if 0 /* What purpose does this serve? -jason */ /* A char, short, wchar_t, etc., should promote to an int if it can handle it, otherwise to an unsigned. So we'll make an unsigned. */ if (type != integer_type_node) h.int_penalty = 1;#endif } else h.code = STD_CODE; return h; } else if (coder == REAL_TYPE) { h.code = STD_CODE; h.distance = 0; return h; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -