#ifndef __GNUC__
#define __inline
#endif
#ifndef PARM_CAN_BE_ARRAY_TYPE
#define PARM_CAN_BE_ARRAY_TYPE 1
#endif
#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"
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 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);
}
static char digit_buffer[128];
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)
{
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);
}
}
static tree *btypelist = NULL;
static tree *ktypelist = NULL;
static int maxbsize = 0;
static int maxksize = 0;
static int maxbtype = 0;
static int maxktype = 0;
static tree *typevec = NULL;
static int typevec_size;
static int maxtype = 0;
static int nofold;
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;
}
}
static __inline void
icat (i)
HOST_WIDE_INT i;
{
unsigned HOST_WIDE_INT ui;
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;
}
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;
dicat (qlo, qhi);
OB_PUTC ('0' + ulo);
}
static __inline int
old_backref_index (type)
tree type;
{
int tindex = 0;
if (! is_back_referenceable_type (type))
return -1;
for (tindex = 0; tindex < maxtype - 1; ++tindex)
if (same_type_p (typevec[tindex], type))
break;
if (tindex == maxtype - 1)
return -1;
return tindex;
}
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;
}
static int
is_back_referenceable_type (type)
tree type;
{
if (TYPE_FOR_JAVA (type))
return 0;
switch (TREE_CODE (type))
{
case BOOLEAN_TYPE:
if (!flag_do_squangling)
return 1;
case INTEGER_TYPE:
case REAL_TYPE:
case VOID_TYPE:
return 0;
case TEMPLATE_TYPE_PARM:
return 0;
default:
return 1;
}
}
static void
issue_nrepeats (nrepeats, type)
int nrepeats;
tree type;
{
if (nrepeats == 1 && !is_back_referenceable_type (type))
build_mangled_name_for_type (type);
else
{
OB_PUTC ('n');
icat (nrepeats);
if (nrepeats > 9)
OB_PUTC ('_');
}
}
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;
}
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;
}
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);
if (!(ktypelist && issue_ktype (context)))
{
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
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_for_type (TREE_OPERAND (value, 0));
build_overload_identifier (TREE_OPERAND (value, 1));
}
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] != '_')
goto bad_value;
for (i = 0; i < operands; ++i)
{
tree operand;
enum tree_code tc;
numeric_output_need_bar = 0;
if (i != 0)
OB_PUTCP (name + 2);
operand = TREE_OPERAND (value, i);
tc = TREE_CODE (operand);
if (TREE_CODE_CLASS (tc) == '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
{
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)))
{
dicat (TREE_INT_CST_LOW (value), TREE_INT_CST_HIGH (value));
numeric_output_need_bar = 1;
return;
}
}
icat (TREE_INT_CST_LOW (value));
numeric_output_need_bar = 1;
}
static void
build_mangled_template_parm_index (s, index)
char* s;
tree index;
{
OB_PUTCP (s);
build_underscore_int (TEMPLATE_PARM_IDX (index));
build_underscore_int (TEMPLATE_PARM_LEVEL (index));
}
#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)
my_friendly_abort (0);
value = PTRMEM_CST_MEMBER (value);
my_friendly_assert (TREE_CODE (value) == FIELD_DECL, 0);
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);
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;
case RECORD_TYPE:
{
tree delta;
tree idx;
tree pfn;
tree delta2;
my_friendly_assert (TYPE_PTRMEMFUNC_P (type), 0);
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);
}
}
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)
{
OB_PUTC ('Z');
}
else if (TREE_CODE (parm) == TEMPLATE_DECL)
{
OB_PUTC ('z');
build_template_template_parm_names (DECL_INNERMOST_TEMPLATE_PARMS (parm));
}
else
build_mangled_name_for_type (TREE_TYPE (parm));
}
}
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)
{
OB_PUTC ('Z');
build_mangled_name_for_type (arg);
}
else if (TREE_CODE (parm) == TEMPLATE_DECL)
{
if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
build_mangled_name_for_type (arg);
else
{
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, 1, NULL_TREE);
build_mangled_name_for_type (TREE_TYPE (parm));
build_overload_value (TREE_TYPE (parm), arg,
uses_template_parms (arglist));
}
}
}
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)))
{
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);
}
}
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 (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 (check_ktype (context, FALSE) == -1)
{
while (1)
{
context = CP_DECL_CONTEXT (context);
if (context == global_namespace)
break;
i += 1;
if (check_ktype (context, FALSE) != -1)
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);
}
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);
}
static void
build_mangled_name_for_type (type)
tree type;
{
build_mangled_name_for_type_with_Gcode (type, 0);
}
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 ;
}
static char *
build_mangled_name (parmtypes, begin, end)
tree parmtypes;
int begin, end;
{
if (begin)
OB_INIT ();
if (TREE_CODE (parmtypes) != TREE_LIST)
build_mangled_name_for_type (parmtypes);
else
{
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))
{
tree parmtype = TREE_VALUE (parmtypes);
if (old_style_repeats)
{
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)))
{
nrepeats++;
continue;
}
}
else if (nrepeats != 0)
{
if (old_style_repeats)
flush_repeats (nrepeats, last_type);
else
issue_nrepeats (nrepeats, last_type);
nrepeats = 0;
}
last_type = parmtype;
if (old_style_repeats && flush_repeats (0, parmtype))
continue;
build_mangled_name_for_type_with_Gcode (parmtype, 1);
}
if (nrepeats != 0)
{
if (old_style_repeats)
flush_repeats (nrepeats, last_type);
else
issue_nrepeats (nrepeats, last_type);
nrepeats = 0;
}
if (!parmtypes)
OB_PUTC ('e');
}
if (end)
OB_FINISH ();
return (char *)obstack_base (&scratch_obstack);
}
static void
process_modifiers (parmtype)
tree parmtype;
{
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');
if (TYPE_RESTRICT (parmtype))
OB_PUTC ('u');
}
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)
{
maxbsize = maxbsize * 3 / 2;
btypelist = (tree *)xrealloc (btypelist, sizeof (tree) * maxbsize);
}
btypelist[maxbtype++] = type;
return 0;
}
static void
process_overload_item (parmtype, extra_Gcode)
tree parmtype;
int extra_Gcode;
{
numeric_output_need_bar = 0;
if (TREE_CODE (parmtype) == ARRAY_TYPE)
parmtype = canonical_type_variant (parmtype);
else
parmtype = TYPE_MAIN_VARIANT (parmtype);
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))
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);
int old_nofold = nofold;
if (!flag_do_squangling)
nofold = 1;
if (TREE_CODE (parmtype) == METHOD_TYPE)
{
OB_PUTC ('M');
build_mangled_name_for_type (TYPE_METHOD_BASETYPE (parmtype));
process_modifiers (TREE_TYPE (TREE_VALUE (parms)));
}
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);
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)
{
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 VECTOR_TYPE:
OB_PUTC ('E');
if (TYPE_MAIN_VARIANT (parmtype) == vector_unsigned_char_type_node)
OB_PUTC ('U'), OB_PUTC ('c');
else if (TYPE_MAIN_VARIANT (parmtype) == vector_signed_char_type_node)
OB_PUTC ('c');
else if (TYPE_MAIN_VARIANT (parmtype) == vector_boolean_char_type_node)
OB_PUTC ('C');
else if (TYPE_MAIN_VARIANT (parmtype) == vector_unsigned_short_type_node)
OB_PUTC ('U'), OB_PUTC ('s');
else if (TYPE_MAIN_VARIANT (parmtype) == vector_signed_short_type_node)
OB_PUTC ('s');
else if (TYPE_MAIN_VARIANT (parmtype) == vector_boolean_short_type_node)
OB_PUTC ('S');
else if (TYPE_MAIN_VARIANT (parmtype) == vector_unsigned_long_type_node)
OB_PUTC ('U'), OB_PUTC ('l');
else if (TYPE_MAIN_VARIANT (parmtype) == vector_signed_long_type_node)
OB_PUTC ('l');
else if (TYPE_MAIN_VARIANT (parmtype) == vector_boolean_long_type_node)
OB_PUTC ('L');
else if (TYPE_MAIN_VARIANT (parmtype) == vector_float_type_node)
OB_PUTC ('f');
else if (TYPE_MAIN_VARIANT (parmtype) == vector_pixel_type_node)
OB_PUTC ('p');
else
my_friendly_abort (75);
break;
case VOID_TYPE:
OB_PUTC ('v');
break;
case ERROR_MARK:
break;
case UNION_TYPE:
case RECORD_TYPE:
{
if (extra_Gcode)
OB_PUTC ('G');
}
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:
OB_PUTC ('?');
break;
case TEMPLATE_TEMPLATE_PARM:
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:
build_qualified_name (parmtype);
break;
default:
my_friendly_abort (75);
}
}
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));
}
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);
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);
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)
OB_PUTC ('F');
if (!for_method && current_namespace != global_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)
{
maxtype = 0;
typevec_size = list_length (parms);
if (!for_method && current_namespace != global_namespace)
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)
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
{
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)
typevec = NULL;
}
if (ret_type != NULL_TREE && for_method != 2)
{
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;
}
}
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);
}
void
set_mangled_name_for_decl (decl)
tree decl;
{
tree parm_types;
if (processing_template_decl)
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
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));
}
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));
}
tree
build_destructor_name (type)
tree type;
{
return build_overload_with_type (get_identifier (DESTRUCTOR_DECL_PREFIX),
type);
}
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);
}
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);
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
cp_error ("invalid use of member `%D'", value);
return error_mark_node;
}
TREE_USED (current_class_ptr) = 1;
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)
mark_used (OVL_FUNCTION (value));
else if (TREE_CODE (value) == TREE_LIST)
{
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;
#ifdef HAVE_COALESCED_SYMBOLS
MARK_THUNK_COALESCED (thunk);
#endif
pushdecl_top_level (thunk);
}
return 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_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
tree a, t;
if (varargs_function_p (function))
cp_error ("generic thunk code fails for method `%#D' which uses `...'",
function);
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;
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);
if (DECL_DEFER_OUTPUT (thunk_fndecl))
{
output_inline_function (thunk_fndecl);
permanent_allocation (1);
}
#endif
}
TREE_SET_CODE (thunk_fndecl, THUNK_DECL);
}
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;
my_friendly_abort (323);
return NULL_TREE;
}
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))
;
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))
current_base_init_list
= tree_cons (BINFO_TYPE (t), parm, current_base_init_list);
for (i = 0; i < n_bases; ++i)
{
t = TREE_VEC_ELT (binfos, i);
if (TREE_VIA_VIRTUAL (t))
continue;
current_base_init_list
= tree_cons (BINFO_TYPE (t), parm, 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;
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))
;
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;
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 ();
#ifdef MARK_SYNTHESIZED_METHOD_COALESCED
MARK_SYNTHESIZED_METHOD_COALESCED (fndecl);
#endif
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);
}