⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cvt.c

📁 gcc-2.95.3 Linux下最常用的C编译器
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 + -