/* Handle the hair of processing (but not expanding) inline functions.
Also manage function and variable name overloading.
- Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
#ifndef PARM_CAN_BE_ARRAY_TYPE
IDENTIFIER_LENGTH (ID)))
# define OB_PUTCP(S) (obstack_grow (&scratch_obstack, (S), strlen (S)))
# define OB_FINISH() (obstack_1grow (&scratch_obstack, '\0'))
-
-#ifdef NO_AUTO_OVERLOAD
-int is_overloaded ();
-#endif
+# define OB_LAST() (obstack_next_free (&scratch_obstack)[-1])
void
init_method ()
if (method && TREE_CODE (method) == TREE_VEC)
{
- if (TREE_VEC_ELT (method, 0))
+ 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, 1);
+ method = TREE_VEC_ELT (method, 2);
}
while (method)
\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;
cp->function);
return;
- case -3:
- if (TYPE_READONLY (TREE_TYPE (TREE_VALUE (parmtypes))))
- cp_error ("call to const %s `%#D' with non-const object", name_kind,
- cp->function);
- else
- cp_error ("call to non-const %s `%#D' with const object", name_kind,
- cp->function);
- return;
case -2:
cp_error ("too few arguments for %s `%#D'", name_kind, cp->function);
return;
cp_error ("too many arguments for %s `%#D'", name_kind, cp->function);
return;
case 0:
- if (TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)
- {
- /* Happens when we have an ambiguous base class. */
- my_friendly_assert (get_binfo (DECL_CLASS_CONTEXT (cp->function),
- TREE_TYPE (TREE_TYPE (TREE_VALUE (parmtypes))), 1) == error_mark_node,
- 241);
- return;
- }
+ 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;
}
ttf = TYPE_ARG_TYPES (TREE_TYPE (cp->function));
} while (0)
/* Code to concatenate an asciified integer to a string. */
+
static
#ifdef __GNUC__
__inline
OB_PUTC ('_');
}
+static int numeric_output_need_bar;
static void build_overload_identifier ();
static void
-build_overload_nested_name (context)
- tree context;
+build_overload_nested_name (decl)
+ tree decl;
{
- /* We use DECL_NAME here, because pushtag now sets the DECL_ASSEMBLER_NAME. */
- tree name = DECL_NAME (context);
- if (DECL_CONTEXT (context))
+ if (DECL_CONTEXT (decl))
{
- context = DECL_CONTEXT (context);
+ tree context = DECL_CONTEXT (decl);
if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
- context = TYPE_NAME (context);
+ context = TYPE_MAIN_DECL (context);
build_overload_nested_name (context);
}
- build_overload_identifier (name);
+
+ 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++;
+
+ if (numeric_output_need_bar)
+ {
+ OB_PUTC ('_');
+ numeric_output_need_bar = 0;
+ }
+ icat (strlen (label));
+ OB_PUTCP (label);
+ }
+ else /* TYPE_DECL */
+ build_overload_identifier (decl);
+}
+
+/* Encoding for an INTEGER_CST value. */
+
+static void
+build_overload_int (value)
+ tree value;
+{
+ 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. */
+ {
+ static int n;
+ sprintf (digit_buffer, " *%d", n++);
+ OB_PUTCP (digit_buffer);
+ 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");
+ }
+ /* else fall through to print in smaller mode */
+ }
+ /* Wordsize or smaller */
+ icat (TREE_INT_CST_LOW (value));
}
static void
value = TREE_OPERAND (value, 0);
my_friendly_assert (TREE_CODE (type) == PARM_DECL, 242);
type = TREE_TYPE (type);
+
+ if (numeric_output_need_bar)
+ {
+ OB_PUTC ('_');
+ numeric_output_need_bar = 0;
+ }
+
+ if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE)
+ {
+ /* Handle a pointer to data member as a template instantiation
+ parameter, boy, what fun! */
+ type = integer_type_node;
+ if (TREE_CODE (value) != INTEGER_CST)
+ {
+ sorry ("unknown pointer to member constant");
+ return;
+ }
+ }
+
+ if (TYPE_PTRMEMFUNC_P (type))
+ type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+
switch (TREE_CODE (type))
{
case INTEGER_TYPE:
case ENUMERAL_TYPE:
- {
- my_friendly_assert (TREE_CODE (value) == INTEGER_CST, 243);
- if (TYPE_PRECISION (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");
- }
- /* else fall through to print in smaller mode */
- }
- /* Wordsize or smaller */
- icat (TREE_INT_CST_LOW (value));
- return;
- }
case BOOLEAN_TYPE:
{
- icat (TREE_INT_CST_LOW (value));
+ build_overload_int (value);
+ numeric_output_need_bar = 1;
return;
}
#ifndef REAL_IS_NOT_DOUBLE
}
}
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 (value) == CONSTRUCTOR)
+ {
+ /* This is dangerous code, crack built up pointer to members. */
+ tree args = CONSTRUCTOR_ELTS (value);
+ tree a1 = TREE_VALUE (args);
+ tree a2 = TREE_VALUE (TREE_CHAIN (args));
+ tree a3 = CONSTRUCTOR_ELTS (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))));
+ a3 = TREE_VALUE (a3);
+ STRIP_NOPS (a3);
+ if (TREE_CODE (a1) == INTEGER_CST
+ && TREE_CODE (a2) == INTEGER_CST)
+ {
+ build_overload_int (a1);
+ OB_PUTC ('_');
+ build_overload_int (a2);
+ OB_PUTC ('_');
+ if (TREE_CODE (a3) == ADDR_EXPR)
+ {
+ a3 = TREE_OPERAND (a3, 0);
+ if (TREE_CODE (a3) == FUNCTION_DECL)
+ {
+ numeric_output_need_bar = 0;
+ build_overload_identifier (DECL_ASSEMBLER_NAME (a3));
+ return;
+ }
+ }
+ else if (TREE_CODE (a3) == INTEGER_CST)
+ {
+ OB_PUTC ('i');
+ build_overload_int (a3);
+ numeric_output_need_bar = 1;
+ return;
+ }
+ }
+ }
+ sorry ("template instantiation with pointer to method that is too complex");
+ return;
+ }
+ if (TREE_CODE (value) == INTEGER_CST)
+ {
+ build_overload_int (value);
+ numeric_output_need_bar = 1;
+ return;
+ }
value = TREE_OPERAND (value, 0);
if (TREE_CODE (value) == VAR_DECL)
{
my_friendly_assert (DECL_NAME (value) != 0, 245);
- build_overload_identifier (DECL_NAME (value));
+ 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_NAME (value));
+ build_overload_identifier (DECL_ASSEMBLER_NAME (value));
return;
}
else
build_overload_identifier (name)
tree name;
{
- if (IDENTIFIER_TEMPLATE (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))))
{
tree template, parmlist, arglist, tname;
int i, nparms;
- template = IDENTIFIER_TEMPLATE (name);
+ template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
arglist = TREE_VALUE (template);
template = TREE_PURPOSE (template);
tname = DECL_NAME (template);
icat (nparms);
for (i = 0; i < nparms; i++)
{
- tree parm = TREE_VEC_ELT (parmlist, i);
+ tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
tree arg = TREE_VEC_ELT (arglist, i);
- if (TREE_CODE (parm) == IDENTIFIER_NODE)
+ if (TREE_CODE (parm) == TYPE_DECL)
{
/* This parameter is a type. */
OB_PUTC ('Z');
}
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);
}
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);
}
tree parmtype;
if (begin) OB_INIT ();
+ numeric_output_need_bar = 0;
if ((just_one = (TREE_CODE (parmtypes) != TREE_LIST)))
{
only_one:
- if (! nofold)
+ if (! nofold && ! just_one)
{
- if (! just_one)
- /* Every argument gets counted. */
- typevec[maxtype++] = parmtype;
+ /* Every argument gets counted. */
+ typevec[maxtype++] = parmtype;
- if (TREE_USED (parmtype))
+ if (TREE_USED (parmtype) && parmtype == typevec[maxtype-2])
{
- if (! just_one && parmtype == typevec[maxtype-2])
- nrepeats++;
- else
- {
- if (nrepeats)
- flush_repeats (parmtype);
- if (! just_one && TREE_CHAIN (parmtypes)
- && parmtype == TREE_VALUE (TREE_CHAIN (parmtypes)))
- nrepeats++;
- else
- {
- int tindex = 0;
-
- while (typevec[tindex] != parmtype)
- tindex++;
- OB_PUTC ('T');
- icat (tindex);
- if (tindex > 9)
- OB_PUTC ('_');
- }
- }
+ nrepeats++;
goto next;
}
+
if (nrepeats)
flush_repeats (typevec[maxtype-2]);
- if (! just_one
- /* Only cache types which take more than one character. */
- && (parmtype != TYPE_MAIN_VARIANT (parmtype)
- || (TREE_CODE (parmtype) != INTEGER_TYPE
- && TREE_CODE (parmtype) != REAL_TYPE)))
+
+ 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;
+ }
+
+ /* 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 (TREE_CODE (name) == TYPE_DECL)
{
tree context = name;
+
+ /* 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;
icat (i);
if (i > 9)
OB_PUTC ('_');
- build_overload_nested_name (TYPE_NAME (parmtype));
+ numeric_output_need_bar = 0;
+ build_overload_nested_name (TYPE_MAIN_DECL (parmtype));
}
- else
- build_overload_identifier (name);
+ else
+ build_overload_identifier (TYPE_MAIN_DECL (parmtype));
break;
}
break;
case TEMPLATE_TYPE_PARM:
- case TEMPLATE_CONST_PARM:
- case UNINSTANTIATED_P_TYPE:
+ 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. */
if (nrepeats)
flush_repeats (typevec[maxtype-1]);
- /* To get here, parms must end with `...'. */
+ /* To get here, parms must end with `...'. */
OB_PUTC ('e');
}
if (end) OB_FINISH ();
return (char *)obstack_base (&scratch_obstack);
}
-\f
-/* Generate an identifier that encodes the (ANSI) exception TYPE. */
-
-/* This should be part of `ansi_opname', or at least be defined by the std. */
-#define EXCEPTION_NAME_PREFIX "__ex"
-#define EXCEPTION_NAME_LENGTH 4
tree
-cplus_exception_name (type)
- tree type;
+build_static_name (basetype, name)
+ tree basetype, name;
{
- OB_INIT ();
- OB_PUTS (EXCEPTION_NAME_PREFIX);
- return get_identifier (build_overload_name (type, 0, 1));
-}
+ 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,
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;
/* member operators new and delete look like methods at this point. */
if (! for_method && parms != NULL_TREE && TREE_CODE (parms) == TREE_LIST)
{
- if (TREE_VALUE (parms) == sizetype
- && 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");
}
- else 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");
}
OB_INIT ();
}
/* Build an overload name for the type expression TYPE. */
+
tree
build_typename_overload (type)
tree type;
return id;
}
-#ifndef NO_DOLLAR_IN_LABEL
-#define T_DESC_FORMAT "TD$"
-#define I_DESC_FORMAT "ID$"
-#define M_DESC_FORMAT "MD$"
-#else
-#if !defined(NO_DOT_IN_LABEL)
-#define T_DESC_FORMAT "TD."
-#define I_DESC_FORMAT "ID."
-#define M_DESC_FORMAT "MD."
-#else
-#define T_DESC_FORMAT "__t_desc_"
-#define I_DESC_FORMAT "__i_desc_"
-#define M_DESC_FORMAT "__m_desc_"
-#endif
-#endif
-
-/* Build an overload name for the type expression TYPE. */
tree
-build_t_desc_overload (type)
- tree type;
+build_overload_with_type (name, type)
+ tree name, type;
{
OB_INIT ();
- OB_PUTS (T_DESC_FORMAT);
+ OB_PUTID (name);
nofold = 1;
-#if 0
- /* Use a different format if the type isn't defined yet. */
- if (TYPE_SIZE (type) == NULL_TREE)
- {
- char *p;
- int changed;
-
- for (p = tname; *p; p++)
- if (isupper (*p))
- {
- changed = 1;
- *p = tolower (*p);
- }
- /* If there's no change, we have an inappropriate T_DESC_FORMAT. */
- my_friendly_assert (changed != 0, 249);
- }
-#endif
-
build_overload_name (type, 0, 1);
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;
+tree
+get_id_2 (name, name2)
+ char *name;
+ tree name2;
{
- /* @@ */
- return (TREE_OVERLOADED (name)
- && (! IDENTIFIER_CLASS_VALUE (name) || current_class_type == 0)
- && ! IDENTIFIER_LOCAL_VALUE (name));
+ OB_INIT ();
+ OB_PUTCP (name);
+ OB_PUTID (name2);
+ OB_FINISH ();
+ return get_identifier (obstack_base (&scratch_obstack));
}
-#endif
\f
/* Given a tree_code CODE, and some arguments (at least one),
attempt to use an overloaded operator on the arguments.
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;
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,
- (struct candidate *)0);
+ return build_overload_call (fnname, args, flags & LOOKUP_COMPLAIN);
rval = build_method_call
(build_indirect_ref (build1 (NOP_EXPR, xarg1, error_mark_node),
if (flags & LOOKUP_GLOBAL)
return build_overload_call (fnname,
build_tree_list (NULL_TREE, xarg1),
- flags & LOOKUP_COMPLAIN,
- (struct candidate *)0);
+ 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, TREE_TYPE (xarg1),
+ (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);
- /* This happens when the user mis-declares `operator delete'.
- Should now be impossible. */
+#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;
/* Try to fail. First, fail if unary */
if (! try_second)
return rval;
- /* Second, see if second argument is non-aggregate. */
+ /* Second, see if second argument is non-aggregate. */
type2 = TREE_TYPE (xarg2);
if (TREE_CODE (type2) == OFFSET_TYPE)
type2 = TREE_TYPE (type2);
/* 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 = TREE_CHAIN (t))
+ for (t = TREE_VALUE (fields1); t ; t = DECL_CHAIN (t))
{
t2 = TYPE_ARG_TYPES (TREE_TYPE (t));
if (TREE_CHAIN (t2) != NULL_TREE
char *op = POSTINCREMENT_EXPR ? "++" : "--";
/* There's probably a LOT of code in the world that
- relies upon this old behavior. So we'll only give this
- warning when we've been given -pedantic. A few
- releases after 2.4, we'll convert this to be a pedwarn
- or something else more appropriate. */
- if (pedantic)
- warning ("no `operator%s (int)' declared for postfix `%s'",
- op, op);
+ relies upon this old behavior. */
+ pedwarn ("no `operator%s (int)' declared for postfix `%s', using prefix operator instead",
+ op, op);
xarg2 = NULL_TREE;
binary_is_unary = 1;
}
}
else if (code == COND_EXPR)
{
- parms = tree_cons (0, xarg2, build_tree_list (NULL_TREE, arg3));
+ 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)
{
parms = tree_cons (NULL_TREE, xarg1,
build_tree_list (NULL_TREE, xarg2));
- rval = build_overload_call (fnname, parms, flags,
- (struct candidate *)0);
+ rval = build_overload_call (fnname, parms, flags);
}
return rval;
NAME is $1 from the bison rule. It is an IDENTIFIER_NODE.
VALUE is $$ from the bison rule. It is the value returned by lookup_name ($1)
- yychar is the pending input character (suitably encoded :-).
As a last ditch, try to look up the name as a label and return that
address.
compiler faster). */
tree
-hack_identifier (value, name, yychar)
+hack_identifier (value, name)
tree value, name;
- int yychar;
{
- tree type;
+ tree type, context;
if (TREE_CODE (value) == ERROR_MARK)
{
type = TREE_TYPE (value);
if (TREE_CODE (value) == FIELD_DECL)
{
- if (current_class_decl == NULL_TREE)
+ if (current_class_ptr == NULL_TREE)
{
error ("request for member `%s' in static member function",
IDENTIFIER_POINTER (DECL_NAME (value)));
return error_mark_node;
}
- TREE_USED (current_class_decl) = 1;
- if (yychar == '(')
- if (! ((TYPE_LANG_SPECIFIC (type)
- && TYPE_OVERLOADS_CALL_EXPR (type))
- || (TREE_CODE (type) == REFERENCE_TYPE
- && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
- && TYPE_OVERLOADS_CALL_EXPR (TREE_TYPE (type))))
- && TREE_CODE (type) != FUNCTION_TYPE
- && TREE_CODE (type) != METHOD_TYPE
- && !TYPE_PTRMEMFUNC_P (type)
- && (TREE_CODE (type) != POINTER_TYPE
- || (TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE
- && TREE_CODE (TREE_TYPE (type)) != METHOD_TYPE)))
- {
- error ("component `%s' is not a method",
- IDENTIFIER_POINTER (name));
- return error_mark_node;
- }
+ TREE_USED (current_class_ptr) = 1;
+
/* Mark so that if we are in a constructor, and then find that
this field was initialized by a base initializer,
we can emit an error message. */
TREE_USED (value) = 1;
- return build_component_ref (C_C_D, name, 0, 1);
+ value = build_component_ref (current_class_ref, name, NULL_TREE, 1);
}
-
- if (really_overloaded_fn (value))
+ else if (really_overloaded_fn (value))
{
+#if 0
tree t = get_first_fn (value);
- while (t)
+ for (; t; t = DECL_CHAIN (t))
{
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ continue;
+
assemble_external (t);
TREE_USED (t) = 1;
- t = DECL_CHAIN (t);
}
+#endif
}
else if (TREE_CODE (value) == TREE_LIST)
{
+ /* Ambiguous reference to base members, possibly other cases?. */
tree t = value;
while (t && TREE_CODE (t) == TREE_LIST)
{
- assemble_external (TREE_VALUE (t));
- TREE_USED (t) = 1;
+ mark_used (TREE_VALUE (t));
t = TREE_CHAIN (t);
}
}
else
+ mark_used (value);
+
+ if (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL)
{
- assemble_external (value);
- TREE_USED (value) = 1;
+ 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;
- enum access_type access;
+ tree path, access;
register tree context
= (TREE_CODE (value) == FUNCTION_DECL && DECL_VIRTUAL_P (value))
? DECL_CLASS_CONTEXT (value)
if (path)
{
access = compute_access (path, value);
- if (access != access_public)
+ if (access != access_public_node)
{
if (TREE_CODE (value) == VAR_DECL)
error ("static member `%s' is %s",
return value;
}
- if (TREE_CODE (type) == REFERENCE_TYPE)
- {
- my_friendly_assert (TREE_CODE (value) == VAR_DECL
- || TREE_CODE (value) == PARM_DECL
- || TREE_CODE (value) == RESULT_DECL, 252);
- if (DECL_REFERENCE_SLOT (value))
- return DECL_REFERENCE_SLOT (value);
- }
+ if (TREE_CODE (type) == REFERENCE_TYPE && ! processing_template_decl)
+ value = convert_from_reference (value);
return value;
}
\f
-#if 0
-/* Given an object OF, and a type conversion operator COMPONENT
- build a call to the conversion operator, if a call is requested,
- or return the address (as a pointer to member function) if one is not.
-
- OF can be a TYPE_DECL or any kind of datum that would normally
- be passed to `build_component_ref'. It may also be NULL_TREE,
- in which case `current_class_type' and `current_class_decl'
- provide default values.
-
- BASETYPE_PATH, if non-null, is the path of basetypes
- to go through before we get the the instance of interest.
-
- PROTECT says whether we apply C++ scoping rules or not. */
-tree
-build_component_type_expr (of, component, basetype_path, protect)
- tree of, component, basetype_path;
- int protect;
-{
- tree cname = NULL_TREE;
- tree tmp, last;
- tree name;
- int flags = protect ? LOOKUP_NORMAL : LOOKUP_COMPLAIN;
-
- if (of)
- my_friendly_assert (IS_AGGR_TYPE (TREE_TYPE (of)), 253);
- my_friendly_assert (TREE_CODE (component) == TYPE_EXPR, 254);
-
- tmp = TREE_OPERAND (component, 0);
- last = NULL_TREE;
-
- while (tmp)
- {
- switch (TREE_CODE (tmp))
- {
- case CALL_EXPR:
- if (last)
- TREE_OPERAND (last, 0) = TREE_OPERAND (tmp, 0);
- else
- TREE_OPERAND (component, 0) = TREE_OPERAND (tmp, 0);
-
- last = groktypename (build_tree_list (TREE_TYPE (component),
- TREE_OPERAND (component, 0)));
- name = build_typename_overload (last);
- TREE_TYPE (name) = last;
-
- if (TREE_OPERAND (tmp, 0)
- && TREE_OPERAND (tmp, 0) != void_list_node)
- {
- cp_error ("`operator %T' requires empty parameter list", last);
- TREE_OPERAND (tmp, 0) = NULL_TREE;
- }
-
- if (of && TREE_CODE (of) != TYPE_DECL)
- return build_method_call (of, name, NULL_TREE, NULL_TREE, flags);
- else if (of)
- {
- tree this_this;
-
- if (current_class_decl == NULL_TREE)
- {
- cp_error ("object required for `operator %T' call",
- TREE_TYPE (name));
- return error_mark_node;
- }
-
- this_this = convert_pointer_to (TREE_TYPE (of),
- current_class_decl);
- this_this = build_indirect_ref (this_this, NULL_PTR);
- return build_method_call (this_this, name, NULL_TREE,
- NULL_TREE, flags | LOOKUP_NONVIRTUAL);
- }
- else if (current_class_decl)
- return build_method_call (tmp, name, NULL_TREE, NULL_TREE, flags);
-
- cp_error ("object required for `operator %T' call",
- TREE_TYPE (name));
- return error_mark_node;
-
- case INDIRECT_REF:
- case ADDR_EXPR:
- case ARRAY_REF:
- break;
-
- case SCOPE_REF:
- my_friendly_assert (cname == 0, 255);
- cname = TREE_OPERAND (tmp, 0);
- tmp = TREE_OPERAND (tmp, 1);
- break;
-
- default:
- my_friendly_abort (77);
- }
- last = tmp;
- tmp = TREE_OPERAND (tmp, 0);
- }
-
- last = groktypename (build_tree_list (TREE_TYPE (component), TREE_OPERAND (component, 0)));
- name = build_typename_overload (last);
- TREE_TYPE (name) = last;
- if (of && TREE_CODE (of) == TYPE_DECL)
- {
- if (cname == NULL_TREE)
- {
- cname = DECL_NAME (of);
- of = NULL_TREE;
- }
- else my_friendly_assert (cname == DECL_NAME (of), 256);
- }
-
- if (of)
- {
- tree this_this;
-
- if (current_class_decl == NULL_TREE)
- {
- cp_error ("object required for `operator %T' call",
- TREE_TYPE (name));
- return error_mark_node;
- }
-
- this_this = convert_pointer_to (TREE_TYPE (of), current_class_decl);
- return build_component_ref (this_this, name, 0, protect);
- }
- else if (cname)
- return build_offset_ref (cname, name);
- else if (current_class_name)
- return build_offset_ref (current_class_name, name);
-
- cp_error ("object required for `operator %T' member reference",
- TREE_TYPE (name));
- return error_mark_node;
-}
-#endif
-\f
static char *
thunk_printable_name (decl)
tree decl;
if (TREE_CODE (func_decl) != FUNCTION_DECL)
abort ();
func_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func_decl));
- sprintf (buffer, "__thunk_%d_%s", -delta, func_name);
+ if (delta<=0)
+ sprintf (buffer, "__thunk_%d_%s", -delta, func_name);
+ else
+ sprintf (buffer, "__thunk_n%d_%s", delta, func_name);
thunk_id = get_identifier (buffer);
thunk = IDENTIFIER_GLOBAL_VALUE (thunk_id);
if (thunk && TREE_CODE (thunk) != THUNK_DECL)
{
- error_with_decl ("implementation-reserved name `%s' used");
+ cp_error ("implementation-reserved name `%D' used", thunk_id);
IDENTIFIER_GLOBAL_VALUE (thunk_id) = thunk = NULL_TREE;
}
if (thunk == NULL_TREE)
{
- thunk = build_decl (THUNK_DECL, thunk_id, TREE_TYPE (func_decl));
+ thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl));
DECL_RESULT (thunk)
- = build_decl (RESULT_DECL, NULL_TREE, TREE_TYPE (vtable_entry_type));
+ = 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);
+ comdat_linkage (thunk);
+ TREE_SET_CODE (thunk, THUNK_DECL);
DECL_INITIAL (thunk) = function;
THUNK_DELTA (thunk) = delta;
+ DECL_EXTERNAL (thunk) = 1;
/* So that finish_file can write out any thunks that need to be: */
pushdecl_top_level (thunk);
}
tree thunk_fndecl;
{
rtx insns;
- char *fnname;
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 current_call_is_indirect = 0; /* needed for HPPA FUNCTION_ARG */
+ int save_ofp;
- /* Used to remember which regs we need to emit a USE rtx for. */
+ /* 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 for the 'this' parameter. */
rtx this_rtx = 0, this_reg_rtx = 0, fixed_this_rtx;
char *(*save_decl_printable_name) () = decl_printable_name;
TREE_ASM_WRITTEN (thunk_fndecl) = 1;
- if (TREE_PUBLIC (function))
- {
- TREE_PUBLIC (thunk_fndecl) = 1;
- if (DECL_EXTERNAL (function))
- {
- DECL_EXTERNAL (thunk_fndecl) = 1;
- assemble_external (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);
+ 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. */
+ 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))
emit_insn (gen_rtx (USE, VOIDmode, need_use[--need_use_count]));
expand_end_bindings (NULL, 1, 0);
- poplevel (0, 0, 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.
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 turn the rtl into assembler code. */
- {
- char *fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
- assemble_start_function (thunk_fndecl, fnname);
- final (insns, asm_out_file, optimize, 0);
- assemble_end_function (thunk_fndecl, fnname);
- };
-
- exit_rest_of_compilation:
+ 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. */
- resume_temporary_allocation ();
+ permanent_allocation (1);
+ flag_omit_frame_pointer = save_ofp;
+#endif /* ASM_OUTPUT_MI_THUNK */
+ TREE_SET_CODE (thunk_fndecl, THUNK_DECL);
decl_printable_name = save_decl_printable_name;
current_function_decl = 0;
}
+\f
+/* Code for synthesizing methods which have default semantics defined. */
+
+/* For the anonymous union in TYPE, return the member that is at least as
+ large as the rest of the members, so we can copy it. */
+
+static tree
+largest_union_member (type)
+ tree type;
+{
+ tree f, type_size = TYPE_SIZE (type);
+
+ for (f = TYPE_FIELDS (type); f; f = TREE_CHAIN (f))
+ if (simple_cst_equal (DECL_SIZE (f), type_size) == 1)
+ return f;
+
+ /* We should always find one. */
+ my_friendly_abort (323);
+ return NULL_TREE;
+}
+
+/* Generate code for default X(X&) constructor. */
+
+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))
+ {
+ t = build (INIT_EXPR, void_type_node, current_class_ref, parm);
+ TREE_SIDE_EFFECTS (t) = 1;
+ cplus_expand_expr_stmt (t);
+ }
+ else
+ {
+ tree fields = TYPE_FIELDS (current_class_type);
+ int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
+ tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
+ int i;
+
+ for (t = CLASSTYPE_VBASECLASSES (current_class_type); t;
+ t = TREE_CHAIN (t))
+ {
+ tree basetype = BINFO_TYPE (t);
+ tree p = convert_to_reference
+ (build_reference_type (basetype), parm,
+ CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
+ p = convert_from_reference (p);
+
+ if (p == error_mark_node)
+ cp_error ("in default copy constructor");
+ else
+ current_base_init_list = tree_cons (basetype,
+ p, current_base_init_list);
+ }
+
+ for (i = 0; i < n_bases; ++i)
+ {
+ tree p, basetype = TREE_VEC_ELT (binfos, i);
+ if (TREE_VIA_VIRTUAL (basetype))
+ continue;
+
+ basetype = BINFO_TYPE (basetype);
+ p = convert_to_reference
+ (build_reference_type (basetype), parm,
+ CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
+
+ if (p == error_mark_node)
+ cp_error ("in default copy constructor");
+ else
+ {
+ p = convert_from_reference (p);
+ current_base_init_list = tree_cons (basetype,
+ p, current_base_init_list);
+ }
+ }
+ for (; fields; fields = TREE_CHAIN (fields))
+ {
+ tree name, init, t;
+ tree field = fields;
+
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+ if (DECL_NAME (field))
+ {
+ if (VFIELD_NAME_P (DECL_NAME (field)))
+ continue;
+ if (VBASE_NAME_P (DECL_NAME (field)))
+ continue;
+
+ /* True for duplicate members. */
+ if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field)
+ continue;
+ }
+ else if ((t = TREE_TYPE (field)) != NULL_TREE
+ && TREE_CODE (t) == UNION_TYPE
+ && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && TYPE_FIELDS (t) != NULL_TREE)
+ field = largest_union_member (t);
+ else
+ continue;
+
+ init = build (COMPONENT_REF, TREE_TYPE (field), parm, 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 ();
+}
+
+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))
+ {
+ 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_tree_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 (TREE_READONLY (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;
+ }
+
+ if (DECL_NAME (field))
+ {
+ if (VFIELD_NAME_P (DECL_NAME (field)))
+ continue;
+ if (VBASE_NAME_P (DECL_NAME (field)))
+ continue;
+
+ /* True for duplicate members. */
+ if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field)
+ continue;
+ }
+ else if ((t = TREE_TYPE (field)) != NULL_TREE
+ && TREE_CODE (t) == UNION_TYPE
+ && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && TYPE_FIELDS (t) != NULL_TREE)
+ field = largest_union_member (t);
+ else
+ continue;
+
+ comp = build (COMPONENT_REF, TREE_TYPE (field), current_class_ref, field);
+ init = build (COMPONENT_REF, TREE_TYPE (field), parm, 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);
+ tree base = DECL_CLASS_CONTEXT (fndecl);
+
+ if (nested)
+ push_cp_function_context (context);
+
+ interface_unknown = 1;
+ start_function (NULL_TREE, fndecl, NULL_TREE, 1);
+ store_parm_decls ();
+
+ if (DECL_NAME (fndecl) == ansi_opname[MODIFY_EXPR])
+ do_build_assign_ref (fndecl);
+ else if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+ ;
+ else
+ {
+ tree arg_chain = FUNCTION_ARG_CHAIN (fndecl);
+ if (DECL_CONSTRUCTOR_FOR_VBASE_P (fndecl))
+ arg_chain = TREE_CHAIN (arg_chain);
+ if (arg_chain != void_list_node)
+ do_build_copy_constructor (fndecl);
+ else if (TYPE_NEEDS_CONSTRUCTING (current_class_type))
+ setup_vtbl_ptr ();
+ }
+
+ finish_function (lineno, 0, nested);
+
+ /* 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)
+ pop_cp_function_context (context);
+}