typeck.c

来自「GCC编译器源代码」· C语言 代码 · 共 2,225 行 · 第 1/5 页

C
2,225
字号
      }    case COND_EXPR:      return build_conditional_expr	(TREE_OPERAND (datum, 0),	 build_component_ref (TREE_OPERAND (datum, 1), component,			      basetype_path, protect),	 build_component_ref (TREE_OPERAND (datum, 2), component,			      basetype_path, protect));    }  code = TREE_CODE (basetype);  if (code == REFERENCE_TYPE)    {      datum = convert_from_reference (datum);      basetype = TREE_TYPE (datum);      code = TREE_CODE (basetype);    }  if (TREE_CODE (datum) == OFFSET_REF)    {      datum = resolve_offset_ref (datum);      basetype = TREE_TYPE (datum);      code = TREE_CODE (basetype);    }  /* First, see if there is a field or component with name COMPONENT.  */  if (TREE_CODE (component) == TREE_LIST)    {      my_friendly_assert (!(TREE_CHAIN (component) == NULL_TREE		&& DECL_CHAIN (TREE_VALUE (component)) == NULL_TREE), 309);      return build (COMPONENT_REF, TREE_TYPE (component), datum, component);    }  if (! IS_AGGR_TYPE_CODE (code))    {      if (code != ERROR_MARK)	cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",		  component, datum, basetype);      return error_mark_node;    }  if (TYPE_SIZE (complete_type (basetype)) == 0)    {      incomplete_type_error (0, basetype);      return error_mark_node;    }  if (TREE_CODE (component) == BIT_NOT_EXPR)    {      if (TYPE_IDENTIFIER (basetype) != TREE_OPERAND (component, 0))	{	  cp_error ("destructor specifier `%T::~%T' must have matching names",		    basetype, TREE_OPERAND (component, 0));	  return error_mark_node;	}      if (! TYPE_HAS_DESTRUCTOR (basetype))	{	  cp_error ("type `%T' has no destructor", basetype);	  return error_mark_node;	}      return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 1);    }  /* Look up component name in the structure type definition.  */  if (CLASSTYPE_VFIELD (basetype)      && DECL_NAME (CLASSTYPE_VFIELD (basetype)) == component)    /* Special-case this because if we use normal lookups in an ambiguous       hierarchy, the compiler will abort (because vptr lookups are       not supposed to be ambiguous.  */    field = CLASSTYPE_VFIELD (basetype);  else if (TREE_CODE (component) == FIELD_DECL	   || TREE_CODE (component) == TYPE_DECL)    {      field = component;    }  else    {      tree name = component;      if (TREE_CODE (component) == VAR_DECL)	name = DECL_NAME (component);      if (basetype_path == NULL_TREE)	basetype_path = TYPE_BINFO (basetype);      field = lookup_field (basetype_path, name,			    protect && !VFIELD_NAME_P (name), 0);      if (field == error_mark_node)	return error_mark_node;      if (field == NULL_TREE)	{	  /* Not found as a data field, look for it as a method.  If found,	     then if this is the only possible one, return it, else	     report ambiguity error.  */	  tree fndecls = lookup_fnfields (basetype_path, name, 1);	  if (fndecls == error_mark_node)	    return error_mark_node;	  if (fndecls)	    {	      if (TREE_CHAIN (fndecls) == NULL_TREE		  && DECL_CHAIN (TREE_VALUE (fndecls)) == NULL_TREE)		{		  tree access, fndecl;		  /* Unique, so use this one now.  */		  basetype = TREE_PURPOSE (fndecls);		  fndecl = TREE_VALUE (fndecls);		  access = compute_access (TREE_PURPOSE (fndecls), fndecl);		  if (access == access_public_node)		    {		      if (DECL_VINDEX (fndecl)			  && ! resolves_to_fixed_type_p (datum, 0))			{			  tree addr = build_unary_op (ADDR_EXPR, datum, 0);			  tree fntype = TREE_TYPE (fndecl);			  addr = convert_pointer_to (DECL_CONTEXT (fndecl), addr);			  datum = build_indirect_ref (addr, NULL_PTR);			  my_friendly_assert (datum != error_mark_node, 310);			  fndecl = build_vfn_ref (&addr, datum, DECL_VINDEX (fndecl));			  TREE_TYPE (fndecl) = build_pointer_type (fntype);			}		      else			mark_used (fndecl);		      return build (OFFSET_REF, TREE_TYPE (fndecl), datum, fndecl);		    }		  if (access == access_protected_node)		    cp_error ("member function `%D' is protected", fndecl);		  else		    cp_error ("member function `%D' is private", fndecl);		  return error_mark_node;		}	      else		{		  /* Just act like build_offset_ref, since the object does                     not matter unless we're actually calling the function.  */		  tree t;		  t = build_tree_list (error_mark_node, fndecls);		  TREE_TYPE (t) = build_offset_type (basetype,						     unknown_type_node);		  return t;		}	    }	  cp_error ("`%#T' has no member named `%D'", basetype, name);	  return error_mark_node;	}      else if (TREE_TYPE (field) == error_mark_node)	return error_mark_node;      if (TREE_CODE (field) != FIELD_DECL)	{	  if (TREE_CODE (field) == TYPE_DECL)	    {	      cp_error ("invalid use of type decl `%#D' as expression", field);	      return error_mark_node;	    }	  else if (DECL_RTL (field) != 0)	    mark_used (field);	  else	    TREE_USED (field) = 1;	  return field;	}    }  /* See if we have to do any conversions so that we pick up the field from the     right context.  */  if (DECL_FIELD_CONTEXT (field) != basetype)    {      tree context = DECL_FIELD_CONTEXT (field);      tree base = context;      while (base != basetype && TYPE_NAME (base)	     && ANON_AGGRNAME_P (TYPE_IDENTIFIER (base)))	{	  base = TYPE_CONTEXT (base);	}      /* Handle base classes here...  */      if (base != basetype && TYPE_USES_COMPLEX_INHERITANCE (basetype))	{	  tree addr = build_unary_op (ADDR_EXPR, datum, 0);	  if (integer_zerop (addr))	    {	      error ("invalid reference to NULL ptr, use ptr-to-member instead");	      return error_mark_node;	    }	  if (VBASE_NAME_P (DECL_NAME (field)))	    {	      /* It doesn't matter which vbase pointer we grab, just		 find one of them.  */	      tree binfo = get_binfo (base,				      TREE_TYPE (TREE_TYPE (addr)), 0);	      addr = convert_pointer_to_real (binfo, addr);	    }	  else	    addr = convert_pointer_to (base, addr);	  datum = build_indirect_ref (addr, NULL_PTR);	  my_friendly_assert (datum != error_mark_node, 311);	}      basetype = base;       /* Handle things from anon unions here...  */      if (TYPE_NAME (context) && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))	{	  tree subfield = lookup_anon_field (basetype, context);	  tree subdatum = build_component_ref (datum, subfield,					       basetype_path, protect);	  return build_component_ref (subdatum, field, basetype_path, protect);	}    }  ref = fold (build (COMPONENT_REF, TREE_TYPE (field),		     break_out_cleanups (datum), field));  if (TREE_READONLY (datum) || TREE_READONLY (field))    TREE_READONLY (ref) = 1;  if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field))    TREE_THIS_VOLATILE (ref) = 1;  if (DECL_MUTABLE_P (field))    TREE_READONLY (ref) = 0;  return ref;}/* Variant of build_component_ref for use in expressions, which should   never have REFERENCE_TYPE.  */treebuild_x_component_ref (datum, component, basetype_path, protect)     tree datum, component, basetype_path;     int protect;{  tree t = build_component_ref (datum, component, basetype_path, protect);  if (! processing_template_decl)    t = convert_from_reference (t);  return t;}/* Given an expression PTR for a pointer, return an expression   for the value pointed to.   ERRORSTRING is the name of the operator to appear in error messages.   This function may need to overload OPERATOR_FNNAME.   Must also handle REFERENCE_TYPEs for C++.  */treebuild_x_indirect_ref (ptr, errorstring)     tree ptr;     char *errorstring;{  tree rval;  if (processing_template_decl)    return build_min_nt (INDIRECT_REF, ptr);  rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, NULL_TREE);  if (rval)    return rval;  return build_indirect_ref (ptr, errorstring);}treebuild_indirect_ref (ptr, errorstring)     tree ptr;     char *errorstring;{  register tree pointer, type;  if (ptr == error_mark_node)    return error_mark_node;  pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE	     ? ptr : default_conversion (ptr));  type = TREE_TYPE (pointer);  if (ptr == current_class_ptr)    return current_class_ref;  if (IS_AGGR_TYPE (type))    {      ptr = build_expr_type_conversion (WANT_POINTER, pointer, 1);      if (ptr)	{	  pointer = ptr;	  type = TREE_TYPE (pointer);	}    }  if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE)    {      if (TREE_CODE (pointer) == ADDR_EXPR	  && !flag_volatile	  && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (pointer, 0)))	      == TYPE_MAIN_VARIANT (TREE_TYPE (type)))	  && (TREE_READONLY (TREE_OPERAND (pointer, 0))	      == TYPE_READONLY (TREE_TYPE (type)))	  && (TREE_THIS_VOLATILE (TREE_OPERAND (pointer, 0))	      == TYPE_VOLATILE (TREE_TYPE (type))))	return TREE_OPERAND (pointer, 0);      else	{	  tree t = TREE_TYPE (type);	  register tree ref = build1 (INDIRECT_REF,				      TYPE_MAIN_VARIANT (t), pointer);	  /* We *must* set TREE_READONLY when dereferencing a pointer to const,	     so that we get the proper error message if the result is used	     to assign to.  Also, &* is supposed to be a no-op.  */	  TREE_READONLY (ref) = TYPE_READONLY (t);	  TREE_SIDE_EFFECTS (ref)	    = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile;	  TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);	  return ref;	}    }  /* `pointer' won't be an error_mark_node if we were given a     pointer to member, so it's cool to check for this here.  */  else if (TYPE_PTRMEMFUNC_P (type))    error ("invalid use of `%s' on pointer to member function", errorstring);  else if (TREE_CODE (type) == RECORD_TYPE	   && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))    error ("cannot dereference signature pointer/reference");  else if (pointer != error_mark_node)    {      if (errorstring)	error ("invalid type argument of `%s'", errorstring);      else	error ("invalid type argument");    }  return error_mark_node;}/* This handles expressions of the form "a[i]", which denotes   an array reference.   This is logically equivalent in C to *(a+i), but we may do it differently.   If A is a variable or a member, we generate a primitive ARRAY_REF.   This avoids forcing the array out of registers, and can work on   arrays that are not lvalues (for example, members of structures returned   by functions).   If INDEX is of some user-defined type, it must be converted to   integer type.  Otherwise, to make a compatible PLUS_EXPR, it   will inherit the type of the array, which will be some pointer type.  */treebuild_array_ref (array, idx)     tree array, idx;{  if (idx == 0)    {      error ("subscript missing in array reference");      return error_mark_node;    }  if (TREE_TYPE (array) == error_mark_node      || TREE_TYPE (idx) == error_mark_node)    return error_mark_node;  if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE      && TREE_CODE (array) != INDIRECT_REF)    {      tree rval, type;      /* Subscripting with type char is likely to lose	 on a machine where chars are signed.	 So warn on any machine, but optionally.	 Don't warn for unsigned char since that type is safe.	 Don't warn for signed char because anyone who uses that	 must have done so deliberately.  */      if (warn_char_subscripts	  && TYPE_MAIN_VARIANT (TREE_TYPE (idx)) == char_type_node)	warning ("array subscript has type `char'");      /* Apply default promotions *after* noticing character types.  */      idx = default_conversion (idx);      if (TREE_CODE (TREE_TYPE (idx)) != 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 (idx) != 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;	}      /* An array that is indexed by a constant value which is not within	 the array bounds cannot be stored in a register either; because we	 would get a crash in store_bit_field/extract_bit_field when trying	 to access a non-existent part of the register.  */      if (TREE_CODE (idx) == INTEGER_CST	  && TYPE_VALUES (TREE_TYPE (array))	  && ! int_fits_type_p (idx, TYPE_VALUES (TREE_TYPE (array))))	{	  if (mark_addressable (array) == 0)	    return error_mark_node;	}      if (pedantic && !lvalue_p (array))	pedwarn ("ANSI C++ forbids subscripting non-lvalue array");      /* Note in C++ it is valid to subscript a `register' array, since	 it is valid to take the address of something with that	 storage specification.  */      if (extra_warnings)	{	  tree foo = array;	  while (TREE_CODE (foo) == COMPONENT_REF)	    foo = TREE_OPERAND (foo, 0);	  if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo))	    warning ("subscripting array declared `register'");	}      type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));      rval = build (ARRAY_REF, type, array, idx);      /* Array ref is const/volatile if the array elements are	 or if the array is..  */      TREE_READONLY (rval)	|= (TYPE_READONLY (TREE_TYPE (TREE_TYPE (array)))	    | TREE_READONLY (array));      TREE_SIDE_EFFECTS (rval)	|= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array)))	    | TREE_SIDE_EFFECTS (array));      TREE_THIS_VOLATILE (rval)	|= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array)))	    /* This was added by rms on 16 Nov 91.	       It fixes  vol struct foo *a;  a->elts[1] 	       in an inline function.	       Hope it doesn't break something else.  */	    | TREE_THIS_VOLATILE (array));      return require_complete_type (fold (rval));    }  {    tree ar = d

⌨️ 快捷键说明

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