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

📄 cp-pt.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Handle parameterized types (templates) for GNU C++.   Written by Ken Raeburn of Watchmaker Computing.   Copyright (C) 1992 Free Software Foundation, Inc.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, 675 Mass Ave, Cambridge, MA 02139, USA.  *//* Known bugs or deficiencies include:   * templates for class static data don't work (methods only)   * duplicated method templates can crash the compiler   * interface/impl data is taken from file defining the template   * all methods must be provided in header files; can't use a source     file that contains only the method templates and "just win"   * method templates must be seen before the expansion of the     class template is done */#include "config.h"#include <stdio.h>#include "obstack.h"#include "tree.h"#include "cp-tree.h"#include "cp-decl.h"#include "cp-parse.h"extern struct obstack permanent_obstack;extern tree grokdeclarator ();extern int lineno;extern char *input_filename;struct pending_inline *pending_template_expansions;int processing_template_decl;int processing_template_defn;#define obstack_chunk_alloc xmalloc#define obstack_chunk_free freestatic int unify ();static void add_pending_template ();void overload_template_name (), pop_template_decls ();/* We've got a template header coming up; set obstacks up to save the   nodes created permanently.  (There might be cases with nested templates   where we don't have to do this, but they aren't implemented, and it   probably wouldn't be worth the effort.)  */voidbegin_template_parm_list (){  pushlevel (0);  push_obstacks (&permanent_obstack, &permanent_obstack);}/* Process information from new template parameter NEXT and append it to the   LIST being built.  The rules for use of a template parameter type name   by later parameters are not well-defined for us just yet.  However, the   only way to avoid having to parse expressions of unknown complexity (and   with tokens of unknown types) is to disallow it completely.	So for now,   that is what is assumed.  */treeprocess_template_parm (list, next)     tree list, next;{  tree parm;  int is_type;  parm = next;  my_friendly_assert (TREE_CODE (parm) == TREE_LIST, 259);  is_type = TREE_CODE (TREE_PURPOSE (parm)) == IDENTIFIER_NODE;  if (!is_type)    {      parm = TREE_PURPOSE (parm);      my_friendly_assert (TREE_CODE (parm) == TREE_LIST, 260);      parm = TREE_VALUE (parm);      /* is a const-param */      parm = grokdeclarator (TREE_VALUE (next), TREE_PURPOSE (next),			     NORMAL, 0, NULL_TREE);      /* A template parameter is not modifiable.  */      TREE_READONLY (parm) = 1;      if (TREE_CODE (TREE_TYPE (parm)) == RECORD_TYPE	  || TREE_CODE (TREE_TYPE (parm)) == UNION_TYPE)	{	  sorry ("aggregate template parameter types");	  TREE_TYPE (parm) = void_type_node;	}    }  return chainon (list, parm);}/* The end of a template parameter list has been reached.  Process the   tree list into a parameter vector, converting each parameter into a more   useful form.	 Type parameters are saved as IDENTIFIER_NODEs, and others   as PARM_DECLs.  */treeend_template_parm_list (parms)     tree parms;{  int nparms = 0;  tree saved_parmlist;  tree parm;  for (parm = parms; parm; parm = TREE_CHAIN (parm))    nparms++;  saved_parmlist = make_tree_vec (nparms);  pushlevel (0);  for (parm = parms, nparms = 0; parm; parm = TREE_CHAIN (parm), nparms++)    {      tree p = parm, decl;      if (TREE_CODE (p) == TREE_LIST)	{	  tree t;	  p = TREE_PURPOSE (p);	  my_friendly_assert (TREE_CODE (p) == IDENTIFIER_NODE, 261);	  t = make_node (TEMPLATE_TYPE_PARM);	  TEMPLATE_TYPE_SET_INFO (t, saved_parmlist, nparms);	  decl = build_lang_decl (TYPE_DECL, p, t);	  TYPE_NAME (t) = decl;	}      else	{	  tree tinfo = make_node (TEMPLATE_CONST_PARM);	  my_friendly_assert (TREE_PERMANENT (tinfo), 262);	  if (!TREE_PERMANENT (p))	    {	      tree old_p = p;	      TREE_PERMANENT (old_p) = 1;	      p = copy_node (p);	      TREE_PERMANENT (old_p) = 0;	    }	  TEMPLATE_CONST_SET_INFO (tinfo, saved_parmlist, nparms);	  TREE_TYPE (tinfo) = TREE_TYPE (p);	  decl = build_decl (CONST_DECL, DECL_NAME (p), TREE_TYPE (p));	  DECL_INITIAL (decl) = tinfo;	}      TREE_VEC_ELT (saved_parmlist, nparms) = p;      pushdecl (decl);    }  set_current_level_tags_transparency (1);  processing_template_decl++;  return saved_parmlist;}/* end_template_decl is called after a template declaration is seen.   D1 is template header; D2 is class_head_sans_basetype or a   TEMPLATE_DECL with its DECL_RESULT field set.  */voidend_template_decl (d1, d2, is_class)     tree d1, d2, is_class;{  tree decl;  struct template_info *tmpl;  tmpl = (struct template_info *) obstack_alloc (&permanent_obstack,					    sizeof (struct template_info));  tmpl->text = 0;  tmpl->length = 0;  tmpl->aggr = is_class;  /* cloned from reinit_parse_for_template */  tmpl->filename = input_filename;  tmpl->lineno = lineno;  tmpl->parm_vec = d1;          /* [eichin:19911015.2306EST] */#ifdef DEBUG_CP_BINDING_LEVELS  indent_to (stderr, debug_bindings_indentation);  fprintf (stderr, "end_template_decl");  debug_bindings_indentation += 4;#endif  if (d2 == NULL_TREE || d2 == error_mark_node)    {      decl = 0;      goto lose;    }  if (is_class)    {      decl = build_lang_decl (TEMPLATE_DECL, d2, NULL_TREE);    }  else    {      if (TREE_CODE (d2) == TEMPLATE_DECL)	decl = d2;      else	{	  /* Class destructor templates and operator templates are	     slipping past as non-template nodes.  Process them here, since	     I haven't figured out where to catch them earlier.  I could	     go do that, but it's a choice between getting that done and	     staying only N months behind schedule.  Sorry....  */	  enum tree_code code;	  my_friendly_assert (TREE_CODE (d2) == CALL_EXPR, 263);	  code = TREE_CODE (TREE_OPERAND (d2, 0));	  my_friendly_assert (code == BIT_NOT_EXPR		  || code == OP_IDENTIFIER		  || code == SCOPE_REF, 264);	  d2 = grokdeclarator (d2, NULL_TREE, MEMFUNCDEF, 0, NULL_TREE);	  decl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (d2),				  TREE_TYPE (d2));	  DECL_TEMPLATE_RESULT (decl) = d2;	  DECL_CONTEXT (decl) = DECL_CONTEXT (d2);	  DECL_CLASS_CONTEXT (decl) = DECL_CLASS_CONTEXT (d2);	  DECL_NAME (decl) = DECL_NAME (d2);	  TREE_TYPE (decl) = TREE_TYPE (d2);	  TREE_PUBLIC (decl) = TREE_PUBLIC (d2) = 0;	  DECL_EXTERNAL (decl) = (DECL_EXTERNAL (d2)				  && !(DECL_CLASS_CONTEXT (d2)				       && !DECL_THIS_EXTERN (d2)));	}      /* All routines creating TEMPLATE_DECL nodes should now be using	 build_lang_decl, which will have set this up already.	*/      my_friendly_assert (DECL_LANG_SPECIFIC (decl) != 0, 265);      /* @@ Somewhere, permanent allocation isn't being used.  */      if (! DECL_TEMPLATE_IS_CLASS (decl)	  && TREE_CODE (DECL_TEMPLATE_RESULT (decl)) == FUNCTION_DECL)	{	  tree result = DECL_TEMPLATE_RESULT (decl);	  /* Will do nothing if allocation was already permanent.  */	  DECL_ARGUMENTS (result) = copy_to_permanent (DECL_ARGUMENTS (result));	}      /* If this is for a method, there's an extra binding level here.	*/      if (! DECL_TEMPLATE_IS_CLASS (decl)	  && DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl)) != NULL_TREE)	{	  /* @@ Find out where this should be getting set!  */	  tree r = DECL_TEMPLATE_RESULT (decl);	  if (DECL_CLASS_CONTEXT (r) == NULL_TREE)	    DECL_CLASS_CONTEXT (r) = DECL_CONTEXT (r);	}    }  DECL_TEMPLATE_INFO (decl) = tmpl;  DECL_TEMPLATE_PARMS (decl) = d1;lose:  if (decl)    {      /* If context of decl is non-null (i.e., method template), add it	 to the appropriate class template, and pop the binding levels.  */      if (! DECL_TEMPLATE_IS_CLASS (decl)	  && DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl)) != NULL_TREE)	{	  tree ctx = DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl));	  tree tmpl;	  my_friendly_assert (TREE_CODE (ctx) == UNINSTANTIATED_P_TYPE, 266);	  tmpl = UPT_TEMPLATE (ctx);	  DECL_TEMPLATE_MEMBERS (tmpl) =	    perm_tree_cons (DECL_NAME (decl), decl,			    DECL_TEMPLATE_MEMBERS (tmpl));	  poplevel (0, 0, 0);	  poplevel (0, 0, 0);	}      /* Otherwise, go back to top level first, and push the template decl	 again there.  */      else	{	  poplevel (0, 0, 0);	  poplevel (0, 0, 0);	  if (TREE_TYPE (decl)	      && IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl)) != NULL_TREE)	    push_overloaded_decl (decl, 0);	  else	    pushdecl (decl);	}    }#if 0 /* It happens sometimes, with syntactic or semantic errors.	 One specific case:	 template <class A, int X, int Y> class Foo { ... };	 template <class A, int X, int y> Foo<X,Y>::method (Foo& x) { ... }	 Note the missing "A" in the class containing "method".  */  my_friendly_assert (global_bindings_p (), 267);#else  while (! global_bindings_p ())    poplevel (0, 0, 0);#endif  pop_obstacks ();  processing_template_decl--;  (void) get_pending_sizes ();#ifdef DEBUG_CP_BINDING_LEVELS  debug_bindings_indentation -= 4;#endif}/* Convert all template arguments to their appropriate types, and return   a vector containing the resulting values.  If any error occurs, return   error_mark_node.  */static treecoerce_template_parms (parms, arglist)     tree parms, arglist;{  int nparms, i, lost = 0;  tree vec;  if (TREE_CODE (arglist) == TREE_VEC)    nparms = TREE_VEC_LENGTH (arglist);  else    nparms = list_length (arglist);  if (nparms != TREE_VEC_LENGTH (parms))    {      error ("incorrect number of parameters (%d, should be %d) in template expansion",	     nparms, TREE_VEC_LENGTH (parms));      return error_mark_node;    }  if (TREE_CODE (arglist) == TREE_VEC)    vec = copy_node (arglist);  else    {      vec = make_tree_vec (nparms);      for (i = 0; i < nparms; i++)	{	  tree arg = arglist;	  arglist = TREE_CHAIN (arglist);	  if (arg == error_mark_node)	    lost++;	  else	    arg = TREE_VALUE (arg);	  TREE_VEC_ELT (vec, i) = arg;	}    }  for (i = 0; i < nparms; i++)    {      tree arg = TREE_VEC_ELT (vec, i);      tree parm = TREE_VEC_ELT (parms, i);      tree val;      int is_type, requires_type;      is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't';      requires_type = TREE_CODE (parm) == IDENTIFIER_NODE;      if (is_type != requires_type)	{	  error ("type/value mismatch in template parameter list");	  lost++;	  TREE_VEC_ELT (vec, i) = error_mark_node;	  continue;	}      if (is_type)	{	  val = groktypename (arg);	}      else	{	  val = digest_init (TREE_TYPE (parm), arg, (tree *) 0);	}      if (val == error_mark_node)	lost++;      TREE_VEC_ELT (vec, i) = val;    }  if (lost)    return error_mark_node;  return vec;}/* Given class template name and parameter list, produce a user-friendly name   for the instantiation.  Note that this name isn't necessarily valid as   input to the compiler, because ">" characters may be adjacent.  */static char *mangle_class_name_for_template (name, parms, arglist)     char *name;     tree parms, arglist;{  static struct obstack scratch_obstack;  static char *scratch_firstobj;  int i, nparms;  char ibuf[100];  if (!scratch_firstobj)    {      gcc_obstack_init (&scratch_obstack);      scratch_firstobj = obstack_alloc (&scratch_obstack, 1);    }  else    obstack_free (&scratch_obstack, scratch_firstobj);#if 0#define buflen	sizeof(buf)#define check	if (bufp >= buf+buflen-1) goto too_long#define ccat(c) *bufp++=(c); check#define advance	bufp+=strlen(bufp); check#define cat(s)	strncpy(bufp, s, buf+buflen-bufp-1); advance#else#define check#define ccat(c)	obstack_1grow (&scratch_obstack, (c));#define advance#define cat(s)	obstack_grow (&scratch_obstack, (s), strlen (s))#endif#define icat(n)	sprintf(ibuf,"%d",(n)); cat(ibuf)#define xcat(n)	sprintf(ibuf,"%ux",n); cat(ibuf)  cat (name);  ccat ('<');  nparms = TREE_VEC_LENGTH (parms);  my_friendly_assert (nparms == TREE_VEC_LENGTH (arglist), 268);  for (i = 0; i < nparms; i++)    {      tree parm = TREE_VEC_ELT (parms, i), arg = TREE_VEC_ELT (arglist, i);      tree type, id;      if (i)	ccat (',');      if (TREE_CODE (parm) == IDENTIFIER_NODE)	{	  /* parm is a type */	  extern char * type_as_string ();	  char *typename;	  if (TYPE_NAME (arg)	      && (TREE_CODE (arg) == RECORD_TYPE		  || TREE_CODE (arg) == UNION_TYPE		  || TREE_CODE (arg) == ENUMERAL_TYPE)	      && TYPE_IDENTIFIER (arg)	      && IDENTIFIER_POINTER (TYPE_IDENTIFIER (arg)))	    typename = IDENTIFIER_POINTER (TYPE_IDENTIFIER (arg));	  else	    typename = type_as_string (arg);	  cat (typename);	  continue;	}      else	my_friendly_assert (TREE_CODE (parm) == PARM_DECL, 269);      /* Should do conversions as for "const" initializers.  */      type = TREE_TYPE (parm);      id = DECL_NAME (parm);	      if (TREE_CODE (arg) == TREE_LIST)	{	  /* New list cell was built because old chain link was in	     use.  */	  my_friendly_assert (TREE_PURPOSE (arg) == NULL_TREE, 270);	  arg = TREE_VALUE (arg);	}            switch (TREE_CODE (type))	{	case INTEGER_TYPE:	case ENUMERAL_TYPE:	  if (TREE_CODE (arg) == INTEGER_CST)	    {	      if (TREE_INT_CST_HIGH (arg)		  != (TREE_INT_CST_LOW (arg) >> (HOST_BITS_PER_WIDE_INT - 1)))		{		  tree val = arg;		  if (TREE_INT_CST_HIGH (val) < 0)		    {		      ccat ('-');		      val = build_int_2 (~TREE_INT_CST_LOW (val),					 -TREE_INT_CST_HIGH (val));		    }		  /* Would "%x%0*x" or "%x%*0x" get zero-padding on all		     systems?  */		  {		    static char format[10]; /* "%x%09999x\0" */		    if (!format[0])		      sprintf (format, "%%x%%0%dx", HOST_BITS_PER_INT / 4);		    sprintf (ibuf, format, TREE_INT_CST_HIGH (val),			     TREE_INT_CST_LOW (val));		    cat (ibuf);		  }		}	      else		icat (TREE_INT_CST_LOW (arg));	    }	  else	    {	      error ("invalid integer constant for template parameter");	      cat ("*error*");	    }	  break;#ifndef REAL_IS_NOT_DOUBLE	case REAL_TYPE:	  sprintf (ibuf, "%e", TREE_REAL_CST (arg));	  cat (ibuf);	  break;#endif	case POINTER_TYPE:	  if (TREE_CODE (arg) != ADDR_EXPR)	    {	      error ("invalid pointer constant for template parameter");	      cat ("*error*");	      break;	    }	  ccat ('&');	  arg = TREE_OPERAND (arg, 0);	  if (TREE_CODE (arg) == FUNCTION_DECL)	    cat (fndecl_as_string (0, arg, 0));	  else	    {	      my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (arg)) == 'd',				  271);	      cat (IDENTIFIER_POINTER (DECL_NAME (arg)));	    }	  break;	default:	  sorry ("encoding %s as template parm",

⌨️ 快捷键说明

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