method.c

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

C
2,227
字号
     tree tparms;     tree targs;     int for_method;{  char *name = IDENTIFIER_POINTER (dname);  /* member operators new and delete look like methods at this point.  */  if (! for_method && parms != NULL_TREE && TREE_CODE (parms) == TREE_LIST)    {      if (dname == ansi_opname[(int) DELETE_EXPR])	return get_identifier ("__builtin_delete");      else if (dname == ansi_opname[(int) VEC_DELETE_EXPR])	return get_identifier ("__builtin_vec_delete");      else if (TREE_CHAIN (parms) == void_list_node)	{	  if (dname == ansi_opname[(int) NEW_EXPR])	    return get_identifier ("__builtin_new");	  else if (dname == ansi_opname[(int) VEC_NEW_EXPR])	    return get_identifier ("__builtin_vec_new");	}    }  OB_INIT ();  if (for_method != 2)    OB_PUTCP (name);  /* Otherwise, we can divine that this is a constructor,     and figure out its name without any extra encoding.  */  OB_PUTC2 ('_', '_');  if (for_method)    {#if 0      /* We can get away without doing this.  */      OB_PUTC ('M');#endif      if (tparms != NULL_TREE)	OB_PUTC ('H');      {	tree this_type = TREE_VALUE (parms);	if (TREE_CODE (this_type) == RECORD_TYPE)  /* a signature pointer */	  parms = temp_tree_cons (NULL_TREE, SIGNATURE_TYPE (this_type),				  TREE_CHAIN (parms));	else	  parms = temp_tree_cons (NULL_TREE, TREE_TYPE (this_type),				  TREE_CHAIN (parms));      }    }  else if (tparms)    OB_PUTC ('H');  else    OB_PUTC ('F');  if (tparms)    {      build_template_parm_names (tparms, targs);      OB_PUTC ('_');    }  if (parms == NULL_TREE)    OB_PUTC ('e');  else if (parms == void_list_node)    OB_PUTC ('v');  else    {      ALLOCATE_TYPEVEC (parms);      nofold = 0;      if (for_method)	{	  build_overload_name (TREE_VALUE (parms), 0, 0);	  typevec[maxtype++] = TREE_VALUE (parms);	  TREE_USED (TREE_VALUE (parms)) = 1;	  if (TREE_CHAIN (parms))	    build_overload_name (TREE_CHAIN (parms), 0, 0);	  else	    OB_PUTC ('e');	}      else	build_overload_name (parms, 0, 0);      DEALLOCATE_TYPEVEC (parms);    }  if (ret_type != NULL_TREE && for_method != 2)    {      /* Add the return type. */      OB_PUTC ('_');      build_overload_name (ret_type, 0, 0);    }  OB_FINISH ();  {    tree n = get_identifier (obstack_base (&scratch_obstack));    if (IDENTIFIER_OPNAME_P (dname))      IDENTIFIER_OPNAME_P (n) = 1;    return n;  }}/* Change the name of a function definition so that it may be   overloaded. NAME is the name of the function to overload,   PARMS is the parameter list (which determines what name the   final function obtains).   FOR_METHOD is 1 if this overload is being performed   for a method, rather than a function type.  It is 2 if   this overload is being performed for a constructor.  */treebuild_decl_overload (dname, parms, for_method)     tree dname;     tree parms;     int for_method;{  return build_decl_overload_real (dname, parms, NULL_TREE, NULL_TREE,				   NULL_TREE, for_method); }/* Like build_decl_overload, but for template functions. */treebuild_template_decl_overload (dname, parms, ret_type, tparms, targs,			      for_method)      tree dname;     tree parms;     tree ret_type;     tree tparms;     tree targs;     int for_method;{  return build_decl_overload_real (dname, parms, ret_type, tparms, targs,				   for_method); }/* Build an overload name for the type expression TYPE.  */treebuild_typename_overload (type)     tree type;{  tree id;  OB_INIT ();  OB_PUTID (ansi_opname[(int) TYPE_EXPR]);  nofold = 1;  build_overload_name (type, 0, 1);  id = get_identifier (obstack_base (&scratch_obstack));  IDENTIFIER_OPNAME_P (id) = 1;#if 0  IDENTIFIER_GLOBAL_VALUE (id) = TYPE_MAIN_DECL (type);#endif  TREE_TYPE (id) = type;  return id;}treebuild_overload_with_type (name, type)     tree name, type;{  OB_INIT ();  OB_PUTID (name);  nofold = 1;  build_overload_name (type, 0, 1);  return get_identifier (obstack_base (&scratch_obstack));}treeget_id_2 (name, name2)     char *name;     tree name2;{  OB_INIT ();  OB_PUTCP (name);  OB_PUTID (name2);  OB_FINISH ();  return get_identifier (obstack_base (&scratch_obstack));}/* Given a tree_code CODE, and some arguments (at least one),   attempt to use an overloaded operator on the arguments.   For unary operators, only the first argument need be checked.   For binary operators, both arguments may need to be checked.   Member functions can convert class references to class pointers,   for one-level deep indirection.  More than that is not supported.   Operators [](), ()(), and ->() must be member functions.   We call function call building calls with LOOKUP_COMPLAIN if they   are our only hope.  This is true when we see a vanilla operator   applied to something of aggregate type.  If this fails, we are free   to return `error_mark_node', because we will have reported the   error.   Operators NEW and DELETE overload in funny ways: operator new takes   a single `size' parameter, and operator delete takes a pointer to the   storage being deleted.  When overloading these operators, success is   assumed.  If there is a failure, report an error message and return   `error_mark_node'.  *//* NOSTRICT */treebuild_opfncall (code, flags, xarg1, xarg2, arg3)     enum tree_code code;     int flags;     tree xarg1, xarg2, arg3;{  tree rval = 0;  tree arg1, arg2;  tree type1, type2, fnname;  tree fields1 = 0, parms = 0;  tree global_fn;  int try_second;  int binary_is_unary;  if (flag_ansi_overloading)    return build_new_op (code, flags, xarg1, xarg2, arg3);  if (xarg1 == error_mark_node)    return error_mark_node;  if (code == COND_EXPR)    {      if (xarg2 == error_mark_node	  || arg3 == error_mark_node)	return error_mark_node;    }  if (code == COMPONENT_REF)    if (TREE_CODE (TREE_TYPE (xarg1)) == POINTER_TYPE)      return rval;  /* First, see if we can work with the first argument */  type1 = TREE_TYPE (xarg1);  /* Some tree codes have length > 1, but we really only want to     overload them if their first argument has a user defined type.  */  switch (code)    {    case PREINCREMENT_EXPR:    case PREDECREMENT_EXPR:    case POSTINCREMENT_EXPR:    case POSTDECREMENT_EXPR:    case COMPONENT_REF:      binary_is_unary = 1;      try_second = 0;      break;      /* ARRAY_REFs and CALL_EXPRs must overload successfully.	 If they do not, return error_mark_node instead of NULL_TREE.  */    case ARRAY_REF:      if (xarg2 == error_mark_node)	return error_mark_node;    case CALL_EXPR:      rval = error_mark_node;      binary_is_unary = 0;      try_second = 0;      break;    case VEC_NEW_EXPR:    case NEW_EXPR:      {	tree args = expr_tree_cons (NULL_TREE, xarg2, arg3);	fnname = ansi_opname[(int) code];	if (flags & LOOKUP_GLOBAL)	  return build_overload_call (fnname, args, flags & LOOKUP_COMPLAIN);	rval = build_method_call	  (build_indirect_ref (build1 (NOP_EXPR, xarg1, error_mark_node),			       "new"),	   fnname, args, NULL_TREE, flags);	if (rval == error_mark_node)	  /* User might declare fancy operator new, but invoke it	     like standard one.  */	  return rval;	TREE_TYPE (rval) = xarg1;	TREE_CALLS_NEW (rval) = 1;	return rval;      }      break;    case VEC_DELETE_EXPR:    case DELETE_EXPR:      {	fnname = ansi_opname[(int) code];	if (flags & LOOKUP_GLOBAL)	  return build_overload_call (fnname,				      build_expr_list (NULL_TREE, xarg1),				      flags & LOOKUP_COMPLAIN);	arg1 = TREE_TYPE (xarg1);	/* This handles the case where we're trying to delete	   X (*a)[10];	   a=new X[5][10];	   delete[] a; */	   	if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE)	  {	    /* Strip off the pointer and the array.  */	    arg1 = TREE_TYPE (TREE_TYPE (arg1));	    while (TREE_CODE (arg1) == ARRAY_TYPE)		arg1 = (TREE_TYPE (arg1));	    arg1 = build_pointer_type (arg1);	  }	rval = build_method_call	  (build_indirect_ref (build1 (NOP_EXPR, arg1,				       error_mark_node),			       NULL_PTR),	   fnname, expr_tree_cons (NULL_TREE, xarg1,			       build_expr_list (NULL_TREE, xarg2)),	   NULL_TREE, flags);#if 0	/* This can happen when operator delete is protected.  */	my_friendly_assert (rval != error_mark_node, 250);	TREE_TYPE (rval) = void_type_node;#endif	return rval;      }      break;    default:      binary_is_unary = 0;      try_second = tree_code_length [(int) code] == 2;      if (try_second && xarg2 == error_mark_node)	return error_mark_node;      break;    }  if (try_second && xarg2 == error_mark_node)    return error_mark_node;  /* What ever it was, we do not know how to deal with it.  */  if (type1 == NULL_TREE)    return rval;  if (TREE_CODE (type1) == OFFSET_TYPE)    type1 = TREE_TYPE (type1);  if (TREE_CODE (type1) == REFERENCE_TYPE)    {      arg1 = convert_from_reference (xarg1);      type1 = TREE_TYPE (arg1);    }  else    {      arg1 = xarg1;    }  if (!IS_AGGR_TYPE (type1) || TYPE_PTRMEMFUNC_P (type1))    {      /* Try to fail. First, fail if unary */      if (! try_second)	return rval;      /* Second, see if second argument is non-aggregate.  */      type2 = TREE_TYPE (xarg2);      if (TREE_CODE (type2) == OFFSET_TYPE)	type2 = TREE_TYPE (type2);      if (TREE_CODE (type2) == REFERENCE_TYPE)	{	  arg2 = convert_from_reference (xarg2);	  type2 = TREE_TYPE (arg2);	}      else	{	  arg2 = xarg2;	}      if (!IS_AGGR_TYPE (type2))	return rval;      try_second = 0;    }  if (try_second)    {      /* First arg may succeed; see whether second should.  */      type2 = TREE_TYPE (xarg2);      if (TREE_CODE (type2) == OFFSET_TYPE)	type2 = TREE_TYPE (type2);      if (TREE_CODE (type2) == REFERENCE_TYPE)	{	  arg2 = convert_from_reference (xarg2);	  type2 = TREE_TYPE (arg2);	}      else	{	  arg2 = xarg2;	}      if (! IS_AGGR_TYPE (type2))	try_second = 0;    }  if (type1 == unknown_type_node      || (try_second && TREE_TYPE (xarg2) == unknown_type_node))    {      /* This will not be implemented in the foreseeable future.  */      return rval;    }  if (code == MODIFY_EXPR)    fnname = ansi_assopname[(int) TREE_CODE (arg3)];  else    fnname = ansi_opname[(int) code];  global_fn = lookup_name_nonclass (fnname);  /* This is the last point where we will accept failure.  This     may be too eager if we wish an overloaded operator not to match,     but would rather a normal operator be called on a type-converted     argument.  */  if (IS_AGGR_TYPE (type1))    {      fields1 = lookup_fnfields (TYPE_BINFO (type1), fnname, 0);      /* ARM $13.4.7, prefix/postfix ++/--.  */      if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)	{	  xarg2 = integer_zero_node;	  binary_is_unary = 0;	  if (fields1)	    {	      tree t, t2;	      int have_postfix = 0;	      /* Look for an `operator++ (int)'.  If they didn't have		 one, then we fall back to the old way of doing things.  */	      for (t = TREE_VALUE (fields1); t ; t = DECL_CHAIN (t))		{		  t2 = TYPE_ARG_TYPES (TREE_TYPE (t));		  if (TREE_CHAIN (t2) != NULL_TREE		      && TREE_VALUE (TREE_CHAIN (t2)) == integer_type_node)		    {		      have_postfix = 1;		      break;		    }		}	      if (! have_postfix)		{		  char *op = POSTINCREMENT_EXPR ? "++" : "--";		  /* There's probably a LOT of code in the world that		     relies upon this old behavior.  */		  pedwarn ("no `operator%s (int)' declared for postfix `%s', using prefix operator instead",			   op, op);		  xarg2 = NULL_TREE;		  binary_is_unary = 1;		}	    }	}    }  if (fields1 == NULL_TREE && global_fn == NULL_TREE)    return rval;  /* If RVAL winds up being `error_mark_node', we will return     that... There is no way that normal semantics of these     operators will succeed.  */  /* This argument may be an uncommitted OFFSET_REF.  This is     the case for example when dealing with static class members     which are referenced from their class name rather than     from a class instance.  */  if (TREE_CODE (xarg1) == OFFSET_REF      && TREE_CODE (TREE_OPERAND (xarg1, 1)) == VAR_DECL)    xarg1 = TREE_OPERAND (xarg1, 1);  if (try_second && xarg2 && TREE_CODE (xarg2) == OFFSET_REF      && TREE_CODE (TREE_OPERAND (xarg2, 1)) == VAR_DECL)    xarg2 = TREE_OPERAND (xarg2, 1);  if (global_fn)    flags |= LOOKUP_GLOBAL;  if (code == CALL_EXPR)    {      /* This can only be a member function.  */      return build_method_call (xarg1, fnname, xarg2,				NULL_TREE, LOOKUP_NORMAL);    }  else if (tree_code_length[(int) code] == 1 || binary_is_unary)    {      parms = NULL_TREE;      rval = build_method_call (xarg1, fnname, NULL_TREE, NULL_TREE, flags);    }  else if (code == COND_EXPR)    {      parms = expr_tree_cons (NULL_TREE, xarg2, build_expr_list (NULL_TREE, arg3));      rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);    }  else if (code == METHOD_CALL_EXPR)    {      /* must be a member function.  */      parms = expr_tree_cons (NULL_TREE, xarg2, arg3);      return build_method_call (xarg1, fnname, parms, NULL_TREE,				LOOKUP_NORMAL);    }  else if (fields1)    {      parms = build_expr_list (NULL_TREE, xarg2);      rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);    }  else    {      parms = expr_tree_cons (NULL_TREE, xarg1,			 build_expr_list (NULL_TREE, xarg2));      rval = build_overload_call (fnname, parms, flags);    }  return rval;}/* This function takes an identifier, ID, and attempts to figure out what   it means. There are a number of possible scenarios, presented in increasing   order of hair:   1) not in a class's scope   2) in class's scope, member name of the class's method   3) in class's scope, but not a member name of the class   4) in class's scope, member name of a class's variable   NAME is $1 from the bison rule. It is an IDENTIFIER_NODE.   VALUE is $$ from the bison rule. It is the value returned by lookup_name ($1)   As a last ditch, try to look up the name as a label and return that   address.   Values which are declared as being of REFERENCE_TYPE are   automatically dereferenced here (as a hack to make the   compiler faster).  */treehack_identifier (value, name)     tree value, name;{  tree type;  if (value == error_mark_node)    {      if (current_class_name)	{	  tree fields = lookup_fnfields (TYPE_BINFO (current_class_type), name, 1);	  if (fields == error_mark_node)	    return error_mark_node;	  if (fields)	    {	      tree fndecl;	      fndecl = TREE_VALUE (fields);	      my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 251);

⌨️ 快捷键说明

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