method.c

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

C
2,227
字号
/* Handle the hair of processing (but not expanding) inline functions.   Also manage function and variable name overloading.   Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc.   Contributed 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.  */#ifndef PARM_CAN_BE_ARRAY_TYPE#define PARM_CAN_BE_ARRAY_TYPE 1#endif/* Handle method declarations.  */#include "config.h"#include <stdio.h>#include "tree.h"#include "cp-tree.h"#include "class.h"#include "obstack.h"#include <ctype.h>#include "rtl.h"#include "expr.h"#include "output.h"#include "hard-reg-set.h"#include "flags.h"#ifdef HAVE_STRING_H#include <string.h>#elseextern char *index ();#endif/* TREE_LIST of the current inline functions that need to be   processed.  */struct pending_inline *pending_inlines;int static_labelno;#define obstack_chunk_alloc xmalloc#define obstack_chunk_free free/* Obstack where we build text strings for overloading, etc.  */static struct obstack scratch_obstack;static char *scratch_firstobj;static void icat PROTO((HOST_WIDE_INT));static void dicat PROTO((HOST_WIDE_INT, HOST_WIDE_INT));static void flush_repeats PROTO((tree));static void build_overload_identifier PROTO((tree));static void build_overload_nested_name PROTO((tree));static void build_overload_int PROTO((tree, int));static void build_overload_identifier PROTO((tree));static void build_qualified_name PROTO((tree));static void build_overload_value PROTO((tree, tree, int));static char *thunk_printable_name PROTO((tree));static void do_build_assign_ref PROTO((tree));static void do_build_copy_constructor PROTO((tree));static tree largest_union_member PROTO((tree));static tree build_decl_overload_real PROTO((tree, tree, tree, tree,					    tree, int)); static void build_template_parm_names PROTO((tree, tree));static void build_underscore_int PROTO((int));# define OB_INIT() (scratch_firstobj ? (obstack_free (&scratch_obstack, scratch_firstobj), 0) : 0)# define OB_PUTC(C) (obstack_1grow (&scratch_obstack, (C)))# define OB_PUTC2(C1,C2)	\  (obstack_1grow (&scratch_obstack, (C1)), obstack_1grow (&scratch_obstack, (C2)))# define OB_PUTS(S) (obstack_grow (&scratch_obstack, (S), sizeof (S) - 1))# define OB_PUTID(ID)  \  (obstack_grow (&scratch_obstack, IDENTIFIER_POINTER (ID),	\		 IDENTIFIER_LENGTH (ID)))# define OB_PUTCP(S) (obstack_grow (&scratch_obstack, (S), strlen (S)))# define OB_FINISH() (obstack_1grow (&scratch_obstack, '\0'))# define OB_LAST() (obstack_next_free (&scratch_obstack)[-1])voidinit_method (){  gcc_obstack_init (&scratch_obstack);  scratch_firstobj = (char *)obstack_alloc (&scratch_obstack, 0);}/* This must be large enough to hold any printed integer or floating-point   value.  */static char digit_buffer[128];/* Move inline function definitions out of structure so that they   can be processed normally.  CNAME is the name of the class   we are working from, METHOD_LIST is the list of method lists   of the structure.  We delete friend methods here, after   saving away their inline function definitions (if any).  */voiddo_inline_function_hair (type, friend_list)     tree type, friend_list;{  tree method = TYPE_METHODS (type);  if (method && TREE_CODE (method) == TREE_VEC)    {      if (TREE_VEC_ELT (method, 1))	method = TREE_VEC_ELT (method, 1);      else if (TREE_VEC_ELT (method, 0))	method = TREE_VEC_ELT (method, 0);      else	method = TREE_VEC_ELT (method, 2);    }  while (method)    {      /* Do inline member functions.  */      struct pending_inline *info = DECL_PENDING_INLINE_INFO (method);      if (info)	{	  tree args;	  my_friendly_assert (info->fndecl == method, 238);	  args = DECL_ARGUMENTS (method);	  while (args)	    {	      DECL_CONTEXT (args) = method;	      args = TREE_CHAIN (args);	    }	  /* Allow this decl to be seen in global scope.  Don't do this for             local class methods, though.  */	  if (! current_function_decl)	    IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (method)) = method;	}      method = TREE_CHAIN (method);    }  while (friend_list)    {      tree fndecl = TREE_VALUE (friend_list);      struct pending_inline *info = DECL_PENDING_INLINE_INFO (fndecl);      if (info)	{	  tree args;	  my_friendly_assert (info->fndecl == fndecl, 239);	  args = DECL_ARGUMENTS (fndecl);	  while (args)	    {	      DECL_CONTEXT (args) = fndecl;	      args = TREE_CHAIN (args);	    }	  /* Allow this decl to be seen in global scope */	  if (! current_function_decl)	    IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (fndecl)) = fndecl;	}      friend_list = TREE_CHAIN (friend_list);    }}/* Report an argument type mismatch between the best declared function   we could find and the current argument list that we have.  */voidreport_type_mismatch (cp, parmtypes, name_kind)     struct candidate *cp;     tree parmtypes;     char *name_kind;{  int i = cp->u.bad_arg;  tree ttf, tta;  char *tmp_firstobj;  switch (i)    {    case -4:      my_friendly_assert (TREE_CODE (cp->function) == TEMPLATE_DECL, 240);      cp_error ("type unification failed for function template `%#D'",		cp->function);      return;    case -2:      cp_error ("too few arguments for %s `%#D'", name_kind, cp->function);      return;    case -1:      cp_error ("too many arguments for %s `%#D'", name_kind, cp->function);      return;    case 0:      if (TREE_CODE (TREE_TYPE (cp->function)) != METHOD_TYPE)	break;    case -3:      /* Happens when the implicit object parameter is rejected.  */      my_friendly_assert (! TYPE_READONLY (TREE_TYPE (TREE_VALUE (parmtypes))),			  241);      if (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (TREE_VALUE (parmtypes))))	  && ! TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (cp->function))))))	cp_error ("call to non-volatile %s `%#D' with volatile object",		  name_kind, cp->function);      else	cp_error ("call to non-const %s `%#D' with const object",		  name_kind, cp->function);      return;    }  ttf = TYPE_ARG_TYPES (TREE_TYPE (cp->function));  tta = parmtypes;  while (i-- > 0)    {      ttf = TREE_CHAIN (ttf);      tta = TREE_CHAIN (tta);    }  OB_INIT ();  OB_PUTS ("bad argument ");  sprintf (digit_buffer, "%d", cp->u.bad_arg	   - (TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)	   + 1);  OB_PUTCP (digit_buffer);  OB_PUTS (" for function `");  OB_PUTCP (decl_as_string (cp->function, 1));  OB_PUTS ("' (type was ");  /* Reset `i' so that type printing routines do the right thing.  */  if (tta)    {      enum tree_code code = TREE_CODE (TREE_TYPE (TREE_VALUE (tta)));      if (code == ERROR_MARK)	OB_PUTS ("(failed type instantiation)");      else	{	  i = (code == FUNCTION_TYPE || code == METHOD_TYPE);	  OB_PUTCP (type_as_string (TREE_TYPE (TREE_VALUE (tta)), 1));	}    }  else OB_PUTS ("void");  OB_PUTC (')');  OB_FINISH ();  tmp_firstobj = (char *)alloca (obstack_object_size (&scratch_obstack));  bcopy (obstack_base (&scratch_obstack), tmp_firstobj,	 obstack_object_size (&scratch_obstack));  error (tmp_firstobj);}/* Here is where overload code starts.  *//* Array of types seen so far in top-level call to `build_overload_name'.   Allocated and deallocated by caller.  */static tree *typevec;/* Number of types interned by `build_overload_name' so far.  */static int maxtype;/* Number of occurrences of last type seen.  */static int nrepeats;/* Nonzero if we should not try folding parameter types.  */static int nofold;#define ALLOCATE_TYPEVEC(PARMTYPES) \  do { maxtype = 0, nrepeats = 0; \       typevec = (tree *)alloca (list_length (PARMTYPES) * sizeof (tree)); } while (0)#define DEALLOCATE_TYPEVEC(PARMTYPES) \  do { tree t = (PARMTYPES); \       while (t) { TREE_USED (TREE_VALUE (t)) = 0; t = TREE_CHAIN (t); } \  } while (0)/* Code to concatenate an asciified integer to a string.  */static#ifdef __GNUC____inline#endifvoidicat (i)     HOST_WIDE_INT i;{  unsigned HOST_WIDE_INT ui;  /* Handle this case first, to go really quickly.  For many common values,     the result of ui/10 below is 1.  */  if (i == 1)    {      OB_PUTC ('1');      return;    }  if (i >= 0)    ui = i;  else    {      OB_PUTC ('m');      ui = -i;    }  if (ui >= 10)    icat (ui / 10);  OB_PUTC ('0' + (ui % 10));}static voiddicat (lo, hi)     HOST_WIDE_INT lo, hi;{  unsigned HOST_WIDE_INT ulo, uhi, qlo, qhi;  if (hi >= 0)    {      uhi = hi;      ulo = lo;    }  else    {      uhi = (lo == 0 ? -hi : -hi-1);      ulo = -lo;    }  if (uhi == 0      && ulo < ((unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT - 1)))    {      icat (ulo);      return;    }  /* Divide 2^HOST_WIDE_INT*uhi+ulo by 10. */  qhi = uhi / 10;  uhi = uhi % 10;  qlo = uhi * (((unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT - 1)) / 5);  qlo += ulo / 10;  ulo = ulo % 10;  ulo += uhi * (((unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT - 1)) % 5)	 * 2;  qlo += ulo / 10;  ulo = ulo % 10;  /* Quotient is 2^HOST_WIDE_INT*qhi+qlo, remainder is ulo. */  dicat (qlo, qhi);  OB_PUTC ('0' + ulo);}static#ifdef __GNUC____inline#endifvoidflush_repeats (type)     tree type;{  int tindex = 0;  while (typevec[tindex] != type)    tindex++;  if (nrepeats > 1)    {      OB_PUTC ('N');      icat (nrepeats);      if (nrepeats > 9)	OB_PUTC ('_');    }  else    OB_PUTC ('T');  nrepeats = 0;  icat (tindex);  if (tindex > 9)    OB_PUTC ('_');}static int numeric_output_need_bar;static voidbuild_overload_nested_name (decl)     tree decl;{  if (DECL_CONTEXT (decl))    {      tree context = DECL_CONTEXT (decl);      /* For a template type parameter, we want to output an 'Xn'	 rather than 'T' or some such. */      if (TREE_CODE (context) == TEMPLATE_TYPE_PARM)	build_overload_name (context, 0, 0);      else	{	  if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')	    context = TYPE_NAME (context);	  build_overload_nested_name (context);	}    }  if (TREE_CODE (decl) == FUNCTION_DECL)    {      tree name = DECL_ASSEMBLER_NAME (decl);      char *label;      ASM_FORMAT_PRIVATE_NAME (label, IDENTIFIER_POINTER (name), static_labelno);      static_labelno++;      if (numeric_output_need_bar)	OB_PUTC ('_');      icat (strlen (label));      OB_PUTCP (label);      numeric_output_need_bar = 1;    }  else				/* TYPE_DECL */    build_overload_identifier (decl);}static voidbuild_underscore_int (i)     int i;{  if (i > 9)    OB_PUTC ('_');  icat (i);  if (i > 9)    OB_PUTC ('_');}/* Encoding for an INTEGER_CST value.  */static voidbuild_overload_int (value, in_template)     tree value;     int in_template;{  if (in_template && TREE_CODE (value) != INTEGER_CST)    /* We don't ever want this output, but it's inconvenient not to       be able to build the string.  This should cause assembler       errors we'll notice.  */    {      static int n;      sprintf (digit_buffer, " *%d", n++);      OB_PUTCP (digit_buffer);      return;    }  my_friendly_assert (TREE_CODE (value) == INTEGER_CST, 243);  if (TYPE_PRECISION (TREE_TYPE (value)) == 2 * HOST_BITS_PER_WIDE_INT)    {      if (TREE_INT_CST_HIGH (value)	  != (TREE_INT_CST_LOW (value) >> (HOST_BITS_PER_WIDE_INT - 1)))	{	  /* need to print a DImode value in decimal */	  dicat (TREE_INT_CST_LOW (value), TREE_INT_CST_HIGH (value));	  return;	}      /* else fall through to print in smaller mode */    }  /* Wordsize or smaller */  icat (TREE_INT_CST_LOW (value));}static voidbuild_overload_value (type, value, in_template)     tree type, value;     int in_template;{  while (TREE_CODE (value) == NON_LVALUE_EXPR	 || TREE_CODE (value) == NOP_EXPR)    value = TREE_OPERAND (value, 0);  my_friendly_assert (TREE_CODE (type) == PARM_DECL, 242);  type = TREE_TYPE (type);  if (numeric_output_need_bar)    {      OB_PUTC ('_');      numeric_output_need_bar = 0;    }  if (TREE_CODE (value) == TEMPLATE_CONST_PARM)    {      OB_PUTC ('Y');      build_underscore_int (TEMPLATE_CONST_IDX (value));      build_underscore_int (TEMPLATE_CONST_LEVEL (value));      return;    }  if (TREE_CODE (type) == POINTER_TYPE      && TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE)    {      /* Handle a pointer to data member as a template instantiation	 parameter, boy, what fun!  */      type = integer_type_node;      if (TREE_CODE (value) != INTEGER_CST)	{	  sorry ("unknown pointer to member constant");	  return;	}    }  if (TYPE_PTRMEMFUNC_P (type))    type = TYPE_PTRMEMFUNC_FN_TYPE (type);  switch (TREE_CODE (type))    {    case INTEGER_TYPE:    case ENUMERAL_TYPE:    case BOOLEAN_TYPE:      {	build_overload_int (value, in_template);	numeric_output_need_bar = 1;	return;      }    case REAL_TYPE:      {	REAL_VALUE_TYPE val;	char *bufp = digit_buffer;	pedwarn ("ANSI C++ forbids floating-point template arguments");	my_friendly_assert (TREE_CODE (value) == REAL_CST, 244);	val = TREE_REAL_CST (value);	if (REAL_VALUE_ISNAN (val))	  {	    sprintf (bufp, "NaN");	  }	else	  {	    if (REAL_VALUE_NEGATIVE (val))	      {		val = REAL_VALUE_NEGATE (val);		*bufp++ = 'm';	      }	    if (REAL_VALUE_ISINF (val))	      {		sprintf (bufp, "Infinity");	      }	    else	      {		REAL_VALUE_TO_DECIMAL (val, "%.20e", bufp);		bufp = (char *) index (bufp, 'e');		if (!bufp)		  strcat (digit_buffer, "e0");		else		  {		    char *p;		    bufp++;		    if (*bufp == '-')		      {			*bufp++ = 'm';		      }		    p = bufp;		    if (*p == '+')		      p++;		    while (*p == '0')

⌨️ 快捷键说明

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