/* Handle the hair of processing (but not expanding) inline functions.
Also manage function and variable name overloading.
- Copyright (C) 1987, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
- This file is part of GNU CC.
+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
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 <stdio.h>
#include "config.h"
+#include "system.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"
processed. */
struct pending_inline *pending_inlines;
+int static_labelno;
+
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
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 void issue_nrepeats PROTO((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 tree build_decl_overload_real PROTO((tree, tree, tree, tree,
+ tree, int));
+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));
+
# 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) \
# define OB_FINISH() (obstack_1grow (&scratch_obstack, '\0'))
# define OB_LAST() (obstack_next_free (&scratch_obstack)[-1])
-#ifdef NO_AUTO_OVERLOAD
-int is_overloaded ();
-#endif
-
void
init_method ()
{
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);
}
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);
}
}
\f
-/* Report an argument type mismatch between the best declared function
- we could find and the current argument list that we have. */
-
-void
-report_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;
+/* Here is where overload code starts. */
- 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;
- }
+/* type tables for K and B type compression */
+static tree *btypelist = NULL;
+static tree *ktypelist = NULL;
+static tree lasttype = NULL;
+static int maxbsize = 0;
+static int maxksize = 0;
- ttf = TYPE_ARG_TYPES (TREE_TYPE (cp->function));
- tta = parmtypes;
+/* number of each type seen */
+static int maxbtype = 0;
+static int maxktype = 0;
- while (i-- > 0)
- {
- ttf = TREE_CHAIN (ttf);
- tta = TREE_CHAIN (tta);
- }
+/* Number of occurrences of last b type seen. */
+static int nrepeats = 0;
- 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);
-}
-\f
-/* Here is where overload code starts. */
-
-/* Array of types seen so far in top-level call to `build_overload_name'.
+/* Array of types seen so far in top-level call to `build_mangled_name'.
Allocated and deallocated by caller. */
-static tree *typevec;
+static tree *typevec = NULL;
-/* Number of types interned by `build_overload_name' so far. */
-static int maxtype;
+/* Number of types interned by `build_mangled_name' so far. */
+static int maxtype = 0;
/* Number of occurrences of last type seen. */
-static int nrepeats;
+static int Nrepeats = 0;
/* 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)
+/* 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;
-#define DEALLOCATE_TYPEVEC(PARMTYPES) \
- do { tree t = (PARMTYPES); \
- while (t) { TREE_USED (TREE_VALUE (t)) = 0; t = TREE_CHAIN (t); } \
- } while (0)
+static __inline void
+start_squangling ()
+{
+ if (flag_do_squangling)
+ {
+ lasttype = NULL;
+ nofold = 0;
+ nrepeats = 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)
+ {
+ lasttype = NULL;
+ 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
-#ifdef __GNUC__
-__inline
-#endif
-void
+static __inline void
icat (i)
- int 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 i/10 below is 1. */
+ the result of ui/10 below is 1. */
if (i == 1)
{
OB_PUTC ('1');
return;
}
- if (i < 0)
+ if (i >= 0)
+ ui = i;
+ else
{
OB_PUTC ('m');
- i = -i;
+ 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;
}
- if (i < 10)
- OB_PUTC ('0' + i);
else
{
- icat (i / 10);
- OB_PUTC ('0' + (i % 10));
+ 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
-#endif
-void
+static __inline void
flush_repeats (type)
tree type;
{
while (typevec[tindex] != type)
tindex++;
- if (nrepeats > 1)
+ if (Nrepeats > 1)
{
OB_PUTC ('N');
- icat (nrepeats);
- if (nrepeats > 9)
+ icat (Nrepeats);
+ if (Nrepeats > 9)
OB_PUTC ('_');
}
else
OB_PUTC ('T');
- nrepeats = 0;
+ Nrepeats = 0;
icat (tindex);
if (tindex > 9)
OB_PUTC ('_');
}
-static int numeric_output_need_bar;
-static void build_overload_identifier ();
+
+/* issue squangling type repeating */
+static void
+issue_nrepeats (lasttype)
+ tree lasttype;
+{
+ if (nrepeats == 1)
+ {
+ switch (TREE_CODE (lasttype))
+ {
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case VOID_TYPE:
+ case BOOLEAN_TYPE:
+ process_overload_item (lasttype, FALSE);
+ nrepeats = 0;
+ return;
+
+ default:
+ break;
+ }
+ }
+ OB_PUTC ('n');
+ icat (nrepeats);
+ if (nrepeats > 9)
+ OB_PUTC ('_');
+ nrepeats = 0;
+}
+
+
+/* Check to see if a tree node has been entered into the Kcode typelist */
+/* if not, add it. Return -1 if it isn't found, otherwise return 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 (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 (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;
+}
static void
build_overload_nested_name (decl)
tree decl;
{
- if (DECL_CONTEXT (decl))
+
+ if (ktypelist && issue_ktype (decl))
+ return;
+
+ if (DECL_CONTEXT (decl))
{
tree context = DECL_CONTEXT (decl);
- if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
- context = TYPE_MAIN_DECL (context);
- build_overload_nested_name (context);
+
+ /* 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 (context, 0, 0);
+ else
+ {
+ if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
+ context = TYPE_NAME (context);
+ build_overload_nested_name (context);
+ }
+ }
}
+ else if (decl == global_namespace)
+ return;
+ else if (DECL_NAMESPACE (decl))
+ build_overload_nested_name (DECL_NAMESPACE (decl));
+ else
+ /* XXX the above does not work for non-namespaces */
+ if (current_namespace && TREE_CODE (decl) != NAMESPACE_DECL)
+ build_overload_nested_name (current_namespace);
if (TREE_CODE (decl) == FUNCTION_DECL)
{
tree name = DECL_ASSEMBLER_NAME (decl);
char *label;
- extern int var_labelno;
- ASM_FORMAT_PRIVATE_NAME (label, IDENTIFIER_POINTER (name), var_labelno);
- var_labelno++;
+ ASM_FORMAT_PRIVATE_NAME (label, IDENTIFIER_POINTER (name), static_labelno);
+ static_labelno++;
if (numeric_output_need_bar)
- {
- OB_PUTC ('_');
- numeric_output_need_bar = 0;
- }
+ 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);
}
+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 (TREE_OPERAND (value, 0), 0, 0);
+ build_overload_identifier (TREE_OPERAND (value, 1));
+}
+
/* Encoding for an INTEGER_CST value. */
static void
-build_overload_int (value)
+build_overload_int (value, in_template)
tree value;
+ int in_template;
{
- if (TREE_CODE (value) == TEMPLATE_CONST_PARM)
- {
- OB_PUTC ('Y');
- if (TEMPLATE_CONST_IDX (value) > 9)
- OB_PUTC ('_');
- icat (TEMPLATE_CONST_IDX (value));
- if (TEMPLATE_CONST_IDX (value) > 9)
- OB_PUTC ('_');
- return;
- }
- else if (processing_template_decl
- && 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. */
+ if (in_template && TREE_CODE (value) != INTEGER_CST)
{
- static int n;
- sprintf (digit_buffer, " *%d", n++);
- OB_PUTCP (digit_buffer);
+ 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);
+ my_friendly_assert (name[0] == '_' && name[1] == '_', 0);
+
+ 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)>); */
+ process_overload_item (operand, 0);
+ 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;
+ 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_lt (value, integer_zero_node))
- {
- OB_PUTC ('m');
- value = build_int_2 (~ TREE_INT_CST_LOW (value),
- - TREE_INT_CST_HIGH (value));
- }
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 */
- sorry ("conversion of long long as PT parameter");
+ 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));
}
+
static void
-build_overload_value (type, value)
+build_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 (TREE_CODE (type) == PARM_DECL)
+ type = TREE_TYPE (type);
+
+ my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (type)) == 't', 0);
if (numeric_output_need_bar)
{
numeric_output_need_bar = 0;
}
+ if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
+ {
+ build_mangled_template_parm_index ("Y", value);
+ return;
+ }
+
if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE)
{
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
{
- build_overload_int (value);
- numeric_output_need_bar = 1;
+ build_overload_int (value, in_template);
return;
}
-#ifndef REAL_IS_NOT_DOUBLE
case REAL_TYPE:
{
REAL_VALUE_TYPE val;
char *bufp = digit_buffer;
- extern char *index ();
+
+ pedwarn ("ANSI C++ forbids floating-point template arguments");
my_friendly_assert (TREE_CODE (value) == REAL_CST, 244);
val = TREE_REAL_CST (value);
- if (val < 0)
+ if (REAL_VALUE_ISNAN (val))
{
- val = -val;
- *bufp++ = 'm';
+ sprintf (bufp, "NaN");
}
- sprintf (bufp, "%e", val);
- bufp = (char *) index (bufp, 'e');
- if (!bufp)
- strcat (digit_buffer, "e0");
else
{
- char *p;
- bufp++;
- if (*bufp == '-')
+ if (REAL_VALUE_NEGATIVE (val))
{
+ val = REAL_VALUE_NEGATE (val);
*bufp++ = 'm';
}
- p = bufp;
- if (*p == '+')
- p++;
- while (*p == '0')
- p++;
- if (*p == 0)
+ if (REAL_VALUE_ISINF (val))
{
- *bufp++ = '0';
- *bufp = 0;
+ sprintf (bufp, "Infinity");
}
- else if (p != bufp)
+ else
{
- while (*p)
- *bufp++ = *p++;
- *bufp = 0;
+ 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;
}
-#endif
case POINTER_TYPE:
if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE
&& TREE_CODE (value) != ADDR_EXPR)
if (TREE_CODE (a1) == INTEGER_CST
&& TREE_CODE (a2) == INTEGER_CST)
{
- build_overload_int (a1);
+ build_overload_int (a1, in_template);
OB_PUTC ('_');
- build_overload_int (a2);
+ build_overload_int (a2, in_template);
OB_PUTC ('_');
if (TREE_CODE (a3) == ADDR_EXPR)
{
else if (TREE_CODE (a3) == INTEGER_CST)
{
OB_PUTC ('i');
- build_overload_int (a3);
- numeric_output_need_bar = 1;
+ build_overload_int (a3, in_template);
return;
}
}
}
if (TREE_CODE (value) == INTEGER_CST)
{
- build_overload_int (value);
+ 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);
if (TREE_CODE (value) == VAR_DECL)
{
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 */
}
}
+
+/* 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 (TREE_TYPE (parm), 0, 0);
+ }
+ }
+}
+
+
+/* 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;
+
+ 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 (arglist, i);
+ if (TREE_CODE (parm) == TYPE_DECL)
+ {
+ /* This parameter is a type. */
+ OB_PUTC ('Z');
+ build_mangled_name (arg, 0, 0);
+ }
+ 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 (arg, 0, 0);
+ 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, NULL_TREE);
+ /* It's a PARM_DECL. */
+ build_mangled_name (TREE_TYPE (parm), 0, 0);
+ build_overload_value (parm, arg, uses_template_parms (arglist));
+ }
+ }
+ }
+
+
static void
build_overload_identifier (name)
tree name;
if (TREE_CODE (name) == TYPE_DECL
&& IS_AGGR_TYPE (TREE_TYPE (name))
&& CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name))
- && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name))))
+ && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name)))
+ || (TREE_CODE (DECL_CONTEXT (CLASSTYPE_TI_TEMPLATE
+ (TREE_TYPE (name))))
+ == FUNCTION_DECL)))
{
tree template, parmlist, arglist, tname;
- int i, nparms;
template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
arglist = TREE_VALUE (template);
template = TREE_PURPOSE (template);
tname = DECL_NAME (template);
- parmlist = DECL_ARGUMENTS (template);
- nparms = TREE_VEC_LENGTH (parmlist);
+ parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
OB_PUTC ('t');
icat (IDENTIFIER_LENGTH (tname));
OB_PUTID (tname);
- icat (nparms);
- for (i = 0; i < nparms; i++)
- {
- tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
- tree arg = TREE_VEC_ELT (arglist, i);
- if (TREE_CODE (parm) == TYPE_DECL)
- {
- /* This parameter is a type. */
- OB_PUTC ('Z');
- build_overload_name (arg, 0, 0);
- }
- else
- {
- parm = tsubst (parm, &TREE_VEC_ELT (arglist, 0),
- TREE_VEC_LENGTH (arglist), NULL_TREE);
- /* It's a PARM_DECL. */
- build_overload_name (TREE_TYPE (parm), 0, 0);
- build_overload_value (parm, arg);
- }
- }
+ build_template_parm_names (parmlist, arglist);
}
else
{
}
}
+/* 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 scopes */
+ while (DECL_CONTEXT (context))
+ {
+ i += 1;
+ context = DECL_CONTEXT (context);
+ if (check_ktype (context, FALSE) != -1) /* found it! */
+ break;
+ if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
+ context = TYPE_NAME (context);
+ }
+ /* now count namespace scopes */
+ if (TREE_CODE (decl) == NAMESPACE_DECL)
+ {
+ i = 0; /* we have nothing done, yet: reset */
+ context = decl;
+ }
+ else
+ /* decl must be a type, which we have to scope with the
+ namespace */
+ {
+ /* XXX MvL somehow, types have no lang_decl, so no namespace */
+ context = current_namespace;
+ }
+ }
+
+ while (context != global_namespace)
+ {
+ i += 1;
+ context = DECL_NAMESPACE (context);
+ }
+
+ if (i > 1)
+ {
+ OB_PUTC ('Q');
+ build_underscore_int (i);
+ numeric_output_need_bar = 0;
+ }
+ build_overload_nested_name (decl);
+}
+
/* 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.
tree parmtypes;
int begin, end;
{
- int just_one;
+ char *ret;
+ start_squangling ();
+ ret = build_mangled_name (parmtypes, begin, end);
+ end_squangling ();
+ return ret ;
+}
+
+static char *
+build_mangled_name (parmtypes, begin, end)
+ tree parmtypes;
+ int begin, end;
+{
tree parmtype;
- if (begin) OB_INIT ();
+ if (begin)
+ OB_INIT ();
numeric_output_need_bar = 0;
- if ((just_one = (TREE_CODE (parmtypes) != TREE_LIST)))
+ if (TREE_CODE (parmtypes) != TREE_LIST) /* just one item */
{
- parmtype = parmtypes;
- goto only_one;
+ if (TYPE_PTRMEMFUNC_P (parmtypes))
+ parmtypes = TYPE_PTRMEMFUNC_FN_TYPE (parmtypes);
+ process_modifiers (parmtypes);
+ process_overload_item (parmtypes, FALSE);
}
+ else {
+ for ( ; parmtypes!=NULL; parmtypes = TREE_CHAIN (parmtypes))
+ {
+ parmtype = TREE_VALUE (parmtypes);
+ if (flag_do_squangling) /* squangling style repeats */
+ {
+ if (parmtype == lasttype)
+ {
+ nrepeats++;
+ continue;
+ }
+ else
+ if (nrepeats != 0)
+ {
+ issue_nrepeats (lasttype);
+ }
+ lasttype = parmtype;
+ }
+ else
+ if (!nofold && typevec)
+ {
+ /* Every argument gets counted. */
+ typevec[maxtype++] = parmtype;
+
+ if (TREE_USED (parmtype) && parmtype == typevec[maxtype-2])
+ {
+ Nrepeats++;
+ continue;
+ }
+
+ if (Nrepeats)
+ flush_repeats (typevec[maxtype-2]);
+
+ if (TREE_USED (parmtype))
+ {
+#if 0
+ /* We can turn this on at some point when we want
+ improved symbol mangling. */
+ Nrepeats++;
+#else
+ /* This is bug compatible with 2.7.x */
+ flush_repeats (parmtype);
+#endif
+ continue;
+ }
+
+ /* Only cache types which take more than one character. */
+ if (parmtype != TYPE_MAIN_VARIANT (parmtype)
+ || (TREE_CODE (parmtype) != INTEGER_TYPE
+ && TREE_CODE (parmtype) != REAL_TYPE))
+ TREE_USED (parmtype) = 1;
+ }
+ if (TYPE_PTRMEMFUNC_P (parmtype))
+ parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype);
+ process_modifiers (parmtype);
+ if (TREE_CODE(parmtype)==VOID_TYPE)
+ {
+#if 0
+ extern tree void_list_node;
- while (parmtypes)
- {
- parmtype = TREE_VALUE (parmtypes);
+ /* See if anybody is wasting memory. */
+ my_friendly_assert (parmtypes == void_list_node, 247);
+#endif
+ /* This is the end of a parameter list. */
+ if (end)
+ OB_FINISH ();
+ return (char *)obstack_base (&scratch_obstack);
+ }
+ process_overload_item (parmtype, TRUE);
+ }
+ if (flag_do_squangling && nrepeats != 0)
+ issue_nrepeats (lasttype);
+ else
+ if (Nrepeats && typevec)
+ flush_repeats (typevec[maxtype-1]);
- only_one:
+ /* To get here, parms must end with `...'. */
+ OB_PUTC ('e');
+ }
+ if (end)
+ OB_FINISH ();
+ return (char *)obstack_base (&scratch_obstack);
+}
- if (! nofold && ! just_one)
- {
- /* Every argument gets counted. */
- typevec[maxtype++] = parmtype;
+/* handles emitting modifiers such as Constant, read-only, and volatile */
+void
+process_modifiers (parmtype)
+ tree parmtype;
+{
- if (TREE_USED (parmtype) && parmtype == typevec[maxtype-2])
- {
- nrepeats++;
- goto next;
- }
- if (nrepeats)
- flush_repeats (typevec[maxtype-2]);
+ if (TREE_READONLY (parmtype))
+ OB_PUTC ('C');
+ if (TREE_CODE (parmtype) == INTEGER_TYPE &&
+ TYPE_MAIN_VARIANT (parmtype) ==
+ unsigned_type (TYPE_MAIN_VARIANT (parmtype)))
+ OB_PUTC ('U');
+ if (TYPE_VOLATILE (parmtype))
+ OB_PUTC ('V');
+}
- if (TREE_USED (parmtype))
- {
-#if 0
- /* We can turn this on at some point when we want
- improved symbol mangling. */
- nrepeats++;
-#else
- /* This is bug compatible with 2.7.x */
- flush_repeats (parmtype);
-#endif
- goto next;
- }
+/* Check to see if a tree node has been entered into the Bcode typelist
+ if not, add it. Otherwise emit the code and return TRUE */
+static int
+check_btype (node)
+ tree node;
+{
+ int x;
- /* Only cache types which take more than one character. */
- if (parmtype != TYPE_MAIN_VARIANT (parmtype)
- || (TREE_CODE (parmtype) != INTEGER_TYPE
- && TREE_CODE (parmtype) != REAL_TYPE))
- TREE_USED (parmtype) = 1;
- }
+ if (btypelist == NULL)
+ return 0;
+
+ switch (TREE_CODE (node))
+ {
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case VOID_TYPE:
+ case BOOLEAN_TYPE:
+ return 0; /* don't compress single char basic types */
- if (TYPE_PTRMEMFUNC_P (parmtype))
- parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype);
+ default:
+ break;
+ }
- if (TREE_READONLY (parmtype))
- OB_PUTC ('C');
- if (TREE_CODE (parmtype) == INTEGER_TYPE
- && TYPE_MAIN_VARIANT (parmtype) == unsigned_type (TYPE_MAIN_VARIANT (parmtype)))
- OB_PUTC ('U');
- if (TYPE_VOLATILE (parmtype))
- OB_PUTC ('V');
+ node = TYPE_MAIN_VARIANT (node);
+ for (x = 0; x < maxbtype; x++)
+ {
+ if (node == btypelist[x])
+ {
+ OB_PUTC ('B');
+ icat (x);
+ if (x > 9)
+ OB_PUTC ('_');
+ return 1 ;
+ }
+ }
+ /* didn't find it, so add it here */
+ if (maxbsize <= maxbtype)
+ {
+ maxbsize = maxbsize * 3 / 2;
+ btypelist = (tree *)xrealloc (sizeof (tree) * maxbsize);
+ }
+ btypelist[maxbtype++] = node;
+ return 0;
+}
- switch (TREE_CODE (parmtype))
- {
- case OFFSET_TYPE:
- OB_PUTC ('O');
- build_overload_name (TYPE_OFFSET_BASETYPE (parmtype), 0, 0);
- OB_PUTC ('_');
- build_overload_name (TREE_TYPE (parmtype), 0, 0);
- break;
+/* handle emitting the correct code for various node types */
+static void
+process_overload_item (parmtype, extra_Gcode)
+ tree parmtype;
+ int extra_Gcode;
+{
- case REFERENCE_TYPE:
- OB_PUTC ('R');
- goto more;
+ /* These tree types are considered modifiers for B code squangling , */
+ /* and therefore should not get entries in the Btypelist */
+ /* they are, however, repeatable types */
- case ARRAY_TYPE:
-#if PARM_CAN_BE_ARRAY_TYPE
- {
- tree length;
+ switch (TREE_CODE (parmtype))
+ {
+ case REFERENCE_TYPE:
+ OB_PUTC ('R');
+ goto more;
- OB_PUTC ('A');
- if (TYPE_DOMAIN (parmtype) == NULL_TREE)
- error ("pointer or reference to array of unknown bound in parm type");
- else
- {
- length = array_type_nelts (parmtype);
- if (TREE_CODE (length) == INTEGER_CST)
- icat (TREE_INT_CST_LOW (length) + 1);
- }
- OB_PUTC ('_');
- goto more;
- }
+ case ARRAY_TYPE:
+#if PARM_CAN_BE_ARRAY_TYPE
+ {
+ tree length;
+
+ OB_PUTC ('A');
+ if (TYPE_DOMAIN (parmtype) == NULL_TREE)
+ error("pointer/reference to array of unknown bound in parm type");
+ else
+ {
+ length = array_type_nelts (parmtype);
+ if (TREE_CODE (length) == INTEGER_CST)
+ icat (TREE_INT_CST_LOW (length) + 1);
+ }
+ OB_PUTC ('_');
+ goto more;
+ }
#else
- OB_PUTC ('P');
- goto more;
+ OB_PUTC ('P');
+ goto more;
#endif
- case POINTER_TYPE:
- OB_PUTC ('P');
- more:
- build_overload_name (TREE_TYPE (parmtype), 0, 0);
- break;
+ case POINTER_TYPE:
+ OB_PUTC ('P');
+ more:
+ build_mangled_name (TREE_TYPE (parmtype), 0, 0);
+ return;
+ break;
- case FUNCTION_TYPE:
- case METHOD_TYPE:
- {
- tree firstarg = TYPE_ARG_TYPES (parmtype);
- /* Otherwise have to implement reentrant typevecs,
- unmark and remark types, etc. */
- int old_nofold = nofold;
- nofold = 1;
-
- if (nrepeats)
- flush_repeats (typevec[maxtype-1]);
-
- /* @@ It may be possible to pass a function type in
- which is not preceded by a 'P'. */
- if (TREE_CODE (parmtype) == FUNCTION_TYPE)
- {
- OB_PUTC ('F');
- if (firstarg == NULL_TREE)
- OB_PUTC ('e');
- else if (firstarg == void_list_node)
- OB_PUTC ('v');
- else
- build_overload_name (firstarg, 0, 0);
- }
- else
- {
- int constp = TYPE_READONLY (TREE_TYPE (TREE_VALUE (firstarg)));
- int volatilep = TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (firstarg)));
- OB_PUTC ('M');
- firstarg = TREE_CHAIN (firstarg);
-
- build_overload_name (TYPE_METHOD_BASETYPE (parmtype), 0, 0);
- if (constp)
- OB_PUTC ('C');
- if (volatilep)
- OB_PUTC ('V');
-
- /* For cfront 2.0 compatibility. */
- OB_PUTC ('F');
-
- if (firstarg == NULL_TREE)
- OB_PUTC ('e');
- else if (firstarg == void_list_node)
- OB_PUTC ('v');
- else
- build_overload_name (firstarg, 0, 0);
- }
+ default:
+ break;
+ }
+
+ /* check if type is already in the typelist. If not, add it now */
- /* Separate args from return type. */
- OB_PUTC ('_');
- build_overload_name (TREE_TYPE (parmtype), 0, 0);
- nofold = old_nofold;
- break;
- }
+ if (flag_do_squangling && btypelist != NULL) {
+ if (check_btype (parmtype)) /* emits the code if it finds it */
+ return;
+ }
- case INTEGER_TYPE:
- parmtype = TYPE_MAIN_VARIANT (parmtype);
- if (parmtype == integer_type_node
- || parmtype == unsigned_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)
- 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)
- OB_PUTC ('c');
- else if (parmtype == wchar_type_node)
- OB_PUTC ('w');
- else if (parmtype == long_long_integer_type_node
- || parmtype == long_long_unsigned_type_node)
- OB_PUTC ('x');
+ switch (TREE_CODE (parmtype))
+ {
+ case OFFSET_TYPE:
+ OB_PUTC ('O');
+ build_mangled_name (TYPE_OFFSET_BASETYPE (parmtype), 0, 0);
+ OB_PUTC ('_');
+ build_mangled_name (TREE_TYPE (parmtype), 0, 0);
+ break;
+
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ {
+ tree firstarg = TYPE_ARG_TYPES (parmtype);
+ /* Otherwise have to implement reentrant typevecs,
+ unmark and remark types, etc. */
+ int old_nofold = nofold;
+ if (!flag_do_squangling) {
+ nofold = 1;
+ if (Nrepeats)
+ flush_repeats (typevec[maxtype-1]);
+ }
+ else
+ if (nrepeats != 0)
+ issue_nrepeats (lasttype);
+
+ /* @@ It may be possible to pass a function type in
+ which is not preceded by a 'P'. */
+ if (TREE_CODE (parmtype) == FUNCTION_TYPE)
+ {
+ OB_PUTC ('F');
+ if (firstarg == NULL_TREE)
+ OB_PUTC ('e');
+ else if (firstarg == void_list_node)
+ OB_PUTC ('v');
+ else
+ build_mangled_name (firstarg, 0, 0);
+ }
+ else
+ {
+ int constp = TYPE_READONLY (TREE_TYPE (TREE_VALUE (firstarg)));
+ int volatilep = TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (firstarg)));
+ OB_PUTC ('M');
+ firstarg = TREE_CHAIN (firstarg);
+
+ build_mangled_name (TYPE_METHOD_BASETYPE (parmtype), 0, 0);
+ if (constp)
+ OB_PUTC ('C');
+ if (volatilep)
+ OB_PUTC ('V');
+
+ /* For cfront 2.0 compatibility. */
+ OB_PUTC ('F');
+
+ if (firstarg == NULL_TREE)
+ OB_PUTC ('e');
+ else if (firstarg == void_list_node)
+ OB_PUTC ('v');
+ else
+ build_mangled_name (firstarg, 0, 0);
+ }
+
+ /* Separate args from return type. */
+ OB_PUTC ('_');
+ build_mangled_name (TREE_TYPE (parmtype), 0, 0);
+ nofold = old_nofold;
+ break;
+ }
+
+ case INTEGER_TYPE:
+ parmtype = TYPE_MAIN_VARIANT (parmtype);
+ if (parmtype == integer_type_node
+ || parmtype == unsigned_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)
+ 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)
+ OB_PUTC ('c');
+ else if (parmtype == wchar_type_node)
+ OB_PUTC ('w');
+ else if (parmtype == long_long_integer_type_node
+ || parmtype == long_long_unsigned_type_node)
+ OB_PUTC ('x');
#if 0
- /* it would seem there is no way to enter these in source code,
- yet. (mrs) */
- else if (parmtype == long_long_long_integer_type_node
- || parmtype == long_long_long_unsigned_type_node)
- OB_PUTC ('q');
+ /* it would seem there is no way to enter these in source code,
+ yet. (mrs) */
+ else if (parmtype == long_long_long_integer_type_node
+ || parmtype == long_long_long_unsigned_type_node)
+ OB_PUTC ('q');
#endif
- else
- my_friendly_abort (73);
- break;
-
- case BOOLEAN_TYPE:
- OB_PUTC ('b');
- break;
-
- case REAL_TYPE:
- parmtype = TYPE_MAIN_VARIANT (parmtype);
- if (parmtype == long_double_type_node)
- OB_PUTC ('r');
- else if (parmtype == double_type_node)
- OB_PUTC ('d');
- else if (parmtype == float_type_node)
- OB_PUTC ('f');
- else my_friendly_abort (74);
- break;
-
- case VOID_TYPE:
- if (! just_one)
- {
-#if 0
- extern tree void_list_node;
+ else
+ my_friendly_abort (73);
+ break;
- /* See if anybody is wasting memory. */
- my_friendly_assert (parmtypes == void_list_node, 247);
-#endif
- /* This is the end of a parameter list. */
- if (end) OB_FINISH ();
- return (char *)obstack_base (&scratch_obstack);
- }
- 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 (! just_one)
- /* Make this type signature look incompatible
- with AT&T. */
- OB_PUTC ('G');
- goto common;
- case ENUMERAL_TYPE:
- common:
- {
- tree name = TYPE_NAME (parmtype);
- int i = 1;
+ case BOOLEAN_TYPE:
+ OB_PUTC ('b');
+ break;
- if (TREE_CODE (name) == TYPE_DECL)
- {
- tree context = name;
+ case REAL_TYPE:
+ parmtype = TYPE_MAIN_VARIANT (parmtype);
+ if (parmtype == long_double_type_node)
+ OB_PUTC ('r');
+ else if (parmtype == double_type_node)
+ OB_PUTC ('d');
+ else if (parmtype == float_type_node)
+ OB_PUTC ('f');
+ else my_friendly_abort (74);
+ break;
- /* If DECL_ASSEMBLER_NAME has been set properly, use it. */
- if (DECL_ASSEMBLER_NAME (context) != DECL_NAME (context))
- {
- OB_PUTID (DECL_ASSEMBLER_NAME (context));
- break;
- }
- while (DECL_CONTEXT (context))
- {
- i += 1;
- context = DECL_CONTEXT (context);
- if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
- context = TYPE_NAME (context);
- }
- name = DECL_NAME (name);
- }
- my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 248);
- if (i > 1)
- {
- OB_PUTC ('Q');
- if (i > 9)
- OB_PUTC ('_');
- icat (i);
- if (i > 9)
- OB_PUTC ('_');
- numeric_output_need_bar = 0;
- build_overload_nested_name (TYPE_MAIN_DECL (parmtype));
- }
- else
- build_overload_identifier (TYPE_MAIN_DECL (parmtype));
- break;
- }
+ case COMPLEX_TYPE:
+ OB_PUTC ('J');
+ build_mangled_name (TREE_TYPE (parmtype), 0, 0);
+ break;
- case UNKNOWN_TYPE:
- /* This will take some work. */
- OB_PUTC ('?');
- break;
-
- case TEMPLATE_TYPE_PARM:
- OB_PUTC ('X');
- if (TEMPLATE_TYPE_IDX (parmtype) > 9)
- OB_PUTC ('_');
- icat (TEMPLATE_TYPE_IDX (parmtype));
- if (TEMPLATE_TYPE_IDX (parmtype) > 9)
- OB_PUTC ('_');
- break;
-
- case TYPENAME_TYPE:
- /* 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);
- }
- break;
+ case VOID_TYPE:
+ OB_PUTC ('v');
+ break;
- default:
- my_friendly_abort (75);
- }
+ case ERROR_MARK: /* not right, but nothing is anyway */
+ break;
- next:
- if (just_one) break;
- parmtypes = TREE_CHAIN (parmtypes);
- }
- if (! just_one)
- {
- if (nrepeats)
- flush_repeats (typevec[maxtype-1]);
+ /* 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);
- /* To get here, parms must end with `...'. */
- OB_PUTC ('e');
+ if (TREE_CODE (name) == IDENTIFIER_NODE)
+ {
+ build_overload_identifier (TYPE_NAME (parmtype));
+ break;
+ }
+ 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 (CLASSTYPE_TEMPLATE_INFO (parmtype))
+ {
+ build_mangled_template_parm_index ("tzX",
+ TEMPLATE_TYPE_PARM_INDEX
+ (parmtype));
+ build_template_parm_names
+ (DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (parmtype)),
+ CLASSTYPE_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);
}
- if (end) OB_FINISH ();
- return (char *)obstack_base (&scratch_obstack);
}
+/* 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 (basetype, name)
- tree basetype, name;
+build_static_name (context, name)
+ tree context, name;
{
- char *basename = build_overload_name (basetype, 1, 1);
- char *buf = (char *) alloca (IDENTIFIER_LENGTH (name)
- + sizeof (STATIC_NAME_FORMAT)
- + strlen (basename));
- sprintf (buf, STATIC_NAME_FORMAT, basename, IDENTIFIER_POINTER (name));
- return get_identifier (buf);
-}
-\f
-/* 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. */
+ 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 ();
-tree
-build_decl_overload (dname, parms, for_method)
+ return get_identifier ((char *)obstack_base (&scratch_obstack));
+}
+\f
+static 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)
+ 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");
- else if (TREE_CHAIN (parms) == void_list_node)
- {
- if (dname == ansi_opname[(int) NEW_EXPR])
- return get_identifier ("__builtin_new");
- else if (dname == ansi_opname[(int) VEC_NEW_EXPR])
- return get_identifier ("__builtin_vec_new");
- }
+ 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);
/* We can get away without doing this. */
OB_PUTC ('M');
#endif
+ if (tparms != NULL_TREE)
+ OB_PUTC ('H');
{
tree this_type = TREE_VALUE (parms);
TREE_CHAIN (parms));
}
}
- else
+ else if (tparms)
+ OB_PUTC ('H');
+ /* 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 */
+ else if (current_namespace == global_namespace)
OB_PUTC ('F');
+ if (tparms)
+ {
+ build_template_parm_names (tparms, targs);
+ OB_PUTC ('_');
+ }
+
+ /* qualify with namespace */
+ if (!for_method && current_namespace != global_namespace)
+ build_qualified_name (current_namespace);
+
if (parms == NULL_TREE)
- OB_PUTC2 ('e', '\0');
+ OB_PUTC ('e');
else if (parms == void_list_node)
- OB_PUTC2 ('v', '\0');
+ OB_PUTC ('v');
else
{
- ALLOCATE_TYPEVEC (parms);
+ if (!flag_do_squangling) /* Allocate typevec array. */
+ {
+ maxtype = 0;
+ Nrepeats = 0;
+ typevec = (tree *)alloca (list_length (parms) * sizeof (tree));
+ }
nofold = 0;
if (for_method)
{
- build_overload_name (TREE_VALUE (parms), 0, 0);
+ build_mangled_name (TREE_VALUE (parms), 0, 0);
- typevec[maxtype++] = TREE_VALUE (parms);
- TREE_USED (TREE_VALUE (parms)) = 1;
+ if (!flag_do_squangling) {
+ typevec[maxtype++] = TREE_VALUE (parms);
+ TREE_USED (TREE_VALUE (parms)) = 1;
+ }
if (TREE_CHAIN (parms))
- build_overload_name (TREE_CHAIN (parms), 0, 1);
+ build_mangled_name (TREE_CHAIN (parms), 0, 0);
else
- OB_PUTC2 ('e', '\0');
+ OB_PUTC ('e');
}
else
- build_overload_name (parms, 0, 1);
- DEALLOCATE_TYPEVEC (parms);
+ {
+ /* the namespace qualifier for a global function
+ will count as type */
+ if (current_namespace != global_namespace
+ && !flag_do_squangling)
+ typevec[maxtype++] = current_namespace;
+ build_mangled_name (parms, 0, 0);
+ }
+
+ if (!flag_do_squangling) /* Deallocate typevec array */
+ {
+ tree t = parms;
+ typevec = NULL;
+ while (t)
+ {
+ TREE_USED (TREE_VALUE (t)) = 0;
+ t = TREE_CHAIN (t);
+ }
+ }
+ }
+
+ if (ret_type != NULL_TREE && for_method != 2)
+ {
+ /* Add the return type. */
+ OB_PUTC ('_');
+ build_mangled_name (ret_type, 0, 0);
}
+
+ OB_FINISH ();
+ end_squangling ();
{
tree n = get_identifier (obstack_base (&scratch_obstack));
if (IDENTIFIER_OPNAME_P (dname))
}
}
+/* 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);
+}
+
+
+/* Like build_decl_overload, but for template functions. */
+
+tree
+build_template_decl_overload (dname, parms, ret_type, tparms, targs,
+ for_method)
+ tree dname;
+ tree parms;
+ tree ret_type;
+ tree tparms;
+ tree targs;
+ int for_method;
+{
+ return build_decl_overload_real (dname, parms, ret_type, tparms, targs,
+ for_method);
+}
+
+
/* Build an overload name for the type expression TYPE. */
tree
OB_INIT ();
OB_PUTID (ansi_opname[(int) TYPE_EXPR]);
nofold = 1;
- build_overload_name (type, 0, 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_NAME (type);
+ IDENTIFIER_GLOBAL_VALUE (id) = TYPE_MAIN_DECL (type);
#endif
TREE_TYPE (id) = type;
+ end_squangling ();
return id;
}
OB_PUTID (name);
nofold = 1;
- build_overload_name (type, 0, 1);
+ start_squangling ();
+ build_mangled_name (type, 0, 1);
+ end_squangling ();
return get_identifier (obstack_base (&scratch_obstack));
}
OB_FINISH ();
return get_identifier (obstack_base (&scratch_obstack));
}
-
-/* Top-level interface to explicit overload requests. Allow NAME
- to be overloaded. Error if NAME is already declared for the current
- scope. Warning if function is redundantly overloaded. */
-
-void
-declare_overloaded (name)
- tree name;
-{
-#ifdef NO_AUTO_OVERLOAD
- if (is_overloaded (name))
- warning ("function `%s' already declared overloaded",
- IDENTIFIER_POINTER (name));
- else if (IDENTIFIER_GLOBAL_VALUE (name))
- error ("overloading function `%s' that is already defined",
- IDENTIFIER_POINTER (name));
- else
- {
- TREE_OVERLOADED (name) = 1;
- IDENTIFIER_GLOBAL_VALUE (name) = build_tree_list (name, NULL_TREE);
- TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)) = unknown_type_node;
- }
-#else
- if (current_lang_name == lang_name_cplusplus)
- {
- if (0)
- warning ("functions are implicitly overloaded in C++");
- }
- else if (current_lang_name == lang_name_c)
- error ("overloading function `%s' cannot be done in C language context");
- else
- my_friendly_abort (76);
-#endif
-}
-
-#ifdef NO_AUTO_OVERLOAD
-/* Check to see if NAME is overloaded. For first approximation,
- check to see if its TREE_OVERLOADED is set. This is used on
- IDENTIFIER nodes. */
-
-int
-is_overloaded (name)
- tree name;
-{
- /* @@ */
- return (TREE_OVERLOADED (name)
- && (! IDENTIFIER_CLASS_VALUE (name) || current_class_type == 0)
- && ! IDENTIFIER_LOCAL_VALUE (name));
-}
-#endif
\f
/* Given a tree_code CODE, and some arguments (at least one),
attempt to use an overloaded operator on the arguments.
int flags;
tree xarg1, xarg2, arg3;
{
- tree rval = 0;
- tree arg1, arg2;
- tree type1, type2, fnname;
- tree fields1 = 0, parms = 0;
- tree global_fn;
- int try_second;
- int binary_is_unary;
-
- if (flag_ansi_overloading)
- return build_new_op (code, flags, xarg1, xarg2, arg3);
-
- if (xarg1 == error_mark_node)
- return error_mark_node;
-
- if (code == COND_EXPR)
- {
- if (TREE_CODE (xarg2) == ERROR_MARK
- || TREE_CODE (arg3) == ERROR_MARK)
- return error_mark_node;
- }
- if (code == COMPONENT_REF)
- if (TREE_CODE (TREE_TYPE (xarg1)) == POINTER_TYPE)
- return rval;
-
- /* First, see if we can work with the first argument */
- type1 = TREE_TYPE (xarg1);
-
- /* Some tree codes have length > 1, but we really only want to
- overload them if their first argument has a user defined type. */
- switch (code)
- {
- case PREINCREMENT_EXPR:
- case PREDECREMENT_EXPR:
- case POSTINCREMENT_EXPR:
- case POSTDECREMENT_EXPR:
- case COMPONENT_REF:
- binary_is_unary = 1;
- try_second = 0;
- break;
-
- /* ARRAY_REFs and CALL_EXPRs must overload successfully.
- If they do not, return error_mark_node instead of NULL_TREE. */
- case ARRAY_REF:
- if (xarg2 == error_mark_node)
- return error_mark_node;
- case CALL_EXPR:
- rval = error_mark_node;
- binary_is_unary = 0;
- try_second = 0;
- break;
-
- case VEC_NEW_EXPR:
- case NEW_EXPR:
- {
- tree args = tree_cons (NULL_TREE, xarg2, arg3);
- fnname = ansi_opname[(int) code];
- if (flags & LOOKUP_GLOBAL)
- return build_overload_call (fnname, args, flags & LOOKUP_COMPLAIN);
-
- rval = build_method_call
- (build_indirect_ref (build1 (NOP_EXPR, xarg1, error_mark_node),
- "new"),
- fnname, args, NULL_TREE, flags);
- if (rval == error_mark_node)
- /* User might declare fancy operator new, but invoke it
- like standard one. */
- return rval;
-
- TREE_TYPE (rval) = xarg1;
- TREE_CALLS_NEW (rval) = 1;
- return rval;
- }
- break;
-
- case VEC_DELETE_EXPR:
- case DELETE_EXPR:
- {
- fnname = ansi_opname[(int) code];
- if (flags & LOOKUP_GLOBAL)
- return build_overload_call (fnname,
- build_tree_list (NULL_TREE, xarg1),
- flags & LOOKUP_COMPLAIN);
- arg1 = TREE_TYPE (xarg1);
-
- /* This handles the case where we're trying to delete
- X (*a)[10];
- a=new X[5][10];
- delete[] a; */
-
- if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE)
- {
- /* Strip off the pointer and the array. */
- arg1 = TREE_TYPE (TREE_TYPE (arg1));
-
- while (TREE_CODE (arg1) == ARRAY_TYPE)
- arg1 = (TREE_TYPE (arg1));
-
- arg1 = build_pointer_type (arg1);
- }
-
- rval = build_method_call
- (build_indirect_ref (build1 (NOP_EXPR, arg1,
- error_mark_node),
- NULL_PTR),
- fnname, tree_cons (NULL_TREE, xarg1,
- build_tree_list (NULL_TREE, xarg2)),
- NULL_TREE, flags);
-#if 0
- /* This can happen when operator delete is protected. */
- my_friendly_assert (rval != error_mark_node, 250);
- TREE_TYPE (rval) = void_type_node;
-#endif
- return rval;
- }
- break;
-
- default:
- binary_is_unary = 0;
- try_second = tree_code_length [(int) code] == 2;
- if (try_second && xarg2 == error_mark_node)
- return error_mark_node;
- break;
- }
-
- if (try_second && xarg2 == error_mark_node)
- return error_mark_node;
-
- /* What ever it was, we do not know how to deal with it. */
- if (type1 == NULL_TREE)
- return rval;
-
- if (TREE_CODE (type1) == OFFSET_TYPE)
- type1 = TREE_TYPE (type1);
-
- if (TREE_CODE (type1) == REFERENCE_TYPE)
- {
- arg1 = convert_from_reference (xarg1);
- type1 = TREE_TYPE (arg1);
- }
- else
- {
- arg1 = xarg1;
- }
-
- if (!IS_AGGR_TYPE (type1) || TYPE_PTRMEMFUNC_P (type1))
- {
- /* Try to fail. First, fail if unary */
- if (! try_second)
- return rval;
- /* Second, see if second argument is non-aggregate. */
- type2 = TREE_TYPE (xarg2);
- if (TREE_CODE (type2) == OFFSET_TYPE)
- type2 = TREE_TYPE (type2);
- if (TREE_CODE (type2) == REFERENCE_TYPE)
- {
- arg2 = convert_from_reference (xarg2);
- type2 = TREE_TYPE (arg2);
- }
- else
- {
- arg2 = xarg2;
- }
-
- if (!IS_AGGR_TYPE (type2))
- return rval;
- try_second = 0;
- }
-
- if (try_second)
- {
- /* First arg may succeed; see whether second should. */
- type2 = TREE_TYPE (xarg2);
- if (TREE_CODE (type2) == OFFSET_TYPE)
- type2 = TREE_TYPE (type2);
- if (TREE_CODE (type2) == REFERENCE_TYPE)
- {
- arg2 = convert_from_reference (xarg2);
- type2 = TREE_TYPE (arg2);
- }
- else
- {
- arg2 = xarg2;
- }
-
- if (! IS_AGGR_TYPE (type2))
- try_second = 0;
- }
-
- if (type1 == unknown_type_node
- || (try_second && TREE_TYPE (xarg2) == unknown_type_node))
- {
- /* This will not be implemented in the foreseeable future. */
- return rval;
- }
-
- if (code == MODIFY_EXPR)
- fnname = ansi_assopname[(int) TREE_CODE (arg3)];
- else
- fnname = ansi_opname[(int) code];
-
- global_fn = lookup_name_nonclass (fnname);
-
- /* This is the last point where we will accept failure. This
- may be too eager if we wish an overloaded operator not to match,
- but would rather a normal operator be called on a type-converted
- argument. */
-
- if (IS_AGGR_TYPE (type1))
- {
- fields1 = lookup_fnfields (TYPE_BINFO (type1), fnname, 0);
- /* ARM $13.4.7, prefix/postfix ++/--. */
- if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
- {
- xarg2 = integer_zero_node;
- binary_is_unary = 0;
-
- if (fields1)
- {
- tree t, t2;
- int have_postfix = 0;
-
- /* Look for an `operator++ (int)'. If they didn't have
- one, then we fall back to the old way of doing things. */
- for (t = TREE_VALUE (fields1); t ; t = DECL_CHAIN (t))
- {
- t2 = TYPE_ARG_TYPES (TREE_TYPE (t));
- if (TREE_CHAIN (t2) != NULL_TREE
- && TREE_VALUE (TREE_CHAIN (t2)) == integer_type_node)
- {
- have_postfix = 1;
- break;
- }
- }
-
- if (! have_postfix)
- {
- char *op = POSTINCREMENT_EXPR ? "++" : "--";
-
- /* There's probably a LOT of code in the world that
- relies upon this old behavior. */
- if (! flag_traditional)
- pedwarn ("no `operator%s (int)' declared for postfix `%s', using prefix operator instead",
- op, op);
- xarg2 = NULL_TREE;
- binary_is_unary = 1;
- }
- }
- }
- }
-
- if (fields1 == NULL_TREE && global_fn == NULL_TREE)
- return rval;
-
- /* If RVAL winds up being `error_mark_node', we will return
- that... There is no way that normal semantics of these
- operators will succeed. */
-
- /* This argument may be an uncommitted OFFSET_REF. This is
- the case for example when dealing with static class members
- which are referenced from their class name rather than
- from a class instance. */
- if (TREE_CODE (xarg1) == OFFSET_REF
- && TREE_CODE (TREE_OPERAND (xarg1, 1)) == VAR_DECL)
- xarg1 = TREE_OPERAND (xarg1, 1);
- if (try_second && xarg2 && TREE_CODE (xarg2) == OFFSET_REF
- && TREE_CODE (TREE_OPERAND (xarg2, 1)) == VAR_DECL)
- xarg2 = TREE_OPERAND (xarg2, 1);
-
- if (global_fn)
- flags |= LOOKUP_GLOBAL;
-
- if (code == CALL_EXPR)
- {
- /* This can only be a member function. */
- return build_method_call (xarg1, fnname, xarg2,
- NULL_TREE, LOOKUP_NORMAL);
- }
- else if (tree_code_length[(int) code] == 1 || binary_is_unary)
- {
- parms = NULL_TREE;
- rval = build_method_call (xarg1, fnname, NULL_TREE, NULL_TREE, flags);
- }
- else if (code == COND_EXPR)
- {
- parms = tree_cons (NULL_TREE, xarg2, build_tree_list (NULL_TREE, arg3));
- rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);
- }
- else if (code == METHOD_CALL_EXPR)
- {
- /* must be a member function. */
- parms = tree_cons (NULL_TREE, xarg2, arg3);
- return build_method_call (xarg1, fnname, parms, NULL_TREE,
- LOOKUP_NORMAL);
- }
- else if (fields1)
- {
- parms = build_tree_list (NULL_TREE, xarg2);
- rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);
- }
- else
- {
- parms = tree_cons (NULL_TREE, xarg1,
- build_tree_list (NULL_TREE, xarg2));
- rval = build_overload_call (fnname, parms, flags);
- }
-
- return rval;
+ return build_new_op (code, flags, xarg1, xarg2, arg3);
}
\f
/* This function takes an identifier, ID, and attempts to figure out what
hack_identifier (value, name)
tree value, name;
{
- tree type, context;
+ tree type;
- if (TREE_CODE (value) == ERROR_MARK)
+ if (value == error_mark_node)
{
if (current_class_name)
{
if (TREE_CODE (value) == VAR_DECL)
error ("static member `%s' is %s",
IDENTIFIER_POINTER (name),
- TREE_PRIVATE (value) ? "private" :
- "from a private base class");
+ TREE_PRIVATE (value) ? "private"
+ : "from a private base class");
else
error ("enum `%s' is from private base class",
IDENTIFIER_POINTER (name));
}
}
}
- return value;
}
- if (TREE_CODE (value) == TREE_LIST && TREE_NONLOCAL_FLAG (value))
+ else if (TREE_CODE (value) == TREE_LIST && TREE_NONLOCAL_FLAG (value))
{
if (type == 0)
{
}
\f
-static char *
-thunk_printable_name (decl)
- tree decl;
-{
- return "<thunk function>";
-}
-
tree
make_thunk (function, delta)
tree function;
int delta;
{
- char buffer[250];
- tree thunk_fndecl, thunk_id;
+ char *buffer;
+ tree thunk_id;
tree thunk;
char *func_name;
- static int thunk_number = 0;
tree func_decl;
if (TREE_CODE (function) != ADDR_EXPR)
abort ();
if (TREE_CODE (func_decl) != FUNCTION_DECL)
abort ();
func_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func_decl));
+ buffer = (char *)alloca (strlen (func_name) + 32);
if (delta<=0)
sprintf (buffer, "__thunk_%d_%s", -delta, func_name);
else
if (thunk == NULL_TREE)
{
thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl));
- DECL_RESULT (thunk)
- = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (vtable_entry_type)));
- TREE_READONLY (thunk) = TYPE_READONLY (TREE_TYPE (vtable_entry_type));
- TREE_THIS_VOLATILE (thunk) = TYPE_VOLATILE (TREE_TYPE (vtable_entry_type));
- make_function_rtl (thunk);
+ 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 thunk_fndecl;
{
- rtx insns;
- char buffer[250];
- tree argp;
- struct args_size stack_args_size;
tree function = TREE_OPERAND (DECL_INITIAL (thunk_fndecl), 0);
int delta = THUNK_DELTA (thunk_fndecl);
- char *fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
- int tem;
- int failure = 0;
- int save_ofp;
-
- /* Used to remember which regs we need to emit a USE rtx for. */
- rtx need_use[FIRST_PSEUDO_REGISTER];
- int need_use_count = 0;
-
- /* rtx for the 'this' parameter. */
- rtx this_rtx = 0, this_reg_rtx = 0, fixed_this_rtx;
-
- char *(*save_decl_printable_name) () = decl_printable_name;
- /* Data on reg parms scanned so far. */
- CUMULATIVE_ARGS args_so_far;
if (TREE_ASM_WRITTEN (thunk_fndecl))
return;
TREE_ADDRESSABLE (function) = 1;
mark_used (function);
- decl_printable_name = thunk_printable_name;
if (current_function_decl)
abort ();
- current_function_decl = thunk_fndecl;
TREE_SET_CODE (thunk_fndecl, FUNCTION_DECL);
-#ifdef ASM_OUTPUT_MI_THUNK
- temporary_allocation ();
- 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);
-#else
- save_ofp = flag_omit_frame_pointer;
- flag_omit_frame_pointer = 1;
- init_function_start (thunk_fndecl, input_filename, lineno);
- pushlevel (0);
- expand_start_bindings (1);
-
- temporary_allocation ();
-
- /* Start updating where the next arg would go. */
- INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (function), NULL_RTX, 0);
- stack_args_size.constant = 0;
- stack_args_size.var = 0;
- /* SETUP for possible structure return address FIXME */
-
- /* Now look through all the parameters, make sure that we
- don't clobber any registers used for parameters.
- Also, pick up an rtx for the first "this" parameter. */
- for (argp = TYPE_ARG_TYPES (TREE_TYPE (function));
- argp != NULL_TREE;
- argp = TREE_CHAIN (argp))
-
- {
- tree passed_type = TREE_VALUE (argp);
- register rtx entry_parm;
- int named = 1; /* FIXME */
- struct args_size stack_offset;
- struct args_size arg_size;
-
- if (passed_type == void_type_node)
- break;
-
- if ((TREE_CODE (TYPE_SIZE (passed_type)) != INTEGER_CST
- && contains_placeholder_p (TYPE_SIZE (passed_type)))
-#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
- || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far,
- TYPE_MODE (passed_type),
- passed_type, named)
-#endif
- )
- passed_type = build_pointer_type (passed_type);
-
- entry_parm = FUNCTION_ARG (args_so_far,
- TYPE_MODE (passed_type),
- passed_type,
- named);
- if (entry_parm != 0)
- need_use[need_use_count++] = entry_parm;
-
- locate_and_pad_parm (TYPE_MODE (passed_type), passed_type,
-#ifdef STACK_PARMS_IN_REG_PARM_AREA
- 1,
-#else
- entry_parm != 0,
-#endif
- thunk_fndecl,
- &stack_args_size, &stack_offset, &arg_size);
-
-/* REGNO (entry_parm);*/
- if (this_rtx == 0)
- {
- this_reg_rtx = entry_parm;
- if (!entry_parm)
- {
- rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
-
- rtx internal_arg_pointer, stack_parm;
-
- if ((ARG_POINTER_REGNUM == STACK_POINTER_REGNUM
- || ! (fixed_regs[ARG_POINTER_REGNUM]
- || ARG_POINTER_REGNUM == FRAME_POINTER_REGNUM)))
- internal_arg_pointer = copy_to_reg (virtual_incoming_args_rtx);
- else
- internal_arg_pointer = virtual_incoming_args_rtx;
-
- if (offset_rtx == const0_rtx)
- entry_parm = gen_rtx (MEM, TYPE_MODE (passed_type),
- internal_arg_pointer);
- else
- entry_parm = gen_rtx (MEM, TYPE_MODE (passed_type),
- gen_rtx (PLUS, Pmode,
- internal_arg_pointer,
- offset_rtx));
- }
-
- this_rtx = entry_parm;
- }
-
- FUNCTION_ARG_ADVANCE (args_so_far,
- TYPE_MODE (passed_type),
- passed_type,
- named);
- }
-
- fixed_this_rtx = plus_constant (this_rtx, delta);
- if (this_rtx != fixed_this_rtx)
- emit_move_insn (this_rtx, fixed_this_rtx);
-
- if (this_reg_rtx)
- emit_insn (gen_rtx (USE, VOIDmode, this_reg_rtx));
-
- emit_indirect_jump (XEXP (DECL_RTL (function), 0));
-
- while (need_use_count > 0)
- emit_insn (gen_rtx (USE, VOIDmode, need_use[--need_use_count]));
-
- expand_end_bindings (NULL, 1, 0);
- poplevel (0, 0, 1);
-
- /* From now on, allocate rtl in current_obstack, not in saveable_obstack.
- Note that that may have been done above, in save_for_inline_copying.
- The call to resume_temporary_allocation near the end of this function
- goes back to the usual state of affairs. */
-
- rtl_in_current_obstack ();
-
- insns = get_insns ();
-
- /* Copy any shared structure that should not be shared. */
-
- unshare_all_rtl (insns);
-
- /* Instantiate all virtual registers. */
-
- instantiate_virtual_regs (current_function_decl, get_insns ());
-
- /* We are no longer anticipating cse in this function, at least. */
-
- cse_not_expected = 1;
-
- /* Now we choose between stupid (pcc-like) register allocation
- (if we got the -noreg switch and not -opt)
- and smart register allocation. */
-
- if (optimize > 0) /* Stupid allocation probably won't work */
- obey_regdecls = 0; /* if optimizations being done. */
-
- regclass_init ();
-
- regclass (insns, max_reg_num ());
- if (obey_regdecls)
- {
- stupid_life_analysis (insns, max_reg_num (), NULL);
- failure = reload (insns, 0, NULL);
- }
- else
- {
- /* Do control and data flow analysis,
- and write some of the results to dump file. */
-
- flow_analysis (insns, max_reg_num (), NULL);
- local_alloc ();
- failure = global_alloc (NULL);
- }
-
- reload_completed = 1;
-
-#ifdef LEAF_REGISTERS
- leaf_function = 0;
- if (optimize > 0 && only_leaf_regs_used () && leaf_function_p ())
- leaf_function = 1;
-#endif
-
- /* If a machine dependent reorganization is needed, call it. */
-#ifdef MACHINE_DEPENDENT_REORG
- MACHINE_DEPENDENT_REORG (insns);
-#endif
-
- /* Now turn the rtl into assembler code. */
-
- assemble_start_function (thunk_fndecl, fnname);
- final (insns, asm_out_file, optimize, 0);
- assemble_end_function (thunk_fndecl, fnname);
-
- reload_completed = 0;
- /* Cancel the effect of rtl_in_current_obstack. */
-
- permanent_allocation (1);
- flag_omit_frame_pointer = save_ofp;
+ {
+#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);
+ 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);
+ }
- decl_printable_name = save_decl_printable_name;
- current_function_decl = 0;
+ TREE_SET_CODE (thunk_fndecl, THUNK_DECL);
}
\f
/* Code for synthesizing methods which have default semantics defined. */
/* Generate code for default X(X&) constructor. */
-void
+static void
do_build_copy_constructor (fndecl)
tree fndecl;
{
}
for (; fields; fields = TREE_CHAIN (fields))
{
- tree name, init, t;
+ 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)))
&& TREE_CODE (t) == UNION_TYPE
&& ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
&& TYPE_FIELDS (t) != NULL_TREE)
- field = largest_union_member (t);
+ {
+ do
+ {
+ init = build (COMPONENT_REF, t, init, field);
+ field = largest_union_member (t);
+ }
+ while ((t = TREE_TYPE (field)) != NULL_TREE
+ && TREE_CODE (t) == UNION_TYPE
+ && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && TYPE_FIELDS (t) != NULL_TREE);
+ }
else
continue;
- init = build (COMPONENT_REF, TREE_TYPE (field), parm, field);
+ init = build (COMPONENT_REF, TREE_TYPE (field), init, field);
init = build_tree_list (NULL_TREE, init);
current_member_init_list
pop_momentary ();
}
-void
+static void
do_build_assign_ref (fndecl)
tree fndecl;
{
CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
p = convert_from_reference (p);
p = build_member_call (basetype, ansi_opname [MODIFY_EXPR],
- build_tree_list (NULL_TREE, p));
+ build_expr_list (NULL_TREE, p));
expand_expr_stmt (p);
}
for (; fields; fields = TREE_CHAIN (fields))
continue;
}
+ comp = current_class_ref;
+ init = parm;
+
if (DECL_NAME (field))
{
if (VFIELD_NAME_P (DECL_NAME (field)))
&& TREE_CODE (t) == UNION_TYPE
&& ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
&& TYPE_FIELDS (t) != NULL_TREE)
- field = largest_union_member (t);
+ {
+ 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
+ && TREE_CODE (t) == UNION_TYPE
+ && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && TYPE_FIELDS (t) != NULL_TREE);
+ }
else
continue;
- comp = build (COMPONENT_REF, TREE_TYPE (field), current_class_ref, field);
- init = build (COMPONENT_REF, TREE_TYPE (field), parm, field);
+ 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));
}
{
int nested = (current_function_decl != NULL_TREE);
tree context = hack_decl_function_context (fndecl);
- tree base = DECL_CLASS_CONTEXT (fndecl);
- if (nested)
+ if (at_eof)
+ import_export_decl (fndecl);
+
+ if (! context)
+ push_to_top_level ();
+ else if (nested)
push_cp_function_context (context);
interface_unknown = 1;
finish_function (lineno, 0, nested);
- /* Do we really *want* to inline this function? */
- if (DECL_INLINE (fndecl))
- {
- /* Turn off DECL_INLINE for the moment so function_cannot_inline_p
- will check our size. */
- DECL_INLINE (fndecl) = 0;
-
- /* We say !at_eof because at the end of the file some of the rtl
- for fndecl may have been allocated on the temporary obstack.
- (The function_obstack is the temporary one if we're not in a
- function). */
- if ((! at_eof) && function_cannot_inline_p (fndecl) == 0)
- DECL_INLINE (fndecl) = 1;
- }
-
extract_interface_info ();
- if (nested)
+ if (! context)
+ pop_from_top_level ();
+ else if (nested)
pop_cp_function_context (context);
}