📄 cvt.c
字号:
/* Language-level data type conversion for GNU C++. Copyright (C) 1987, 88, 92-97, 1998 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 contains the functions for converting C expressions to different data types. The only entry point is `convert'. Every language front end must have a `convert' function but what kind of conversions it does will depend on the language. */#include "config.h"#include "system.h"#include "tree.h"#include "flags.h"#include "cp-tree.h"#include "convert.h"#include "toplev.h"#include "decl.h"static tree cp_convert_to_pointer PROTO((tree, tree));static tree convert_to_pointer_force PROTO((tree, tree));static tree build_up_reference PROTO((tree, tree, int));/* Change of width--truncation and extension of integers or reals-- is represented with NOP_EXPR. Proper functioning of many things assumes that no other conversions can be NOP_EXPRs. Conversion between integer and pointer is represented with CONVERT_EXPR. Converting integer to real uses FLOAT_EXPR and real to integer uses FIX_TRUNC_EXPR. Here is a list of all the functions that assume that widening and narrowing is always done with a NOP_EXPR: In convert.c, convert_to_integer. In c-typeck.c, build_binary_op_nodefault (boolean ops), and truthvalue_conversion. In expr.c: expand_expr, for operands of a MULT_EXPR. In fold-const.c: fold. In tree.c: get_narrower and get_unwidened. C++: in multiple-inheritance, converting between pointers may involve adjusting them by a delta stored within the class definition. *//* Subroutines of `convert'. *//* if converting pointer to pointer if dealing with classes, check for derived->base or vice versa else if dealing with method pointers, delegate else convert blindly else if converting class, pass off to build_type_conversion else try C-style pointer conversion */static treecp_convert_to_pointer (type, expr) tree type, expr;{ register tree intype = TREE_TYPE (expr); register enum tree_code form; tree rval; if (IS_AGGR_TYPE (intype)) { intype = complete_type (intype); if (TYPE_SIZE (intype) == NULL_TREE) { cp_error ("can't convert from incomplete type `%T' to `%T'", intype, type); return error_mark_node; } rval = build_type_conversion (type, expr, 1); if (rval) { if (rval == error_mark_node) cp_error ("conversion of `%E' from `%T' to `%T' is ambiguous", expr, intype, type); return rval; } } /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */ if (TREE_CODE (type) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)) { /* Allow an implicit this pointer for pointer to member functions. */ if (TYPE_PTRMEMFUNC_P (intype)) { tree fntype = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (intype)); tree decl = maybe_dummy_object (TYPE_METHOD_BASETYPE (fntype), 0); expr = build (OFFSET_REF, fntype, decl, expr); } if (TREE_CODE (expr) == OFFSET_REF && TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE) expr = resolve_offset_ref (expr); if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE) expr = build_addr_func (expr); if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) { if (TREE_CODE (TREE_TYPE (TREE_TYPE (expr))) == METHOD_TYPE) if (pedantic || warn_pmf2ptr) cp_pedwarn ("converting from `%T' to `%T'", TREE_TYPE (expr), type); return build1 (NOP_EXPR, type, expr); } intype = TREE_TYPE (expr); } form = TREE_CODE (intype); if (POINTER_TYPE_P (intype)) { intype = TYPE_MAIN_VARIANT (intype); if (TYPE_MAIN_VARIANT (type) != intype && TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype)) && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE /* If EXPR is NULL, then we don't need to do any arithmetic to convert it: [conv.ptr] The null pointer value is converted to the null pointer value of the destination type. */ && !integer_zerop (expr)) { enum tree_code code = PLUS_EXPR; tree binfo = get_binfo (TREE_TYPE (type), TREE_TYPE (intype), 1); if (binfo == error_mark_node) return error_mark_node; if (binfo == NULL_TREE) { binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 1); if (binfo == error_mark_node) return error_mark_node; code = MINUS_EXPR; } if (binfo) { if (TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (type)) || TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (intype)) || ! BINFO_OFFSET_ZEROP (binfo)) { /* Need to get the path we took. */ tree path; if (code == PLUS_EXPR) get_base_distance (TREE_TYPE (type), TREE_TYPE (intype), 0, &path); else get_base_distance (TREE_TYPE (intype), TREE_TYPE (type), 0, &path); return build_vbase_path (code, type, expr, path, 0); } } } if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)) { tree b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type)); tree b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)); tree binfo = get_binfo (b2, b1, 1); enum tree_code code = PLUS_EXPR; if (binfo == NULL_TREE) { binfo = get_binfo (b1, b2, 1); code = MINUS_EXPR; } if (binfo == error_mark_node) return error_mark_node; if (binfo && ! TREE_VIA_VIRTUAL (binfo)) expr = size_binop (code, expr, BINFO_OFFSET (binfo)); } else if (TYPE_PTRMEMFUNC_P (type)) { cp_error ("cannot convert `%E' from type `%T' to type `%T'", expr, intype, type); return error_mark_node; } rval = build1 (NOP_EXPR, type, expr); TREE_CONSTANT (rval) = TREE_CONSTANT (expr); return rval; } else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)) return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 1); else if (TYPE_PTRMEMFUNC_P (intype)) { cp_error ("cannot convert `%E' from type `%T' to type `%T'", expr, intype, type); return error_mark_node; } my_friendly_assert (form != OFFSET_TYPE, 186); if (TYPE_LANG_SPECIFIC (intype) && (IS_SIGNATURE_POINTER (intype) || IS_SIGNATURE_REFERENCE (intype))) return convert_to_pointer (type, build_optr_ref (expr)); if (integer_zerop (expr)) { if (TYPE_PTRMEMFUNC_P (type)) return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0); expr = build_int_2 (0, 0); TREE_TYPE (expr) = type; return expr; } if (INTEGRAL_CODE_P (form)) { if (TYPE_PRECISION (intype) == POINTER_SIZE) return build1 (CONVERT_EXPR, type, expr); expr = cp_convert (type_for_size (POINTER_SIZE, 0), expr); /* Modes may be different but sizes should be the same. */ if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) != GET_MODE_SIZE (TYPE_MODE (type))) /* There is supposed to be some integral type that is the same width as a pointer. */ abort (); return convert_to_pointer (type, expr); } if (type_unknown_p (expr)) return instantiate_type (type, expr, 1); cp_error ("cannot convert `%E' from type `%T' to type `%T'", expr, intype, type); return error_mark_node;}/* Like convert, except permit conversions to take place which are not normally allowed due to access restrictions (such as conversion from sub-type to private super-type). */static treeconvert_to_pointer_force (type, expr) tree type, expr;{ register tree intype = TREE_TYPE (expr); register enum tree_code form = TREE_CODE (intype); if (integer_zerop (expr)) { expr = build_int_2 (0, 0); TREE_TYPE (expr) = type; return expr; } /* Convert signature pointer/reference to `void *' first. */ if (form == RECORD_TYPE && (IS_SIGNATURE_POINTER (intype) || IS_SIGNATURE_REFERENCE (intype))) { expr = build_optr_ref (expr); intype = TREE_TYPE (expr); form = TREE_CODE (intype); } if (form == POINTER_TYPE) { intype = TYPE_MAIN_VARIANT (intype); if (TYPE_MAIN_VARIANT (type) != intype && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype)) && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE) { enum tree_code code = PLUS_EXPR; tree path; int distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (intype), 0, &path); if (distance == -2) { ambig: cp_error ("type `%T' is ambiguous baseclass of `%s'", TREE_TYPE (type), TYPE_NAME_STRING (TREE_TYPE (intype))); return error_mark_node; } if (distance == -1) { distance = get_base_distance (TREE_TYPE (intype), TREE_TYPE (type), 0, &path); if (distance == -2) goto ambig; if (distance < 0) /* Doesn't need any special help from us. */ return build1 (NOP_EXPR, type, expr); code = MINUS_EXPR; } return build_vbase_path (code, type, expr, path, 0); } } return cp_convert_to_pointer (type, expr);}/* We are passing something to a function which requires a reference. The type we are interested in is in TYPE. The initial value we have to begin with is in ARG. FLAGS controls how we manage access checking. DIRECT_BIND in FLAGS controls how any temporaries are generated. */static treebuild_up_reference (type, arg, flags) tree type, arg; int flags;{ tree rval; tree argtype = TREE_TYPE (arg); tree target_type = TREE_TYPE (type); my_friendly_assert (TREE_CODE (type) == REFERENCE_TYPE, 187); if ((flags & DIRECT_BIND) && ! real_lvalue_p (arg)) { tree targ = arg; if (toplevel_bindings_p ()) arg = get_temp_name (argtype, 1); else { arg = pushdecl (build_decl (VAR_DECL, NULL_TREE, argtype)); DECL_ARTIFICIAL (arg) = 1; } DECL_INITIAL (arg) = targ; cp_finish_decl (arg, targ, NULL_TREE, 0, LOOKUP_ONLYCONVERTING|DIRECT_BIND); } else if (!(flags & DIRECT_BIND) && ! lvalue_p (arg)) { tree slot = build_decl (VAR_DECL, NULL_TREE, argtype); DECL_ARTIFICIAL (slot) = 1; arg = build (TARGET_EXPR, argtype, slot, arg, NULL_TREE, NULL_TREE); TREE_SIDE_EFFECTS (arg) = 1; } /* If we had a way to wrap this up, and say, if we ever needed it's address, transform all occurrences of the register, into a memory reference we could win better. */ rval = build_unary_op (ADDR_EXPR, arg, 1); if (rval == error_mark_node) return error_mark_node; if ((flags & LOOKUP_PROTECT) && TYPE_MAIN_VARIANT (argtype) != TYPE_MAIN_VARIANT (target_type) && IS_AGGR_TYPE (argtype) && IS_AGGR_TYPE (target_type)) { /* We go through get_binfo for the access control. */ tree binfo = get_binfo (target_type, argtype, 1); if (binfo == error_mark_node) return error_mark_node; if (binfo == NULL_TREE) return error_not_base_type (target_type, argtype); rval = convert_pointer_to_real (binfo, rval);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -