home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
bbs
/
gnu
/
gcc-2.3.3-src.lha
/
GNU
/
src
/
amiga
/
gcc-2.3.3
/
cp-pt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
57KB
|
2,058 lines
/* 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 modify
it under the terms of the GNU General Public License as published by
the 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 of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the 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 free
static 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.) */
void
begin_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. */
tree
process_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. */
tree
end_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. */
void
end_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;