call.c

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

C
2,271
字号
			   LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);    }  if (flag_ansi_overloading)    return build_new_method_call (instance, name, parms, basetype_path, flags);  {    char *xref_name;        /* Initialize name for error reporting.  */    if (IDENTIFIER_OPNAME_P (name) && ! IDENTIFIER_TYPENAME_P (name))      {	char *p = operator_name_string (name);	xref_name = (char *)alloca (strlen (p) + 10);	sprintf (xref_name, "operator %s", p);      }    else if (TREE_CODE (name) == SCOPE_REF)      xref_name = IDENTIFIER_POINTER (TREE_OPERAND (name, 1));    else      xref_name = IDENTIFIER_POINTER (name);    GNU_xref_call (current_function_decl, xref_name);  }  if (instance == NULL_TREE)    {      basetype = NULL_TREE;      /* Check cases where this is really a call to raise	 an exception.  */      if (current_class_type && TREE_CODE (name) == IDENTIFIER_NODE)	{	  basetype = purpose_member (name, CLASSTYPE_TAGS (current_class_type));	  if (basetype)	    basetype = TREE_VALUE (basetype);	}      else if (TREE_CODE (name) == SCOPE_REF	       && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)	{	  if (! is_aggr_typedef (TREE_OPERAND (name, 0), 1))	    return error_mark_node;	  basetype = purpose_member (TREE_OPERAND (name, 1),				     CLASSTYPE_TAGS (IDENTIFIER_TYPE_VALUE (TREE_OPERAND (name, 0))));	  if (basetype)	    basetype = TREE_VALUE (basetype);	}      if (basetype != NULL_TREE)	;      /* call to a constructor...  */      else if (basetype_path)	{	  basetype = BINFO_TYPE (basetype_path);	  if (name == TYPE_IDENTIFIER (basetype))	    name = ctor_identifier;	}      else if (IDENTIFIER_HAS_TYPE_VALUE (name))	{	  basetype = IDENTIFIER_TYPE_VALUE (name);	  name = ctor_identifier;	}      else	{	  tree typedef_name = lookup_name (name, 1);	  if (typedef_name && TREE_CODE (typedef_name) == TYPE_DECL)	    {	      /* Canonicalize the typedef name.  */	      basetype = TREE_TYPE (typedef_name);	      name = ctor_identifier;	    }	  else	    {	      cp_error ("no constructor named `%T' in scope",			name);	      return error_mark_node;	    }	}      if (! IS_AGGR_TYPE (basetype))	{	non_aggr_error:	  if ((flags & LOOKUP_COMPLAIN) && basetype != error_mark_node)	    cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",		      name, instance, basetype);	  return error_mark_node;	}    }  else if (instance == current_class_ref || instance == current_class_ptr)    {      /* When doing initialization, we side-effect the TREE_TYPE of	 current_class_ref, hence we cannot set up BASETYPE from CURRENT_CLASS_TYPE.  */      basetype = TREE_TYPE (current_class_ref);      /* Anything manifestly `this' in constructors and destructors	 has a known type, so virtual function tables are not needed.  */      if (TYPE_VIRTUAL_P (basetype)	  && !(flags & LOOKUP_NONVIRTUAL))	need_vtbl = (dtor_label || ctor_label)	  ? unneeded : maybe_needed;      /* If `this' is a signature pointer and `name' is not a constructor,	 we are calling a signature member function.  In that case, set the	 `basetype' to the signature type and dereference the `optr' field.  */      if (IS_SIGNATURE_POINTER (basetype)	  && TYPE_IDENTIFIER (basetype) != name)	{	  basetype = SIGNATURE_TYPE (basetype);	  instance_ptr = instance;	  basetype_path = TYPE_BINFO (basetype);	}      else	{	  instance = current_class_ref;	  instance_ptr = current_class_ptr;	  basetype_path = TYPE_BINFO (current_class_type);	}      result = build_field_call (basetype_path, instance_ptr, name, parms);      if (result)	return result;    }  else if (TREE_CODE (instance) == RESULT_DECL)    {      basetype = TREE_TYPE (instance);      /* Should we ever have to make a virtual function reference	 from a RESULT_DECL, know that it must be of fixed type	 within the scope of this function.  */      if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))	need_vtbl = maybe_needed;      instance_ptr = build1 (ADDR_EXPR, build_pointer_type (basetype), instance);    }  else    {      /* The MAIN_VARIANT of the type that `instance_ptr' winds up being.  */      tree inst_ptr_basetype;      static_call_context	= (TREE_CODE (instance) == INDIRECT_REF	   && TREE_CODE (TREE_OPERAND (instance, 0)) == NOP_EXPR	   && TREE_OPERAND (TREE_OPERAND (instance, 0), 0) == error_mark_node);      if (TREE_CODE (instance) == OFFSET_REF)	instance = resolve_offset_ref (instance);      /* the base type of an instance variable is pointer to class */      basetype = TREE_TYPE (instance);      if (TREE_CODE (basetype) == REFERENCE_TYPE)	{	  basetype = TREE_TYPE (basetype);	  if (! IS_AGGR_TYPE (basetype))	    goto non_aggr_error;	  /* Call to convert not needed because we are remaining	     within the same type.  */	  instance_ptr = build1 (NOP_EXPR, build_pointer_type (basetype),				 instance);	  inst_ptr_basetype = TYPE_MAIN_VARIANT (basetype);	}      else	{	  if (! IS_AGGR_TYPE (basetype)	      && ! (TYPE_LANG_SPECIFIC (basetype)		    && (IS_SIGNATURE_POINTER (basetype)			|| IS_SIGNATURE_REFERENCE (basetype))))	    goto non_aggr_error;	  /* If `instance' is a signature pointer/reference and `name' is	     not a constructor, we are calling a signature member function.	     In that case set the `basetype' to the signature type.  */	  if ((IS_SIGNATURE_POINTER (basetype)	       || IS_SIGNATURE_REFERENCE (basetype))	      && TYPE_IDENTIFIER (basetype) != name)	    basetype = SIGNATURE_TYPE (basetype);	  basetype = complete_type (basetype);	  if ((IS_SIGNATURE (basetype)	       && (instance_ptr = instance))	      || (lvalue_p (instance)		  && (instance_ptr = build_unary_op (ADDR_EXPR, instance, 0)))	      || (instance_ptr = unary_complex_lvalue (ADDR_EXPR, instance)))	    {	      if (instance_ptr == error_mark_node)		return error_mark_node;	    }	  else if (TREE_CODE (instance) == NOP_EXPR		   || TREE_CODE (instance) == CONSTRUCTOR)	    {	      /* A cast is not an lvalue.  Initialize a fresh temp		 with the value we are casting from, and proceed with		 that temporary.  We can't cast to a reference type,		 so that simplifies the initialization to something		 we can manage.  */	      tree temp = get_temp_name (TREE_TYPE (instance), 0);	      if (IS_AGGR_TYPE (TREE_TYPE (instance)))		expand_aggr_init (temp, instance, 0, flags);	      else		{		  store_init_value (temp, instance);		  expand_decl_init (temp);		}	      instance = temp;	      instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);	    }	  else	    {	      if (TREE_CODE (instance) != CALL_EXPR)		my_friendly_abort (125);	      if (TYPE_NEEDS_CONSTRUCTING (basetype))		instance = build_cplus_new (basetype, instance);	      else		{		  instance = get_temp_name (basetype, 0);		  TREE_ADDRESSABLE (instance) = 1;		}	      instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);	    }	  /* @@ Should we call comp_target_types here?  */	  if (IS_SIGNATURE (basetype))	    inst_ptr_basetype = basetype;	  else	    inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr));	  if (TYPE_MAIN_VARIANT (basetype) == TYPE_MAIN_VARIANT (inst_ptr_basetype))	    basetype = inst_ptr_basetype;	  else	    {	      instance_ptr = cp_convert (build_pointer_type (basetype), instance_ptr);	      if (instance_ptr == error_mark_node)		return error_mark_node;	    }	}      /* After converting `instance_ptr' above, `inst_ptr_basetype' was	 not updated, so we use `basetype' instead.  */      if (basetype_path == NULL_TREE	  && IS_SIGNATURE (basetype))	basetype_path = TYPE_BINFO (basetype);      else if (basetype_path == NULL_TREE	       || (BINFO_TYPE (basetype_path)		   != TYPE_MAIN_VARIANT (inst_ptr_basetype)))	basetype_path = TYPE_BINFO (inst_ptr_basetype);      result = build_field_call (basetype_path, instance_ptr, name, parms);      if (result)	return result;      if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))	{	  if (TREE_SIDE_EFFECTS (instance_ptr))	    {	      /* This action is needed because the instance is needed		 for providing the base of the virtual function table.		 Without using a SAVE_EXPR, the function we are building		 may be called twice, or side effects on the instance		 variable (such as a post-increment), may happen twice.  */	      instance_ptr = save_expr (instance_ptr);	      instance = build_indirect_ref (instance_ptr, NULL_PTR);	    }	  else if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)	    {	      /* This happens when called for operator new ().  */	      instance = build_indirect_ref (instance, NULL_PTR);	    }	  need_vtbl = maybe_needed;	}    }  if (save_name == ctor_identifier)    save_name = TYPE_IDENTIFIER (basetype);  if (TYPE_SIZE (complete_type (basetype)) == 0)    {      /* This is worth complaining about, I think.  */      cp_error ("cannot lookup method in incomplete type `%T'", basetype);      return error_mark_node;    }  save_basetype = TYPE_MAIN_VARIANT (basetype);  parmtypes = default_parm_conversions (parms, &last);  if (parmtypes == error_mark_node)    {      return error_mark_node;    }  if (instance && IS_SIGNATURE (basetype))    {      /* @@ Should this be the constp/volatilep flags for the optr field	 of the signature pointer?  */      constp = TYPE_READONLY (basetype);      volatilep = TYPE_VOLATILE (basetype);      parms = expr_tree_cons (NULL_TREE, instance_ptr, parms);    }  else if (instance)    {      /* TREE_READONLY (instance) fails for references.  */      constp = TYPE_READONLY (TREE_TYPE (TREE_TYPE (instance_ptr)));      volatilep = TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (instance_ptr)));      parms = expr_tree_cons (NULL_TREE, instance_ptr, parms);    }  else    {      /* Raw constructors are always in charge.  */      if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)	  && ! (flags & LOOKUP_HAS_IN_CHARGE))	{	  flags |= LOOKUP_HAS_IN_CHARGE;	  parms = expr_tree_cons (NULL_TREE, integer_one_node, parms);	  parmtypes = scratch_tree_cons (NULL_TREE, integer_type_node, parmtypes);	}      constp = 0;      volatilep = 0;      instance_ptr = build_int_2 (0, 0);      TREE_TYPE (instance_ptr) = build_pointer_type (basetype);      parms = expr_tree_cons (NULL_TREE, instance_ptr, parms);    }  parmtypes = scratch_tree_cons (NULL_TREE, TREE_TYPE (instance_ptr), parmtypes);  if (last == NULL_TREE)    last = parmtypes;  /* Look up function name in the structure type definition.  */  /* FIXME Axe most of this now?  */  if ((IDENTIFIER_HAS_TYPE_VALUE (name)       && ! IDENTIFIER_OPNAME_P (name)       && IS_AGGR_TYPE (IDENTIFIER_TYPE_VALUE (name)))      || name == constructor_name (basetype)      || name == ctor_identifier)    {      tree tmp = NULL_TREE;      if (IDENTIFIER_TYPE_VALUE (name) == basetype	  || name == constructor_name (basetype)	  || name == ctor_identifier)	tmp = TYPE_BINFO (basetype);      else	tmp = get_binfo (IDENTIFIER_TYPE_VALUE (name), basetype, 0);            if (tmp != NULL_TREE)	{	  name_kind = "constructor";	  	  if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)	      && ! (flags & LOOKUP_HAS_IN_CHARGE))	    {	      /* Constructors called for initialization		 only are never in charge.  */	      tree tmplist;	      	      flags |= LOOKUP_HAS_IN_CHARGE;	      tmplist = expr_tree_cons (NULL_TREE, integer_zero_node,				   TREE_CHAIN (parms));	      TREE_CHAIN (parms) = tmplist;	      tmplist = scratch_tree_cons (NULL_TREE, integer_type_node, TREE_CHAIN (parmtypes));	      TREE_CHAIN (parmtypes) = tmplist;	    }	  basetype = BINFO_TYPE (tmp);	}      else	name_kind = "method";    }  else    name_kind = "method";    if (basetype_path == NULL_TREE      || BINFO_TYPE (basetype_path) != TYPE_MAIN_VARIANT (basetype))    basetype_path = TYPE_BINFO (basetype);  result = lookup_fnfields (basetype_path, name,			    (flags & LOOKUP_COMPLAIN));  if (result == error_mark_node)    return error_mark_node;  for (pass = 0; pass < 2; pass++)    {      struct candidate *candidates;      struct candidate *cp;      int len;      unsigned best = 1;      baselink = result;      if (pass > 0)	{	  candidates	    = (struct candidate *) alloca ((ever_seen+1)					   * sizeof (struct candidate));	  bzero ((char *) candidates, (ever_seen + 1) * sizeof (struct candidate));	  cp = candidates;	  len = list_length (parms);	  ever_seen = 0;	  /* First see if a global function has a shot at it.  */	  if (flags & LOOKUP_GLOBAL)	    {	      tree friend_parms;	      tree parm = instance_ptr;	      if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE)		parm = convert_from_reference (parm);	      else if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)		parm = build_indirect_ref (parm, "friendifying parms (compiler error)");	      else		my_friendly_abort (167);	      friend_parms = expr_tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));	      cp->h_len = len;	      cp->harshness = (struct harshness_code *)		alloca ((len + 1) * sizeof (struct harshness_code));	      result = build_overload_call_real (name, friend_parms, 0, cp, 1);	      /* If it turns out to be the one we were actually looking for		 (it was probably a friend function), the return the		 good result.  */	      if (TREE_CODE (result) == CALL_EXPR)		return result;	      while ((cp->h.code & EVIL_CODE) == 0)		{		  /* non-standard uses: set the field to 0 to indicate		     we are using a non-member function.  */		  cp->u.field = 0;		  if (cp->harshness[len].distance == 0		      && cp->h.code < best)		    best = cp->h.code;		  cp += 1;		}	    }	}      if (baselink)	{	  /* We have a hit (of sorts). If the parameter list is	     "error_mark_node", or some variant thereof, it won't	     match any methods.  Since we have verified that the is	     some method vaguely matching this one (in name at least),	     silently return.	     	     Don't stop for friends, however.  */	  basetype_path = TREE_PURPOSE (baselink);	  function = TREE_VALUE (baselink);	  if (TREE_CODE (basetype_path) == TREE_LIST)	    basetype_path = TREE_VALUE (basetype_path);	  basetype = BINFO_TYPE (basetype_path);	  for (; function; func

⌨️ 快捷键说明

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