📄 typeck.c
字号:
/* Build expressions with type checking for C++ compiler. Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc. Hacked 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, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* This file is part of the C++ front end. It contains routines to build C++ expressions given their operands, including computing the types of the result, C and C++ specific error checks, and some optimization. There are also routines to build RETURN_STMT nodes and CASE_STMT nodes, and to process initializations in declarations (since they work like a strange sort of assignment). */extern void error ();extern void warning ();#include "config.h"#include <stdio.h>#include "tree.h"#include "rtl.h"#include "cp-tree.h"#include "flags.h"#include "output.h"int mark_addressable ();static tree convert_for_assignment ();/* static */ tree convert_for_initialization ();extern tree shorten_compare ();extern void binary_op_error ();static tree pointer_int_sum ();static tree pointer_diff ();static tree convert_sequence ();/* static */ tree unary_complex_lvalue ();static tree get_delta_difference PROTO((tree, tree, int));extern rtx original_result_rtx;extern int warn_synth;/* Return the target type of TYPE, which meas return T for: T*, T&, T[], T (...), and otherwise, just T. */treetarget_type (type) tree type;{ if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); while (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE || TREE_CODE (type) == OFFSET_TYPE) type = TREE_TYPE (type); return type;}/* Do `exp = require_complete_type (exp);' to make sure exp does not have an incomplete type. (That includes void types.) */treerequire_complete_type (value) tree value;{ tree type = TREE_TYPE (value); /* First, detect a valid value with a complete type. */ if (TYPE_SIZE (type) != 0 && type != void_type_node && ! (TYPE_LANG_SPECIFIC (type) && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)) && TYPE_SIZE (SIGNATURE_TYPE (type)) == 0)) return value; /* If we see X::Y, we build an OFFSET_TYPE which has not been laid out. Try to avoid an error by interpreting it as this->X::Y, if reasonable. */ if (TREE_CODE (value) == OFFSET_REF && C_C_D != 0 && TREE_OPERAND (value, 0) == C_C_D) { tree base, member = TREE_OPERAND (value, 1); tree basetype = TYPE_OFFSET_BASETYPE (type); my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305); base = convert_pointer_to (basetype, current_class_decl); value = build (COMPONENT_REF, TREE_TYPE (member), build_indirect_ref (base, NULL_PTR), member); return require_complete_type (value); } incomplete_type_error (value, type); return error_mark_node;}/* Return truthvalue of whether type of EXP is instantiated. */inttype_unknown_p (exp) tree exp;{ return (TREE_CODE (exp) == TREE_LIST || TREE_TYPE (exp) == unknown_type_node || (TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE && TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node));}/* Return truthvalue of whether T is function (or pfn) type. */intfntype_p (t) tree t;{ return (TREE_CODE (t) == FUNCTION_TYPE || TREE_CODE (t) == METHOD_TYPE || (TREE_CODE (t) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)));}/* Do `exp = require_instantiated_type (type, exp);' to make sure EXP does not have an uninstantiated type. TYPE is type to instantiate with, if uninstantiated. */treerequire_instantiated_type (type, exp, errval) tree type, exp, errval;{ if (TREE_TYPE (exp) == NULL_TREE) { error ("argument list may not have an initializer list"); return errval; } if (TREE_TYPE (exp) == unknown_type_node || (TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE && TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node)) { exp = instantiate_type (type, exp, 1); if (TREE_TYPE (exp) == error_mark_node) return errval; } return exp;}/* Return a variant of TYPE which has all the type qualifiers of LIKE as well as those of TYPE. */static treequalify_type (type, like) tree type, like;{ int constflag = TYPE_READONLY (type) || TYPE_READONLY (like); int volflag = TYPE_VOLATILE (type) || TYPE_VOLATILE (like); /* @@ Must do member pointers here. */ return cp_build_type_variant (type, constflag, volflag);}/* Return the common type of two parameter lists. We assume that comptypes has already been done and returned 1; if that isn't so, this may crash. As an optimization, free the space we allocate if the parameter lists are already common. */treecommonparms (p1, p2) tree p1, p2;{ tree oldargs = p1, newargs, n; int i, len; int any_change = 0; char *first_obj = (char *) oballoc (0); len = list_length (p1); newargs = tree_last (p1); if (newargs == void_list_node) i = 1; else { i = 0; newargs = 0; } for (; i < len; i++) newargs = tree_cons (NULL_TREE, NULL_TREE, newargs); n = newargs; for (i = 0; p1; p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n), i++) { if (TREE_PURPOSE (p1) && !TREE_PURPOSE (p2)) { TREE_PURPOSE (n) = TREE_PURPOSE (p1); any_change = 1; } else if (! TREE_PURPOSE (p1)) { if (TREE_PURPOSE (p2)) { TREE_PURPOSE (n) = TREE_PURPOSE (p2); any_change = 1; } } else { if (1 != simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2))) any_change = 1; TREE_PURPOSE (n) = TREE_PURPOSE (p2); } if (TREE_VALUE (p1) != TREE_VALUE (p2)) { any_change = 1; TREE_VALUE (n) = common_type (TREE_VALUE (p1), TREE_VALUE (p2)); } else TREE_VALUE (n) = TREE_VALUE (p1); } if (! any_change) { obfree (first_obj); return oldargs; } return newargs;}/* Return the common type of two types. We assume that comptypes has already been done and returned 1; if that isn't so, this may crash. This is the type for the result of most arithmetic operations if the operands have the given two types. We do not deal with enumeral types here because they have already been converted to integer types. */treecommon_type (t1, t2) tree t1, t2;{ register enum tree_code code1; register enum tree_code code2; tree attributes; /* Save time if the two types are the same. */ if (t1 == t2) return t1; /* If one type is nonsense, use the other. */ if (t1 == error_mark_node) return t2; if (t2 == error_mark_node) return t1; /* Merge the attributes */ { register tree a1, a2; a1 = TYPE_ATTRIBUTES (t1); a2 = TYPE_ATTRIBUTES (t2); /* Either one unset? Take the set one. */ if (!(attributes = a1)) attributes = a2; /* One that completely contains the other? Take it. */ else if (a2 && !attribute_list_contained (a1, a2)) if (attribute_list_contained (a2, a1)) attributes = a2; else { /* Pick the longest list, and hang on the other list. */ /* ??? For the moment we punt on the issue of attrs with args. */ if (list_length (a1) < list_length (a2)) attributes = a2, a2 = a1; for (; a2; a2 = TREE_CHAIN (a2)) if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)), attributes) == NULL_TREE) { a1 = copy_node (a2); TREE_CHAIN (a1) = attributes; attributes = a1; } } } /* Treat an enum type as the unsigned integer type of the same width. */ if (TREE_CODE (t1) == ENUMERAL_TYPE) t1 = type_for_size (TYPE_PRECISION (t1), 1); if (TREE_CODE (t2) == ENUMERAL_TYPE) t2 = type_for_size (TYPE_PRECISION (t2), 1); code1 = TREE_CODE (t1); code2 = TREE_CODE (t2); switch (code1) { case INTEGER_TYPE: case REAL_TYPE: /* If only one is real, use it as the result. */ if (code1 == REAL_TYPE && code2 != REAL_TYPE) return build_type_attribute_variant (t1, attributes); if (code2 == REAL_TYPE && code1 != REAL_TYPE) return build_type_attribute_variant (t2, attributes); /* Both real or both integers; use the one with greater precision. */ if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) return build_type_attribute_variant (t1, attributes); else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1)) return build_type_attribute_variant (t2, attributes); /* Same precision. Prefer longs to ints even when same size. */ if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node) return build_type_attribute_variant (long_unsigned_type_node, attributes); if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node || TYPE_MAIN_VARIANT (t2) == long_integer_type_node) { /* But preserve unsignedness from the other type, since long cannot hold all the values of an unsigned int. */ if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2)) t1 = long_unsigned_type_node; else t1 = long_integer_type_node; return build_type_attribute_variant (t1, attributes); } if (TYPE_MAIN_VARIANT (t1) == long_double_type_node || TYPE_MAIN_VARIANT (t2) == long_double_type_node) return build_type_attribute_variant (long_double_type_node, attributes); /* Otherwise prefer the unsigned one. */ if (TREE_UNSIGNED (t1)) return build_type_attribute_variant (t1, attributes); else return build_type_attribute_variant (t2, attributes); case POINTER_TYPE: case REFERENCE_TYPE: /* For two pointers, do this recursively on the target type, and combine the qualifiers of the two types' targets. */ /* This code was turned off; I don't know why. But ANSI C++ specifies doing this with the qualifiers. So I turned it on again. */ { tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (t1)); tree tt2 = TYPE_MAIN_VARIANT (TREE_TYPE (t2)); int constp = TYPE_READONLY (TREE_TYPE (t1)) || TYPE_READONLY (TREE_TYPE (t2)); int volatilep = TYPE_VOLATILE (TREE_TYPE (t1)) || TYPE_VOLATILE (TREE_TYPE (t2)); tree target; if (tt1 == tt2) target = tt1; else if (tt1 == void_type_node || tt2 == void_type_node) target = void_type_node; else target = common_type (tt1, tt2); target = cp_build_type_variant (target, constp, volatilep); if (code1 == POINTER_TYPE) t1 = build_pointer_type (target); else t1 = build_reference_type (target); t1 = build_type_attribute_variant (t1, attributes); if (TREE_CODE (target) == METHOD_TYPE) t1 = build_ptrmemfunc_type (t1); return t1; }#if 0 case POINTER_TYPE: t1 = build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2))); return build_type_attribute_variant (t1, attributes); case REFERENCE_TYPE: t1 = build_reference_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2))); return build_type_attribute_variant (t1, attributes);#endif case ARRAY_TYPE: { tree elt = common_type (TREE_TYPE (t1), TREE_TYPE (t2)); /* Save space: see if the result is identical to one of the args. */ if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1)) return build_type_attribute_variant (t1, attributes); if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2)) return build_type_attribute_variant (t2, attributes); /* Merge the element types, and have a size if either arg has one. */ t1 = build_cplus_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2)); return build_type_attribute_variant (t1, attributes); } case FUNCTION_TYPE: /* Function types: prefer the one that specified arg types. If both do, merge the arg types. Also merge the return types. */ { tree valtype = common_type (TREE_TYPE (t1), TREE_TYPE (t2)); tree p1 = TYPE_ARG_TYPES (t1); tree p2 = TYPE_ARG_TYPES (t2); tree rval, raises; /* Save space: see if the result is identical to one of the args. */ if (valtype == TREE_TYPE (t1) && ! p2) return build_type_attribute_variant (t1, attributes); if (valtype == TREE_TYPE (t2) && ! p1) return build_type_attribute_variant (t2, attributes); /* Simple way if one arg fails to specify argument types. */ if (p1 == NULL_TREE || TREE_VALUE (p1) == void_type_node) { rval = build_function_type (valtype, p2); if ((raises = TYPE_RAISES_EXCEPTIONS (t2))) rval = build_exception_variant (rval, raises); return build_type_attribute_variant (rval, attributes); } raises = TYPE_RAISES_EXCEPTIONS (t1); if (p2 == NULL_TREE || TREE_VALUE (p2) == void_type_node) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -