📄 typeck.c
字号:
/* Build expressions with type checking for C++ compiler. Copyright (C) 1987, 88, 89, 92-98, 1999 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). */#include "config.h"#include "system.h"#include "tree.h"#include "rtl.h"#include "cp-tree.h"#include "flags.h"#include "output.h"#include "expr.h"#include "toplev.h"static tree convert_for_assignment PROTO((tree, tree, const char *, tree, int));static tree pointer_int_sum PROTO((enum tree_code, tree, tree));static tree rationalize_conditional_expr PROTO((enum tree_code, tree));static int comp_target_parms PROTO((tree, tree, int));static int comp_ptr_ttypes_real PROTO((tree, tree, int));static int comp_ptr_ttypes_const PROTO((tree, tree));static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));static int comp_array_types PROTO((int (*) (tree, tree, int), tree, tree, int));static tree common_base_type PROTO((tree, tree));#if 0static tree convert_sequence PROTO((tree, tree));#endifstatic tree lookup_anon_field PROTO((tree, tree));static tree pointer_diff PROTO((tree, tree, tree));static tree build_component_addr PROTO((tree, tree));static tree qualify_type PROTO((tree, tree));static tree get_delta_difference PROTO((tree, tree, int));static int comp_cv_target_types PROTO((tree, tree, int));/* 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.) Returns the error_mark_node if the VALUE does not have complete type when this function returns. */treerequire_complete_type (value) tree value;{ tree type; if (processing_template_decl || value == error_mark_node) return value; if (TREE_CODE (value) == OVERLOAD) type = unknown_type_node; else type = TREE_TYPE (value); /* First, detect a valid value with a complete type. */ if (TYPE_SIZE (type) != 0 && TYPE_SIZE (type) != size_zero_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 && current_class_ref != 0 && TREE_OPERAND (value, 0) == current_class_ref) { 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_ptr); value = build (COMPONENT_REF, TREE_TYPE (member), build_indirect_ref (base, NULL_PTR), member); return require_complete_type (value); } if (complete_type_or_else (type, value)) return value; else return error_mark_node;}/* Makes sure EXPR is a complete type when used in a void context, like a whole expression, or lhs of a comma operator. Issue a diagnostic and return error_mark_node on failure. This is a little tricky, because some valid void types look stunningly similar to invalid void types. We err on the side of caution */treerequire_complete_type_in_void (expr) tree expr;{ switch (TREE_CODE (expr)) { case COND_EXPR: { tree op; op = TREE_OPERAND (expr,2); op = require_complete_type_in_void (op); TREE_OPERAND (expr,2) = op; if (op == error_mark_node) { expr = op; break; } /* fallthrough */ } case COMPOUND_EXPR: { tree op; op = TREE_OPERAND (expr,1); op = require_complete_type_in_void (op); TREE_OPERAND (expr,1) = op; if (op == error_mark_node) { expr = op; break; } break; } case NON_LVALUE_EXPR: case NOP_EXPR: { tree op; op = TREE_OPERAND (expr,0); op = require_complete_type_in_void (op); TREE_OPERAND (expr,0) = op; if (op == error_mark_node) { expr = op; break; } break; } case CALL_EXPR: /* function call return can be ignored */ case RTL_EXPR: /* RTL nodes have no value */ case DELETE_EXPR: /* delete expressions have no type */ case VEC_DELETE_EXPR: case INTEGER_CST: /* used for null pointer */ case EXIT_EXPR: /* have no return */ case LOOP_EXPR: /* have no return */ case BIND_EXPR: /* have no return */ case THROW_EXPR: /* have no return */ case MODIFY_EXPR: /* sometimes this has a void type, but that's ok */ case CONVERT_EXPR: /* sometimes has a void type */ break; case INDIRECT_REF: { tree op = TREE_OPERAND (expr,0); /* Calling a function returning a reference has an implicit dereference applied. We don't want to make that an error. */ if (TREE_CODE (op) == CALL_EXPR && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE) break; /* else fallthrough */ } default: expr = require_complete_type (expr); break; } return expr;}/* Try to complete TYPE, if it is incomplete. For example, if TYPE is a template instantiation, do the instantiation. Returns TYPE, whether or not it could be completed, unless something goes horribly wrong, in which case the error_mark_node is returned. */treecomplete_type (type) tree type;{ if (type == NULL_TREE) /* Rather than crash, we return something sure to cause an error at some point. */ return error_mark_node; if (type == error_mark_node || TYPE_SIZE (type) != NULL_TREE) ; else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type)) { tree t = complete_type (TREE_TYPE (type)); if (TYPE_SIZE (t) != NULL_TREE && ! processing_template_decl) layout_type (type); TYPE_NEEDS_CONSTRUCTING (type) = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t)); TYPE_NEEDS_DESTRUCTOR (type) = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (t)); } else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type)) instantiate_class_template (TYPE_MAIN_VARIANT (type)); return type;}/* Like complete_type, but issue an error if the TYPE cannot be completed. VALUE is used for informative diagnostics. Returns NULL_TREE if the type cannot be made complete. */treecomplete_type_or_else (type, value) tree type; tree value;{ type = complete_type (type); if (type == error_mark_node) /* We already issued an error. */ return NULL_TREE; else if (!TYPE_SIZE (type) || TYPE_SIZE (type) == size_zero_node) { incomplete_type_error (value, type); return NULL_TREE; } else return type;}/* Return truthvalue of whether type of EXP is instantiated. */inttype_unknown_p (exp) tree exp;{ return (TREE_CODE (exp) == OVERLOAD || 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)));}/* 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;{ /* @@ Must do member pointers here. */ return cp_build_qualified_type (type, (CP_TYPE_QUALS (type) | CP_TYPE_QUALS (like)));}/* 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;}/* Given a type, perhaps copied for a typedef, find the "original" version of it. */treeoriginal_type (t) tree t;{ while (TYPE_NAME (t) != NULL_TREE) { tree x = TYPE_NAME (t); if (TREE_CODE (x) != TYPE_DECL) break; x = DECL_ORIGINAL_TYPE (x); if (x == NULL_TREE) break; t = x; } return t;}/* 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; t1 = original_type (t1); t2 = original_type (t2); 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. */ attributes = merge_machine_type_attributes (t1, t2); { 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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -