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

📄 cvt.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Language-level data type conversion for GNU C++.   Copyright (C) 1987, 88, 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 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 "tree.h"#include "flags.h"#include "cp-tree.h"#include "class.h"#include "convert.h"#undef NULL#define NULL (char *)0/* 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'.  *//* Build a thunk.  What it is, is an entry point that when called will   adjust the this pointer (the first argument) by offset, and then   goto the real address of the function given by REAL_ADDR that we   would like called.  What we return is the address of the thunk.  */static treebuild_thunk (offset, real_addr)     tree offset, real_addr;{  if (TREE_CODE (real_addr) != ADDR_EXPR      || TREE_CODE (TREE_OPERAND (real_addr, 0)) != FUNCTION_DECL)    {      sorry ("MI pointer to member conversion too complex");      return error_mark_node;    }  sorry ("MI pointer to member conversion too complex");  return error_mark_node;}/* Convert a `pointer to member' (POINTER_TYPE to METHOD_TYPE) into   another `pointer to method'.  This may involved the creation of   a thunk to handle the this offset calculation.  */static treeconvert_fn_ptr (type, expr)     tree type, expr;{  if (flag_vtable_thunks)    {      tree intype = TREE_TYPE (expr);      tree binfo = get_binfo (TYPE_METHOD_BASETYPE (TREE_TYPE (intype)),			      TYPE_METHOD_BASETYPE (TREE_TYPE (type)), 1);      if (binfo == error_mark_node)	{	  error ("  in pointer to member conversion");	  return error_mark_node;	}      if (binfo == NULL_TREE)	{	  /* ARM 4.8 restriction. */	  error ("invalid pointer to member conversion");	  return error_mark_node;	}      if (BINFO_OFFSET_ZEROP (binfo))	return build1 (NOP_EXPR, type, expr);      return build1 (NOP_EXPR, type, build_thunk (BINFO_OFFSET (binfo), expr));    }  else    return build_ptrmemfunc (type, expr, 1);}/* 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;  if (TYPE_PTRMEMFUNC_P (type))    type = TYPE_PTRMEMFUNC_FN_TYPE (type);  if (TYPE_PTRMEMFUNC_P (intype))    intype = TYPE_PTRMEMFUNC_FN_TYPE (intype);  form = TREE_CODE (intype);  if (form == POINTER_TYPE || form == REFERENCE_TYPE)    {      intype = TYPE_MAIN_VARIANT (intype);      if (TYPE_MAIN_VARIANT (type) != intype	  && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE	  && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)	{	  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 (TREE_CODE (TREE_TYPE (intype)) == METHOD_TYPE	  && TREE_CODE (type) == POINTER_TYPE	  && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)	return convert_fn_ptr (type, expr);      if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE	  && TREE_CODE (TREE_TYPE (intype)) == OFFSET_TYPE)	{	  tree b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));	  tree b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));	  tree binfo = get_binfo (b1, b2, 1);	  if (binfo == NULL_TREE)	    binfo = get_binfo (b2, b1, 1);	  if (binfo == error_mark_node)	    return error_mark_node;	}      if (TREE_CODE (TREE_TYPE (intype)) == METHOD_TYPE	  || (TREE_CODE (type) == POINTER_TYPE	      && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE))	{	  cp_error ("cannot convert `%E' from type `%T' to type `%T'",		    expr, intype, type);	  return error_mark_node;	}      return build1 (NOP_EXPR, type, expr);    }  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 (IS_AGGR_TYPE (intype))    {      tree rval;      rval = build_type_conversion (CONVERT_EXPR, 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;	}    }  if (integer_zerop (expr))    {      if (type == TREE_TYPE (null_pointer_node))	return null_pointer_node;      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 = 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);    }  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))    {      if (type == TREE_TYPE (null_pointer_node))	return null_pointer_node;      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	  && 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 build1 (NOP_EXPR, type, expr);    }  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.   CHECKCONST controls if we report error messages on const subversion.  */static treebuild_up_reference (type, arg, flags, checkconst)     tree type, arg;     int flags, checkconst;{  tree rval, targ;  int literal_flag = 0;  tree argtype = TREE_TYPE (arg);  tree target_type = TREE_TYPE (type);  tree binfo = NULL_TREE;  my_friendly_assert (TREE_CODE (type) == REFERENCE_TYPE, 187);  if ((flags & LOOKUP_PROTECT)      && TYPE_MAIN_VARIANT (argtype) != TYPE_MAIN_VARIANT (target_type)      && IS_AGGR_TYPE (argtype)      && IS_AGGR_TYPE (target_type))    {      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);    }  /* Pass along const and volatile down into the type. */  if (TYPE_READONLY (type) || TYPE_VOLATILE (type))    target_type = cp_build_type_variant (target_type, TYPE_READONLY (type),					TYPE_VOLATILE (type));  targ = arg;  if (TREE_CODE (targ) == SAVE_EXPR)    targ = TREE_OPERAND (targ, 0);  while (TREE_CODE (targ) == NOP_EXPR	 && (TYPE_MAIN_VARIANT (argtype)	     == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (targ, 0)))))    targ = TREE_OPERAND (targ, 0);  switch (TREE_CODE (targ))    {    case INDIRECT_REF:      /* This is a call to a constructor which did not know what it was	 initializing until now: it needs to initialize a temporary.  */      if (TREE_HAS_CONSTRUCTOR (targ))	{	  tree temp = build_cplus_new (argtype, TREE_OPERAND (targ, 0), 1);	  TREE_HAS_CONSTRUCTOR (targ) = 0;	  return build_up_reference (type, temp, flags, 1);	}      /* Let &* cancel out to simplify resulting code.         Also, throw away intervening NOP_EXPRs.  */      arg = TREE_OPERAND (targ, 0);      if (TREE_CODE (arg) == NOP_EXPR || TREE_CODE (arg) == NON_LVALUE_EXPR	  || (TREE_CODE (arg) == CONVERT_EXPR && TREE_REFERENCE_EXPR (arg)))	arg = TREE_OPERAND (arg, 0);      /* in doing a &*, we have to get rid of the const'ness on the pointer	 value.  Haven't thought about volatile here.  Pointers come to mind	 here.  */      if (TREE_READONLY (arg))	{	  arg = copy_node (arg);	  TREE_READONLY (arg) = 0;	}      rval = build1 (CONVERT_EXPR, type, arg);      TREE_REFERENCE_EXPR (rval) = 1;      /* propagate the const flag on something like:	 class Base {	 public:	   int foo;	 };      class Derived : public Base {      public:	int bar;      };      void func(Base&);      void func2(const Derived& d) {	func(d);      }        on the d parameter.  The below could have been avoided, if the flags        were down in the tree, not sure why they are not.  (mrs) */      /* The below code may have to be propagated to other parts of this	 switch.  */      if (TREE_READONLY (targ) && !TREE_READONLY (arg)	  && (TREE_CODE (arg) == PARM_DECL || TREE_CODE (arg) == VAR_DECL)	  && TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE	  && (TYPE_READONLY (target_type) && checkconst))	{	  arg = copy_node (arg);	  TREE_READONLY (arg) = TREE_READONLY (targ);	}      literal_flag = TREE_CONSTANT (arg);      goto done;      /* Get this out of a register if we happened to be in one by accident.	 Also, build up references to non-lvalues it we must.  */      /* For &x[y], return (&) x+y */    case ARRAY_REF:      if (mark_addressable (TREE_OPERAND (targ, 0)) == 0)	return error_mark_node;      rval = build_binary_op (PLUS_EXPR, TREE_OPERAND (targ, 0),			      TREE_OPERAND (targ, 1), 1);      TREE_TYPE (rval) = type;      if (TREE_CONSTANT (TREE_OPERAND (targ, 1))	  && staticp (TREE_OPERAND (targ, 0)))	TREE_CONSTANT (rval) = 1;      goto done;    case SCOPE_REF:      /* Could be a reference to a static member.  */      {	tree field = TREE_OPERAND (targ, 1);	if (TREE_STATIC (field))	  {	    rval = build1 (ADDR_EXPR, type, field);	    literal_flag = 1;	    goto done;	  }      }      /* We should have farmed out member pointers above.  */      my_friendly_abort (188);    case COMPONENT_REF:      rval = build_component_addr (targ, build_pointer_type (argtype),				   "attempt to make a reference to bit-field structure member `%s'");      TREE_TYPE (rval) = type;      literal_flag = staticp (TREE_OPERAND (targ, 0));      goto done;      /* Anything not already handled and not a true memory reference	 needs to have a reference built up.  Do so silently for	 things like integers and return values from function,	 but complain if we need a reference to something declared	 as `register'.  */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -