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

📄 c-typeck.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
  if (index == 0)    {      error ("subscript missing in array reference");      return error_mark_node;    }  if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE      && TREE_CODE (array) != INDIRECT_REF)    {      tree rval, type;      index = default_conversion (index);      if (index != error_mark_node	  && TREE_CODE (TREE_TYPE (index)) != INTEGER_TYPE)	{	  error ("array subscript is not an integer");	  return error_mark_node;	}      /* An array that is indexed by a non-constant	 cannot be stored in a register; we must be able to do	 address arithmetic on its address.	 Likewise an array of elements of variable size.  */      if (TREE_CODE (index) != INTEGER_CST	  || (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0	      && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST))	{	  if (mark_addressable (array) == 0)	    return error_mark_node;	}      if (pedantic && !lvalue_p (array))	warning ("ANSI C forbids subscripting non-lvalue array");      if (pedantic)	{	  tree foo = array;	  while (TREE_CODE (foo) == COMPONENT_REF)	    foo = TREE_OPERAND (foo, 0);	  if (TREE_CODE (foo) == VAR_DECL && TREE_REGDECL (foo))	    warning ("ANSI C forbids subscripting non-lvalue array");	}      type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));      rval = build (ARRAY_REF, type, array, index);      /* Array ref is const/volatile if the array elements are,         or if the array object is.  */      TREE_READONLY (rval)	|= (TREE_READONLY (TREE_TYPE (TREE_TYPE (array)))	    | TREE_READONLY (array));      TREE_VOLATILE (rval)	|= (TREE_VOLATILE (TREE_TYPE (TREE_TYPE (array)))	    | TREE_VOLATILE (array));      TREE_THIS_VOLATILE (rval)	|= TREE_VOLATILE (TREE_TYPE (TREE_TYPE (array)));      return require_complete_type (fold (rval));    }  {    tree ar = default_conversion (array);    tree ind = default_conversion (index);    /* Put the integer in IND to simplify error checking.  */    if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE)      {	tree temp = ar;	ar = ind;	ind = temp;      }    if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE)      {	error ("subscripted value is neither array nor pointer");	return error_mark_node;      }    if (TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE)      {	error ("array subscript is not an integer");	return error_mark_node;      }    return build_indirect_ref (build_binary_op_nodefault (PLUS_EXPR, ar, ind, PLUS_EXPR),			       "array indexing");  }}/* Build a function call to function FUNCTION with parameters PARAMS.   PARAMS is a list--a chain of TREE_LIST nodes--in which the   TREE_VALUE of each node is a parameter-expression.   FUNCTION's data type may be a function type or a pointer-to-function.  */treebuild_function_call (function, params)     tree function, params;{  register tree fntype;  register tree value_type;  register tree coerced_params;  tree name = NULL_TREE;  tree actualparameterlist ();  /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.     Strip such NOP_EXPRs, since FUNCTION is used in non-lvalue context.  */  if (TREE_CODE (function) == NOP_EXPR      && TREE_TYPE (function) == TREE_TYPE (TREE_OPERAND (function, 0)))    function = TREE_OPERAND (function, 0);  /* Convert anything with function type to a pointer-to-function.  */  if (TREE_CODE (function) == FUNCTION_DECL)    {      name = DECL_NAME (function);      /* Differs from default_conversion by not setting TREE_ADDRESSABLE	 (because calling an inline function does not mean the function	 needs to be separately compiled).  */      function = build (ADDR_EXPR, build_pointer_type (TREE_TYPE (function)),			function);    }  else    function = default_conversion (function);  fntype = TREE_TYPE (function);  if (TREE_CODE (fntype) == ERROR_MARK)    return error_mark_node;  if (!(TREE_CODE (fntype) == POINTER_TYPE	&& TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE))    {      error ("called object is not a function");      return error_mark_node;    }  /* fntype now gets the type of function pointed to.  */  fntype = TREE_TYPE (fntype);  /* Convert the parameters to the types declared in the     function prototype, or apply default promotions.  */  coerced_params = actualparameterlist (TYPE_ARG_TYPES (fntype), params, name);  /* Recognize certain built-in functions so we can make tree-codes     other than CALL_EXPR.  We do this when it enables fold-const.c     to do something useful.  */  if (TREE_CODE (function) == ADDR_EXPR      && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)    switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0)))      {      case BUILT_IN_ABS:      case BUILT_IN_LABS:      case BUILT_IN_FABS:	if (coerced_params == 0)	  return integer_zero_node;	return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);      }  value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;    {    register tree result =       build (CALL_EXPR, value_type, function, coerced_params, NULL_TREE);    TREE_VOLATILE (result) = 1;    if (value_type == void_type_node)      return result;    return require_complete_type (result);  }}/* Convert the actual parameter expressions in the list VALUES   to the types in the list TYPELIST.   If parmdecls is exhausted, or when an element has NULL as its type,   perform the default conversions.   NAME is an IDENTIFIER_NODE or 0.  It is used only for error messages.   This is also where warnings about wrong number of args are generated.      Return a list of expressions for the parameters as converted.   Both VALUES and the returned value are chains of TREE_LIST nodes   with the elements of the list in the TREE_VALUE slots of those nodes.  */treeactualparameterlist (typelist, values, name)     tree typelist, values, name;{  register tree typetail, valtail;  register tree result = NULL;  for (valtail = values, typetail = typelist;       valtail;       valtail = TREE_CHAIN (valtail))    {      register tree type = typetail ? TREE_VALUE (typetail) : 0;      register tree val = TREE_VALUE (valtail);      register tree parm;      if (type == void_type_node)	{	  if (name)	    error ("too many arguments to function `%s'",		   IDENTIFIER_POINTER (name));	  else	    error ("too many arguments to function");	  break;	}      /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.	 Strip such NOP_EXPRs, since VAL is used in non-lvalue context.  */      if (TREE_CODE (val) == NOP_EXPR	  && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0)))	val = TREE_OPERAND (val, 0);      if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE	  || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE)	val = default_conversion (val);      val = require_complete_type (val);      if (type != 0)	{	  /* Formal parm type is specified by a function prototype.  */	  tree parmval;	  if (TYPE_SIZE (type) == 0)	    {	      error ("parameter type of called function is incomplete");	      parmval = val;	    }	  else	    {#ifdef PROMOTE_PROTOTYPES	      /* Rather than truncating and then reextending,		 convert directly to int, if that's the type we will want.  */	      if (! flag_traditional		  && TREE_CODE (type) == INTEGER_TYPE		  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))		type = integer_type_node;#endif	      parmval = convert_for_assignment (type, val, "argument passing");#ifdef PROMOTE_PROTOTYPES	      if (TREE_CODE (type) == INTEGER_TYPE		  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))		parmval = default_conversion (parmval);#endif	    }	  parm = build_tree_list (0, parmval);	}      else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE               && (TYPE_PRECISION (TREE_TYPE (val))	           < TYPE_PRECISION (double_type_node)))	/* Convert `float' to `double'.  */	parm = build_tree_list (NULL_TREE, convert (double_type_node, val));      else	/* Convert `short' and `char' to full-size `int'.  */	parm = build_tree_list (NULL_TREE, default_conversion (val));      result = chainon (result, parm);      if (typetail)	typetail = TREE_CHAIN (typetail);    }  if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)    {      if (name)	error ("too few arguments to function `%s'",	       IDENTIFIER_POINTER (name));      else	error ("too few arguments to function");    }  return result;}/* Build a binary-operation expression, after performing default   conversions on the operands.  CODE is the kind of expression to build.  */treebuild_binary_op (code, arg1, arg2)     enum tree_code code;     tree arg1, arg2;{  return build_binary_op_nodefault (code, default_conversion (arg1),				    default_conversion (arg2), code);}/* Build a binary-operation expression without default conversions.   CODE is the kind of expression to build.   This function differs from `build' in several ways:   the data type of the result is computed and recorded in it,   warnings are generated if arg data types are invalid,   special handling for addition and subtraction of pointers is known,   and some optimization is done (operations on narrow ints   are done in the narrower type when that gives the same result).   Constant folding is also done before the result is returned.   ERROR_CODE is the code that determines what to say in error messages.   It is usually, but not always, the same as CODE.   Note that the operands will never have enumeral types   because either they have just had the default conversions performed   or they have both just been converted to some other type in which   the arithmetic is to be done.  */treebuild_binary_op_nodefault (code, op0, op1, error_code)     enum tree_code code;     tree op0, op1;     enum tree_code error_code;{  tree dt0 = datatype (op0), dt1 = datatype (op1);  /* The expression codes of the data types of the arguments tell us     whether the arguments are integers, floating, pointers, etc.  */  register enum tree_code code0 = TREE_CODE (dt0);  register enum tree_code code1 = TREE_CODE (dt1);  /* Expression code to give to the expression when it is built.     Normally this is CODE, which is what the caller asked for,     but in some special cases we change it.  */  register enum tree_code resultcode = code;  /* Data type in which the computation is to be performed.     In the simplest cases this is the common type of the arguments.  */  register tree result_type = NULL;  /* Nonzero means operands have already been type-converted     in whatever way is necessary.     Zero means they need to be converted to RESULT_TYPE.  */  int converted = 0;  /* Nonzero means after finally constructing the expression     give it this type.  Otherwise, give it type RESULT_TYPE.  */  tree final_type = 0;  /* Nonzero if this is an operation like MIN or MAX which can     safely be computed in short if both args are promoted shorts.     Also implies COMMON.     -1 indicates a bitwise operation; this makes a difference     in the exact conditions for when it is safe to do the operation     in a narrower mode.  */  int shorten = 0;  /* Nonzero if this is a comparison operation;     if both args are promoted shorts, compare the original shorts.     Also implies COMMON.  */  int short_compare = 0;  /* Nonzero if this is a right-shift operation, which can be computed on the     original short and then promoted if the operand is a promoted short.  */  int short_shift = 0;  /* Nonzero means set RESULT_TYPE to the common type of the args.  */  int common = 0;  /* If an error was already reported for one of the arguments,     avoid reporting another error.  */  if (code0 == ERROR_MARK || code1 == ERROR_MARK)    return error_mark_node;  switch (code)    {    case PLUS_EXPR:      /* Handle the pointer + int case.  */      if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)	return pointer_int_sum (PLUS_EXPR, op0, op1);      else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)	return pointer_int_sum (PLUS_EXPR, op1, op0);      else	common = 1;      break;    case MINUS_EXPR:      /* Subtraction of two similar pointers.	 We must subtract them as integers, then divide by object size.  */      if (code0 == POINTER_TYPE && code1 == POINTER_TYPE	  && comp_target_types (dt0, dt1))	return pointer_diff (op0, op1);      /* Handle pointer minus int.  Just like pointer plus int.  */      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)	return pointer_int_sum (MINUS_EXPR, op0, op1);      else	common = 1;      break;    case MULT_EXPR:      common = 1;      break;    case TRUNC_DIV_EXPR:    case CEIL_DIV_EXPR:    case FLOOR_DIV_EXPR:    case ROUND_DIV_EXPR:    case EXACT_DIV_EXPR:      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)	  && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))	{	  if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))	    resultcode = RDIV_EXPR;	  else	    /* When dividing two signed integers, you have to promote to int.	       E.g. (short) -32868 / (short) -1 doesn't fit in a short.  */	    shorten = TREE_UNSIGNED (dt0);	  common = 1;	}      break;    case BIT_AND_EXPR:    case BIT_ANDTC_EXPR:    case BIT_IOR_EXPR:    case BIT_XOR_EXPR:      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)	shorten = -1;      /* If one operand is a constant, and the other is a short type	 that has been converted to an int,	 really do the work in the short type and then convert the	 result to int.  If we are lucky, the constant will be 0 or 1	 in the short type, making the entire operation go away.  */      if (TREE_CODE (op0) == INTEGER_CST	  && TREE_CODE (op1) == NOP_EXPR	  && TYPE_PRECISION (dt1) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0)))	  && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op1, 0))))	{	  final_type = result_type;	  op1 = TREE_OPERAND (op1, 0);	  result_type = TREE_TYPE (op1);	}      if (TREE_CODE (op1) == INTEGER_CST	  && TREE_CODE (op0) == NOP_EXPR

⌨️ 快捷键说明

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