diff options
author | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
commit | 0126e157b87f137fc08dc7f46f6c291b9d06ac5d (patch) | |
tree | f8555e3e504eb82b4cd3cba5cec20ae4ce8124ff /gnu/egcs/gcc/cp/method.c | |
parent | ff8e9a4356e55ed142306c3a375fa280800abc86 (diff) |
egcs projects compiler system
Exact copy of the snapshot, except for the removal of
texinfo/
gcc/ch/
libchill/
Diffstat (limited to 'gnu/egcs/gcc/cp/method.c')
-rw-r--r-- | gnu/egcs/gcc/cp/method.c | 2460 |
1 files changed, 2460 insertions, 0 deletions
diff --git a/gnu/egcs/gcc/cp/method.c b/gnu/egcs/gcc/cp/method.c new file mode 100644 index 00000000000..39f7f041937 --- /dev/null +++ b/gnu/egcs/gcc/cp/method.c @@ -0,0 +1,2460 @@ +/* Handle the hair of processing (but not expanding) inline functions. + Also manage function and variable name overloading. + Copyright (C) 1987, 89, 92-97, 1998, 1999 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 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#ifndef __GNUC__ +#define __inline +#endif + +#ifndef PARM_CAN_BE_ARRAY_TYPE +#define PARM_CAN_BE_ARRAY_TYPE 1 +#endif + +/* Handle method declarations. */ +#include "config.h" +#include "system.h" +#include "tree.h" +#include "cp-tree.h" +#include "obstack.h" +#include "rtl.h" +#include "expr.h" +#include "output.h" +#include "hard-reg-set.h" +#include "flags.h" +#include "toplev.h" + +/* 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 int old_backref_index PROTO((tree)); +static int flush_repeats PROTO((int, 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 void issue_nrepeats PROTO((int, tree)); +static char *build_mangled_name PROTO((tree,int,int)); +static void process_modifiers PROTO((tree)); +static void process_overload_item PROTO((tree,int)); +static void do_build_assign_ref PROTO((tree)); +static void do_build_copy_constructor PROTO((tree)); +static tree largest_union_member PROTO((tree)); +static void build_template_template_parm_names PROTO((tree)); +static void build_template_parm_names PROTO((tree, tree)); +static void build_underscore_int PROTO((int)); +static void start_squangling PROTO((void)); +static void end_squangling PROTO((void)); +static int check_ktype PROTO((tree, int)); +static int issue_ktype PROTO((tree)); +static void build_overload_scope_ref PROTO((tree)); +static void build_mangled_template_parm_index PROTO((char *, tree)); +#if HOST_BITS_PER_WIDE_INT >= 64 +static void build_mangled_C9x_name PROTO((int)); +#endif +static int is_back_referenceable_type PROTO((tree)); +static int check_btype PROTO((tree)); +static void build_mangled_name_for_type PROTO((tree)); +static void build_mangled_name_for_type_with_Gcode PROTO((tree, 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]) + +void +init_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). */ + +void +do_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); + } + } + 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); + } + } + + friend_list = TREE_CHAIN (friend_list); + } +} + +/* Here is where overload code starts. */ + +/* type tables for K and B type compression */ +static tree *btypelist = NULL; +static tree *ktypelist = NULL; +static int maxbsize = 0; +static int maxksize = 0; + +/* number of each type seen */ +static int maxbtype = 0; +static int maxktype = 0; + +/* Array of types seen so far in top-level call to `build_mangled_name'. + Allocated and deallocated by caller. */ +static tree *typevec = NULL; +static int typevec_size; + +/* Number of types interned by `build_mangled_name' so far. */ +static int maxtype = 0; + +/* Nonzero if we should not try folding parameter types. */ +static int nofold; + +/* This appears to be set to true if an underscore is required to be + comcatenated before another number can be outputed. */ +static int numeric_output_need_bar; + +static __inline void +start_squangling () +{ + if (flag_do_squangling) + { + nofold = 0; + maxbtype = 0; + maxktype = 0; + maxbsize = 50; + maxksize = 50; + btypelist = (tree *)xmalloc (sizeof (tree) * maxbsize); + ktypelist = (tree *)xmalloc (sizeof (tree) * maxksize); + } +} + +static __inline void +end_squangling () +{ + if (flag_do_squangling) + { + if (ktypelist) + free (ktypelist); + if (btypelist) + free (btypelist); + maxbsize = 0; + maxksize = 0; + maxbtype = 0; + maxktype = 0; + ktypelist = NULL; + btypelist = NULL; + } +} + +/* Code to concatenate an asciified integer to a string. */ + +static __inline void +icat (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 void +dicat (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); +} + +/* Returns the index of TYPE in the typevec, or -1 if it's not there. */ + +static __inline int +old_backref_index (type) + tree type; +{ + int tindex = 0; + + if (! is_back_referenceable_type (type)) + return -1; + + /* The entry for this parm is at maxtype-1, so don't look there for + something to repeat. */ + for (tindex = 0; tindex < maxtype - 1; ++tindex) + if (same_type_p (typevec[tindex], type)) + break; + + if (tindex == maxtype - 1) + return -1; + + return tindex; +} + +/* Old mangling style: If TYPE has already been used in the parameter list, + emit a backward reference and return non-zero; otherwise, return 0. + + NREPEATS is the number of repeats we've recorded of this type, or 0 if + this is the first time we've seen it and we're just looking to see if + it had been used before. */ + +static __inline int +flush_repeats (nrepeats, type) + int nrepeats; + tree type; +{ + int tindex = old_backref_index (type); + + if (tindex == -1) + { + my_friendly_assert (nrepeats == 0, 990316); + return 0; + } + + if (nrepeats > 1) + { + OB_PUTC ('N'); + icat (nrepeats); + if (nrepeats > 9) + OB_PUTC ('_'); + } + else + OB_PUTC ('T'); + icat (tindex); + if (tindex > 9) + OB_PUTC ('_'); + + return 1; +} + +/* Returns nonzero iff this is a type to which we will want to make + back-references (using the `B' code). */ + +static int +is_back_referenceable_type (type) + tree type; +{ + /* For some reason, the Java folks don't want back refs on these. */ + if (TYPE_FOR_JAVA (type)) + return 0; + + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + case REAL_TYPE: + case VOID_TYPE: + case BOOLEAN_TYPE: + /* These types have single-character manglings, so there's no + point in generating back-references. */ + return 0; + + case TEMPLATE_TYPE_PARM: + /* It would be a bit complex to demangle signatures correctly if + we generated back-references to these, and the manglings of + type parameters are short. */ + return 0; + + default: + return 1; + } +} + +/* Issue the squangling code indicating NREPEATS repetitions of TYPE, + which was the last parameter type output. */ + +static void +issue_nrepeats (nrepeats, type) + int nrepeats; + tree type; +{ + if (nrepeats == 1 && !is_back_referenceable_type (type)) + /* For types whose manglings are short, don't bother using the + repetition code if there's only one repetition, since the + repetition code will be about as long as the ordinary mangling. */ + build_mangled_name_for_type (type); + else + { + OB_PUTC ('n'); + icat (nrepeats); + if (nrepeats > 9) + OB_PUTC ('_'); + } +} + +/* Check to see if a tree node has been entered into the Kcode typelist. + If not, add it. Returns -1 if it isn't found, otherwise returns the + index. */ + +static int +check_ktype (node, add) + tree node; + int add; +{ + int x; + tree localnode = node; + + if (ktypelist == NULL) + return -1; + + if (TREE_CODE (node) == TYPE_DECL) + localnode = TREE_TYPE (node); + + for (x=0; x < maxktype; x++) + { + if (same_type_p (localnode, ktypelist[x])) + return x; + } + /* Didn't find it, so add it here. */ + if (add) + { + if (maxksize <= maxktype) + { + maxksize = maxksize* 3 / 2; + ktypelist = (tree *)xrealloc (ktypelist, sizeof (tree) * maxksize); + } + ktypelist[maxktype++] = localnode; + } + return -1; +} + + +static __inline int +issue_ktype (decl) + tree decl; +{ + int kindex; + kindex = check_ktype (decl, FALSE); + if (kindex != -1) + { + OB_PUTC ('K'); + icat (kindex); + if (kindex > 9) + OB_PUTC ('_'); + return TRUE; + } + return FALSE; +} + +/* Build a representation for DECL, which may be an entity not at + global scope. If so, a marker indicating that the name is + qualified has already been output, but the qualifying context has + not. */ + +static void +build_overload_nested_name (decl) + tree decl; +{ + tree context; + + if (ktypelist && issue_ktype (decl)) + return; + + if (decl == global_namespace) + return; + + context = CP_DECL_CONTEXT (decl); + + /* try to issue a K type, and if we can't continue the normal path */ + if (!(ktypelist && issue_ktype (context))) + { + /* For a template type parameter, we want to output an 'Xn' + rather than 'T' or some such. */ + if (TREE_CODE (context) == TEMPLATE_TYPE_PARM + || TREE_CODE (context) == TEMPLATE_TEMPLATE_PARM) + build_mangled_name_for_type (context); + 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 if (TREE_CODE (decl) == NAMESPACE_DECL) + build_overload_identifier (DECL_NAME (decl)); + else /* TYPE_DECL */ + build_overload_identifier (decl); +} + +/* Output the decimal representation of I. If I > 9, the decimal + representation is preceeded and followed by an underscore. */ + +static void +build_underscore_int (i) + int i; +{ + if (i > 9) + OB_PUTC ('_'); + icat (i); + if (i > 9) + OB_PUTC ('_'); +} + +static void +build_overload_scope_ref (value) + tree value; +{ + OB_PUTC2 ('Q', '2'); + numeric_output_need_bar = 0; + build_mangled_name_for_type (TREE_OPERAND (value, 0)); + build_overload_identifier (TREE_OPERAND (value, 1)); +} + +/* Encoding for an INTEGER_CST value. */ + +static void +build_overload_int (value, in_template) + tree value; + int in_template; +{ + if (in_template && TREE_CODE (value) != INTEGER_CST) + { + if (TREE_CODE (value) == SCOPE_REF) + { + build_overload_scope_ref (value); + return; + } + + OB_PUTC ('E'); + numeric_output_need_bar = 0; + + if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (value)))) + { + int i; + int operands = tree_code_length[(int) TREE_CODE (value)]; + tree id; + char* name; + + id = ansi_opname [(int) TREE_CODE (value)]; + my_friendly_assert (id != NULL_TREE, 0); + name = IDENTIFIER_POINTER (id); + if (name[0] != '_' || name[1] != '_') + /* On some erroneous inputs, we can get here with VALUE a + LOOKUP_EXPR. In that case, the NAME will be the + identifier for "<invalid operator>". We must survive + this routine in order to issue a sensible error + message, so we fall through to the case below. */ + goto bad_value; + + for (i = 0; i < operands; ++i) + { + tree operand; + enum tree_code tc; + + /* We just outputted either the `E' or the name of the + operator. */ + numeric_output_need_bar = 0; + + if (i != 0) + /* Skip the leading underscores. */ + OB_PUTCP (name + 2); + + operand = TREE_OPERAND (value, i); + tc = TREE_CODE (operand); + + if (TREE_CODE_CLASS (tc) == 't') + /* We can get here with sizeof, e.g.: + + template <class T> void f(A<sizeof(T)>); */ + build_mangled_name_for_type (operand); + else if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (tc))) + build_overload_int (operand, in_template); + else + build_overload_value (TREE_TYPE (operand), + operand, + in_template); + } + } + else + { + /* 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; + bad_value: + sprintf (digit_buffer, " *%d", n++); + OB_PUTCP (digit_buffer); + } + + OB_PUTC ('W'); + numeric_output_need_bar = 0; + 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)); + numeric_output_need_bar = 1; + return; + } + /* else fall through to print in smaller mode */ + } + /* Wordsize or smaller */ + icat (TREE_INT_CST_LOW (value)); + numeric_output_need_bar = 1; +} + + +/* Output S followed by a representation of the TEMPLATE_PARM_INDEX + supplied in INDEX. */ + +static void +build_mangled_template_parm_index (s, index) + char* s; + tree index; +{ + OB_PUTCP (s); + build_underscore_int (TEMPLATE_PARM_IDX (index)); + /* We use the LEVEL, not the ORIG_LEVEL, because the mangling is a + representation of the function from the point of view of its + type. */ + build_underscore_int (TEMPLATE_PARM_LEVEL (index)); +} + + +/* Mangling for C9X integer types (and Cygnus extensions for 128-bit + and other types) is based on the letter "I" followed by the hex + representations of the bitsize for the type in question. For + encodings that result in larger than two digits, a leading and + trailing underscore is added. + + Thus: + int1_t = 001 = I01 + int8_t = 008 = I08 + int16_t = 010 = I10 + int24_t = 018 = I18 + int32_t = 020 = I20 + int64_t = 040 = I40 + int80_t = 050 = I50 + int128_t = 080 = I80 + int256_t = 100 = I_100_ + int512_t = 200 = I_200_ + + Given an integer in decimal format, mangle according to this scheme. */ + +#if HOST_BITS_PER_WIDE_INT >= 64 +static void +build_mangled_C9x_name (bits) + int bits; +{ + char mangled[10] = ""; + + if (bits > 255) + sprintf (mangled, "I_%x_", bits); + else + sprintf (mangled, "I%.2x", bits); + + OB_PUTCP (mangled); +} +#endif + +static void +build_overload_value (type, value, in_template) + tree type, value; + int in_template; +{ + my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (type)) == 't', 0); + + while (TREE_CODE (value) == NON_LVALUE_EXPR + || TREE_CODE (value) == NOP_EXPR) + value = TREE_OPERAND (value, 0); + + if (numeric_output_need_bar) + { + OB_PUTC ('_'); + numeric_output_need_bar = 0; + } + + if (TREE_CODE (value) == TEMPLATE_PARM_INDEX) + { + build_mangled_template_parm_index ("Y", value); + return; + } + + if (TYPE_PTRMEM_P (type)) + { + if (TREE_CODE (value) != PTRMEM_CST) + /* We should have already rejected this pointer to member, + since it is not a constant. */ + my_friendly_abort (0); + + /* Get the actual FIELD_DECL. */ + value = PTRMEM_CST_MEMBER (value); + my_friendly_assert (TREE_CODE (value) == FIELD_DECL, 0); + + /* Output the name of the field. */ + build_overload_identifier (DECL_NAME (value)); + return; + } + + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + { + build_overload_int (value, in_template); + 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') + p++; + if (*p == 0) + { + *bufp++ = '0'; + *bufp = 0; + } + else if (p != bufp) + { + while (*p) + *bufp++ = *p++; + *bufp = 0; + } + } +#ifdef NO_DOT_IN_LABEL + bufp = (char *) index (bufp, '.'); + if (bufp) + *bufp = '_'; +#endif + } + } + OB_PUTCP (digit_buffer); + numeric_output_need_bar = 1; + return; + } + case POINTER_TYPE: + if (TREE_CODE (value) == INTEGER_CST) + { + build_overload_int (value, in_template); + return; + } + else if (TREE_CODE (value) == TEMPLATE_PARM_INDEX) + { + build_mangled_template_parm_index ("", value); + numeric_output_need_bar = 1; + return; + } + + value = TREE_OPERAND (value, 0); + + /* Fall through. */ + + case REFERENCE_TYPE: + if (TREE_CODE (value) == VAR_DECL) + { + my_friendly_assert (DECL_NAME (value) != 0, 245); + build_overload_identifier (DECL_ASSEMBLER_NAME (value)); + return; + } + else if (TREE_CODE (value) == FUNCTION_DECL) + { + my_friendly_assert (DECL_NAME (value) != 0, 246); + build_overload_identifier (DECL_ASSEMBLER_NAME (value)); + return; + } + else if (TREE_CODE (value) == SCOPE_REF) + build_overload_scope_ref (value); + else + my_friendly_abort (71); + break; /* not really needed */ + + case RECORD_TYPE: + { + tree delta; + tree idx; + tree pfn; + tree delta2; + + my_friendly_assert (TYPE_PTRMEMFUNC_P (type), 0); + + /* We'll get a ADDR_EXPR of a SCOPE_REF here if we're + mangling, an instantiation of something like: + + template <class T, void (T::*fp)()> class C {}; + template <class T> C<T, &T::f> x(); + + We mangle the return type of the function, and that + contains template parameters. */ + if (TREE_CODE (value) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (value, 0)) == SCOPE_REF) + { + build_overload_scope_ref (TREE_OPERAND (value, 0)); + break; + } + + my_friendly_assert (TREE_CODE (value) == PTRMEM_CST, 0); + + expand_ptrmemfunc_cst (value, &delta, &idx, &pfn, &delta2); + build_overload_int (delta, in_template); + OB_PUTC ('_'); + build_overload_int (idx, in_template); + OB_PUTC ('_'); + if (pfn) + { + numeric_output_need_bar = 0; + build_overload_identifier (DECL_ASSEMBLER_NAME + (PTRMEM_CST_MEMBER (value))); + } + else + { + OB_PUTC ('i'); + build_overload_int (delta2, in_template); + } + } + break; + + default: + sorry ("conversion of %s as template parameter", + tree_code_name [(int) TREE_CODE (type)]); + my_friendly_abort (72); + } +} + + +/* Add encodings for the declaration of template template parameters. + PARMLIST must be a TREE_VEC. */ + +static void +build_template_template_parm_names (parmlist) + tree parmlist; +{ + int i, nparms; + + my_friendly_assert (TREE_CODE (parmlist) == TREE_VEC, 246.5); + nparms = TREE_VEC_LENGTH (parmlist); + icat (nparms); + for (i = 0; i < nparms; i++) + { + tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i)); + if (TREE_CODE (parm) == TYPE_DECL) + { + /* This parameter is a type. */ + OB_PUTC ('Z'); + } + else if (TREE_CODE (parm) == TEMPLATE_DECL) + { + /* This parameter is a template. */ + OB_PUTC ('z'); + build_template_template_parm_names (DECL_INNERMOST_TEMPLATE_PARMS (parm)); + } + else + /* It's a PARM_DECL. */ + build_mangled_name_for_type (TREE_TYPE (parm)); + } +} + + +/* Add encodings for the vector of template parameters in PARMLIST, + given the vector of arguments to be substituted in ARGLIST. */ + +static void +build_template_parm_names (parmlist, arglist) + tree parmlist; + tree arglist; +{ + int i, nparms; + tree inner_args = innermost_args (arglist); + + nparms = TREE_VEC_LENGTH (parmlist); + icat (nparms); + for (i = 0; i < nparms; i++) + { + tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i)); + tree arg = TREE_VEC_ELT (inner_args, i); + if (TREE_CODE (parm) == TYPE_DECL) + { + /* This parameter is a type. */ + OB_PUTC ('Z'); + build_mangled_name_for_type (arg); + } + else if (TREE_CODE (parm) == TEMPLATE_DECL) + { + /* This parameter is a template. */ + if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM) + /* Output parameter declaration, argument index and level. */ + build_mangled_name_for_type (arg); + else + { + /* A TEMPLATE_DECL node, output the parameter declaration + and template name */ + + OB_PUTC ('z'); + build_template_template_parm_names + (DECL_INNERMOST_TEMPLATE_PARMS (parm)); + icat (IDENTIFIER_LENGTH (DECL_NAME (arg))); + OB_PUTID (DECL_NAME (arg)); + } + } + else + { + parm = tsubst (parm, arglist, /*complain=*/1, NULL_TREE); + /* It's a PARM_DECL. */ + build_mangled_name_for_type (TREE_TYPE (parm)); + build_overload_value (TREE_TYPE (parm), arg, + uses_template_parms (arglist)); + } + } + } + +/* Output the representation for NAME, which is either a TYPE_DECL or + an IDENTIFIER. */ + +static void +build_overload_identifier (name) + tree name; +{ + if (TREE_CODE (name) == TYPE_DECL + && CLASS_TYPE_P (TREE_TYPE (name)) + && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name)) + && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name))) + || (TREE_CODE (DECL_CONTEXT (CLASSTYPE_TI_TEMPLATE + (TREE_TYPE (name)))) + == FUNCTION_DECL))) + { + /* NAME is the TYPE_DECL for a template specialization. */ + tree template, parmlist, arglist, tname; + template = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name)); + arglist = CLASSTYPE_TI_ARGS (TREE_TYPE (name)); + tname = DECL_NAME (template); + parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template); + OB_PUTC ('t'); + icat (IDENTIFIER_LENGTH (tname)); + OB_PUTID (tname); + build_template_parm_names (parmlist, arglist); + } + else + { + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + if (numeric_output_need_bar) + { + OB_PUTC ('_'); + numeric_output_need_bar = 0; + } + icat (IDENTIFIER_LENGTH (name)); + OB_PUTID (name); + } +} + +/* Given DECL, either a class TYPE, TYPE_DECL or FUNCTION_DECL, produce + the mangling for it. Used by build_mangled_name and build_static_name. */ + +static void +build_qualified_name (decl) + tree decl; +{ + tree context; + int i = 1; + + if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't') + decl = TYPE_NAME (decl); + + /* If DECL_ASSEMBLER_NAME has been set properly, use it. */ + if (TREE_CODE (decl) == TYPE_DECL + && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !flag_do_squangling) + { + tree id = DECL_ASSEMBLER_NAME (decl); + OB_PUTID (id); + if (ISDIGIT (IDENTIFIER_POINTER (id) [IDENTIFIER_LENGTH (id) - 1])) + numeric_output_need_bar = 1; + return; + } + + context = decl; + /* If we can't find a Ktype, do it the hard way. */ + if (check_ktype (context, FALSE) == -1) + { + /* Count type and namespace scopes. */ + while (1) + { + context = CP_DECL_CONTEXT (context); + if (context == global_namespace) + break; + i += 1; + if (check_ktype (context, FALSE) != -1) + /* Found one! */ + break; + if (TREE_CODE_CLASS (TREE_CODE (context)) == 't') + context = TYPE_NAME (context); + } + } + + if (i > 1) + { + OB_PUTC ('Q'); + build_underscore_int (i); + numeric_output_need_bar = 0; + } + build_overload_nested_name (decl); +} + +/* Output the mangled representation for TYPE. If EXTRA_GCODE is + non-zero, mangled names for structure/union types are intentionally + mangled differently from the method described in the ARM. */ + +static void +build_mangled_name_for_type_with_Gcode (type, extra_Gcode) + tree type; + int extra_Gcode; +{ + if (TYPE_PTRMEMFUNC_P (type)) + type = TYPE_PTRMEMFUNC_FN_TYPE (type); + process_modifiers (type); + process_overload_item (type, extra_Gcode); +} + +/* Like build_mangled_name_for_type_with_Gcode, but never outputs the + `G'. */ + +static void +build_mangled_name_for_type (type) + tree type; +{ + build_mangled_name_for_type_with_Gcode (type, 0); +} + +/* Given a list of parameters in PARMTYPES, create an unambiguous + overload string. Should distinguish any type that C (or C++) can + distinguish. I.e., pointers to functions are treated correctly. + + Caller must deal with whether a final `e' goes on the end or not. + + Any default conversions must take place before this function + is called. + + BEGIN and END control initialization and finalization of the + obstack where we build the string. */ + +char * +build_overload_name (parmtypes, begin, end) + tree parmtypes; + int begin, end; +{ + char *ret; + start_squangling (); + ret = build_mangled_name (parmtypes, begin, end); + end_squangling (); + return ret ; +} + +/* Output the mangled representation for PARMTYPES. If PARMTYPES is a + TREE_LIST, then it is a list of parameter types. Otherwise, + PARMTYPES must be a single type. */ + +static char * +build_mangled_name (parmtypes, begin, end) + tree parmtypes; + int begin, end; +{ + if (begin) + OB_INIT (); + + if (TREE_CODE (parmtypes) != TREE_LIST) + /* There is only one type. */ + build_mangled_name_for_type (parmtypes); + else + { + /* There are several types in a parameter list. */ + int nrepeats = 0; + int old_style_repeats = !flag_do_squangling && !nofold && typevec; + tree last_type = NULL_TREE; + + for (; parmtypes && parmtypes != void_list_node; + parmtypes = TREE_CHAIN (parmtypes)) + { + /* We used to call canonical_type_variant here, but that isn't + good enough; it doesn't handle pointers to typedef types. So + we can't just set TREE_USED to say we've seen a type already; + we have to check each of the earlier types with same_type_p. */ + tree parmtype = TREE_VALUE (parmtypes); + + if (old_style_repeats) + { + /* Every argument gets counted. */ + my_friendly_assert (maxtype < typevec_size, 387); + typevec[maxtype++] = parmtype; + } + + if (last_type && same_type_p (parmtype, last_type)) + { + if (flag_do_squangling + || (old_style_repeats + && is_back_referenceable_type (parmtype))) + { + /* The next type is the same as this one. Keep + track of the repetition, and output the repeat + count later. */ + nrepeats++; + continue; + } + } + else if (nrepeats != 0) + { + /* Indicate how many times the previous parameter was + repeated. */ + if (old_style_repeats) + flush_repeats (nrepeats, last_type); + else + issue_nrepeats (nrepeats, last_type); + nrepeats = 0; + } + + last_type = parmtype; + + /* Note that for bug-compatibility with 2.7.2, we can't build up + repeats of types other than the most recent one. So we call + flush_repeats every round, if we get this far. */ + if (old_style_repeats && flush_repeats (0, parmtype)) + continue; + + /* Output the PARMTYPE. */ + build_mangled_name_for_type_with_Gcode (parmtype, 1); + } + + /* Output the repeat count for the last parameter, if + necessary. */ + if (nrepeats != 0) + { + if (old_style_repeats) + flush_repeats (nrepeats, last_type); + else + issue_nrepeats (nrepeats, last_type); + nrepeats = 0; + } + + if (!parmtypes) + /* The parameter list ends in an ellipsis. */ + OB_PUTC ('e'); + } + + if (end) + OB_FINISH (); + return (char *)obstack_base (&scratch_obstack); +} + +/* Emit modifiers such as constant, read-only, and volatile. */ + +static void +process_modifiers (parmtype) + tree parmtype; +{ + /* Note that here we do not use CP_TYPE_CONST_P and friends because + we describe types recursively; we will get the `const' in + `const int ()[10]' when processing the `const int' part. */ + if (TYPE_READONLY (parmtype)) + OB_PUTC ('C'); + if (TREE_CODE (parmtype) == INTEGER_TYPE + && parmtype != char_type_node + && parmtype != wchar_type_node + && (TYPE_MAIN_VARIANT (parmtype) + == unsigned_type (TYPE_MAIN_VARIANT (parmtype))) + && ! TYPE_FOR_JAVA (parmtype)) + OB_PUTC ('U'); + if (TYPE_VOLATILE (parmtype)) + OB_PUTC ('V'); + /* It would be better to use `R' for `restrict', but that's already + used for reference types. And `r' is used for `long double'. */ + if (TYPE_RESTRICT (parmtype)) + OB_PUTC ('u'); +} + +/* Check to see if TYPE has been entered into the Bcode typelist. If + so, return 1 and emit a backreference to TYPE. Otherwise, add TYPE + to the list of back-referenceable types and return 0. */ + +static int +check_btype (type) + tree type; +{ + int x; + + if (btypelist == NULL) + return 0; + + if (!is_back_referenceable_type (type)) + return 0; + + for (x = 0; x < maxbtype; x++) + if (same_type_p (type, btypelist[x])) + { + OB_PUTC ('B'); + icat (x); + if (x > 9) + OB_PUTC ('_'); + return 1 ; + } + + if (maxbsize <= maxbtype) + { + /* Enlarge the table. */ + maxbsize = maxbsize * 3 / 2; + btypelist = (tree *)xrealloc (btypelist, sizeof (tree) * maxbsize); + } + + /* Register the TYPE. */ + btypelist[maxbtype++] = type; + + return 0; +} + +/* Emit the correct code for various node types. */ + +static void +process_overload_item (parmtype, extra_Gcode) + tree parmtype; + int extra_Gcode; +{ + numeric_output_need_bar = 0; + + /* Our caller should have already handed any qualifiers, so pull out the + TYPE_MAIN_VARIANT to avoid typedef confusion. Except we can't do that + for arrays, because they are transparent to qualifiers. Sigh. */ + if (TREE_CODE (parmtype) == ARRAY_TYPE) + parmtype = canonical_type_variant (parmtype); + else + parmtype = TYPE_MAIN_VARIANT (parmtype); + + /* These tree types are considered modifiers for B code squangling, + and therefore should not get entries in the Btypelist. They are, + however, repeatable types. */ + + switch (TREE_CODE (parmtype)) + { + case REFERENCE_TYPE: + OB_PUTC ('R'); + goto more; + + case ARRAY_TYPE: +#if PARM_CAN_BE_ARRAY_TYPE + { + OB_PUTC ('A'); + if (TYPE_DOMAIN (parmtype) == NULL_TREE) + OB_PUTC ('_'); + else + { + tree length = array_type_nelts (parmtype); + if (TREE_CODE (length) != INTEGER_CST || flag_do_squangling) + { + length = fold (build (PLUS_EXPR, TREE_TYPE (length), + length, integer_one_node)); + STRIP_NOPS (length); + } + build_overload_value (sizetype, length, 1); + } + if (numeric_output_need_bar && ! flag_do_squangling) + OB_PUTC ('_'); + goto more; + } +#else + OB_PUTC ('P'); + goto more; +#endif + + case POINTER_TYPE: + OB_PUTC ('P'); + more: + build_mangled_name_for_type (TREE_TYPE (parmtype)); + return; + break; + + default: + break; + } + + if (flag_do_squangling && check_btype (parmtype)) + /* If PARMTYPE is already in the list of back-referenceable types, + then check_btype will output the appropriate reference, and + there's nothing more to do. */ + return; + + switch (TREE_CODE (parmtype)) + { + case OFFSET_TYPE: + OB_PUTC ('O'); + build_mangled_name_for_type (TYPE_OFFSET_BASETYPE (parmtype)); + OB_PUTC ('_'); + build_mangled_name_for_type (TREE_TYPE (parmtype)); + break; + + case FUNCTION_TYPE: + case METHOD_TYPE: + { + tree parms = TYPE_ARG_TYPES (parmtype); + + /* Rather than implementing a reentrant TYPEVEC, we turn off + repeat codes here, unless we're squangling. Squangling + doesn't make use of the TYPEVEC, so there's no reentrancy + problem. */ + int old_nofold = nofold; + if (!flag_do_squangling) + nofold = 1; + + if (TREE_CODE (parmtype) == METHOD_TYPE) + { + /* Mark this as a method. */ + OB_PUTC ('M'); + /* Output the class of which this method is a member. */ + build_mangled_name_for_type (TYPE_METHOD_BASETYPE (parmtype)); + /* Output any qualifiers for the `this' parameter. */ + process_modifiers (TREE_TYPE (TREE_VALUE (parms))); + } + + /* Output the parameter types. */ + OB_PUTC ('F'); + if (parms == NULL_TREE) + OB_PUTC ('e'); + else if (parms == void_list_node) + OB_PUTC ('v'); + else + build_mangled_name (parms, 0, 0); + + /* Output the return type. */ + OB_PUTC ('_'); + build_mangled_name_for_type (TREE_TYPE (parmtype)); + + nofold = old_nofold; + break; + } + + case INTEGER_TYPE: + if (parmtype == integer_type_node + || parmtype == unsigned_type_node + || parmtype == java_int_type_node) + OB_PUTC ('i'); + else if (parmtype == long_integer_type_node + || parmtype == long_unsigned_type_node) + OB_PUTC ('l'); + else if (parmtype == short_integer_type_node + || parmtype == short_unsigned_type_node + || parmtype == java_short_type_node) + OB_PUTC ('s'); + else if (parmtype == signed_char_type_node) + { + OB_PUTC ('S'); + OB_PUTC ('c'); + } + else if (parmtype == char_type_node + || parmtype == unsigned_char_type_node + || parmtype == java_byte_type_node) + OB_PUTC ('c'); + else if (parmtype == wchar_type_node + || parmtype == java_char_type_node) + OB_PUTC ('w'); + else if (parmtype == long_long_integer_type_node + || parmtype == long_long_unsigned_type_node + || parmtype == java_long_type_node) + OB_PUTC ('x'); + else if (parmtype == java_boolean_type_node) + OB_PUTC ('b'); +#if HOST_BITS_PER_WIDE_INT >= 64 + else if (parmtype == intTI_type_node + || parmtype == unsigned_intTI_type_node) + { + /* Should just check a flag here instead of specific + *_type_nodes, because all C9x types could use this. */ + int bits = TREE_INT_CST_LOW (TYPE_SIZE (parmtype)); + build_mangled_C9x_name (bits); + } +#endif + else + my_friendly_abort (73); + break; + + case BOOLEAN_TYPE: + OB_PUTC ('b'); + break; + + case REAL_TYPE: + if (parmtype == long_double_type_node) + OB_PUTC ('r'); + else if (parmtype == double_type_node + || parmtype == java_double_type_node) + OB_PUTC ('d'); + else if (parmtype == float_type_node + || parmtype == java_float_type_node) + OB_PUTC ('f'); + else my_friendly_abort (74); + break; + + case COMPLEX_TYPE: + OB_PUTC ('J'); + build_mangled_name_for_type (TREE_TYPE (parmtype)); + break; + + case VOID_TYPE: + OB_PUTC ('v'); + break; + + case ERROR_MARK: /* not right, but nothing is anyway */ + break; + + /* have to do these */ + case UNION_TYPE: + case RECORD_TYPE: + { + if (extra_Gcode) + OB_PUTC ('G'); /* make it look incompatible with AT&T */ + /* drop through into next case */ + } + case ENUMERAL_TYPE: + { + tree name = TYPE_NAME (parmtype); + + my_friendly_assert (TREE_CODE (name) == TYPE_DECL, 248); + + build_qualified_name (name); + break; + } + + case UNKNOWN_TYPE: + /* This will take some work. */ + OB_PUTC ('?'); + break; + + case TEMPLATE_TEMPLATE_PARM: + /* Find and output the original template parameter + declaration. */ + if (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parmtype)) + { + build_mangled_template_parm_index ("tzX", + TEMPLATE_TYPE_PARM_INDEX + (parmtype)); + build_template_parm_names + (DECL_INNERMOST_TEMPLATE_PARMS (TYPE_TI_TEMPLATE (parmtype)), + TYPE_TI_ARGS (parmtype)); + } + else + { + build_mangled_template_parm_index ("ZzX", + TEMPLATE_TYPE_PARM_INDEX + (parmtype)); + build_template_template_parm_names + (DECL_INNERMOST_TEMPLATE_PARMS (TYPE_STUB_DECL (parmtype))); + } + break; + + case TEMPLATE_TYPE_PARM: + build_mangled_template_parm_index ("X", + TEMPLATE_TYPE_PARM_INDEX + (parmtype)); + break; + + case TYPENAME_TYPE: + /* When mangling the type of a function template whose + declaration looks like: + + template <class T> void foo(typename T::U) + + we have to mangle these. */ + build_qualified_name (parmtype); + break; + + default: + my_friendly_abort (75); + } + +} + +/* Produce the mangling for a variable named NAME in CONTEXT, which can + be either a class TYPE or a FUNCTION_DECL. */ + +tree +build_static_name (context, name) + tree context, name; +{ + OB_INIT (); + numeric_output_need_bar = 0; + start_squangling (); +#ifdef JOINER + OB_PUTC ('_'); + build_qualified_name (context); + OB_PUTC (JOINER); +#else + OB_PUTS ("__static_"); + build_qualified_name (context); + OB_PUTC ('_'); +#endif + OB_PUTID (name); + OB_FINISH (); + end_squangling (); + + return get_identifier ((char *)obstack_base (&scratch_obstack)); +} + +/* FOR_METHOD should be 1 if the declaration in question is for a member + of a class (including a static member) and 2 if the declaration is + for a constructor. */ +tree +build_decl_overload_real (dname, parms, ret_type, tparms, targs, + for_method) + tree dname; + tree parms; + tree ret_type; + 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 + && TREE_CHAIN (parms) == void_list_node) + { + 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"); + 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"); + } + + start_squangling (); + 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 ('_', '_'); + numeric_output_need_bar = 0; + + if (tparms) + { + OB_PUTC ('H'); + build_template_parm_names (tparms, targs); + OB_PUTC ('_'); + } + else if (!for_method && current_namespace == global_namespace) + /* XXX this works only if we call this in the same namespace + as the declaration. Unfortunately, we don't have the _DECL, + only its name */ + OB_PUTC ('F'); + + if (!for_method && current_namespace != global_namespace) + /* qualify with namespace */ + build_qualified_name (current_namespace); + + if (parms == NULL_TREE) + OB_PUTC ('e'); + else if (parms == void_list_node) + OB_PUTC ('v'); + else + { + if (!flag_do_squangling) + { + /* Allocate typevec array. */ + maxtype = 0; + typevec_size = list_length (parms); + if (!for_method && current_namespace != global_namespace) + /* The namespace of a global function needs one slot. */ + typevec_size++; + typevec = (tree *)alloca (typevec_size * sizeof (tree)); + } + nofold = 0; + + if (for_method) + { + tree this_type = TREE_VALUE (parms); + + if (TREE_CODE (this_type) == RECORD_TYPE) /* a signature pointer */ + this_type = SIGNATURE_TYPE (this_type); + else + this_type = TREE_TYPE (this_type); + + build_mangled_name_for_type (this_type); + + if (!flag_do_squangling) + { + my_friendly_assert (maxtype < typevec_size, 387); + typevec[maxtype++] = this_type; + } + + if (TREE_CHAIN (parms)) + build_mangled_name (TREE_CHAIN (parms), 0, 0); + else + OB_PUTC ('e'); + } + else + { + /* the namespace qualifier for a global function + will count as type */ + if (current_namespace != global_namespace + && !flag_do_squangling) + { + my_friendly_assert (maxtype < typevec_size, 387); + typevec[maxtype++] = current_namespace; + } + build_mangled_name (parms, 0, 0); + } + + if (!flag_do_squangling) + /* Deallocate typevec array. */ + typevec = NULL; + } + + if (ret_type != NULL_TREE && for_method != 2) + { + /* Add the return type. */ + OB_PUTC ('_'); + build_mangled_name_for_type (ret_type); + } + + OB_FINISH (); + end_squangling (); + { + 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. */ + +tree +build_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); +} + +/* Set the mangled name (DECL_ASSEMBLER_NAME) for DECL. */ + +void +set_mangled_name_for_decl (decl) + tree decl; +{ + tree parm_types; + + if (processing_template_decl) + /* There's no need to mangle the name of a template function. */ + return; + + parm_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); + + if (DECL_STATIC_FUNCTION_P (decl)) + parm_types = + hash_tree_chain (build_pointer_type (DECL_CLASS_CONTEXT (decl)), + parm_types); + else + /* The only member functions whose type is a FUNCTION_TYPE, rather + than a METHOD_TYPE, should be static members. */ + my_friendly_assert (!DECL_CONTEXT (decl) + || !IS_AGGR_TYPE_CODE (TREE_CODE (DECL_CONTEXT (decl))) + || TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE, + 0); + + DECL_ASSEMBLER_NAME (decl) + = build_decl_overload (DECL_NAME (decl), parm_types, + DECL_FUNCTION_MEMBER_P (decl) + + DECL_CONSTRUCTOR_P (decl)); +} + +/* Build an overload name for the type expression TYPE. */ + +tree +build_typename_overload (type) + tree type; +{ + tree id; + + OB_INIT (); + OB_PUTID (ansi_opname[(int) TYPE_EXPR]); + nofold = 1; + start_squangling (); + build_mangled_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; + end_squangling (); + return id; +} + +tree +build_overload_with_type (name, type) + tree name, type; +{ + OB_INIT (); + OB_PUTID (name); + nofold = 1; + + start_squangling (); + build_mangled_name (type, 0, 1); + end_squangling (); + return get_identifier (obstack_base (&scratch_obstack)); +} + +tree +get_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)); +} + +/* Returns a DECL_ASSEMBLER_NAME for the destructor of type TYPE. */ + +tree +build_destructor_name (type) + tree type; +{ + return build_overload_with_type (get_identifier (DESTRUCTOR_DECL_PREFIX), + type); +} + +/* 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 */ +tree +build_opfncall (code, flags, xarg1, xarg2, arg3) + enum tree_code code; + int flags; + tree xarg1, xarg2, arg3; +{ + return build_new_op (code, flags, xarg1, xarg2, arg3); +} + +/* 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). */ + +tree +hack_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); + /* I could not trigger this code. MvL */ + my_friendly_abort (980325); +#ifdef DEAD + if (DECL_CHAIN (fndecl) == NULL_TREE) + { + warning ("methods cannot be converted to function pointers"); + return fndecl; + } + else + { + error ("ambiguous request for method pointer `%s'", + IDENTIFIER_POINTER (name)); + return error_mark_node; + } +#endif + } + } + if (flag_labels_ok && IDENTIFIER_LABEL_VALUE (name)) + { + return IDENTIFIER_LABEL_VALUE (name); + } + return error_mark_node; + } + + type = TREE_TYPE (value); + if (TREE_CODE (value) == FIELD_DECL) + { + if (current_class_ptr == NULL_TREE) + { + if (current_function_decl + && DECL_STATIC_FUNCTION_P (current_function_decl)) + cp_error ("invalid use of member `%D' in static member function", + value); + else + /* We can get here when processing a bad default + argument, like: + struct S { int a; void f(int i = a); } */ + cp_error ("invalid use of member `%D'", value); + + return error_mark_node; + } + TREE_USED (current_class_ptr) = 1; + + /* Mark so that if we are in a constructor, and then find that + this field was initialized by a base initializer, + we can emit an error message. */ + TREE_USED (value) = 1; + value = build_component_ref (current_class_ref, name, NULL_TREE, 1); + } + else if ((TREE_CODE (value) == FUNCTION_DECL + && DECL_FUNCTION_MEMBER_P (value)) + || (TREE_CODE (value) == OVERLOAD + && DECL_FUNCTION_MEMBER_P (OVL_CURRENT (value)))) + { + tree decl; + + if (TREE_CODE (value) == OVERLOAD) + value = OVL_CURRENT (value); + + if (IS_SIGNATURE (DECL_CLASS_CONTEXT (value))) + return value; + + decl = maybe_dummy_object (DECL_CLASS_CONTEXT (value), 0); + value = build_component_ref (decl, name, NULL_TREE, 1); + } + else if (really_overloaded_fn (value)) + ; + else if (TREE_CODE (value) == OVERLOAD) + /* not really overloaded function */ + mark_used (OVL_FUNCTION (value)); + else if (TREE_CODE (value) == TREE_LIST) + { + /* Ambiguous reference to base members, possibly other cases?. */ + tree t = value; + while (t && TREE_CODE (t) == TREE_LIST) + { + mark_used (TREE_VALUE (t)); + t = TREE_CHAIN (t); + } + } + else if (TREE_CODE (value) == NAMESPACE_DECL) + { + cp_error ("use of namespace `%D' as expression", value); + return error_mark_node; + } + else if (DECL_CLASS_TEMPLATE_P (value)) + { + cp_error ("use of class template `%T' as expression", value); + return error_mark_node; + } + else + mark_used (value); + + if (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL + || TREE_CODE (value) == RESULT_DECL) + { + tree context = decl_function_context (value); + if (context != NULL_TREE && context != current_function_decl + && ! TREE_STATIC (value)) + { + cp_error ("use of %s from containing function", + (TREE_CODE (value) == VAR_DECL + ? "`auto' variable" : "parameter")); + cp_error_at (" `%#D' declared here", value); + value = error_mark_node; + } + } + + if (TREE_CODE_CLASS (TREE_CODE (value)) == 'd' && DECL_NONLOCAL (value)) + { + if (DECL_LANG_SPECIFIC (value) + && DECL_CLASS_CONTEXT (value) != current_class_type) + { + tree path; + register tree context + = (TREE_CODE (value) == FUNCTION_DECL && DECL_VIRTUAL_P (value)) + ? DECL_CLASS_CONTEXT (value) + : DECL_CONTEXT (value); + + get_base_distance (context, current_class_type, 0, &path); + if (path && !enforce_access (current_class_type, value)) + return error_mark_node; + } + } + else if (TREE_CODE (value) == TREE_LIST + && TREE_TYPE (value) == error_mark_node) + { + error ("request for member `%s' is ambiguous in multiple inheritance lattice", + IDENTIFIER_POINTER (name)); + print_candidates (value); + return error_mark_node; + } + + if (! processing_template_decl) + value = convert_from_reference (value); + return value; +} + + +tree +make_thunk (function, delta) + tree function; + int delta; +{ + tree thunk_id; + tree thunk; + tree func_decl; + + if (TREE_CODE (function) != ADDR_EXPR) + abort (); + func_decl = TREE_OPERAND (function, 0); + if (TREE_CODE (func_decl) != FUNCTION_DECL) + abort (); + + OB_INIT (); + OB_PUTS ("__thunk_"); + if (delta > 0) + { + OB_PUTC ('n'); + icat (delta); + } + else + icat (-delta); + OB_PUTC ('_'); + OB_PUTID (DECL_ASSEMBLER_NAME (func_decl)); + OB_FINISH (); + thunk_id = get_identifier (obstack_base (&scratch_obstack)); + + thunk = IDENTIFIER_GLOBAL_VALUE (thunk_id); + if (thunk && TREE_CODE (thunk) != THUNK_DECL) + { + cp_error ("implementation-reserved name `%D' used", thunk_id); + thunk = NULL_TREE; + SET_IDENTIFIER_GLOBAL_VALUE (thunk_id, thunk); + } + if (thunk == NULL_TREE) + { + thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl)); + TREE_READONLY (thunk) = TREE_READONLY (func_decl); + TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (func_decl); + comdat_linkage (thunk); + TREE_SET_CODE (thunk, THUNK_DECL); + DECL_INITIAL (thunk) = function; + THUNK_DELTA (thunk) = delta; + DECL_EXTERNAL (thunk) = 1; + DECL_ARTIFICIAL (thunk) = 1; + /* So that finish_file can write out any thunks that need to be: */ + pushdecl_top_level (thunk); + } + return thunk; +} + +/* Emit the definition of a C++ multiple inheritance vtable thunk. */ + +void +emit_thunk (thunk_fndecl) + tree thunk_fndecl; +{ + tree function = TREE_OPERAND (DECL_INITIAL (thunk_fndecl), 0); + int delta = THUNK_DELTA (thunk_fndecl); + + if (TREE_ASM_WRITTEN (thunk_fndecl)) + return; + + TREE_ASM_WRITTEN (thunk_fndecl) = 1; + + TREE_ADDRESSABLE (function) = 1; + mark_used (function); + + if (current_function_decl) + abort (); + + TREE_SET_CODE (thunk_fndecl, FUNCTION_DECL); + + { +#ifdef ASM_OUTPUT_MI_THUNK + char *fnname; + current_function_decl = thunk_fndecl; + /* Make sure we build up its RTL before we go onto the + temporary obstack. */ + make_function_rtl (thunk_fndecl); + temporary_allocation (); + DECL_RESULT (thunk_fndecl) + = build_decl (RESULT_DECL, 0, integer_type_node); + fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0); + init_function_start (thunk_fndecl, input_filename, lineno); + current_function_is_thunk = 1; + assemble_start_function (thunk_fndecl, fnname); + ASM_OUTPUT_MI_THUNK (asm_out_file, thunk_fndecl, delta, function); + assemble_end_function (thunk_fndecl, fnname); + permanent_allocation (1); + current_function_decl = 0; +#else /* ASM_OUTPUT_MI_THUNK */ + /* If we don't have the necessary macro for efficient thunks, generate a + thunk function that just makes a call to the real function. + Unfortunately, this doesn't work for varargs. */ + + tree a, t; + + if (varargs_function_p (function)) + cp_error ("generic thunk code fails for method `%#D' which uses `...'", + function); + + /* Set up clone argument trees for the thunk. */ + t = NULL_TREE; + for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a)) + { + tree x = copy_node (a); + TREE_CHAIN (x) = t; + DECL_CONTEXT (x) = thunk_fndecl; + t = x; + } + a = nreverse (t); + DECL_ARGUMENTS (thunk_fndecl) = a; + DECL_RESULT (thunk_fndecl) = NULL_TREE; + DECL_LANG_SPECIFIC (thunk_fndecl) = DECL_LANG_SPECIFIC (function); + copy_lang_decl (thunk_fndecl); + DECL_INTERFACE_KNOWN (thunk_fndecl) = 1; + DECL_NOT_REALLY_EXTERN (thunk_fndecl) = 1; + + start_function (NULL_TREE, thunk_fndecl, NULL_TREE, 1); + store_parm_decls (); + current_function_is_thunk = 1; + + /* Build up the call to the real function. */ + t = build_int_2 (delta, -1 * (delta < 0)); + TREE_TYPE (t) = signed_type (sizetype); + t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t)); + t = expr_tree_cons (NULL_TREE, t, NULL_TREE); + for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a)) + t = expr_tree_cons (NULL_TREE, a, t); + t = nreverse (t); + t = build_call (function, TREE_TYPE (TREE_TYPE (function)), t); + c_expand_return (t); + + finish_function (lineno, 0, 0); + + /* Don't let the backend defer this function. */ + if (DECL_DEFER_OUTPUT (thunk_fndecl)) + { + output_inline_function (thunk_fndecl); + permanent_allocation (1); + } +#endif /* ASM_OUTPUT_MI_THUNK */ + } + + TREE_SET_CODE (thunk_fndecl, THUNK_DECL); +} + +/* Code for synthesizing methods which have default semantics defined. */ + +/* For the anonymous union in TYPE, return the member that is at least as + large as the rest of the members, so we can copy it. */ + +static tree +largest_union_member (type) + tree type; +{ + tree f, type_size = TYPE_SIZE (type); + + for (f = TYPE_FIELDS (type); f; f = TREE_CHAIN (f)) + if (simple_cst_equal (DECL_SIZE (f), type_size) == 1) + return f; + + /* We should always find one. */ + my_friendly_abort (323); + return NULL_TREE; +} + +/* Generate code for default X(X&) constructor. */ + +static void +do_build_copy_constructor (fndecl) + tree fndecl; +{ + tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); + tree t; + + clear_last_expr (); + push_momentary (); + + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + parm = TREE_CHAIN (parm); + parm = convert_from_reference (parm); + + if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type) + && is_empty_class (current_class_type)) + /* Don't copy the padding byte; it might not have been allocated + if *this is a base subobject. */; + else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)) + { + t = build (INIT_EXPR, void_type_node, current_class_ref, parm); + TREE_SIDE_EFFECTS (t) = 1; + cplus_expand_expr_stmt (t); + } + else + { + tree fields = TYPE_FIELDS (current_class_type); + int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type); + tree binfos = TYPE_BINFO_BASETYPES (current_class_type); + int i; + + for (t = CLASSTYPE_VBASECLASSES (current_class_type); t; + t = TREE_CHAIN (t)) + { + tree basetype = BINFO_TYPE (t); + tree p = convert_to_reference + (build_reference_type (basetype), parm, + CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE); + p = convert_from_reference (p); + + if (p == error_mark_node) + cp_error ("in default copy constructor"); + else + current_base_init_list = tree_cons (basetype, + p, current_base_init_list); + } + + for (i = 0; i < n_bases; ++i) + { + tree p, basetype = TREE_VEC_ELT (binfos, i); + if (TREE_VIA_VIRTUAL (basetype)) + continue; + + basetype = BINFO_TYPE (basetype); + p = convert_to_reference + (build_reference_type (basetype), parm, + CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE); + + if (p == error_mark_node) + cp_error ("in default copy constructor"); + else + { + p = convert_from_reference (p); + current_base_init_list = tree_cons (basetype, + p, current_base_init_list); + } + } + for (; fields; fields = TREE_CHAIN (fields)) + { + tree init, t; + tree field = fields; + + if (TREE_CODE (field) != FIELD_DECL) + continue; + + init = parm; + if (DECL_NAME (field)) + { + if (VFIELD_NAME_P (DECL_NAME (field))) + continue; + if (VBASE_NAME_P (DECL_NAME (field))) + continue; + + /* True for duplicate members. */ + if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field) + continue; + } + else if ((t = TREE_TYPE (field)) != NULL_TREE + && ANON_UNION_TYPE_P (t) + && TYPE_FIELDS (t) != NULL_TREE) + { + do + { + init = build (COMPONENT_REF, t, init, field); + field = largest_union_member (t); + } + while ((t = TREE_TYPE (field)) != NULL_TREE + && ANON_UNION_TYPE_P (t) + && TYPE_FIELDS (t) != NULL_TREE); + } + else + continue; + + init = build (COMPONENT_REF, TREE_TYPE (field), init, field); + init = build_tree_list (NULL_TREE, init); + + current_member_init_list + = tree_cons (DECL_NAME (field), init, current_member_init_list); + } + current_member_init_list = nreverse (current_member_init_list); + current_base_init_list = nreverse (current_base_init_list); + setup_vtbl_ptr (); + } + + pop_momentary (); +} + +static void +do_build_assign_ref (fndecl) + tree fndecl; +{ + tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); + + clear_last_expr (); + push_momentary (); + + parm = convert_from_reference (parm); + + if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type) + && is_empty_class (current_class_type)) + /* Don't copy the padding byte; it might not have been allocated + if *this is a base subobject. */; + else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)) + { + tree t = build (MODIFY_EXPR, void_type_node, current_class_ref, parm); + TREE_SIDE_EFFECTS (t) = 1; + cplus_expand_expr_stmt (t); + } + else + { + tree fields = TYPE_FIELDS (current_class_type); + int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type); + tree binfos = TYPE_BINFO_BASETYPES (current_class_type); + int i; + + for (i = 0; i < n_bases; ++i) + { + tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i)); + tree p = convert_to_reference + (build_reference_type (basetype), parm, + CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE); + p = convert_from_reference (p); + p = build_member_call (basetype, ansi_opname [MODIFY_EXPR], + build_expr_list (NULL_TREE, p)); + expand_expr_stmt (p); + } + for (; fields; fields = TREE_CHAIN (fields)) + { + tree comp, init, t; + tree field = fields; + + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (CP_TYPE_CONST_P (TREE_TYPE (field))) + { + if (DECL_NAME (field)) + cp_error ("non-static const member `%#D', can't use default assignment operator", field); + else + cp_error ("non-static const member in type `%T', can't use default assignment operator", current_class_type); + continue; + } + else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE) + { + if (DECL_NAME (field)) + cp_error ("non-static reference member `%#D', can't use default assignment operator", field); + else + cp_error ("non-static reference member in type `%T', can't use default assignment operator", current_class_type); + continue; + } + + comp = current_class_ref; + init = parm; + + if (DECL_NAME (field)) + { + if (VFIELD_NAME_P (DECL_NAME (field))) + continue; + if (VBASE_NAME_P (DECL_NAME (field))) + continue; + + /* True for duplicate members. */ + if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field) + continue; + } + else if ((t = TREE_TYPE (field)) != NULL_TREE + && ANON_UNION_TYPE_P (t) + && TYPE_FIELDS (t) != NULL_TREE) + { + do + { + comp = build (COMPONENT_REF, t, comp, field); + init = build (COMPONENT_REF, t, init, field); + field = largest_union_member (t); + } + while ((t = TREE_TYPE (field)) != NULL_TREE + && ANON_UNION_TYPE_P (t) + && TYPE_FIELDS (t) != NULL_TREE); + } + else + continue; + + comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field); + init = build (COMPONENT_REF, TREE_TYPE (field), init, field); + + expand_expr_stmt (build_modify_expr (comp, NOP_EXPR, init)); + } + } + c_expand_return (current_class_ref); + pop_momentary (); +} + +void +synthesize_method (fndecl) + tree fndecl; +{ + int nested = (current_function_decl != NULL_TREE); + tree context = hack_decl_function_context (fndecl); + + if (at_eof) + import_export_decl (fndecl); + + if (! context) + push_to_top_level (); + else if (nested) + push_cp_function_context (context); + + interface_unknown = 1; + start_function (NULL_TREE, fndecl, NULL_TREE, 1); + store_parm_decls (); + + if (DECL_NAME (fndecl) == ansi_opname[MODIFY_EXPR]) + do_build_assign_ref (fndecl); + else if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl))) + ; + else + { + tree arg_chain = FUNCTION_ARG_CHAIN (fndecl); + if (DECL_CONSTRUCTOR_FOR_VBASE_P (fndecl)) + arg_chain = TREE_CHAIN (arg_chain); + if (arg_chain != void_list_node) + do_build_copy_constructor (fndecl); + else if (TYPE_NEEDS_CONSTRUCTING (current_class_type)) + setup_vtbl_ptr (); + } + + finish_function (lineno, 0, nested); + + extract_interface_info (); + if (! context) + pop_from_top_level (); + else if (nested) + pop_cp_function_context (context); +} |